From 127961742cf7992f6989c6e89a18ab6d8f0b297f Mon Sep 17 00:00:00 2001 From: Patrick Rudolph <patrick.rudolph@9elements.com> Date: Thu, 3 Dec 2020 13:44:55 +0100 Subject: [PATCH 20/22] grub-core/bus/usb/usbhub: Add xHCI non root hub support Tested on Intel PCH C246, the USB3 hub can be configured by grub. Issues: * USB3 devices connected behind that hub are sometimes not detected. Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com> --- grub-core/bus/usb/usbhub.c | 38 +++++++++++++++++++++++++++++++++----- include/grub/usbdesc.h | 1 + include/grub/usbtrans.h | 4 ++++ 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/grub-core/bus/usb/usbhub.c b/grub-core/bus/usb/usbhub.c index b4b3a1a61..e96505aa9 100644 --- a/grub-core/bus/usb/usbhub.c +++ b/grub-core/bus/usb/usbhub.c @@ -148,19 +148,32 @@ grub_usb_hub_add_dev (grub_usb_controller_t controller, return dev; } - +static grub_usb_err_t +grub_usb_set_hub_depth(grub_usb_device_t dev, grub_uint8_t depth) +{ + return grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT + | GRUB_USB_REQTYPE_CLASS + | GRUB_USB_REQTYPE_TARGET_DEV), + GRUB_USB_HUB_REQ_SET_HUB_DEPTH, depth, + 0, 0, NULL); +} + static grub_usb_err_t grub_usb_add_hub (grub_usb_device_t dev) { struct grub_usb_usb_hubdesc hubdesc; grub_usb_err_t err; + grub_uint16_t req; int i; + req = (dev->speed == GRUB_USB_SPEED_SUPER) ? GRUB_USB_DESCRIPTOR_SS_HUB : + GRUB_USB_DESCRIPTOR_HUB; + err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_IN | GRUB_USB_REQTYPE_CLASS | GRUB_USB_REQTYPE_TARGET_DEV), - GRUB_USB_REQ_GET_DESCRIPTOR, - (GRUB_USB_DESCRIPTOR_HUB << 8) | 0, + GRUB_USB_REQ_GET_DESCRIPTOR, + (req << 8) | 0, 0, sizeof (hubdesc), (char *) &hubdesc); if (err) return err; @@ -183,6 +196,19 @@ grub_usb_add_hub (grub_usb_device_t dev) return GRUB_USB_ERR_INTERNAL; } + if (dev->speed == GRUB_USB_SPEED_SUPER) + { + grub_uint8_t depth; + grub_uint32_t route; + /* Depth maximum value is 5, but root hubs doesn't count */ + for (depth = 0, route = dev->route; (route & 0xf) > 0; route >>= 4) + depth++; + + err = grub_usb_set_hub_depth(dev, depth); + if (err) + return err; + } + /* Power on all Hub ports. */ for (i = 1; i <= hubdesc.portcnt; i++) { @@ -637,7 +663,9 @@ poll_nonroot_hub (grub_usb_device_t dev) int split_hubaddr = 0; /* Determine the device speed. */ - if (status & GRUB_USB_HUB_STATUS_PORT_LOWSPEED) + if (dev->speed == GRUB_USB_SPEED_SUPER) + speed = GRUB_USB_SPEED_SUPER; + else if (status & GRUB_USB_HUB_STATUS_PORT_LOWSPEED) speed = GRUB_USB_SPEED_LOW; else { @@ -651,7 +679,7 @@ poll_nonroot_hub (grub_usb_device_t dev) grub_millisleep (10); /* Find correct values for SPLIT hubport and hubaddr */ - if (speed == GRUB_USB_SPEED_HIGH) + if (speed == GRUB_USB_SPEED_HIGH || speed == GRUB_USB_SPEED_SUPER) { /* HIGH speed device needs not transaction translation */ split_hubport = 0; diff --git a/include/grub/usbdesc.h b/include/grub/usbdesc.h index bb2ab2e27..1697aa465 100644 --- a/include/grub/usbdesc.h +++ b/include/grub/usbdesc.h @@ -30,6 +30,7 @@ typedef enum { GRUB_USB_DESCRIPTOR_ENDPOINT, GRUB_USB_DESCRIPTOR_DEBUG = 10, GRUB_USB_DESCRIPTOR_HUB = 0x29, + GRUB_USB_DESCRIPTOR_SS_HUB = 0x2a, GRUB_USB_DESCRIPTOR_SS_ENDPOINT_COMPANION = 0x30 } grub_usb_descriptor_t; diff --git a/include/grub/usbtrans.h b/include/grub/usbtrans.h index 039ebed65..d6c3f71dc 100644 --- a/include/grub/usbtrans.h +++ b/include/grub/usbtrans.h @@ -110,6 +110,10 @@ enum GRUB_USB_REQ_SET_INTERFACE = 0x0B, GRUB_USB_REQ_SYNC_FRAME = 0x0C }; +enum + { + GRUB_USB_HUB_REQ_SET_HUB_DEPTH = 0x0C, + }; #define GRUB_USB_FEATURE_ENDP_HALT 0x00 #define GRUB_USB_FEATURE_DEV_REMOTE_WU 0x01 -- 2.39.2