Forráskód Böngészése

update(hub): update hub macros and hub params for usb3.0

sakumisu 1 éve
szülő
commit
e4b56cee89
7 módosított fájl, 198 hozzáadás és 87 törlés
  1. 1 0
      README.md
  2. 1 0
      README_zh.md
  3. 72 24
      class/hub/usb_hub.h
  4. 104 51
      class/hub/usbh_hub.c
  5. 0 4
      class/hub/usbh_hub.h
  6. 8 6
      core/usbh_core.c
  7. 12 2
      core/usbh_core.h

+ 1 - 0
README.md

@@ -87,6 +87,7 @@ The CherryUSB Host Stack has a standard enumeration implementation for devices m
 
 CherryUSB Host Stack has the following functions:
 
+- Support low speed, full speed, high speed and super speed devices
 - Automatic loading of supported Class drivers
 - Support blocking transfers and asynchronous transfers
 - Support Composite Device

+ 1 - 0
README_zh.md

@@ -87,6 +87,7 @@ CherryUSB Host 协议栈对挂载在 roothub、外部 hub 上的设备规范了
 
 CherryUSB Host 协议栈当前实现以下功能:
 
+- 支持 low speed, full speed, high speed 和 super speed 设备
 - 自动加载支持的Class 驱动
 - 支持阻塞式传输和异步传输
 - 支持复合设备

+ 72 - 24
class/hub/usb_hub.h

@@ -10,6 +10,12 @@
 #define HUB_DESCRIPTOR_TYPE_HUB  0x29
 #define HUB_DESCRIPTOR_TYPE_HUB3 0x2A
 
+#define HUB_MAX_DEPTH 5
+
+#define HUB_SUBCLASS     0x00
+#define HUB_PROTOCOL_STT 0x01
+#define HUB_PROTOCOL_MTT 0x02
+
 /* Hub class requests */
 #define HUB_REQUEST_GET_STATUS      USB_REQUEST_GET_STATUS
 #define HUB_REQUEST_CLEAR_FEATURE   USB_REQUEST_CLEAR_FEATURE
@@ -27,23 +33,31 @@
 #define HUB_FEATURE_HUB_C_OVERCURRENT (0x1)
 
 /* Port features */
-#define HUB_PORT_FEATURE_CONNECTION    (0x00)
-#define HUB_PORT_FEATURE_ENABLE        (0x01)
-#define HUB_PORT_FEATURE_SUSPEND       (0x02)
-#define HUB_PORT_FEATURE_OVERCURRENT   (0x03)
-#define HUB_PORT_FEATURE_RESET         (0x04)
-#define HUB_PORT_FEATURE_L1            (0x05)
-#define HUB_PORT_FEATURE_POWER         (0x08)
-#define HUB_PORT_FEATURE_LOWSPEED      (0x09)
-#define HUB_PORT_FEATURE_HIGHSPEED     (0x0a)
+#define HUB_PORT_FEATURE_CONNECTION  (0x00)
+#define HUB_PORT_FEATURE_ENABLE      (0x01)
+#define HUB_PORT_FEATURE_SUSPEND     (0x02)
+#define HUB_PORT_FEATURE_OVERCURRENT (0x03)
+#define HUB_PORT_FEATURE_RESET       (0x04)
+#define HUB_PORT_FEATURE_L1          (0x05) /* USB 2.0 only */
+
+#define HUB_PORT_FEATURE_POWER    (0x08) /* USB 2.0 only */
+#define HUB_PORT_FEATURE_POWER_SS (0x09) /* USB 3.0 only */
+/* This is a bit tricky because HUB_PORT_FEATURE_POWER_SS and
+   HUB_PORT_FEATURE_LOWSPEED share the same bit. */
+#define HUB_PORT_FEATURE_LOWSPEED  (0x09) /* USB 2.0 only */
+#define HUB_PORT_FEATURE_HIGHSPEED (0x0a) /* USB 2.0 only */
+#define HUB_PORT_FEATURE_TEST      (0x0b) /* USB 2.0 only */
+#define HUB_PORT_FEATURE_INDICATOR (0x0c) /* USB 2.0 only */
+
+/* Port status change (wPortChange) */
 #define HUB_PORT_FEATURE_C_CONNECTION  (0x10)
