USB HAL: Bind UDC to ConfigFS when re-added
Upon role switch to host mode, the upstream DWC3 driver completely
removes the UDC device. If a composition switch then occurs, the
ConfigFS driver cannot bind to the UDC as it is not present.
For ADB-enabled compositions this is mitigated because the ADBD
daemon has a retry mechanism and will trigger sys.usb.ffs.ready=1
on each attempt which will kick init.qcom.usb.rc rules to re-execute
the composition rules (or MonitorFfs if UsbGadget HAL is used).
However for non-ADB compositions, there is no mechanism to attempt
to re-bind the UDC once the controller role is switched back to
device mode, causing enumeration failure as there is no active
gadget driver. Fix this by performing the bind write in the HAL's
uevent handler upon UDC device add. While at it, consolidate this to
occur with the sys.usb.adb.disabled property handling which occurs
similarly upon UDC add/removal.
Change-Id: Ic2df76d83d8b7d0d138cbb72c42564617708accc
diff --git a/hal/Usb.cpp b/hal/Usb.cpp
index df858e7..8a4afae 100644
--- a/hal/Usb.cpp
+++ b/hal/Usb.cpp
@@ -729,10 +729,8 @@
"usb\\d/\\d-\\d(?:/[\\d\\.-]+)*)");
static std::regex bind_regex("bind@(/devices/platform/soc/.*dwc3/xhci-hcd\\.\\d\\.auto/"
"usb\\d/\\d-\\d(?:/[\\d\\.-]+)*)/([^/]*:[^/]*)");
- static std::regex host_regex("add@/devices/platform/soc/.*" + gadgetName +
- "/xhci-hcd\\.\\d\\.auto");
- static std::regex peripheral_regex("remove@/devices/platform/soc/.*" + gadgetName +
- "/xhci-hcd\\.\\d\\.auto");
+ static std::regex udc_regex("(add|remove)@/devices/platform/soc/.*/" + gadgetName +
+ "/udc/" + gadgetName);
n = uevent_kernel_multicast_recv(payload->uevent_fd, msg, UEVENT_MSG_LEN);
if (n <= 0) return;
@@ -759,10 +757,27 @@
std::csub_match intfpath = match[2];
checkUsbInterfaceAutoSuspend("/sys" + devpath.str(), intfpath.str());
}
- } else if (std::regex_match(msg, host_regex)) {
- SetProperty(VENDOR_USB_ADB_DISABLED_PROP, "1");
- } else if (std::regex_match(msg, peripheral_regex)) {
- SetProperty(VENDOR_USB_ADB_DISABLED_PROP, "0");
+ } else if (std::regex_match(msg, match, udc_regex)) {
+ if (!strncmp(msg, "add", 3)) {
+ // Allow ADBD to resume its FFS monitor thread
+ SetProperty(VENDOR_USB_ADB_DISABLED_PROP, "0");
+
+ // In case ADB is not enabled, we need to manually re-bind the UDC to
+ // ConfigFS since ADBD is not there to trigger it (sys.usb.ffs.ready=1)
+ if (GetProperty("init.svc.adbd", "") != "running") {
+ ALOGI("Binding UDC %s to ConfigFS", gadgetName.c_str());
+ writeFile("/config/usb_gadget/g1/UDC", gadgetName);
+ }
+
+ } else {
+ // When the UDC is removed, the ConfigFS gadget will no longer be
+ // bound. If ADBD is running it would keep opening/writing to its
+ // FFS EP0 file but since FUNCTIONFS_BIND doesn't happen it will
+ // just keep repeating this in a 1 second retry loop. Each iteration
+ // will re-trigger a ConfigFS UDC bind which will keep failing.
+ // Setting this property stops ADBD from proceeding with the retry.
+ SetProperty(VENDOR_USB_ADB_DISABLED_PROP, "1");
+ }
}
}