From 1cb1f490f27aeffb466a6ac2f29e0754bac6c159 Mon Sep 17 00:00:00 2001 From: mpi Date: Sat, 9 Aug 2014 09:58:11 +0000 Subject: [PATCH] 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. --- sys/dev/usb/uhub.c | 30 ++++++++++++++++++++++++------ 1 file 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); -- 2.20.1