diff options
| author | Yueyao Zhu <yueyao@google.com> | 2017-06-28 12:13:28 -0700 |
|---|---|---|
| committer | Jan Altensen <info@stricted.net> | 2021-05-04 02:41:18 +0200 |
| commit | ed8b4608fccf395ed92a052160c461ccee94a283 (patch) | |
| tree | 5f18e5f11b4c170d6adf032c9f8a8b01cf16c03f | |
| parent | e5853236d47843784c742d1e4554538676610005 (diff) | |
lineage/interfaces: USB: HAL: enable auto suspend for USB headsets
Adds a thread that handles add uevents of USB devices, and
enables auto suspend on that USB device (i.e. set power/control
to auto) if the device idProduct/idVendor is whitelisted.
The android kernel will already autosuspend audio devices,
however this enables autosuspend for the Google USB-C to
3.5mm adapter, which presents an HID-only interface when
no 3.5mm headset is connected.
Test: with the selinux and .rc changes for access permission
- MIR without headset: power/control set to auto
- MIR with headset: power/control set to auto
- regular mouse: power/control set to on
Bug: 38352281
Change-Id: I81572584ea02f6bdc814e70ab3439ab86c34a50a
| -rw-r--r-- | usb/1.1-typec/Usb.cpp | 77 |
1 files changed, 75 insertions, 2 deletions
diff --git a/usb/1.1-typec/Usb.cpp b/usb/1.1-typec/Usb.cpp index 601c70b..3fc188e 100644 --- a/usb/1.1-typec/Usb.cpp +++ b/usb/1.1-typec/Usb.cpp @@ -41,10 +41,15 @@ namespace usb { namespace V1_1 { namespace implementation { +const char GOOGLE_USB_VENDOR_ID_STR[] = "18d1"; +const char GOOGLE_USBC_35_ADAPTER_UNPLUGGED_ID_STR[] = "5029"; + // Set by the signal handler to destroy the thread volatile bool destroyThread; -int32_t readFile(const std::string &filename, std::string *contents) { +static void checkUsbDeviceAutoSuspend(const std::string& devicePath); + +static int32_t readFile(const std::string &filename, std::string *contents) { FILE *fp; ssize_t read = 0; char *line = NULL; @@ -61,7 +66,28 @@ int32_t readFile(const std::string &filename, std::string *contents) { fclose(fp); return 0; } else { - ALOGE("fopen failed"); + ALOGE("fopen failed in readFile %s, errno=%d", filename.c_str(), errno); + } + + return -1; +} + +static int32_t writeFile(const std::string &filename, + const std::string &contents) { + FILE *fp; + int ret; + + fp = fopen(filename.c_str(), "w"); + if (fp != NULL) { + ret = fputs(contents.c_str(), fp); + fclose(fp); + if (ret == EOF) { + ALOGE("fputs failed in writeFile %s", filename.c_str()); + return -1; + } + return 0; + } else { + ALOGE("fopen failed in writeFile %s, errno=%d", filename.c_str(), errno); } return -1; @@ -501,6 +527,7 @@ static void uevent_event(uint32_t /*epevents*/, struct data *payload) { cp = msg; while (*cp) { + std::cmatch match; if (std::regex_match(cp, std::regex("(add)(.*)(-partner)"))) { ALOGI("partner added"); pthread_mutex_lock(&payload->usb->mPartnerLock); @@ -558,7 +585,15 @@ static void uevent_event(uint32_t /*epevents*/, struct data *payload) { pthread_mutex_unlock(&payload->usb->mRoleSwitchLock); } break; + } else if (std::regex_match(cp, match, + std::regex("add@(/devices/soc/a800000\\.ssusb/a800000\\.dwc3/xhci-hcd\\.0\\.auto/" + "usb\\d/\\d-\\d)/.*"))) { + if (match.size() == 2) { + std::csub_match submatch = match[1]; + checkUsbDeviceAutoSuspend("/sys" + submatch.str()); + } } + /* advance to after the next \0 */ while (*cp++) {} } @@ -689,6 +724,44 @@ Return<void> Usb::setCallback(const sp<V1_0::IUsbCallback> &callback) { return Void(); } +/* + * whitelisting USB device idProduct and idVendor to allow auto suspend. + */ +static bool canProductAutoSuspend(const std::string &deviceIdVendor, + const std::string &deviceIdProduct) { + if (deviceIdVendor == GOOGLE_USB_VENDOR_ID_STR && + deviceIdProduct == GOOGLE_USBC_35_ADAPTER_UNPLUGGED_ID_STR) { + return true; + } + return false; +} + +static bool canUsbDeviceAutoSuspend(const std::string &devicePath) { + std::string deviceIdVendor; + std::string deviceIdProduct; + readFile(devicePath + "/idVendor", &deviceIdVendor); + readFile(devicePath + "/idProduct", &deviceIdProduct); + + // deviceIdVendor and deviceIdProduct will be empty strings if readFile fails + return canProductAutoSuspend(deviceIdVendor, deviceIdProduct); +} + +/* + * function to consume USB device plugin events (on receiving a + * USB device path string), and enable autosupend on the USB device if + * necessary. + */ +void checkUsbDeviceAutoSuspend(const std::string& devicePath) { + /* + * Currently we only actively enable devices that should be autosuspended, and leave others + * to the defualt. + */ + if (canUsbDeviceAutoSuspend(devicePath)) { + ALOGI("auto suspend usb device %s", devicePath.c_str()); + writeFile(devicePath + "/power/control", "auto"); + } +} + } // namespace implementation } // namespace V1_0 } // namespace usb |
