[PATCH v2] USB: Warn about USB3 devices plugged into USB2 hub.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



When a SuperSpeed device is plugged into a high speed hub or an EHCI
port, it will show up as a high speed device with a BCD of 0x0201 or
0x210 and it will contain a SuperSpeed Capabilities BOS descriptor.  If
we see such a high speed 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.

We could attempt to fetch BOS descriptors for low or full speed devices,
in case the user plugs in a USB 3.0 device into an OHCI or UHCI-only
port, but it's possible those devices will choke on the request and fail
to be enumerated.  Keep the current behavior of only asking for BOS
descriptors for devices that advertise a bcdUSB of 0x0201 and above.

Signed-off-by: Sarah Sharp <sarah.a.sharp@xxxxxxxxxxxxxxx>
Cc: Alan Stern <stern@xxxxxxxxxxxxxxxxxxx>
Cc: Sebastian Andrzej Siewior <bigeasy@xxxxxxxxxxxxx>
---
 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 79d339e..1224a69 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1246,6 +1246,7 @@ static void hub_release(struct kref *kref)
 }
 
 static unsigned highspeed_hubs;
+static unsigned superspeed_hubs;
 
 static void hub_disconnect(struct usb_interface *intf)
 {
@@ -1269,6 +1270,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);
@@ -1352,6 +1355,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;
@@ -3142,6 +3147,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->speed != USB_SPEED_SUPER && 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)
 {
@@ -3361,6 +3375,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_HIGH &&
+				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.5.4

--
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


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux