aboutsummaryrefslogtreecommitdiff
path: root/src/hw
diff options
context:
space:
mode:
authorKevin O'Connor <kevin@koconnor.net>2014-12-12 14:16:43 -0500
committerKevin O'Connor <kevin@koconnor.net>2014-12-15 21:46:03 -0500
commit73fe49aef4a4328bf0edd4302f5f6dd99e61ba49 (patch)
tree843fa5b15294b4bdb30b9494ab6a08532db391d9 /src/hw
parented675ad4193bc7f929e5b39074d50672970aefa3 (diff)
downloadseabios-73fe49aef4a4328bf0edd4302f5f6dd99e61ba49.zip
seabios-73fe49aef4a4328bf0edd4302f5f6dd99e61ba49.tar.gz
seabios-73fe49aef4a4328bf0edd4302f5f6dd99e61ba49.tar.bz2
usb: Update USB hub code to support super speed hubs
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>
Diffstat (limited to 'src/hw')
-rw-r--r--src/hw/usb-hub.c36
-rw-r--r--src/hw/usb-hub.h6
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)