Merge "Usb: Listen to USB sysfs attribute for device state" into main

This commit is contained in:
Roy Luo 2023-08-10 04:33:29 +00:00 committed by Android (Google) Code Review
commit 46e7663fab
2 changed files with 186 additions and 24 deletions

View file

@ -88,10 +88,15 @@ constexpr char kPogoUsbActive[] = "/sys/devices/platform/google,pogo/pogo_usb_ac
constexpr char kPogoEnableUsb[] = "/sys/devices/platform/google,pogo/enable_usb"; constexpr char kPogoEnableUsb[] = "/sys/devices/platform/google,pogo/enable_usb";
constexpr char kPowerSupplyUsbType[] = "/sys/class/power_supply/usb/usb_type"; constexpr char kPowerSupplyUsbType[] = "/sys/class/power_supply/usb/usb_type";
constexpr char kIrqHpdCounPath[] = "-0025/irq_hpd_count"; constexpr char kIrqHpdCounPath[] = "-0025/irq_hpd_count";
constexpr char kUdcState[] = "/sys/devices/platform/11210000.usb/11210000.dwc3/udc/11210000.dwc3/state";
// xhci-hcd-exynos and usb device numbering could vary on different platforms
constexpr char kHostUeventRegex[] = "^(bind|unbind)@(/devices/platform/11210000\\.usb/11210000\\.dwc3/xhci-hcd-exynos\\.[0-9]\\.auto/)usb([0-9])/[0-9]-0:1\\.0";
constexpr int kSamplingIntervalSec = 5; constexpr int kSamplingIntervalSec = 5;
void queryVersionHelper(android::hardware::usb::Usb *usb, void queryVersionHelper(android::hardware::usb::Usb *usb,
std::vector<PortStatus> *currentPortStatus); std::vector<PortStatus> *currentPortStatus);
#define USB_STATE_MAX_LEN 20
ScopedAStatus Usb::enableUsbData(const string& in_portName, bool in_enable, ScopedAStatus Usb::enableUsbData(const string& in_portName, bool in_enable,
int64_t in_transactionId) { int64_t in_transactionId) {
bool result = true; bool result = true;
@ -942,13 +947,114 @@ enum UeventType matchUeventType(char* str) {
return UeventType::UNKNOWN; return UeventType::UNKNOWN;
} }
static void uevent_event(uint32_t /*epevents*/, struct data *payload) { static void unregisterEpollEntry(Usb *usb, std::string name) {
std::map<std::string, struct Usb::epollEntry> *map;
int fd;
map = &usb->mEpollEntries;
auto it = map->find(name);
if (it != map->end()) {
ALOGI("epoll unregister %s", name.c_str());
fd = it->second.payload.fd;
epoll_ctl(usb->mEpollFd, EPOLL_CTL_DEL, fd, NULL);
close(fd);
map->erase(it);
}
}
static void unregisterEpollEntries(Usb *usb) {
std::map<std::string, struct Usb::epollEntry> *map;
std::string name;
map = &usb->mEpollEntries;
for (auto it = map->begin(); it != map->end();) {
name = it->first;
it++;
unregisterEpollEntry(usb, name);
}
}
static int registerEpollEntry(Usb *usb, std::string name, int fd, int flags,
void (*func)(uint32_t, struct Usb::payload*)) {
std::map<std::string, struct Usb::epollEntry> *map;
struct Usb::epollEntry *entry;
struct epoll_event ev;
map = &usb->mEpollEntries;
if (map->find(name) != map->end()) {
ALOGE("%s already registered", name.c_str());
unregisterEpollEntry(usb, name);
}
entry = &(*map)[name];
entry->payload.fd = fd;
entry->payload.name = name;
entry->payload.usb = usb;
entry->cb = std::bind(func, std::placeholders::_1, &entry->payload);
ev.events = flags;
ev.data.ptr = (void *)&entry->cb;
if (epoll_ctl(usb->mEpollFd, EPOLL_CTL_ADD, fd, &ev) != 0) {
ALOGE("epoll_ctl failed; errno=%d", errno);
unregisterEpollEntry(usb, name);
return -1;
}
ALOGI("epoll register %s", name.c_str());
return 0;
}
static int registerEpollEntryByFile(Usb *usb, std::string name, int flags,
void (*func)(uint32_t, struct Usb::payload*)) {
int fd;
fd = open(name.c_str(), O_RDONLY);
if (fd < 0) {
ALOGE("Cannot open %s", name.c_str());
return -1;
}
return registerEpollEntry(usb, name, fd, flags, func);
}
static void clearUsbDeviceState(struct Usb::usbDeviceState *device) {
device->latestState.clear();
device->portResetCount = 0;
}
static void updateUsbDeviceState(struct Usb::usbDeviceState *device, char *state) {
ALOGI("Update USB device state: %s", state);
device->latestState = state;
if (!std::strcmp(state, "configured\n")) {
device->portResetCount = 0;
} else if (!std::strcmp(state, "default\n")) {
device->portResetCount++;
}
}
static void host_event(uint32_t /*epevents*/, struct Usb::payload *payload) {
int n;
char state[USB_STATE_MAX_LEN] = {0};
struct Usb::usbDeviceState *device;
lseek(payload->fd, 0, SEEK_SET);
n = read(payload->fd, &state, USB_STATE_MAX_LEN);
updateUsbDeviceState(&payload->usb->mHostStateMap[payload->name], state);
}
static void uevent_event(uint32_t /*epevents*/, struct Usb::payload *payload) {
char msg[UEVENT_MSG_LEN + 2]; char msg[UEVENT_MSG_LEN + 2];
char *cp; char *cp;
int n; int n;
enum UeventType uevent_type = UeventType::UNKNOWN; enum UeventType uevent_type = UeventType::UNKNOWN;
std::cmatch match;
n = uevent_kernel_multicast_recv(payload->uevent_fd, msg, UEVENT_MSG_LEN); n = uevent_kernel_multicast_recv(payload->fd, msg, UEVENT_MSG_LEN);
if (n <= 0) if (n <= 0)
return; return;
if (n >= UEVENT_MSG_LEN) /* overflow -- discard */ if (n >= UEVENT_MSG_LEN) /* overflow -- discard */
@ -1016,6 +1122,29 @@ static void uevent_event(uint32_t /*epevents*/, struct data *payload) {
pthread_mutex_unlock(&payload->usb->mDisplayPortLock); pthread_mutex_unlock(&payload->usb->mDisplayPortLock);
} }
break; break;
} else if (std::regex_match(cp, match, std::regex(kHostUeventRegex))) {
/*
* Matched strings:
* 1st: entire string
* 2nd: uevent action, either "bind" or "unbind"
* 3rd: xhci device path, e.g. devices/platform/11210000.usb/11210000.dwc3/xhci-hcd-exynos.4.auto
* 4th: usb device number, e.g. 1 for usb1
*
* The strings are used to composed usb device state path, e.g.
* /sys/devices/platform/11210000.usb/11210000.dwc3/xhci-hcd-exynos.4.auto/usb2/2-0:1.0/usb2-port1/state
*/
if (match.size() == 4) {
std::string action = match[1].str();
std::string id = match[3].str();
std::string path = "/sys" + match[2].str() + "usb" + id + "/" +
id + "-0:1.0/usb" + id + "-port1/state";
if (action == "bind") {
registerEpollEntryByFile(payload->usb, path, EPOLLPRI, host_event);
} else if (action == "unbind") {
unregisterEpollEntry(payload->usb, path);
clearUsbDeviceState(&payload->usb->mHostStateMap[path]);
}
}
} }
/* advance to after the next \0 */ /* advance to after the next \0 */
while (*cp++) { while (*cp++) {
@ -1023,37 +1152,46 @@ static void uevent_event(uint32_t /*epevents*/, struct data *payload) {
} }
} }
static void udc_event(uint32_t /*epevents*/, struct Usb::payload *payload) {
int n;
char state[USB_STATE_MAX_LEN] = {0};
lseek(payload->fd, 0, SEEK_SET);
n = read(payload->fd, &state, USB_STATE_MAX_LEN);
updateUsbDeviceState(&payload->usb->mDeviceState, state);
}
void *work(void *param) { void *work(void *param) {
int epoll_fd, uevent_fd; int epoll_fd, uevent_fd;
struct epoll_event ev;
int nevents = 0; int nevents = 0;
struct data payload; Usb *usb = (Usb *)param;
ALOGE("creating thread"); ALOGE("creating thread");
uevent_fd = uevent_open_socket(64 * 1024, true);
if (uevent_fd < 0) {
ALOGE("uevent_init: uevent_open_socket failed\n");
return NULL;
}
payload.uevent_fd = uevent_fd;
payload.usb = (::aidl::android::hardware::usb::Usb *)param;
fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
ev.events = EPOLLIN;
ev.data.ptr = (void *)uevent_event;
epoll_fd = epoll_create(64); epoll_fd = epoll_create(64);
if (epoll_fd == -1) { if (epoll_fd == -1) {
ALOGE("epoll_create failed; errno=%d", errno); ALOGE("epoll_create failed; errno=%d", errno);
return NULL;
}
usb->mEpollFd = epoll_fd;
// Monitor uevent
uevent_fd = uevent_open_socket(64 * 1024, true);
if (uevent_fd < 0) {
ALOGE("uevent_init: uevent_open_socket failed");
goto error;
}
fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
if (registerEpollEntry(usb, "uevent", uevent_fd, EPOLLIN, uevent_event)) {
ALOGE("failed to monitor uevent");
goto error; goto error;
} }
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, uevent_fd, &ev) == -1) { // Monitor udc state
ALOGE("epoll_ctl failed; errno=%d", errno); if (registerEpollEntryByFile(usb, kUdcState, EPOLLPRI, udc_event)) {
ALOGE("failed to monitor udc state");
goto error; goto error;
} }
@ -1070,14 +1208,15 @@ void *work(void *param) {
for (int n = 0; n < nevents; ++n) { for (int n = 0; n < nevents; ++n) {
if (events[n].data.ptr) if (events[n].data.ptr)
(*(void (*)(int, struct data *payload))events[n].data.ptr)(events[n].events, (*(std::function<void(uint32_t)>*)events[n].data.ptr)(events[n].events);
&payload);
} }
} }
ALOGI("exiting worker thread"); ALOGI("exiting worker thread");
error: error:
close(uevent_fd); unregisterEpollEntries(usb);
usb->mEpollFd = -1;
if (epoll_fd >= 0) if (epoll_fd >= 0)
close(epoll_fd); close(epoll_fd);

View file

@ -121,6 +121,29 @@ struct Usb : public BnUsb {
pthread_mutex_t mDisplayPortLock; pthread_mutex_t mDisplayPortLock;
// eventfd to signal DisplayPort thread // eventfd to signal DisplayPort thread
int mDisplayPortEventPipe; int mDisplayPortEventPipe;
// USB device state monitoring
struct usbDeviceState {
std::string latestState;
int portResetCount;
};
struct usbDeviceState mDeviceState;
// Map host device path name to usbDeviceState
std::map<std::string, struct usbDeviceState> mHostStateMap;
// File monitoring through epoll
int mEpollFd;
struct payload {
int fd;
std::string name;
Usb *usb;
};
struct epollEntry {
struct payload payload;
std::function<void(uint32_t)> cb;
};
std::map<std::string, struct epollEntry> mEpollEntries;
private: private:
pthread_t mPoll; pthread_t mPoll;
pthread_t mDisplayPortPoll; pthread_t mDisplayPortPoll;