Merge "Usb: Listen to USB sysfs attribute for device state" into main
This commit is contained in:
commit
46e7663fab
2 changed files with 186 additions and 24 deletions
187
usb/usb/Usb.cpp
187
usb/usb/Usb.cpp
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue