Module Name:    src
Committed By:   skrll
Date:           Thu May 28 06:15:47 UTC 2015

Modified Files:
        src/sys/dev/usb [nick-nhusb]: uhub.c usb.h xhci.c

Log Message:
More changes from Takahiro HAYASHI

+ Add sc_statuspend that stores ports bitmap of pending interrupts
  instead of sc_isxhciroothub hack til someone implements suspend pipe.
  While sc_explorepending == 1, uhub_intr shall merge sc_status into
  sc_statuspend.
+ Eliminate confusing UPS_SUPER_SPEED flag and introduce
  UPS_OTHER_SPEED flag that indicates ud_speed of device is
  super speed (or more).
  uhub shall set this flag if ud_speed is super speed (or more).
+ Add the macro that checks ud_speed is super speed.
  The codes shall use this macro to check ud_speed is super speed.
+ Add speed type conversion functions.
+ Include port link status in port_status if port is super speed.

Various other changes to support SS hubs and devices


To generate a diff of this commit:
cvs rdiff -u -r1.126.2.11 -r1.126.2.12 src/sys/dev/usb/uhub.c
cvs rdiff -u -r1.111.2.6 -r1.111.2.7 src/sys/dev/usb/usb.h
cvs rdiff -u -r1.28.2.26 -r1.28.2.27 src/sys/dev/usb/xhci.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/usb/uhub.c
diff -u src/sys/dev/usb/uhub.c:1.126.2.11 src/sys/dev/usb/uhub.c:1.126.2.12
--- src/sys/dev/usb/uhub.c:1.126.2.11	Tue Apr  7 06:23:10 2015
+++ src/sys/dev/usb/uhub.c	Thu May 28 06:15:47 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: uhub.c,v 1.126.2.11 2015/04/07 06:23:10 skrll Exp $	*/
+/*	$NetBSD: uhub.c,v 1.126.2.12 2015/05/28 06:15:47 skrll Exp $	*/
 /*	$FreeBSD: src/sys/dev/usb/uhub.c,v 1.18 1999/11/17 22:33:43 n_hibma Exp $	*/
 
 /*
@@ -36,7 +36,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uhub.c,v 1.126.2.11 2015/04/07 06:23:10 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uhub.c,v 1.126.2.12 2015/05/28 06:15:47 skrll Exp $");
 
 #include <sys/param.h>
 
@@ -104,6 +104,7 @@ struct uhub_softc {
 
 	/* XXX second buffer needed because we can't suspend pipes yet */
 	uint8_t			*sc_statusbuf;
+	uint8_t			*sc_statuspend;
 	uint8_t			*sc_status;
 	size_t			sc_statuslen;
 	int			sc_explorepending;
@@ -112,7 +113,8 @@ struct uhub_softc {
 	u_char			sc_running;
 };
 
-#define UHUB_IS_HIGH_SPEED(sc) ((sc)->sc_proto != UDPROTO_FSHUB)
+#define UHUB_IS_HIGH_SPEED(sc) \
+    ((sc)->sc_proto == UDPROTO_HSHUBSTT || (sc)->sc_proto == UDPROTO_HSHUBMTT)
 #define UHUB_IS_SINGLE_TT(sc) ((sc)->sc_proto == UDPROTO_HSHUBSTT)
 
 #define PORTSTAT_ISSET(sc, port) \
