summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--payloads/libpayload/drivers/usb/usbhub.c22
1 files changed, 21 insertions, 1 deletions
diff --git a/payloads/libpayload/drivers/usb/usbhub.c b/payloads/libpayload/drivers/usb/usbhub.c
index f75141eae5..340e47ae3d 100644
--- a/payloads/libpayload/drivers/usb/usbhub.c
+++ b/payloads/libpayload/drivers/usb/usbhub.c
@@ -158,6 +158,21 @@ static const generic_hub_ops_t usb_hub_ops = {
.reset_port = generic_hub_resetport,
};
+/* Clear CSC if set and enumerate port if it's connected regardless of change
+ bits. Some broken hubs don't set CSC if already connected during reset. */
+static void
+usb_hub_port_initialize(usbdev_t *const dev, const int port)
+{
+ unsigned short buf[2];
+ int ret = get_status(dev, port, DR_PORT, sizeof(buf), buf);
+ if (ret < 0)
+ return;
+ if (buf[1] & PORT_CONNECTION)
+ clear_feature(dev, port, SEL_C_PORT_CONNECTION, DR_PORT);
+ if (buf[0] & PORT_CONNECTION)
+ generic_hub_scanport(dev, port);
+}
+
void
usb_hub_init(usbdev_t *const dev)
{
@@ -172,5 +187,10 @@ usb_hub_init(usbdev_t *const dev)
if (dev->speed == SUPER_SPEED)
usb_hub_set_hub_depth(dev);
- generic_hub_init(dev, desc.bNbrPorts, &usb_hub_ops);
+ if (generic_hub_init(dev, desc.bNbrPorts, &usb_hub_ops) < 0)
+ return;
+
+ int port;
+ for (port = 1; port <= GEN_HUB(dev)->num_ports; ++port)
+ usb_hub_port_initialize(dev, port);
}