summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb/uhub.c
diff options
context:
space:
mode:
authormpi <mpi@openbsd.org>2014-08-09 09:58:11 +0000
committermpi <mpi@openbsd.org>2014-08-09 09:58:11 +0000
commit1cb1f490f27aeffb466a6ac2f29e0754bac6c159 (patch)
tree6c9613aaa2b7f614b629b958efe8c76241747c45 /sys/dev/usb/uhub.c
parentHandle super speed hub descriptors. (diff)
downloadwireguard-openbsd-1cb1f490f27aeffb466a6ac2f29e0754bac6c159.tar.xz
wireguard-openbsd-1cb1f490f27aeffb466a6ac2f29e0754bac6c159.zip
Correctly recognize Super Speed devices, this is part of the work to
be able to use USB 3.0 devices behind an external hub. This is a bit tricky because the SS status use a different power bit that maps to the Low speed one. So no longer accept devices without power bit and fallback to the parent hub's speed in case the status does not report any particular speed. Note that xhci(4) root hubs still set the traditionnal UPS_PORT_POWER bit with the correct device speed.
Diffstat (limited to 'sys/dev/usb/uhub.c')
-rw-r--r--sys/dev/usb/uhub.c30
1 files changed, 24 insertions, 6 deletions
diff --git a/sys/dev/usb/uhub.c b/sys/dev/usb/uhub.c
index 29cdbb1c2b4..6a2d90b61df 100644
--- a/sys/dev/usb/uhub.c
+++ b/sys/dev/usb/uhub.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uhub.c,v 1.71 2014/08/09 09:48:32 mpi Exp $ */
+/* $OpenBSD: uhub.c,v 1.72 2014/08/09 09:58:11 mpi Exp $ */
/* $NetBSD: uhub.c,v 1.64 2003/02/08 03:32:51 ichiro Exp $ */
/* $FreeBSD: src/sys/dev/usb/uhub.c,v 1.18 1999/11/17 22:33:43 n_hibma Exp $ */
@@ -414,9 +414,11 @@ uhub_explore(struct usbd_device *dev)
}
/* Connected */
- if (!(status & UPS_PORT_POWER))
- printf("%s: strange, connected port %d has no power\n",
+ if (!(status & (UPS_PORT_POWER|UPS_PORT_POWER_SS))) {
+ printf("%s: connected port %d has no power\n",
sc->sc_dev.dv_xname, port);
+ continue;
+ }
/* Wait for maximum device power up time. */
usbd_delay_ms(dev, USB_PORT_POWERUP_DELAY);
@@ -443,15 +445,31 @@ uhub_explore(struct usbd_device *dev)
continue;
}
- /* Figure out device speed */
+ /*
+ * Figure out device speed. This is a bit tricky because
+ * UPS_PORT_POWER_SS and UPS_LOW_SPEED share the same bit.
+ */
+ if ((status & UPS_PORT_POWER) == 0)
+ status &= ~UPS_PORT_POWER_SS;
+
if (status & UPS_SUPER_SPEED)
speed = USB_SPEED_SUPER;
else if (status & UPS_HIGH_SPEED)
speed = USB_SPEED_HIGH;
else if (status & UPS_LOW_SPEED)
speed = USB_SPEED_LOW;
- else
- speed = USB_SPEED_FULL;
+ else {
+ /*
+ * If there is no power bit set, it is certainly
+ * a Super Speed device, so use the speed of its
+ * parent hub.
+ */
+ if (status & UPS_PORT_POWER)
+ speed = USB_SPEED_FULL;
+ else
+ speed = sc->sc_hub->speed;
+ }
+
/* Get device info and set its address. */
err = usbd_new_device(&sc->sc_dev, dev->bus,
dev->depth + 1, speed, port, up);