-#define HUB_PORT_FEATURE_C_ENABLE      (0x11)
-#define HUB_PORT_FEATURE_C_SUSPEND     (0x12)
+#define HUB_PORT_FEATURE_C_ENABLE      (0x11) /* USB 2.0 only */
+#define HUB_PORT_FEATURE_C_SUSPEND     (0x12) /* USB 2.0 only */
 #define HUB_PORT_FEATURE_C_OVER_CURREN (0x13)
 #define HUB_PORT_FEATURE_C_RESET       (0x14)
-#define HUB_PORT_FEATURE_TEST          (0x15)
-#define HUB_PORT_FEATURE_INDICATOR     (0x16)
-#define HUB_PORT_FEATURE_C_PORTL1      (0x17)
+#define HUB_PORT_FEATURE_C_BH_RESET    (0x15) /* USB 3.0 only */
+#define HUB_PORT_FEATURE_C_LINK_STATE  (0x16) /* USB 3.0 only */
+#define HUB_PORT_FEATURE_C_CONFIG_ERR  (0x17) /* USB 3.0 only */
 
 /* Hub status */
 #define HUB_STATUS_LOCALPOWER  (1 << 0)
@@ -56,23 +70,42 @@
 /* Hub port status */
 #define HUB_PORT_STATUS_CONNECTION  (1 << 0)
 #define HUB_PORT_STATUS_ENABLE      (1 << 1)
-#define HUB_PORT_STATUS_SUSPEND     (1 << 2)
+#define HUB_PORT_STATUS_SUSPEND     (1 << 2) /* USB 2.0 only */
 #define HUB_PORT_STATUS_OVERCURRENT (1 << 3)
 #define HUB_PORT_STATUS_RESET       (1 << 4)
-#define HUB_PORT_STATUS_L1          (1 << 5)
-#define HUB_PORT_STATUS_POWER       (1 << 8)
-#define HUB_PORT_STATUS_LOW_SPEED   (1 << 9)
-#define HUB_PORT_STATUS_HIGH_SPEED  (1 << 10)
-#define HUB_PORT_STATUS_TEST        (1 << 11)
-#define HUB_PORT_STATUS_INDICATOR   (1 << 12)
+#define HUB_PORT_STATUS_L1          (1 << 5) /* USB 2.0 only */
+
+/* Port Link State (PORT_LINK_STATE), USB 3.0 only */
+#define HUB_PORT_STATUS_LS_U0          (0x00 << 5)
+#define HUB_PORT_STATUS_LS_U1          (0x01 << 5)
+#define HUB_PORT_STATUS_LS_U2          (0x02 << 5)
+#define HUB_PORT_STATUS_LS_U3          (0x03 << 5)
+#define HUB_PORT_STATUS_LS_SS_DISABLED (0x04 << 5)
+#define HUB_PORT_STATUS_LS_RX_DETECT   (0x05 << 5)
+#define HUB_PORT_STATUS_LS_SS_INACTIVE (0x06 << 5)
+#define HUB_PORT_STATUS_LS_POLLING     (0x07 << 5)
+#define HUB_PORT_STATUS_LS_RECOVERY    (0x08 << 5)
+#define HUB_PORT_STATUS_LS_HOT_RESET   (0x09 << 5)
+#define HUB_PORT_STATUS_LS_COMP_MOD    (0x0a << 5)
+#define HUB_PORT_STATUS_LS_LOOPBACK    (0x0b << 5)
+
+#define HUB_PORT_STATUS_POWER      (1 << 8)
+#define HUB_PORT_STATUS_POWER_SS   (1 << 9)  /* USB 3.0 only */
+#define HUB_PORT_STATUS_LOW_SPEED  (1 << 9)  /* USB 2.0 only */
+#define HUB_PORT_STATUS_HIGH_SPEED (1 << 10) /* USB 2.0 only */
+#define HUB_PORT_STATUS_TEST       (1 << 11) /* USB 2.0 only */
+#define HUB_PORT_STATUS_INDICATOR  (1 << 12) /* USB 2.0 only */
 
 /* Hub port status change */
 #define HUB_PORT_STATUS_C_CONNECTION  (1 << 0)
