When a SuperSpeed device is plugged into non-SuperSpeed host or hub, it will show up as a high speed or full speed device with a BCD USB version number of 0x0201 or 0x210. It will also contain a SuperSpeed Capabilities BOS descriptor. If we see such a device, warn the user that they should plug their device into a USB 3.0 hub or xHCI root port. Only warn the user if there is at least one SuperSpeed roothub available. Signed-off-by: Sarah Sharp <sarah.a.sharp@xxxxxxxxxxxxxxx> Cc: Alan Stern <stern@xxxxxxxxxxxxxxxxxxx> Cc: Sebastian Andrzej Siewior <bigeasy@xxxxxxxxxxxxx> --- v3: - Remove redundant speed checking. - Warn about full or low speed devices that could run at SuperSpeed. - Change description to remove false assumption about what BCD USB shows up as under a UHCI/OHCI host. drivers/usb/core/hub.c | 18 ++++++++++++++++++ 1 files changed, 18 insertions(+), 0 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index d4f0624..2553bcf 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1272,6 +1272,7 @@ static void hub_release(struct kref *kref) } static unsigned highspeed_hubs; +static unsigned superspeed_hubs; static void hub_disconnect(struct usb_interface *intf) { @@ -1295,6 +1296,8 @@ static void hub_disconnect(struct usb_interface *intf) if (hub->hdev->speed == USB_SPEED_HIGH) highspeed_hubs--; + if (hub->hdev->speed == USB_SPEED_SUPER) + superspeed_hubs--; usb_free_urb(hub->urb); kfree(hub->port_owners); @@ -1372,6 +1375,8 @@ descriptor_error: if (hdev->speed == USB_SPEED_HIGH) highspeed_hubs++; + if (hub->hdev->speed == USB_SPEED_SUPER) + superspeed_hubs++; if (hub_configure(hub, endpoint) >= 0) return 0; @@ -3230,6 +3235,15 @@ check_highspeed (struct usb_hub *hub, struct usb_device *udev, int port1) kfree(qual); } +static void check_superspeed(struct usb_hub *hub, struct usb_device *udev, + int port1) +{ + if (udev->bos && udev->bos->ss_cap) { + dev_info(&udev->dev, "not running at top speed; " + "connect to a SuperSpeed port\n"); + } +} + static unsigned hub_power_remaining (struct usb_hub *hub) { @@ -3449,6 +3463,10 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, && udev->speed == USB_SPEED_FULL && highspeed_hubs != 0) check_highspeed (hub, udev, port1); + if (le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0201 && + udev->speed < USB_SPEED_SUPER && + superspeed_hubs != 0) + check_superspeed(hub, udev, port1); /* Store the parent's children[] pointer. At this point * udev becomes globally accessible, although presumably -- 1.7.9 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html