Make xhci(4)'s root hub report the same status bits as physical USB3 hubs.
authormpi <mpi@openbsd.org>
Mon, 22 Jun 2015 10:29:18 +0000 (10:29 +0000)
committermpi <mpi@openbsd.org>
Mon, 22 Jun 2015 10:29:18 +0000 (10:29 +0000)
There's not bit to indicate the speed of a USB3.0 device attached to a hub
port so do not abuse the PORT_TEST bit.  Instead make the xhci(4) root hub
report the PORT_POWER_SS bit when appropriate and use it to determin the
speed of a new device.

While here make the root hub report the link state and config error, from
FreeBSD.

sys/dev/usb/uhub.c
sys/dev/usb/usb.h
sys/dev/usb/xhci.c

index 340064c..ce8d0c8 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: uhub.c,v 1.84 2015/06/15 16:46:21 mpi Exp $ */
+/*     $OpenBSD: uhub.c,v 1.85 2015/06/22 10:29:18 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 $       */
 
@@ -460,14 +460,14 @@ uhub_explore(struct usbd_device *dev)
                        continue;
                }
                /* Get port status again, it might have changed during reset */
-               err = usbd_get_port_status(dev, port, &up->status);
-               if (err) {
-                       DPRINTF("%s: get port %d status failed, error=%s\n",
-                           sc->sc_dev.dv_xname, port, usbd_errstr(err));
+               if (usbd_get_port_status(dev, port, &up->status))
                        continue;
-               }
+
                status = UGETW(up->status.wPortStatus);
                change = UGETW(up->status.wPortChange);
+               DPRINTF("%s: port %d status=0x%04x change=0x%04x\n",
+                   sc->sc_dev.dv_xname, port, status, change);
+
                if (!(status & UPS_CURRENT_CONNECT_STATUS)) {
                        /* Nothing connected, just ignore it. */
                        DPRINTF("%s: port %d, device disappeared after reset\n",
@@ -482,9 +482,7 @@ uhub_explore(struct usbd_device *dev)
                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)
+               if (status & UPS_HIGH_SPEED)
                        speed = USB_SPEED_HIGH;
                else if (status & UPS_LOW_SPEED)
                        speed = USB_SPEED_LOW;
index 0f549de..a68c831 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: usb.h,v 1.50 2015/02/14 06:18:58 uebayasi Exp $ */
+/*     $OpenBSD: usb.h,v 1.51 2015/06/22 10:29:18 mpi Exp $ */
 /*     $NetBSD: usb.h,v 1.69 2002/09/22 23:20:50 augustss Exp $        */
 /*     $FreeBSD: src/sys/dev/usb/usb.h,v 1.14 1999/11/17 22:33:46 n_hibma Exp $        */
 
@@ -423,13 +423,14 @@ typedef struct {
 #define UPS_PORT_LS_HOT_RESET          0x0120
 #define UPS_PORT_LS_COMP_MOD           0x0140
 #define UPS_PORT_LS_LOOPBACK           0x0160
+#define UPS_PORT_LS_GET(x)             (((x) >> 5) & 0xf)
+#define UPS_PORT_LS_SET(x)             (((x) & 0xf) << 5)
 
 #define UPS_PORT_POWER                 0x0100
 #define UPS_PORT_POWER_SS              0x0200  /* USB 3.0 only */
 #define UPS_FULL_SPEED                 0x0000
 #define UPS_LOW_SPEED                  0x0200
 #define UPS_HIGH_SPEED                 0x0400
-#define UPS_SUPER_SPEED                        0x0800
 #define UPS_PORT_TEST                  0x0800
 #define UPS_PORT_INDICATOR             0x1000
 
index 436bf53..1d43f1c 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: xhci.c,v 1.60 2015/05/27 11:13:34 mikeb Exp $ */
+/* $OpenBSD: xhci.c,v 1.61 2015/06/22 10:29:18 mpi Exp $ */
 
 /*
  * Copyright (c) 2014-2015 Martin Pieuchot
@@ -2245,32 +2245,40 @@ xhci_root_ctrl_start(struct usbd_xfer *xfer)
                }
                v = XOREAD4(sc, XHCI_PORTSC(index));
                DPRINTFN(8,("xhci_root_ctrl_start: port status=0x%04x\n", v));
+               i = UPS_PORT_LS_SET(XHCI_PS_GET_PLS(v));
                switch (XHCI_PS_SPEED(v)) {
                case XHCI_SPEED_FULL:
-                       i = UPS_FULL_SPEED;
+                       i |= UPS_FULL_SPEED;
                        break;
                case XHCI_SPEED_LOW:
-                       i = UPS_LOW_SPEED;
+                       i |= UPS_LOW_SPEED;
                        break;
                case XHCI_SPEED_HIGH:
-                       i = UPS_HIGH_SPEED;
+                       i |= UPS_HIGH_SPEED;
                        break;
                case XHCI_SPEED_SUPER:
                default:
-                       i = UPS_SUPER_SPEED;
                        break;
                }
                if (v & XHCI_PS_CCS)    i |= UPS_CURRENT_CONNECT_STATUS;
                if (v & XHCI_PS_PED)    i |= UPS_PORT_ENABLED;
                if (v & XHCI_PS_OCA)    i |= UPS_OVERCURRENT_INDICATOR;
                if (v & XHCI_PS_PR)     i |= UPS_RESET;
-               if (v & XHCI_PS_PP)     i |= UPS_PORT_POWER;
+               if (v & XHCI_PS_PP)     {
+                       if (XHCI_PS_SPEED(v) >= XHCI_SPEED_FULL &&
+                           XHCI_PS_SPEED(v) <= XHCI_SPEED_HIGH)
+                               i |= UPS_PORT_POWER;
+                       else
+                               i |= UPS_PORT_POWER_SS;
+               }
                USETW(ps.wPortStatus, i);
                i = 0;
                if (v & XHCI_PS_CSC)    i |= UPS_C_CONNECT_STATUS;
                if (v & XHCI_PS_PEC)    i |= UPS_C_PORT_ENABLED;
                if (v & XHCI_PS_OCC)    i |= UPS_C_OVERCURRENT_INDICATOR;
                if (v & XHCI_PS_PRC)    i |= UPS_C_PORT_RESET;
+               if (v & XHCI_PS_PLC)    i |= UPS_C_PORT_LINK_STATE;
+               if (v & XHCI_PS_CEC)    i |= UPS_C_PORT_CONFIG_ERROR;
                USETW(ps.wPortChange, i);
                l = min(len, sizeof ps);
                memcpy(buf, &ps, l);