@@ -147,6 +149,76 @@ CFATTACH_DECL2_NEW(uroothub, sizeof(stru
  */
 int uhub_ubermatch = 0;
 
+static usbd_status
+usbd_get_hub_desc(struct usbd_device *dev, usb_hub_descriptor_t *hd, int speed)
+{
+	usb_device_request_t req;
+	usbd_status err;
+	int nports;
+
+	UHUBHIST_FUNC(); UHUBHIST_CALLED();
+
+	/* don't issue UDESC_HUB to SS hub, or it would stall */
+	if (dev->ud_depth != 0 && USB_IS_SS(dev->ud_speed)) {
+		usb_hub_ss_descriptor_t hssd;
+		int rmvlen;
+
+		memset(&hssd, 0, sizeof(hssd));
+		req.bmRequestType = UT_READ_CLASS_DEVICE;
+		req.bRequest = UR_GET_DESCRIPTOR;
+		USETW2(req.wValue, UDESC_SS_HUB, 0);
+		USETW(req.wIndex, 0);
+		USETW(req.wLength, USB_HUB_SS_DESCRIPTOR_SIZE);
+		DPRINTFN(1, "getting sshub descriptor", 0, 0, 0, 0);
+		err = usbd_do_request(dev, &req, &hssd);
+		nports = hssd.bNbrPorts;
+		if (dev->ud_depth != 0 && nports > UHD_SS_NPORTS_MAX) {
+			DPRINTF("num of ports %d exceeds maxports %d",
+			    nports, UHD_SS_NPORTS_MAX, 0, 0);
+			nports = hd->bNbrPorts = UHD_SS_NPORTS_MAX;
+		}
+		rmvlen = (nports + 7) / 8;
+		hd->bDescLength = USB_HUB_DESCRIPTOR_SIZE +
+		    (rmvlen > 1 ? rmvlen : 1) - 1;
+		memcpy(hd->DeviceRemovable, hssd.DeviceRemovable, rmvlen);
+		hd->bDescriptorType		= hssd.bDescriptorType;
+		hd->bNbrPorts			= hssd.bNbrPorts;
+		hd->wHubCharacteristics[0]	= hssd.wHubCharacteristics[0];
+		hd->wHubCharacteristics[1]	= hssd.wHubCharacteristics[1];
+		hd->bPwrOn2PwrGood		= hssd.bPwrOn2PwrGood;
+		hd->bHubContrCurrent		= hssd.bHubContrCurrent;
+	} else {
+		req.bmRequestType = UT_READ_CLASS_DEVICE;
+		req.bRequest = UR_GET_DESCRIPTOR;
+		USETW2(req.wValue, UDESC_HUB, 0);
+		USETW(req.wIndex, 0);
+		USETW(req.wLength, USB_HUB_DESCRIPTOR_SIZE);
+		DPRINTFN(1, "getting hub descriptor", 0, 0, 0, 0);
+		err = usbd_do_request(dev, &req, hd);
+		nports = hd->bNbrPorts;
+		if (!err && nports > 7) {
+			USETW(req.wLength,
+			    USB_HUB_DESCRIPTOR_SIZE + (nports+1) / 8);
+			err = usbd_do_request(dev, &req, hd);
+		}
+	}
+
+	return err;
+}
+
+static usbd_status
+usbd_set_hub_depth(struct usbd_device *dev, int depth)
+{
+	usb_device_request_t req;
+
+	req.bmRequestType = UT_WRITE_CLASS_DEVICE;
+	req.bRequest = UR_SET_HUB_DEPTH;
+	USETW(req.wValue, depth);
+	USETW(req.wIndex, 0);
+	USETW(req.wLength, 0);
+	return usbd_do_request(dev, &req, 0);
+}
+
 int
 uhub_match(device_t parent, cfdata_t match, void *aux)
 {
@@ -179,7 +251,6 @@ uhub_attach(device_t parent, device_t se
 	char *devinfop;
 	usbd_status err;
 	struct usbd_hub *hub = NULL;
-	usb_device_request_t req;
 	usb_hub_descriptor_t hubdesc;
 	int p, port, nports, nremov, pwrdly;
 	struct usbd_interface *iface;
@@ -219,18 +290,9 @@ uhub_attach(device_t parent, device_t se
 	}
 
 	/* Get hub descriptor. */
-	req.bmRequestType = UT_READ_CLASS_DEVICE;
-	req.bRequest = UR_GET_DESCRIPTOR;
-	USETW2(req.wValue, UDESC_HUB, 0);
-	USETW(req.wIndex, 0);
-	USETW(req.wLength, USB_HUB_DESCRIPTOR_SIZE);
-	DPRINTF("uhub %d getting hub descriptor", device_unit(self), 0, 0, 0);
-	err = usbd_do_request(dev, &req, &hubdesc);
+	memset(&hubdesc, 0, sizeof(hubdesc));
+	err = usbd_get_hub_desc(dev, &hubdesc, dev->ud_speed);
 	nports = hubdesc.bNbrPorts;
-	if (!err && nports > 7) {
-		USETW(req.wLength, USB_HUB_DESCRIPTOR_SIZE + (nports+1) / 8);
-		err = usbd_do_request(dev, &req, &hubdesc);
-	}
 	if (err) {
 		DPRINTF("getting hub descriptor failed, uhub %d error %d",
 		    device_unit(self), err, 0, 0);
@@ -258,6 +320,16 @@ uhub_attach(device_t parent, device_t se
 	hub->uh_explore = uhub_explore;
 	hub->uh_hubdesc = hubdesc;
 
+	if (USB_IS_SS(dev->ud_speed) && dev->ud_depth != 0) {
+		aprint_debug_dev(self, "setting hub depth %u\n",
+		    dev->ud_depth-1);
+		err = usbd_set_hub_depth(dev, dev->ud_depth - 1);
+		if (err) {
+			aprint_error_dev(self, "can't set depth\n");
+			goto bad;
+		}
+	}
+
 	/* Set up interrupt pipe. */
 	err = usbd_device2interface_handle(dev, 0, &iface);
 	if (err) {
@@ -285,6 +357,9 @@ uhub_attach(device_t parent, device_t se
 	sc->sc_statusbuf = kmem_alloc(sc->sc_statuslen, KM_SLEEP);
 	if (!sc->sc_statusbuf)
 		goto bad;
+	sc->sc_statuspend = kmem_zalloc(sc->sc_statuslen, KM_SLEEP);
+	if (!sc->sc_statuspend)
+		goto bad;
 	sc->sc_status = kmem_alloc(sc->sc_statuslen, KM_SLEEP);
 	if (!sc->sc_status)
 		goto bad;
@@ -395,6 +470,8 @@ uhub_attach(device_t parent, device_t se
  bad:
 	if (sc->sc_status)
 		kmem_free(sc->sc_status, sc->sc_statuslen);
+	if (sc->sc_statuspend)
+		kmem_free(sc->sc_statuspend, sc->sc_statuslen);
 	if (sc->sc_statusbuf)
 		kmem_free(sc->sc_statusbuf, sc->sc_statuslen);
 	if (hub)
@@ -469,6 +546,10 @@ uhub_explore(struct usbd_device *dev)
 			}
 			status = UGETW(up->up_status.wPortStatus);
 			change = UGETW(up->up_status.wPortChange);
+			if (USB_IS_SS(dev->ud_speed)) {
+				status |= UPS_OTHER_SPEED;
+				USETW(up->up_status.wPortStatus, status);
+			}
 
 			DPRINTF("uhub %d port %d: s/c=%x/%x",
 			    device_unit(sc->sc_dev), port, status, change);
@@ -505,10 +586,26 @@ uhub_explore(struct usbd_device *dev)
 					    port);
 			}
 		}
+		int is_wrc = 0;
+		if (change & UPS_C_PORT_RESET)
+			usbd_clear_port_feature(dev, port, UHF_C_PORT_RESET);
+		if (change & UPS_C_BH_PORT_RESET) {
+			is_wrc = 1;
+			usbd_clear_port_feature(dev, port,
+			    UHF_C_BH_PORT_RESET);
+		}
+		if (change & UPS_C_PORT_LINK_STATE)
+			usbd_clear_port_feature(dev, port,
+			    UHF_C_PORT_LINK_STATE);
+		if (change & UPS_C_PORT_CONFIG_ERROR)
+			usbd_clear_port_feature(dev, port,
+			    UHF_C_PORT_CONFIG_ERROR);
 
 		/* XXX handle overcurrent and resume events! */
 
-		if (!reconnect && !(change & UPS_C_CONNECT_STATUS)) {
+		/* xHCI sets WRC instead of CSC when port is reset */
+		if (!reconnect && !(change & UPS_C_CONNECT_STATUS) &&
+		    !(is_wrc && (status & UPS_CURRENT_CONNECT_STATUS))) {
 			/* No status change, just do recursive explore. */
 			if (up->up_dev != NULL && up->up_dev->ud_hub != NULL)
 				up->up_dev->ud_hub->uh_explore(up->up_dev);
@@ -537,11 +634,15 @@ uhub_explore(struct usbd_device *dev)
 			usb_disconnect_port(up, sc->sc_dev, DETACH_FORCE);
 			usbd_clear_port_feature(dev, port,
 						UHF_C_PORT_CONNECTION);
+			continue;
 		}
 		if (!(status & UPS_CURRENT_CONNECT_STATUS)) {
 			/* Nothing connected, just ignore it. */
 			DPRINTFN(3, "uhub %d port=%d !CURRENT_CONNECT_STATUS",
 			    device_unit(sc->sc_dev), port, 0, 0);
+			usb_disconnect_port(up, sc->sc_dev, DETACH_FORCE);
+			usbd_clear_port_feature(dev, port,
+						UHF_C_PORT_CONNECTION);
 			continue;
 		}
 
@@ -549,9 +650,22 @@ uhub_explore(struct usbd_device *dev)
 		DPRINTF("unit %d dev->speed=%u dev->depth=%u",
 		    device_unit(sc->sc_dev), dev->ud_speed, dev->ud_depth, 0);
 
-		if (!(status & UPS_PORT_POWER))
-			aprint_normal_dev(sc->sc_dev,
-			    "strange, connected port %d has no power\n", port);
+		/*
+		 * To check whether port has power,
+		 *  check UPS_PORT_POWER bit if port speed is HS/FS/LS and
+		 *  check UPS_PORT_POWER_SS bit if port speed is SS.
+		 */
+		if (status & UPS_OTHER_SPEED) {
+			if (!(status & UPS_PORT_POWER_SS))
+				aprint_normal_dev(sc->sc_dev,
+				    "strange, connected port %d has no power\n",
+				    port);
+		} else {
+			if (!(status & UPS_PORT_POWER))
+				aprint_normal_dev(sc->sc_dev,
+				    "strange, connected port %d has no power\n",
+				    port);
+		}
 
 		/* Wait for maximum device power up time. */
 		usbd_delay_ms(dev, USB_PORT_POWERUP_DELAY);
@@ -571,6 +685,10 @@ uhub_explore(struct usbd_device *dev)
 		}
 		status = UGETW(up->up_status.wPortStatus);
 		change = UGETW(up->up_status.wPortChange);
+		if (USB_IS_SS(dev->ud_speed)) {
+			status |= UPS_OTHER_SPEED;
+			USETW(up->up_status.wPortStatus, status);
+		}
 		DPRINTF("hub %d port %d after reset: s/c=%x/%x",
 		    device_unit(sc->sc_dev), port, status, change);
 
@@ -590,14 +708,15 @@ uhub_explore(struct usbd_device *dev)
 #endif
 			continue;
 		}
+		/* port reset may cause Warm Reset Change, drop it. */
+		if (change & UPS_C_BH_PORT_RESET)
+			usbd_clear_port_feature(dev, port,
+			    UHF_C_BH_PORT_RESET);
 
 		/* Figure out device speed */
-#if 0
-		if (status & UPS_SUPER_SPEED)
+		if (status & UPS_OTHER_SPEED) {
 			speed = USB_SPEED_SUPER;
-		else
-#endif
-		if (status & UPS_HIGH_SPEED)
+		} else if (status & UPS_HIGH_SPEED)
 			speed = USB_SPEED_HIGH;
 		else if (status & UPS_LOW_SPEED)
 			speed = USB_SPEED_LOW;
@@ -637,6 +756,15 @@ uhub_explore(struct usbd_device *dev)
 	if (!sc->sc_isehciroothub)
 		memset(sc->sc_status, 0, sc->sc_statuslen);
 	sc->sc_explorepending = 0;
+	for (int i = 0; i < sc->sc_statuslen; i++) {
+		if (sc->sc_statuspend[i] != 0) {
+			memcpy(sc->sc_status, sc->sc_statuspend,
+			    sc->sc_statuslen);
+			memset(sc->sc_statuspend, 0, sc->sc_statuslen);
+			usb_needs_explore(sc->sc_hub);
+			break;
+		}
+	}
 	return USBD_NORMAL_COMPLETION;
 }
 
@@ -692,6 +820,8 @@ uhub_detach(device_t self, int flags)
 	sc->sc_hub->ud_hub = NULL;
 	if (sc->sc_status)
 		kmem_free(sc->sc_status, sc->sc_statuslen);
+	if (sc->sc_statuspend)
+		kmem_free(sc->sc_statuspend, sc->sc_statuslen);
 	if (sc->sc_statusbuf)
 		kmem_free(sc->sc_statusbuf, sc->sc_statuslen);
 
@@ -771,15 +901,26 @@ uhub_intr(struct usbd_xfer *xfer, void *
 
 	if (status == USBD_STALLED)
 		usbd_clear_endpoint_stall_async(sc->sc_ipipe);
-	else if (status == USBD_NORMAL_COMPLETION &&
-		 !sc->sc_explorepending) {
-		/*
-		 * Make sure the status is not overwritten in between.
-		 * XXX we should suspend the pipe instead
-		 */
-		memcpy(sc->sc_status, sc->sc_statusbuf, sc->sc_statuslen);
-		sc->sc_explorepending = 1;
-		usb_needs_explore(sc->sc_hub);
+	else if (status == USBD_NORMAL_COMPLETION) {
+		int i;
+
+		/* merge port bitmap into pending interrupts list */
+		for (i = 0; i < sc->sc_statuslen; i++)
+			sc->sc_statuspend[i] |= sc->sc_statusbuf[i];
+
+		if (!sc->sc_explorepending) {
+			/*
+			 * Make sure the status is not overwritten in between.
+			 * XXX we should suspend the pipe instead
+			 */
+			sc->sc_explorepending = 1;
+			memcpy(sc->sc_status, sc->sc_statuspend,
+			    sc->sc_statuslen);
+			memset(sc->sc_statuspend, 0, sc->sc_statuslen);
+			DPRINTFN(5, "uhub%d: exploring ports %02x",
+			    device_unit(sc->sc_dev), *sc->sc_status, 0, 0);
+			usb_needs_explore(sc->sc_hub);
+		}
 	}
 	/*
 	 * XXX workaround for broken implementation of the interrupt

Index: src/sys/dev/usb/usb.h
diff -u src/sys/dev/usb/usb.h:1.111.2.6 src/sys/dev/usb/usb.h:1.111.2.7
--- src/sys/dev/usb/usb.h:1.111.2.6	Mon Apr  6 15:18:13 2015
+++ src/sys/dev/usb/usb.h	Thu May 28 06:15:47 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: usb.h,v 1.111.2.6 2015/04/06 15:18:13 skrll Exp $	*/
+/*	$NetBSD: usb.h,v 1.111.2.7 2015/05/28 06:15:47 skrll Exp $	*/
 /*	$FreeBSD: src/sys/dev/usb/usb.h,v 1.14 1999/11/17 22:33:46 n_hibma Exp $	*/
 
 /*
@@ -561,7 +561,9 @@ typedef struct {
 #define UPS_OVERCURRENT_INDICATOR	0x0008
 #define UPS_RESET			0x0010
 #define UPS_PORT_L1			0x0020
-#define UPS_PORT_LS_GET(x)		__SHIFTOUT(x, __BITS(8,5))
+#define UPS_PORT_LS_MASK		__BITS(8,5)
+#define UPS_PORT_LS_GET(x)		__SHIFTOUT(x, UPS_PORT_LS_MASK)
+#define UPS_PORT_LS_SET(x)		__SHIFTIN(x, UPS_PORT_LS_MASK)
 #define UPS_PORT_LS_U0			0x00
 #define UPS_PORT_LS_U1			0x01
 #define UPS_PORT_LS_U2			0x02
@@ -580,9 +582,9 @@ typedef struct {
 #define UPS_FULL_SPEED			0x0000	/* for completeness */
 #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
+#define UPS_OTHER_SPEED			0x2000	/* currently NetBSD specific */
 	uWord		wPortChange;
 #define UPS_C_CONNECT_STATUS		0x0001
 #define UPS_C_PORT_ENABLED		0x0002
@@ -852,6 +854,7 @@ struct usb_device_info {
 #define USB_SPEED_FULL 2
 #define USB_SPEED_HIGH 3
 #define USB_SPEED_SUPER 4
+#define USB_IS_SS(X) ((X) == USB_SPEED_SUPER)
 	int		udi_power;	/* power consumption in mA, 0 if selfpowered */
 	int		udi_nports;
 	char		udi_devnames[USB_MAX_DEVNAMES][USB_MAX_DEVNAMELEN];

Index: src/sys/dev/usb/xhci.c
diff -u src/sys/dev/usb/xhci.c:1.28.2.26 src/sys/dev/usb/xhci.c:1.28.2.27
--- src/sys/dev/usb/xhci.c:1.28.2.26	Wed May 27 07:22:51 2015
+++ src/sys/dev/usb/xhci.c	Thu May 28 06:15:47 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: xhci.c,v 1.28.2.26 2015/05/27 07:22:51 skrll Exp $	*/
+/*	$NetBSD: xhci.c,v 1.28.2.27 2015/05/28 06:15:47 skrll Exp $	*/
 
 /*
  * Copyright (c) 2013 Jonathan A. Kollasch
@@ -36,7 +36,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.28.2.26 2015/05/27 07:22:51 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.28.2.27 2015/05/28 06:15:47 skrll Exp $");
 
 #include "opt_usb.h"
 
@@ -1004,31 +1004,52 @@ xhci_intr1(struct xhci_softc * const sc)
  *	ioctl interface uses these values too.
  * port_status speed
  *	definition: UPS_*_SPEED in usb.h
- *	They are used in usb_port_status_t.
- *	Some 3.0 values overlap with 2.0 values.
+ *	They are used in usb_port_status_t and valid only for USB 2.0.
+ *	Speed value is 0 for Super Speed or more.
+ *	Note that some 3.0 values overlap with 2.0 values.
  *	(e.g. 0x200 means UPS_POER_POWER_SS in SS and
  *	            means UPS_LOW_SPEED in HS.)
  *	port status sent from hub also uses these values.
- *	(but I've never seen UPS_SUPER_SPEED in port_status from hub.)
  * xspeed:
  *	definition: Protocol Speed ID (PSI) (xHCI 1.1 7.2.1)
  *	They are used in only slot context and PORTSC reg of xhci.
- *	The difference between usbdi speed and them are that
- *	FS and LS values are swapped.
+ *	The difference between usbdi speed and xspeed is
+ *	that FS and LS values are swapped.
  */
 
+/* convert usbdi speed to xspeed */
 static int
 xhci_speed2xspeed(int speed)
 {
 	switch (speed) {
 	case USB_SPEED_LOW:	return 2;
 	case USB_SPEED_FULL:	return 1;
-	case USB_SPEED_HIGH:	return 3;
-	case USB_SPEED_SUPER:	return 4;
-	default:
-		break;
+	default:		return speed;
+	}
+}
+
+/* convert xspeed to usbdi speed */
+static int
+xhci_xspeed2speed(int xspeed)
+{
+	switch (xspeed) {
+	case 1: return USB_SPEED_FULL;
+	case 2: return USB_SPEED_LOW;
+	default: return xspeed;
+	}
+}
+
+/* convert xspeed to port status speed */
+static int
+xhci_xspeed2psspeed(int xspeed)
+{
+	switch (xspeed) {
+	case 0: return 0;
+	case 1: return UPS_FULL_SPEED;
+	case 2: return UPS_LOW_SPEED;
+	case 3: return UPS_HIGH_SPEED;
+	default: return UPS_OTHER_SPEED;
 	}
-	return 0;
 }
 
 /* construct slot context */
@@ -1179,7 +1200,7 @@ xhci_configure_endpoint(struct usbd_pipe
 	if (xfertype != UE_ISOCHRONOUS)
 		cp[1] |= htole32(XHCI_EPCTX_1_CERR_SET(3));
 
-	if (speed == USB_SPEED_SUPER) {
+	if (USB_IS_SS(speed)) {
 		usbd_desc_iter_t iter;
 		const usb_cdc_descriptor_t *cdcd;
 		const usb_endpoint_ss_comp_descriptor_t * esscd = NULL;
@@ -1233,7 +1254,7 @@ xhci_configure_endpoint(struct usbd_pipe
 		} else {
 			ival = ival > 15 ? 15 : ival;
 		}
-		if (speed == USB_SPEED_SUPER) {
+		if (USB_IS_SS(speed)) {
 			if (maxb > 0)
 				mps = 1024;
 		} else {
@@ -1246,7 +1267,7 @@ xhci_configure_endpoint(struct usbd_pipe
 		    );
 		break;
 	case UE_CONTROL:
-		if (speed == USB_SPEED_SUPER)
+		if (USB_IS_SS(speed))
 			mps = 512;
 		else
 			mps = mps ? mps : 8;
@@ -1261,7 +1282,7 @@ xhci_configure_endpoint(struct usbd_pipe
 		} else {
 			ival = ival > 15 ? 15 : ival;
 		}
-		if (speed == USB_SPEED_SUPER) {
+		if (USB_IS_SS(speed)) {
 			mps = 1024;
 		} else {
 			mps = mps ? mps : 1024;
@@ -1271,7 +1292,7 @@ xhci_configure_endpoint(struct usbd_pipe
 		break;
 #endif
 	default:
-		if (speed == USB_SPEED_SUPER)
+		if (USB_IS_SS(speed))
 			mps = 1024;
 		else
 			mps = mps ? mps : 512;
@@ -1985,10 +2006,10 @@ xhci_new_device(device_t parent, struct 
 	dev->ud_ep0desc.bEndpointAddress = USB_CONTROL_ENDPOINT;
 	dev->ud_ep0desc.bmAttributes = UE_CONTROL;
 	/* 4.3,  4.8.2.1 */
-	switch (speed) {
-	case USB_SPEED_SUPER:
+	if (USB_IS_SS(speed)) {
 		USETW(dev->ud_ep0desc.wMaxPacketSize, USB_3_MAX_CTRL_PACKET);
-		break;
+	} else
+	switch (speed) {
 	case USB_SPEED_FULL:
 		/* XXX using 64 as initial mps of ep0 in FS */
 	case USB_SPEED_HIGH:
@@ -2119,7 +2140,7 @@ xhci_new_device(device_t parent, struct 
 		if (err)
 			goto bad;
 		/* 4.8.2.1 */
-		if (speed == USB_SPEED_SUPER) {
+		if (USB_IS_SS(speed)) {
 			if (dd->bMaxPacketSize != 9) {
 				printf("%s: invalid mps 2^%u for SS ep0,"
 				    " using 512\n",
@@ -2766,34 +2787,20 @@ xhci_roothub_ctrl(struct usbd_bus *bus, 
 		}
 		v = xhci_op_read_4(sc, XHCI_PORTSC(index));
 		DPRINTFN(4, "getrhportsc %d %08x", index, v, 0, 0);
-		switch (XHCI_PS_SPEED_GET(v)) {
-		case 1:
-			i = UPS_FULL_SPEED;
-			break;
-		case 2:
-			i = UPS_LOW_SPEED;
-			break;
-		case 3:
-			i = UPS_HIGH_SPEED;
-			break;
-		case 4:
-			i = UPS_SUPER_SPEED;
-			break;
-		default:
-			i = 0;
-			break;
-		}
+		i = xhci_xspeed2psspeed(XHCI_PS_SPEED_GET(v));
 		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_SUSP)	i |= UPS_SUSPEND;
 		if (v & XHCI_PS_PR)	i |= UPS_RESET;
 		if (v & XHCI_PS_PP) {
-			if (i & UPS_SUPER_SPEED)
+			if (i & UPS_OTHER_SPEED)
 					i |= UPS_PORT_POWER_SS;
 			else
 					i |= UPS_PORT_POWER;
 		}
+		if (i & UPS_OTHER_SPEED)
+			i |= UPS_PORT_LS_SET(XHCI_PS_PLS_GET(v));
 		USETW(ps.wPortStatus, i);
 		i = 0;
 		if (v & XHCI_PS_CSC)    i |= UPS_C_CONNECT_STATUS;
@@ -2853,7 +2860,7 @@ xhci_roothub_ctrl(struct usbd_bus *bus, 
 			xhci_op_write_4(sc, port, v | XHCI_PS_PRC);
 			break;
 		case UHF_PORT_U1_TIMEOUT:
-			if (XHCI_PS_SPEED_GET(v) != 4) {
+			if (USB_IS_SS(xhci_xspeed2speed(XHCI_PS_SPEED_GET(v)))){
 				return -1;
 			}
 			port = XHCI_PORTPMSC(index);
@@ -2863,7 +2870,7 @@ xhci_roothub_ctrl(struct usbd_bus *bus, 
 			xhci_op_write_4(sc, port, v);
 			break;
 		case UHF_PORT_U2_TIMEOUT:
-			if (XHCI_PS_SPEED_GET(v) != 4) {
+			if (USB_IS_SS(xhci_xspeed2speed(XHCI_PS_SPEED_GET(v)))){
 				return -1;
 			}
 			port = XHCI_PORTPMSC(index);

Reply via email to