Super speed hubs (usb3 spec) have specific initialization requirements. Add the code necessary to detect and initialize these hubs.
Signed-off-by: Kevin O'Connor kevin@koconnor.net --- src/hw/usb-hub.c | 36 ++++++++++++++++++++++++++++++++++-- src/hw/usb-hub.h | 6 +++++- 2 files changed, 39 insertions(+), 3 deletions(-)
diff --git a/src/hw/usb-hub.c b/src/hw/usb-hub.c index c21cbfb..54e341b 100644 --- a/src/hw/usb-hub.c +++ b/src/hw/usb-hub.c @@ -17,13 +17,28 @@ get_hub_desc(struct usb_pipe *pipe, struct usb_hub_descriptor *desc) struct usb_ctrlrequest req; req.bRequestType = USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE; req.bRequest = USB_REQ_GET_DESCRIPTOR; - req.wValue = USB_DT_HUB<<8; + if (pipe->speed == USB_SUPERSPEED) + req.wValue = USB_DT_HUB3<<8; + else + req.wValue = USB_DT_HUB<<8; req.wIndex = 0; req.wLength = sizeof(*desc); return usb_send_default_control(pipe, &req, desc); }
static int +set_hub_depth(struct usb_pipe *pipe, u16 depth) +{ + struct usb_ctrlrequest req; + req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_DEVICE; + req.bRequest = HUB_REQ_SET_HUB_DEPTH; + req.wValue = depth; + req.wIndex = 0; + req.wLength = 0; + return usb_send_default_control(pipe, &req, NULL); +} + +static int set_port_feature(struct usbhub_s *hub, int port, int feature) { struct usb_ctrlrequest req; @@ -105,7 +120,9 @@ usb_hub_reset(struct usbhub_s *hub, u32 port) ret = get_port_status(hub, port, &sts); if (ret) goto fail; - if (!(sts.wPortStatus & USB_PORT_STAT_RESET)) + if (!(sts.wPortStatus & USB_PORT_STAT_RESET) + && (hub->usbdev->speed != USB_SUPERSPEED + || !(sts.wPortStatus & USB_PORT_STAT_LINK_MASK))) break; if (timer_check(end)) { warn_timeout(); @@ -119,6 +136,8 @@ usb_hub_reset(struct usbhub_s *hub, u32 port) // Device no longer present return -1;
+ if (hub->usbdev->speed == USB_SUPERSPEED) + return USB_SUPERSPEED; return ((sts.wPortStatus & USB_PORT_STAT_SPEED_MASK) >> USB_PORT_STAT_SPEED_SHIFT);
@@ -154,6 +173,19 @@ usb_hub_setup(struct usbdevice_s *usbdev) hub.portcount = desc.bNbrPorts; hub.op = &HubOp;
+ if (usbdev->speed == USB_SUPERSPEED) { + int depth = 0; + struct usbdevice_s *parent = usbdev->hub->usbdev; + while (parent) { + depth++; + parent = parent->hub->usbdev; + } + + ret = set_hub_depth(usbdev->defpipe, depth); + if (ret) + return ret; + } + // Turn on power to ports. int port; for (port=0; port<desc.bNbrPorts; port++) { diff --git a/src/hw/usb-hub.h b/src/hw/usb-hub.h index 5b09947..880378c 100644 --- a/src/hw/usb-hub.h +++ b/src/hw/usb-hub.h @@ -11,6 +11,9 @@ int usb_hub_setup(struct usbdevice_s *usbdev); ****************************************************************/
#define USB_DT_HUB (USB_TYPE_CLASS | 0x09) +#define USB_DT_HUB3 (USB_TYPE_CLASS | 0x0a) + +#define HUB_REQ_SET_HUB_DEPTH 0x0C
struct usb_hub_descriptor { u8 bDescLength; @@ -48,7 +51,8 @@ struct usb_port_status { #define USB_PORT_STAT_SUSPEND 0x0004 #define USB_PORT_STAT_OVERCURRENT 0x0008 #define USB_PORT_STAT_RESET 0x0010 -#define USB_PORT_STAT_L1 0x0020 +#define USB_PORT_STAT_LINK_SHIFT 5 +#define USB_PORT_STAT_LINK_MASK (0x7 << USB_PORT_STAT_LINK_SHIFT) #define USB_PORT_STAT_POWER 0x0100 #define USB_PORT_STAT_SPEED_SHIFT 9 #define USB_PORT_STAT_SPEED_MASK (0x3 << USB_PORT_STAT_SPEED_SHIFT)