-#define HUB_PORT_STATUS_C_ENABLE      (1 << 1)
-#define HUB_PORT_STATUS_C_SUSPEND     (1 << 2)
+#define HUB_PORT_STATUS_C_ENABLE      (1 << 1) /* USB 2.0 only */
+#define HUB_PORT_STATUS_C_SUSPEND     (1 << 2) /* USB 2.0 only */
 #define HUB_PORT_STATUS_C_OVERCURRENT (1 << 3)
 #define HUB_PORT_STATUS_C_RESET       (1 << 4)
-#define HUB_PORT_STATUS_C_L1          (1 << 5)
+#define HUB_PORT_STATUS_C_L1          (1 << 5) /* USB 2.0 only */
+#define HUB_PORT_STATUS_C_BH_RESET    (1 << 5) /* USB 3.0 only */
+#define HUB_PORT_STATUS_C_PORTLINK    (1 << 6) /* USB 3.0 only */
+#define HUB_PORT_STATUS_C_CONFIGERR   (1 << 7) /* USB 3.0 only */
 
 /* Hub characteristics */
 #define HUB_CHAR_LPSM_SHIFT      (0) /* Bits 0-1: Logical Power Switching Mode */
@@ -106,6 +139,21 @@ struct usb_hub_descriptor {
 
 #define USB_SIZEOF_HUB_DESC 9
 
+/* Super speed Hub descriptor */
+struct usb_hub_ss_descriptor {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint8_t bNbrPorts;
+    uint16_t wHubCharacteristics;
+    uint8_t bPwrOn2PwrGood;
+    uint8_t bHubContrCurrent;
+    uint8_t bHubHdrDecLat;
+    uint16_t wHubDelay;
+    uint8_t DeviceRemovable;
+} __PACKED;
+
+#define USB_SIZEOF_HUB_SS_DESC 11
+
 /* Hub status */
 struct hub_status {
     uint16_t wPortStatus;

+ 104 - 51
class/hub/usbh_hub.c

@@ -55,9 +55,7 @@ static void usbh_hub_class_free(struct usbh_hub *hub_class)
     }
     memset(hub_class, 0, sizeof(struct usbh_hub));
 }
-#endif
 
-#if CONFIG_USBHOST_MAX_EXTHUBS > 0
 static int _usbh_hub_get_hub_descriptor(struct usbh_hub *hub, uint8_t *buffer)
 {
     struct usb_setup_packet *setup;
@@ -67,15 +65,7 @@ static int _usbh_hub_get_hub_descriptor(struct usbh_hub *hub, uint8_t *buffer)
 
     setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_DEVICE;
     setup->bRequest = USB_REQUEST_GET_DESCRIPTOR;
-
-    /* TODO: hub descriptor has some difference between USB 2.0 and USB 3.x,
-       and we havn't handle the difference here */
-    if ((hub->parent->speed == USB_SPEED_SUPER) ||
-        (hub->parent->speed == USB_SPEED_SUPER_PLUS)) {
-        setup->wValue = HUB_DESCRIPTOR_TYPE_HUB3 << 8;
-    } else {
-        setup->wValue = HUB_DESCRIPTOR_TYPE_HUB << 8;
-    }
+    setup->wValue = HUB_DESCRIPTOR_TYPE_HUB << 8;
 
     setup->wIndex = 0;
     setup->wLength = USB_SIZEOF_HUB_DESC;
@@ -87,8 +77,8 @@ static int _usbh_hub_get_hub_descriptor(struct usbh_hub *hub, uint8_t *buffer)
     memcpy(buffer, g_hub_buf[hub->bus->busid], USB_SIZEOF_HUB_DESC);
     return ret;
 }
