mirror of
https://github.com/Evolution-X-Devices/device_google_wahoo
synced 2026-02-01 07:50:47 +00:00
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
This commit is contained in:
77
usb/Usb.cpp
77
usb/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
|
||||
|
||||
Reference in New Issue
Block a user