-#if 0
-static int _usbh_hub_get_status(struct usbh_hub *hub, uint8_t *buffer)
+
+static int _usbh_hub_get_hub_ss_descriptor(struct usbh_hub *hub, uint8_t *buffer)
 {
     struct usb_setup_packet *setup;
     int ret;
@@ -96,20 +86,20 @@ static int _usbh_hub_get_status(struct usbh_hub *hub, uint8_t *buffer)
     setup = hub->parent->setup;
 
     setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_DEVICE;
-    setup->bRequest = HUB_REQUEST_GET_STATUS;
-    setup->wValue = 0;
+    setup->bRequest = USB_REQUEST_GET_DESCRIPTOR;
+    setup->wValue = HUB_DESCRIPTOR_TYPE_HUB3 << 8;
+
     setup->wIndex = 0;
-    setup->wLength = 2;
+    setup->wLength = USB_SIZEOF_HUB_SS_DESC;
 
     ret = usbh_control_transfer(hub->parent, setup, g_hub_buf[hub->bus->busid]);
     if (ret < 0) {
         return ret;
     }
-    memcpy(buffer, g_hub_buf[hub->bus->busid], 2);
+    memcpy(buffer, g_hub_buf[hub->bus->busid], USB_SIZEOF_HUB_SS_DESC);
     return ret;
 }
 #endif
-#endif
 
 static int _usbh_hub_get_portstatus(struct usbh_hub *hub, uint8_t port, struct hub_port_status *port_status)
 {
@@ -199,6 +189,27 @@ static int parse_hub_descriptor(struct usb_hub_descriptor *desc, uint16_t length
     }
     return 0;
 }
+
+static int parse_hub_ss_descriptor(struct usb_hub_ss_descriptor *desc, uint16_t length)
+{
+    if (desc->bLength < USB_SIZEOF_HUB_SS_DESC) {
+        USB_LOG_ERR("invalid device bLength 0x%02x\r\n", desc->bLength);
+        return -1;
+    } else if (desc->bDescriptorType != HUB_DESCRIPTOR_TYPE_HUB3) {
+        USB_LOG_ERR("unexpected descriptor 0x%02x\r\n", desc->bDescriptorType);
+        return -2;
+    } else {
+        USB_LOG_RAW("SuperSpeed Hub Descriptor:\r\n");
+        USB_LOG_RAW("bLength: 0x%02x             \r\n", desc->bLength);
+        USB_LOG_RAW("bDescriptorType: 0x%02x     \r\n", desc->bDescriptorType);
+        USB_LOG_RAW("bNbrPorts: 0x%02x           \r\n", desc->bNbrPorts);
+        USB_LOG_RAW("wHubCharacteristics: 0x%04x \r\n", desc->wHubCharacteristics);
+        USB_LOG_RAW("bPwrOn2PwrGood: 0x%02x      \r\n", desc->bPwrOn2PwrGood);
+        USB_LOG_RAW("bHubContrCurrent: 0x%02x    \r\n", desc->bHubContrCurrent);
+        USB_LOG_RAW("DeviceRemovable: 0x%02x     \r\n", desc->DeviceRemovable);
+    }
+    return 0;
+}
 #endif
 
 static int usbh_hub_get_portstatus(struct usbh_hub *hub, uint8_t port, struct hub_port_status *port_status)
@@ -311,22 +322,65 @@ static int usbh_hub_connect(struct usbh_hubport *hport, uint8_t intf)
     hub->hub_addr = hport->dev_addr;
     hub->parent = hport;
     hub->bus = hport->bus;
+    hub->speed = hport->speed;
 
+    hport->self = hub;
     hport->config.intf[intf].priv = hub;
 
-    ret = _usbh_hub_get_hub_descriptor(hub, (uint8_t *)&hub->hub_desc);
-    if (ret < 0) {
-        return ret;
+    if (hport->depth > HUB_MAX_DEPTH) {
+        USB_LOG_ERR("Hub depth(%d) is overflow\r\n", hport->depth);
+        return -USB_ERR_INVAL;
     }
 
-    parse_hub_descriptor(&hub->hub_desc, USB_SIZEOF_HUB_DESC);
+    /*
+	 * Super-Speed hubs need to know their depth to be able to
+	 * parse the bits of the route-string that correspond to
+	 * their downstream port number.
+	 *
+	 */
+    if ((hport->depth != 0) && (hport->speed == USB_SPEED_SUPER)) {
+        ret = usbh_hub_set_depth(hub, hport->depth - 1);
+        if (ret < 0) {
+            USB_LOG_ERR("Unable to set hub depth \r\n");
+            return ret;
+        }
+    }
 
-    for (uint8_t port = 0; port < hub->hub_desc.bNbrPorts; port++) {
+    /* Get hub descriptor. */
+    if (hport->speed == USB_SPEED_SUPER) {
+        ret = _usbh_hub_get_hub_ss_descriptor(hub, (uint8_t *)&hub->hub_ss_desc);
+        if (ret < 0) {
+            return ret;
+        }
+
+        parse_hub_ss_descriptor(&hub->hub_ss_desc, USB_SIZEOF_HUB_SS_DESC);
+        hub->nports = hub->hub_ss_desc.bNbrPorts;
+        hub->powerdelay = hub->hub_ss_desc.bPwrOn2PwrGood * 2;
+        hub->tt_think = 0U;
+    } else {
+        ret = _usbh_hub_get_hub_descriptor(hub, (uint8_t *)&hub->hub_desc);
+        if (ret < 0) {
+            return ret;
+        }
+
+        parse_hub_descriptor(&hub->hub_desc, USB_SIZEOF_HUB_DESC);
+        hub->nports = hub->hub_desc.bNbrPorts;
+        hub->powerdelay = hub->hub_desc.bPwrOn2PwrGood * 2;
+        hub->tt_think = ((hub->hub_desc.wHubCharacteristics & HUB_CHAR_TTTT_MASK) >> 5);
+    }
+
+    for (uint8_t port = 0; port < hub->nports; port++) {
         hub->child[port].port = port + 1;
         hub->child[port].parent = hub;
         hub->child[port].bus = hport->bus;
     }
 
+    if (hport->device_desc.bDeviceProtocol == HUB_PROTOCOL_MTT) {
+        hub->ismtt = 1;
+    } else {
+        hub->ismtt = 0;
+    }
+
     ep_desc = &hport->config.intf[intf].altsetting[0].ep[0].ep_desc;
     if (ep_desc->bEndpointAddress & 0x80) {
         USBH_EP_INIT(hub->intin, ep_desc);
@@ -334,28 +388,16 @@ static int usbh_hub_connect(struct usbh_hubport *hport, uint8_t intf)
         return -1;
     }
 
-    if (hport->speed == USB_SPEED_SUPER) {
-        uint16_t depth = 0;
-        struct usbh_hubport *parent = hport->parent->parent;
-        while (parent) {
-            depth++;
-            parent = parent->parent->parent;
-        }
-
-        ret = usbh_hub_set_depth(hub, depth);
-        if (ret < 0) {
-            return ret;
-        }
-    }
-
-    for (uint8_t port = 0; port < hub->hub_desc.bNbrPorts; port++) {
+    for (uint8_t port = 0; port < hub->nports; port++) {
         ret = usbh_hub_set_feature(hub, port + 1, HUB_PORT_FEATURE_POWER);
         if (ret < 0) {
             return ret;
         }
     }
 
-    for (uint8_t port = 0; port < hub->hub_desc.bNbrPorts; port++) {
+    usb_osal_msleep(hub->powerdelay);
+
+    for (uint8_t port = 0; port < hub->nports; port++) {
         ret = usbh_hub_get_portstatus(hub, port + 1, &port_status);
         USB_LOG_INFO("port %u, status:0x%02x, change:0x%02x\r\n", port + 1, port_status.wPortStatus, port_status.wPortChange);
         if (ret < 0) {
@@ -395,7 +437,7 @@ static int usbh_hub_disconnect(struct usbh_hubport *hport, uint8_t intf)
             usb_osal_timer_delete(hub->int_timer);
         }
 
-        for (uint8_t port = 0; port < hub->hub_desc.bNbrPorts; port++) {
+        for (uint8_t port = 0; port < hub->nports; port++) {
             child = &hub->child[port];
             usbh_hubport_release(child);
             child->parent = NULL;
@@ -415,7 +457,7 @@ static void usbh_hub_events(struct usbh_hub *hub)
 {
     struct usbh_hubport *child;
     struct hub_port_status port_status;
-    uint8_t portchange_index;
+    uint16_t portchange_index;
     uint16_t portstatus;
     uint16_t portchange;
     uint16_t mask;
@@ -429,11 +471,10 @@ static void usbh_hub_events(struct usbh_hub *hub)
     }
 
     flags = usb_osal_enter_critical_section();
-    portchange_index = hub->int_buffer[0];
-    hub->int_buffer[0] &= ~portchange_index;
+    memcpy(&portchange_index, hub->int_buffer, 2);
     usb_osal_leave_critical_section(flags);
 
-    for (uint8_t port = 0; port < hub->hub_desc.bNbrPorts; port++) {
+    for (uint8_t port = 0; port < hub->nports; port++) {
         USB_LOG_DBG("Port change:0x%02x\r\n", portchange_index);
 
         if (!(portchange_index & (1 << (port + 1)))) {
@@ -539,12 +580,23 @@ static void usbh_hub_events(struct usbh_hub *hub)
                         }
                     }
 
-                    if (portstatus & HUB_PORT_STATUS_HIGH_SPEED) {
-                        speed = USB_SPEED_HIGH;
-                    } else if (portstatus & HUB_PORT_STATUS_LOW_SPEED) {
-                        speed = USB_SPEED_LOW;
+                    /*
+                    * Figure out device speed.  This is a bit tricky because
+                    * HUB_PORT_STATUS_POWER_SS and HUB_PORT_STATUS_LOW_SPEED share the same bit.
+                    */
+                    if (portstatus & HUB_PORT_STATUS_POWER) {
+                        if (portstatus & HUB_PORT_STATUS_HIGH_SPEED) {
+                            speed = USB_SPEED_HIGH;
+                        } else if (portstatus & HUB_PORT_STATUS_LOW_SPEED) {
+                            speed = USB_SPEED_LOW;
+                        } else {
+                            speed = USB_SPEED_FULL;
+                        }
+                    } else if (portstatus & HUB_PORT_STATUS_POWER_SS) {
+                        speed = USB_SPEED_SUPER;
                     } else {
-                        speed = USB_SPEED_FULL;
+                        USB_LOG_WRN("Port %u does not enable power\r\n", port + 1);
+                        continue;
                     }
 
                     child = &hub->child[port];
@@ -553,6 +605,7 @@ static void usbh_hub_events(struct usbh_hub *hub)
 
                     memset(child, 0, sizeof(struct usbh_hubport));
                     child->parent = hub;
+                    child->depth = (hub->parent ? hub->parent->depth : 0) + 1;
                     child->connected = true;
                     child->port = port + 1;
                     child->speed = speed;
@@ -624,7 +677,7 @@ int usbh_hub_initialize(struct usbh_bus *bus)
     hub->is_roothub = true;
     hub->parent = NULL;
     hub->hub_addr = 1;
-    hub->hub_desc.bNbrPorts = CONFIG_USBHOST_MAX_RHPORTS;
+    hub->nports = CONFIG_USBHOST_MAX_RHPORTS;
     hub->int_buffer = bus->hcd.roothub_intbuf;
     hub->bus = bus;
 
@@ -652,7 +705,7 @@ int usbh_hub_deinitialize(struct usbh_bus *bus)
     flags = usb_osal_enter_critical_section();
 
     hub = &bus->hcd.roothub;
-    for (uint8_t port = 0; port < hub->hub_desc.bNbrPorts; port++) {
+    for (uint8_t port = 0; port < hub->nports; port++) {
         hport = &hub->child[port];
 
         usbh_hubport_release(hport);

+ 0 - 4
class/hub/usbh_hub.h

@@ -10,10 +10,6 @@
 
 struct usbh_hub;
 
-#define USBH_HUB_MAX_PORTS 4
-/* Maximum size of an interrupt IN transfer */
-#define USBH_HUB_INTIN_BUFSIZE ((USBH_HUB_MAX_PORTS + 8) >> 3)
-
 #ifdef __cplusplus
 extern "C" {
 #endif

+ 8 - 6
core/usbh_core.c

@@ -731,7 +731,7 @@ static void *usbh_list_all_interface_name(struct usbh_hub *hub, const char *devn
     struct usbh_hub *hub_next;
     void *priv;
 
-    for (uint8_t port = 0; port < hub->hub_desc.bNbrPorts; port++) {
+    for (uint8_t port = 0; port < hub->nports; port++) {
         hport = &hub->child[port];
         if (hport->connected) {
             for (uint8_t itf = 0; itf < hport->config.config_desc.bNumInterfaces; itf++) {
@@ -760,8 +760,9 @@ static void usbh_list_all_interface_driver(struct usbh_hub *hub)
 {
     struct usbh_hubport *hport;
     struct usbh_hub *hub_next;
+    const char *speed_table[] = { "error-speed", "low-speed", "full-speed", "high-speed", "wireless-speed", "super-speed", "superplus-speed" };
 
-    for (uint8_t port = 0; port < hub->hub_desc.bNbrPorts; port++) {
+    for (uint8_t port = 0; port < hub->nports; port++) {
         hport = &hub->child[port];
         if (hport->connected) {
             for (uint8_t itf = 0; itf < hport->config.config_desc.bNumInterfaces; itf++) {
@@ -770,11 +771,12 @@ static void usbh_list_all_interface_driver(struct usbh_hub *hub)
                         USB_LOG_RAW("\t");
                     }
 
-                    USB_LOG_RAW("|__Port %u, dev addr:0x%02x, If %u, ClassDriver=%s\r\n",
+                    USB_LOG_RAW("|__Port %u, dev addr:0x%02x, If %u, ClassDriver=%s, %s\r\n",
                                 hport->port,
                                 hport->dev_addr,
                                 itf,
-                                hport->config.intf[itf].class_driver->driver_name);
+                                hport->config.intf[itf].class_driver->driver_name,
+                                speed_table[hport->speed]);
 
                     if (strcmp(hport->config.intf[itf].class_driver->driver_name, "hub") == 0) {
                         hub_next = hport->config.intf[itf].priv;
@@ -794,7 +796,7 @@ static void usbh_list_all_interface_desc(struct usbh_bus *bus, struct usbh_hub *
     struct usbh_hubport *hport;
     struct usbh_hub *hub_next;
 
-    for (uint8_t port = 0; port < hub->hub_desc.bNbrPorts; port++) {
+    for (uint8_t port = 0; port < hub->nports; port++) {
         hport = &hub->child[port];
         if (hport->connected) {
             USB_LOG_RAW("\r\nBus %u, Hub %u, Port %u, dev addr:0x%02x, VID:PID 0x%04x:0x%04x\r\n",
@@ -888,7 +890,7 @@ int lsusb(int argc, char **argv)
             USB_LOG_RAW("/: Bus %u, Hub %u, ports=%u, is roothub\r\n",
                         bus->busid,
                         hub->index,
-                        hub->hub_desc.bNbrPorts);
+                        hub->nports);
             usbh_list_all_interface_driver(hub);
         }
     }

+ 12 - 2
core/usbh_core.h

@@ -101,6 +101,9 @@ struct usbh_hubport {
     uint8_t port;     /* Hub port index */
     uint8_t dev_addr; /* device address */
     uint8_t speed;    /* device speed */
+    uint8_t depth;    /* distance from root hub */
+    uint8_t route;    /* route string */
+    uint8_t slot_id;  /* slot id */
     struct usb_device_descriptor device_desc;
     struct usbh_configuration config;
     const char *iManufacturer;
@@ -109,6 +112,7 @@ struct usbh_hubport {
     uint8_t *raw_config_desc;
     struct usb_setup_packet *setup;
     struct usbh_hub *parent;
+    struct usbh_hub *self; /* if this hubport is a hub */
     struct usbh_bus *bus;
     struct usb_endpoint_descriptor ep0;
     struct usbh_urb ep0_urb;
@@ -120,7 +124,13 @@ struct usbh_hub {
     bool is_roothub;
     uint8_t index;
     uint8_t hub_addr;
-    struct usb_hub_descriptor hub_desc;
+    uint8_t speed;
+    uint8_t nports;
+    uint8_t powerdelay;
+    uint8_t tt_think;
+    bool ismtt;
+    struct usb_hub_descriptor hub_desc; /* USB 2.0 only */
+    struct usb_hub_ss_descriptor hub_ss_desc; /* USB 3.0 only */
     struct usbh_hubport child[CONFIG_USBHOST_MAX_EHPORTS];
     struct usbh_hubport *parent;
     struct usbh_bus *bus;
@@ -145,7 +155,7 @@ struct usbh_devaddr_map {
 struct usbh_hcd {
     uint32_t reg_base;
     uint8_t hcd_id;
-    uint8_t roothub_intbuf[1];
+    uint8_t roothub_intbuf[2]; /* at most 15 roothub ports */
     struct usbh_hub roothub;
 };