tech-kern archive

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

Re: Help: USB 3.0 xHCI driver does not support non-root hub



Hello,

I think 3.0 hub should work with this patch, but
either HS hub or SS hub in 3.0 hub may not be recognised.

still xhci is at best experimental.


Fixes:

- Fix incorrect route string was set.
  Correct route string does not contain root hub port.
- Fix FS and LS devices were not recognised.
  Speed values were swapped.

Known bugs:

- 3.0 hub should work, but either HS hub or SS hub in 3.0 hub
  may not be recognised.
  It looks one of these simultaneous interrupts is lost.
- xhci may not recognise devices at boot.
  This is regression.
- Detaching hubs or devices may cause panic.
- MTT,TTT and TT* fields in slot context is not set.
- Power management is not implemented.

Misc bugs:

- Closing pipe does not work correctly,
  e.g. ifconfig axen0 up -> down -> up won't work.
- Some of umass devices won't work due to STALL error.
  They don't understand MODE_SENSE_{6,10} command but stalls.
  xhci.c cannot recover stalled bulk endpoints.
- xhci.c cannot handle cross-64k transfer yet.
- Memory leaks here and there in error paths.
- Slot leaks.
  Devices cannot be added more than 32 times on xhci.
- Conextant umodem is not recognised (fail with XACT/PARAMETER).
  hmmmmm what is missing...
- may not work on big endian.
- Address of root hub is 0.
- needs more comments.


If your xhci fortunately recognise 3.0 hub successfully,
things will go like this:

# usbdevs -dv -f /dev/usb5
Controller /dev/usb5:
addr 0: super speed, self powered, config 1, xHCI Root Hub(0x0000), NetBSD(0x000
0), rev 1.00
  uhub0
 port 1 addr 1: super speed, self powered, config 1, USB3.0 Hub(0x0616), Genesys
Logic(0x05e3), rev 4.01
   uhub6
  port 1 powered
  port 2 powered
  port 3 addr 3: super speed, power 124 mA, config 1, AX88179(0x1790), ASIX Elec
. Corp.(0x0b95), rev 1.00, serial xxxxxxxxxxxxxx
    axen0
  port 4 addr 2: super speed, power 126 mA, config 1, ADATA USB Flash Drive(0x31
2b), ADATA(0x125f), rev 11.00, serial xxxxxxxxxxxxxxxx
    umass0
 port 2 powered
# dd if=/dev/rsd0d bs=256k count=1024 of=/dev/null msgfmt=human
1024+0 records in
1024+0 records out
268435456 bytes (256 MB) transferred in 3.614 secs (74276551 bytes/sec - 71 MB/s
ec)
#


Thanks,
--
t-hash
--- src/sys/dev/usb/uhub.c.orig	2014-08-14 07:02:24.000000000 +0900
+++ src/sys/dev/usb/uhub.c	2014-10-12 09:08:20.000000000 +0900
@@ -38,12 +38,15 @@
 #include <sys/cdefs.h>
 __KERNEL_RCSID(0, "$NetBSD: uhub.c,v 1.126 2014/08/13 06:26:32 skrll Exp $");
 
+#include "opt_usb.h"
+
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
 #include <sys/malloc.h>
 #include <sys/device.h>
 #include <sys/proc.h>
+#include <sys/sysctl.h>
 
 #include <sys/bus.h>
 
@@ -52,14 +55,44 @@ __KERNEL_RCSID(0, "$NetBSD: uhub.c,v 1.1
 #include <dev/usb/usbdi_util.h>
 #include <dev/usb/usbdivar.h>
 
-#ifdef UHUB_DEBUG
-#define DPRINTF(x)	if (uhubdebug) printf x
-#define DPRINTFN(n,x)	if (uhubdebug>(n)) printf x
-int	uhubdebug = 0;
-#else
+#ifdef USB_DEBUG
+#ifndef UHUB_DEBUG
+#define uhubdebug 0
 #define DPRINTF(x)
 #define DPRINTFN(n,x)
-#endif
+#else
+int	uhubdebug = 0;
+#define DPRINTF(x)	if (uhubdebug) printf x
+#define DPRINTFN(n,x)	if (uhubdebug>(n)) printf x
+
+SYSCTL_SETUP(sysctl_hw_uhub_setup, "sysctl hw.uhub setup")
+{
+	int err;
+	const struct sysctlnode *rnode;
+	const struct sysctlnode *cnode;
+
+	err = sysctl_createv(clog, 0, NULL, &rnode,
+	    CTLFLAG_PERMANENT, CTLTYPE_NODE, "uhub",
+	    SYSCTL_DESCR("uhub global controls"),
+	    NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL);
+
+	if (err)
+		goto fail;
+
+	/* control debugging printfs */
+	err = sysctl_createv(clog, 0, &rnode, &cnode,
+	    CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT,
+	    "debug", SYSCTL_DESCR("Enable debugging output"),
+	    NULL, 0, &uhubdebug, sizeof(uhubdebug), CTL_CREATE, CTL_EOL);
+	if (err)
+		goto fail;
+
+	return;
+fail:
+	aprint_error("%s: sysctl_createv failed (err = %d)\n", __func__, err);
+}
+#endif /* UHUB_DEBUG */
+#endif /* USB_DEBUG */
 
 struct uhub_softc {
 	device_t		sc_dev;		/* base device */
@@ -77,7 +110,12 @@ struct uhub_softc {
 	u_char			sc_running;
 };
 
+#if 1
+#define UHUB_IS_HIGH_SPEED(sc) \
+    ((sc)->sc_proto == UDPROTO_HSHUBSTT || (sc)->sc_proto == UDPROTO_HSHUBMTT)
+#else
 #define UHUB_IS_HIGH_SPEED(sc) ((sc)->sc_proto != UDPROTO_FSHUB)
+#endif
 #define UHUB_IS_SINGLE_TT(sc) ((sc)->sc_proto == UDPROTO_HSHUBSTT)
 
 #define PORTSTAT_ISSET(sc, port) \
@@ -182,6 +220,47 @@ uhub_attach(device_t parent, device_t se
 	}
 
 	/* Get hub descriptor. */
+#if 1
+	memset(&hubdesc, 0, sizeof(hubdesc));
+	if (dev->speed == USB_SPEED_SUPER && dev->depth != 0) {
+		usb_hub_ss_descriptor_t hubssdesc;
+
+		/* XXX: should add member hubssdesc to usbd_hub ? */
+		memset(&hubssdesc, 0, sizeof(hubssdesc));
+		req.bmRequestType = UT_READ_CLASS_DEVICE;
+		req.bRequest = UR_GET_DESCRIPTOR;
+		USETW2(req.wValue, UDESC_SSHUB, 0);
+		USETW(req.wIndex, 0);
+		USETW(req.wLength, USB_HUB_SS_DESCRIPTOR_SIZE);
+		DPRINTFN(1,("%s: getting sshub descriptor\n", __func__));
+		err = usbd_do_request(dev, &req, &hubssdesc);
+		memcpy(&hubdesc, &hubssdesc, sizeof(hubdesc));
+		memcpy(hubdesc.DeviceRemovable, hubssdesc.DeviceRemovable, 2);
+		hubdesc.bDescLength = USB_HUB_DESCRIPTOR_SIZE;
+		hubdesc.bDescriptorType = UDESC_HUB;
+		nports = hubdesc.bNbrPorts;
+		if (dev->depth != 0 && nports > UHD_SS_NPORTS_MAX) {
+			DPRINTF(("%s: num of ports %d exceeds maxports %d\n",
+			    device_xname(sc->sc_dev),
+			    nports, UHD_SS_NPORTS_MAX));
+			nports = hubdesc.bNbrPorts = UHD_SS_NPORTS_MAX;
+		}
+	} 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,("%s: getting hub descriptor\n", __func__));
+		err = usbd_do_request(dev, &req, &hubdesc);
+		nports = hubdesc.bNbrPorts;
+		if (!err && nports > 7) {
+			USETW(req.wLength,
+			    USB_HUB_DESCRIPTOR_SIZE + (nports+1) / 8);
+			err = usbd_do_request(dev, &req, &hubdesc);
+		}
+	}
+#else
 	req.bmRequestType = UT_READ_CLASS_DEVICE;
 	req.bRequest = UR_GET_DESCRIPTOR;
 	USETW2(req.wValue, UDESC_HUB, 0);
@@ -194,6 +273,7 @@ uhub_attach(device_t parent, device_t se
 		USETW(req.wLength, USB_HUB_DESCRIPTOR_SIZE + (nports+1) / 8);
 		err = usbd_do_request(dev, &req, &hubdesc);
 	}
+#endif
 	if (err) {
 		DPRINTF(("%s: getting hub descriptor failed, error=%s\n",
 		    device_xname(sc->sc_dev), usbd_errstr(err)));
@@ -221,6 +301,17 @@ uhub_attach(device_t parent, device_t se
 	hub->explore = uhub_explore;
 	hub->hubdesc = hubdesc;
 
+#if 1
+	if (dev->speed == USB_SPEED_SUPER && dev->depth != 0) {
+		aprint_debug_dev(self, "setting hub depth %u\n", dev->depth-1);
+		err = usbd_set_hub_depth(dev, dev->depth - 1);
+		if (err) {
+			aprint_error_dev(self, "can't set depth\n");
+			goto bad;
+		}
+	}
+#endif
+
 	/* Set up interrupt pipe. */
 	err = usbd_device2interface_handle(dev, 0, &iface);
 	if (err) {
@@ -475,6 +566,12 @@ uhub_explore(usbd_device_handle dev)
 		DPRINTF(("uhub_explore: status change hub=%d port=%d\n",
 			 dev->address, port));
 		usbd_clear_port_feature(dev, port, UHF_C_PORT_CONNECTION);
+#if 1
+		if (dev->speed == USB_SPEED_SUPER &&
+		    (change & UPS_C_PORT_LINK_STATE))
+			usbd_clear_port_feature(dev, port,
+			    UHF_C_PORT_LINK_STATE);
+#endif
 		/*
 		 * If there is already a device on the port the change status
 		 * must mean that is has disconnected.  Looking at the
@@ -500,7 +597,14 @@ uhub_explore(usbd_device_handle dev)
 
 		/* Connected */
 
+#if 0
+		if (!((status & UPS_PORT_POWER) &&
+		      (dev->speed != USB_SPEED_SUPER)) &&
+		    !((status & UPS_PORT_POWER_SS) &&
+		      (dev->speed == USB_SPEED_SUPER)))
+#else
 		if (!(status & UPS_PORT_POWER))
+#endif
 			aprint_normal_dev(sc->sc_dev,
 			    "strange, connected port %d has no power\n", port);
 
@@ -522,6 +626,10 @@ uhub_explore(usbd_device_handle dev)
 		}
 		status = UGETW(up->status.wPortStatus);
 		change = UGETW(up->status.wPortChange);
+#if 0
+		printf("%s port %d: s/c=%x/%x\n",
+		       device_xname(sc->sc_dev), port, status, change);
+#endif
 		if (!(status & UPS_CURRENT_CONNECT_STATUS)) {
 			/* Nothing connected, just ignore it. */
 #ifdef DIAGNOSTIC
@@ -540,8 +648,10 @@ uhub_explore(usbd_device_handle dev)
 		}
 
 		/* Figure out device speed */
-#if 0
-		if (status & UPS_SUPER_SPEED)
+#if 1
+		if ((status & UPS_SUPER_SPEED) ||
+		    (dev->speed == USB_SPEED_SUPER &&
+		    dev->powersrc->parent != NULL))
 			speed = USB_SPEED_SUPER;
 		else
 #endif
--- src/sys/dev/usb/usb.h.orig	2014-09-13 22:14:45.000000000 +0900
+++ src/sys/dev/usb/usb.h	2014-10-11 16:29:00.000000000 +0900
@@ -165,6 +165,8 @@ typedef struct {
 #define  UDESC_OTG		0x09
 #define  UDESC_DEBUG		0x0a
 #define  UDESC_INTERFACE_ASSOC	0x0b
+#define  UDESC_BOS		0x0f
+#define  UDESC_DEVICE_CAPABILITY 0x10
 #define  UDESC_CS_DEVICE	0x21	/* class specific */
 #define  UDESC_CS_CONFIG	0x22
 #define  UDESC_CS_STRING	0x23
@@ -172,23 +174,46 @@ typedef struct {
 #define  UDESC_CS_ENDPOINT	0x25
 #define  UDESC_HUB		0x29
 #define  UDESC_SSHUB		0x2a
+#define  UDESC_ENDPOINT_SS_COMP 0x30
+#define  UDESC_ENDPOINT_ISOCH_SSP_COMP	0x31
 #define UR_SET_DESCRIPTOR	0x07
 #define UR_GET_CONFIG		0x08
 #define UR_SET_CONFIG		0x09
 #define UR_GET_INTERFACE	0x0a
 #define UR_SET_INTERFACE	0x0b
 #define UR_SYNCH_FRAME		0x0c
+#define UR_SET_ENCRYPTION	0x0d
+#define UR_GET_ENCRYPTION	0x0e
+#define UR_SET_HANDSHAKE	0x0f
+#define UR_GET_HANDSHAKE	0x10
+#define UR_SET_CONNECTION	0x11
+#define UR_SET_SECURITY_DATA	0x12
+#define UR_GET_SECURITY_DATA	0x13
+#define UR_SET_WUSB_DATA	0x14
+#define UR_LOOPBACK_DATA_WRITE	0x15
+#define UR_LOOPBACK_DATA_READ	0x16
+#define UR_SET_INTERFACE_DS	0x17
+#define UR_SET_SEL		0x30
+#define UR_SET_ISOCH_DELAY	0x31
 
 /*
  * Feature selectors. USB 2.0 spec, table 9-6 and OTG and EH suppliment,
  * table 6-2
  */
 #define UF_ENDPOINT_HALT	0
+#define UF_INTERFACE_FUNCTION_SUSPEND	0
 #define UF_DEVICE_REMOTE_WAKEUP	1
 #define UF_TEST_MODE		2
 #define UF_DEVICE_B_HNP_ENABLE	3
 #define UF_DEVICE_A_HNP_SUPPORT	4
 #define UF_DEVICE_A_ALT_HNP_SUPPORT 5
+#define UF_DEVICE_WUSB_DEVICE	6
+#define UF_DEVICE_U1_ENABLE	48
+#define UF_DEVICE_U2_ENABLE	49
+#define UF_DEVICE_LTM_ENABLE	50
+#define UF_DEVICE_B3_NTF_HOST_SEL	51
+#define UF_DEVICE_B3_RESP_ENABLE	52
+#define UF_DEVICE_LDM_ENABLE	53
 
 #define USB_MAX_IPACKET		8 /* maximum size of the initial packet */
 
@@ -207,6 +232,7 @@ typedef struct {
 	uByte		bDescriptorType;
 	uWord		bcdUSB;
 #define UD_USB_2_0		0x0200
+#define UD_USB_3_0		0x0300
 #define UD_IS_USB2(d) (UGETW((d)->bcdUSB) >= UD_USB_2_0)
 	uByte		bDeviceClass;
 	uByte		bDeviceSubClass;
@@ -296,6 +322,105 @@ typedef struct {
 typedef struct {
 	uByte		bLength;
 	uByte		bDescriptorType;
+	uByte		bMaxBurst;
+	uByte		bmAttributes;
+#define UE_SSC_MAXSTREAMS(x)	__SHIFTOUT(x, __BITS(4,0))	/* bulk */
+#define UE_SSC_MULT(x)		__SHIFTOUT(x, __BITS(1,0))	/* isoch */
+#define UE_SSC_SSP_ISO(x) 	__SHIFTOUT(x, __BIT(7))		/* isoch */
+	/* The fields below are only valid for periodic endpoints */
+	uWord		wBytesPerInterval;
+} UPACKED usb_endpoint_ss_comp_descriptor_t;
+#define USB_ENDPOINT_SS_COMP_DESCRIPTOR_SIZE 6
+
+typedef struct {
+	uByte		bLength;
+	uByte		bDescriptorType;
+	uWord		wTotalLength;
+	uByte		bNumDeviceCaps;
+} UPACKED usb_bos_descriptor_t;
+#define USB_BOS_DESCRIPTOR_SIZE 5
+
+typedef struct {
+	uByte		bLength;
+	uByte		bDescriptorType;
+	uByte		bDevCapabilityType;
+#define USB_DEVCAP_RESERVED			0x00
+#define USB_DEVCAP_WUSB				0x01
+#define USB_DEVCAP_USB2EXT			0x02
+#define USB_DEVCAP_SUPER_SPEED			0x03
+#define USB_DEVCAP_CONTAINER_ID			0x04
+#define USB_DEVCAP_PLATFORM			0x05
+#define USB_DEVCAP_POWER_DELIVERY_CAPABILITY	0x06
+#define USB_DEVCAP_BATTERY_INFO_CAPABILITY	0x07
+#define USB_DEVCAP_PD_CONSUMER_PORT_CAPABILITY	0x08
+#define USB_DEVCAP_PD_PROVIDER_PORT_CAPABILITY	0x09
+#define USB_DEVCAP_SUPERSPEED_PLUS		0x0A
+#define USB_DEVCAP_PRECISION_TIME_MEASUREMENT	0x0B
+#define USB_DEVCAP_WUSB_EXT			0x0C
+	/* data ... */
+} UPACKED usb_device_capability_descriptor_t;
+#define USB_DEVICE_CAPABILITY_DESCRIPTOR_SIZE 3 /* variable length */
+
+typedef struct {
+	uByte		bLength;
+	uByte		bDescriptorType;
+	uByte		bDevCapabilityType;
+	uDWord		bmAttributes;
+#define USB_DEVCAP_USB2EXT_LPM __BIT(1)
+} UPACKED usb_usb2ext_descriptor_t;
+#define USB_DEVCAP_USB2EXT_DESCRIPTOR_SIZE 7
+
+typedef struct {
+	uByte		bLength;
+	uByte		bDescriptorType;
+	uByte		bDevCapabilityType;
+	uByte		bmAttributes;
+#define USB_DEVCAP_SS_LTM __BIT(1)
+	uWord		wSpeedsSupported;
+#define USB_DEVCAP_SS_SPEED_SS __BIT(0)
+#define USB_DEVCAP_SS_SPEED_FS __BIT(1)
+#define USB_DEVCAP_SS_SPEED_HS __BIT(2)
+#define USB_DEVCAP_SS_SPEED_LS __BIT(3)
+	uByte		bFunctionalitySupport;
+	uByte		bU1DevExitLat;
+	uWord		wU2DevExitLat;
+} UPACKED usb_devcap_ss_descriptor_t;
+#define USB_DEVCAP_SS_DESCRIPTOR_SIZE 10
+
+typedef struct {
+	uByte		bLength;
+	uByte		bDescriptorType;
+	uByte		bDevCapabilityType;
+	uByte		bReserved;
+	uByte		ContainerID[16];
+} UPACKED usb_devcap_container_id_descriptor_t;
+#define USB_DEVCAP_CONTAINER_ID_DESCRIPTOR_SIZE 20
+
+typedef struct {
+	uByte		bLength;
+	uByte		bDescriptorType;
+	uByte		bDevCapabilityType;
+	uByte		bReserved;
+	uByte		PlatformCapabilityUUID[16];
+	uByte		CapabilityData[0];
+} UPACKED usb_devcap_platform_descriptor_t;
+#define USB_DEVCAP_PLATFORM_DESCRIPTOR_SIZE 20
+
+typedef struct {
+	uByte		bLength;
+	uByte		bDescriptorType;
+	uByte		bDevCapabilityType;
+	uByte		bReserved;
+	uDWord		bmAttributes;
+	uWord		wFunctionalitySupport;
+	uWord		wReserved;
+	uDWord		bmSublinkSpeedAttr[0];
+} UPACKED usb_devcap_ssp_descriptor_t;
+#define USB_DEVCAP_SSP_DESCRIPTOR_SIZE 12 /* variable length */
+
+typedef struct {
+	uByte		bLength;
+	uByte		bDescriptorType;
 	uWord		bString[126];
 } UPACKED usb_string_descriptor_t;
 #define USB_MAX_STRING_LEN 128
@@ -308,6 +433,8 @@ typedef struct {
 #define UR_RESET_TT		0x09
 #define UR_GET_TT_STATE		0x0a
 #define UR_STOP_TT		0x0b
+#define UR_SET_HUB_DEPTH	0x0c
+#define UR_GET_PORT_ERR_COUNT	0x0d
 
 /*
  * Hub features from USB 2.0 spec, table 11-17 and updated by the
@@ -320,6 +447,7 @@ typedef struct {
 #define UHF_PORT_SUSPEND	2
 #define UHF_PORT_OVER_CURRENT	3
 #define UHF_PORT_RESET		4
+#define UHF_PORT_LINK_STATE	5
 #define UHF_PORT_POWER		8
 #define UHF_PORT_LOW_SPEED	9
 #define UHF_PORT_L1		10
@@ -332,10 +460,21 @@ typedef struct {
 #define UHF_PORT_INDICATOR	22
 #define UHF_C_PORT_L1		23
 
+/* SS HJB specific features */
+#define UHF_PORT_U1_TIMEOUT	23
+#define UHF_PORT_U2_TIMEOUT	24
+#define UHF_C_PORT_LINK_STATE	25
+#define UHF_C_PORT_CONFIG_ERROR	26
+#define UHF_PORT_REMOTE_WAKE_MASK	27
+#define UHF_BH_PORT_RESET	28
+#define UHF_C_BH_PORT_RESET	29
+#define UHF_FORCE_LINKPM_ACCEPT	30
+
 typedef struct {
 	uByte		bDescLength;
 	uByte		bDescriptorType;
 	uByte		bNbrPorts;
+#define UHD_NPORTS_MAX		255
 	uWord		wHubCharacteristics;
 #define UHD_PWR			0x0003
 #define  UHD_PWR_GANGED		0x0000
@@ -365,6 +504,20 @@ typedef struct {
 typedef struct {
 	uByte		bLength;
 	uByte		bDescriptorType;
+	uByte		bNbrPorts;
+#define UHD_SS_NPORTS_MAX	15
+	uWord		wHubCharacteristics;
+	uByte		bPwrOn2PwrGood;	/* delay in 2 ms units */
+	uByte		bHubContrCurrent;
+	uByte		bHubHdrDecLat;
+	uWord		wHubDelay;	/* forward delay in nanosec */
+	uByte		DeviceRemovable[2]; /* max 15 ports */
+} UPACKED usb_hub_ss_descriptor_t;
+#define USB_HUB_SS_DESCRIPTOR_SIZE 12
+
+typedef struct {
+	uByte		bLength;
+	uByte		bDescriptorType;
 	uWord		bcdUSB;
 	uByte		bDeviceClass;
 	uByte		bDeviceSubClass;
@@ -419,11 +572,26 @@ 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_U0			0x00
+#define UPS_PORT_LS_U1			0x01
+#define UPS_PORT_LS_U2			0x02
+#define UPS_PORT_LS_U3			0x03
+#define UPS_PORT_LS_SS_DIS		0x04
+#define UPS_PORT_LS_RX_DET		0x05
+#define UPS_PORT_LS_SS_INA		0x06
+#define UPS_PORT_LS_POLL		0x07
+#define UPS_PORT_LS_RECOVER		0x08
+#define UPS_PORT_LS_HOT_RST		0x09
+#define UPS_PORT_LS_COMP_MODE		0x0A
+#define UPS_PORT_LS_LOOPBACK		0x0B
+#define UPS_PORT_LS_RESUME		0x0F
 #define UPS_PORT_POWER			0x0100
+#define UPS_PORT_POWER_SS		0x0200
 #define UPS_FULL_SPEED			0x0000	/* for completeness */
 #define UPS_LOW_SPEED			0x0200
 #define UPS_HIGH_SPEED			0x0400
-#define UPS_SUPER_SPEED			0x0600
+#define UPS_SUPER_SPEED			0x0800
 #define UPS_PORT_TEST			0x0800
 #define UPS_PORT_INDICATOR		0x1000
 	uWord		wPortChange;
@@ -433,6 +601,9 @@ typedef struct {
 #define UPS_C_OVERCURRENT_INDICATOR	0x0008
 #define UPS_C_PORT_RESET		0x0010
 #define UPS_C_PORT_L1			0x0020
+#define UPS_C_BH_PORT_RESET		0x0020
+#define UPS_C_PORT_LINK_STATE		0x0040
+#define UPS_C_PORT_CONFIG_ERROR		0x0080
 } UPACKED usb_port_status_t;
 
 /* Device class codes */
@@ -501,6 +672,7 @@ typedef struct {
 #define  UIPROTO_MASS_CBI	1
 #define  UIPROTO_MASS_BBB_OLD	2	/* Not in the spec anymore */
 #define  UIPROTO_MASS_BBB	80	/* 'P' for the Iomega Zip drive */
+#define  UIPROTO_MASS_UAS	98	/* USB Attached SCSI */
 
 #define UICLASS_HUB		0x09
 #define  UISUBCLASS_HUB		0
--- src/sys/dev/usb/usb_subr.c.orig	2014-09-22 02:57:10.000000000 +0900
+++ src/sys/dev/usb/usb_subr.c	2014-10-07 01:21:12.000000000 +0900
@@ -1415,7 +1415,14 @@ usbd_fill_deviceinfo(usbd_device_handle 
 					err = USB_PORT_ENABLED;
 				else if (s & UPS_SUSPEND)
 					err = USB_PORT_SUSPENDED;
+#if 0
 				else if (s & UPS_PORT_POWER)
+#else
+				else if (s & UPS_PORT_POWER) /* 2.0 */
+					err = USB_PORT_POWERED;
+				else if ((s & UPS_PORT_POWER_SS) && /* 3.0 */
+				    dev->speed == USB_SPEED_SUPER)
+#endif
 					err = USB_PORT_POWERED;
 				else
 					err = USB_PORT_DISABLED;
--- src/sys/dev/usb/usbdi_util.c.orig	2014-09-13 22:14:45.000000000 +0900
+++ src/sys/dev/usb/usbdi_util.c	2014-10-06 23:22:36.000000000 +0900
@@ -191,6 +191,19 @@ usbd_set_hub_feature(usbd_device_handle 
 }
 
 usbd_status
+usbd_set_hub_depth(usbd_device_handle 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);
+}
+
+usbd_status
 usbd_clear_port_feature(usbd_device_handle dev, int port, int sel)
 {
 	usb_device_request_t req;
--- src/sys/dev/usb/usbdi_util.h.orig	2013-09-28 09:25:34.000000000 +0900
+++ src/sys/dev/usb/usbdi_util.h	2014-10-06 23:22:29.000000000 +0900
@@ -51,6 +51,7 @@ usbd_status	usbd_set_port_feature(usbd_d
 usbd_status	usbd_clear_port_feature(usbd_device_handle, int, int);
 usbd_status	usbd_get_device_status(usbd_device_handle, usb_status_t *);
 usbd_status	usbd_get_hub_status(usbd_device_handle, usb_hub_status_t *);
+usbd_status	usbd_set_hub_depth(usbd_device_handle, int);
 usbd_status	usbd_get_protocol(usbd_interface_handle dev, u_int8_t *report);
 usbd_status	usbd_set_protocol(usbd_interface_handle dev, int report);
 usbd_status	usbd_get_report_descriptor(usbd_device_handle dev, int ifcno,
--- src/sys/dev/usb/xhci.c.orig	2014-10-04 16:17:07.000000000 +0900
+++ src/sys/dev/usb/xhci.c	2014-10-12 10:08:27.000000000 +0900
@@ -100,6 +100,8 @@ fail:
 #define XHCIHIST_FUNC() USBHIST_FUNC()
 #define XHCIHIST_CALLED(name) USBHIST_CALLED(xhcidebug)
 
+#define XHCI_OLD_RH	/* overlap SS port and HS port */
+
 #define XHCI_DCI_SLOT 0
 #define XHCI_DCI_EP_CONTROL 1
 
@@ -113,7 +115,9 @@ struct xhci_pipe {
 #define XHCI_COMMAND_RING_TRBS 256
 #define XHCI_EVENT_RING_TRBS 256
 #define XHCI_EVENT_RING_SEGMENTS 1
+#ifndef XHCI_TRB_3_ED_BIT
 #define XHCI_TRB_3_ED_BIT XHCI_TRB_3_ISP_BIT
+#endif
 
 static usbd_status xhci_open(usbd_pipe_handle);
 static int xhci_intr1(struct xhci_softc * const);
@@ -140,6 +144,7 @@ static usbd_status xhci_init_slot(struct
     int, int, int, int);
 static usbd_status xhci_enable_slot(struct xhci_softc * const,
     uint8_t * const);
+//static usbd_status xhci_disable_slot(struct xhci_softc * const, uint8_t);
 static usbd_status xhci_address_device(struct xhci_softc * const,
     uint64_t, uint8_t, bool);
 static usbd_status xhci_update_ep0_mps(struct xhci_softc * const,
@@ -245,12 +250,29 @@ static const struct usbd_pipe_methods xh
 	.done = xhci_device_intr_done,
 };
 
+#if 0
+static inline uint32_t
+xhci_read_1(const struct xhci_softc * const sc, bus_size_t offset)
+{
+	return bus_space_read_1(sc->sc_iot, sc->sc_ioh, offset);
+}
+#endif
+
 static inline uint32_t
 xhci_read_4(const struct xhci_softc * const sc, bus_size_t offset)
 {
 	return bus_space_read_4(sc->sc_iot, sc->sc_ioh, offset);
 }
 
+#if 0
+static inline void
+xhci_write_1(const struct xhci_softc * const sc, bus_size_t offset,
+    uint32_t value)
+{
+	bus_space_write_1(sc->sc_iot, sc->sc_ioh, offset, value);
+}
+#endif
+
 #if 0 /* unused */
 static inline void
 xhci_write_4(const struct xhci_softc * const sc, bus_size_t offset,
@@ -615,8 +637,7 @@ xhci_init(struct xhci_softc *sc)
 
 	XHCIHIST_FUNC(); XHCIHIST_CALLED();
 
-	/* XXX Low/Full/High speeds for now */
-	sc->sc_bus.usbrev = USBREV_2_0;
+	sc->sc_bus.usbrev = USBREV_3_0;
 
 	cap = xhci_read_4(sc, XHCI_CAPLENGTH);
 	caplength = XHCI_CAP_CAPLENGTH(cap);
@@ -749,6 +770,7 @@ xhci_init(struct xhci_softc *sc)
 	aprint_debug_dev(sc->sc_dev, "sc_pgsz 0x%08x\n", (uint32_t)sc->sc_pgsz);
 	aprint_debug_dev(sc->sc_dev, "sc_maxslots 0x%08x\n",
 	    (uint32_t)sc->sc_maxslots);
+	aprint_debug_dev(sc->sc_dev, "sc_maxports %d\n", sc->sc_maxports);
 
 	usbd_status err;
 
@@ -952,21 +974,40 @@ xhci_intr1(struct xhci_softc * const sc)
 	return 1;
 }
 
+#ifdef XHCI_OLD_RH
+static int
+xhci_xspeed2speed(int xspeed/*, int devspeed*/)
+{
+	switch (xspeed) {
+	case 1:	return USB_SPEED_FULL;
+	case 2:	return USB_SPEED_LOW;
+	case 3:	return USB_SPEED_HIGH;
+	case 4:	return USB_SPEED_SUPER;
+	default:
+		break;
+	}
+	return 0;
+}
+#endif
+
 static usbd_status
 xhci_configure_endpoint(usbd_pipe_handle pipe)
 {
 	struct xhci_softc * const sc = pipe->device->bus->hci_private;
 	struct xhci_slot * const xs = pipe->device->hci_private;
-	const u_int dci = xhci_ep_get_dci(pipe->endpoint->edesc);
 	usb_endpoint_descriptor_t * const ed = pipe->endpoint->edesc;
+	const u_int dci = xhci_ep_get_dci(ed);
 	const uint8_t xfertype = UE_GET_XFERTYPE(ed->bmAttributes);
 	struct xhci_trb trb;
 	usbd_status err;
 	uint32_t *cp;
+	uint32_t mps = UGETW(ed->wMaxPacketSize);
+	int speed = pipe->device->speed;
+	bool ishub = (pipe->device->ddesc.bDeviceClass == UDCLASS_HUB);
 
 	XHCIHIST_FUNC(); XHCIHIST_CALLED();
-	DPRINTFN(4, "dci %u epaddr 0x%02x attr 0x%02x",
-	    dci, ed->bEndpointAddress, ed->bmAttributes, 0);
+	DPRINTFN(4, "slot %u dci %u epaddr 0x%02x attr 0x%02x",
+	    xs->xs_idx, dci, ed->bEndpointAddress, ed->bmAttributes);
 
 	/* XXX ensure input context is available? */
 
@@ -978,33 +1019,69 @@ xhci_configure_endpoint(usbd_pipe_handle
 
 	/* set up input slot context */
 	cp = xhci_slot_get_icv(sc, xs, xhci_dci_to_ici(XHCI_DCI_SLOT));
-	cp[0] = htole32(XHCI_SCTX_0_CTX_NUM_SET(dci));
+	cp[0] = htole32(
+	    XHCI_SCTX_0_CTX_NUM_SET(dci) |
+	    XHCI_SCTX_0_HUB_SET(ishub)
+#ifdef notyet
+	    XHCI_SCTX_0_MTT_SET(x)
+#endif
+	    );
 	cp[1] = htole32(0);
 	cp[2] = htole32(0);
 	cp[3] = htole32(0);
+	if (ishub && pipe->device->hub) {
+		usb_hub_descriptor_t *hd = &pipe->device->hub->hubdesc;
+
+		cp[1] |= htole32(XHCI_SCTX_1_NUM_PORTS_SET(hd->bNbrPorts));
+		cp[2] |= htole32(0);
+#ifdef notyet
+			XHCI_SCTX_2_TT_HUB_SID_SET(x) |
+			XHCI_SCTX_2_TT_PORT_NUM_SET(x) |
+			XHCI_SCTX_2_TT_THINK_TIME_SET(x) |
+#endif
+	}
 
 	cp = xhci_slot_get_icv(sc, xs, xhci_dci_to_ici(dci));
-	if (xfertype == UE_INTERRUPT) {
 	cp[0] = htole32(
-	    XHCI_EPCTX_0_IVAL_SET(3) /* XXX */
+	    XHCI_EPCTX_0_EPSTATE_SET(0) |
+	    XHCI_EPCTX_0_MAXP_STREAMS_SET(0) |
+	    XHCI_EPCTX_0_LSA_SET(0)
 	    );
 	cp[1] = htole32(
-	    XHCI_EPCTX_1_CERR_SET(3) |
-	    XHCI_EPCTX_1_EPTYPE_SET(xhci_ep_get_type(pipe->endpoint->edesc)) |
-	    XHCI_EPCTX_1_MAXB_SET(0) |
-	    XHCI_EPCTX_1_MAXP_SIZE_SET(8) /* XXX */
-	    );
-	cp[4] = htole32(
-		XHCI_EPCTX_4_AVG_TRB_LEN_SET(8)
-		);
-	} else {
-	cp[0] = htole32(0);
-	cp[1] = htole32(
-	    XHCI_EPCTX_1_CERR_SET(3) |
-	    XHCI_EPCTX_1_EPTYPE_SET(xhci_ep_get_type(pipe->endpoint->edesc)) |
-	    XHCI_EPCTX_1_MAXB_SET(0) |
-	    XHCI_EPCTX_1_MAXP_SIZE_SET(512) /* XXX */
+	    XHCI_EPCTX_1_EPTYPE_SET(xhci_ep_get_type(ed)) |
+	    XHCI_EPCTX_1_MAXB_SET(0)
 	    );
+	if (xfertype != UE_ISOCHRONOUS)
+		cp[1] |= htole32(XHCI_EPCTX_1_CERR_SET(3));
+
+	switch (xfertype) {
+	case UE_INTERRUPT:
+		cp[0] |= htole32(XHCI_EPCTX_0_IVAL_SET(3)); /* XXX */
+		cp[1] |= htole32(XHCI_EPCTX_1_MAXP_SIZE_SET(mps ? mps : 8));
+		cp[4] = htole32(
+		    XHCI_EPCTX_4_AVG_TRB_LEN_SET(8) | /* XXX */
+		    XHCI_EPCTX_4_MAX_ESIT_PAYLOAD_SET(8) /* XXX */
+		    );
+		break;
+	case UE_CONTROL:
+		cp[1] |= htole32(XHCI_EPCTX_1_MAXP_SIZE_SET(mps ? mps : 8));
+		cp[4] = htole32(XHCI_EPCTX_4_AVG_TRB_LEN_SET(8)); /* XXX */
+		break;
+#ifdef notyet
+	case UE_ISOCHRONOUS:
+		cp[1] |= htole32(XHCI_EPCTX_1_MAXP_SIZE_SET(mps ? mps : 512));
+		cp[4] = htole32(XHCI_EPCTX_4_AVG_TRB_LEN_SET(1024)); /* XXX */
+		break;
+#endif
+	default:
+		cp[1] |= htole32(XHCI_EPCTX_1_MAXP_SIZE_SET(mps ? mps : 512));
+		cp[4] = htole32(XHCI_EPCTX_4_AVG_TRB_LEN_SET(1024)); /* XXX */
+#if 1
+		if (speed == USB_SPEED_SUPER)
+		    /* XXX should be taken from endp SS comp desc */
+		    cp[1] |= htole32(XHCI_EPCTX_1_MAXB_SET(15));
+#endif
+		break;
 	}
 	*(uint64_t *)(&cp[2]) = htole64(
 	    xhci_ring_trbp(&xs->xs_ep[dci].xe_tr, 0) |
@@ -1034,6 +1111,49 @@ xhci_configure_endpoint(usbd_pipe_handle
 static usbd_status
 xhci_unconfigure_endpoint(usbd_pipe_handle pipe)
 {
+#if 0
+	struct xhci_softc * const sc = pipe->device->bus->hci_private;
+	struct xhci_slot * const xs = pipe->device->hci_private;
+	usb_endpoint_descriptor_t * const ed = pipe->endpoint->edesc;
+	const u_int dci = xhci_ep_get_dci(ed);
+	struct xhci_trb trb;
+	usbd_status err;
+	uint32_t *cp;
+
+	XHCIHIST_FUNC(); XHCIHIST_CALLED();
+	DPRINTFN(4, "slot %u dci %u", xs->xs_idx, dci, 0, 0);
+
+#if 0
+	if (dci == XHCI_DCI_EP_CONTROL) {
+		DPRINTFN(4, "avoid closing ep0");
+		return USBD_INVAL;
+	}
+#endif
+
+	(void)xhci_stop_endpoint(pipe);
+
+	memset(xhci_slot_get_icv(sc, xs, 0), 0, sc->sc_pgsz);
+
+	cp = xhci_slot_get_icv(sc, xs, XHCI_ICI_INPUT_CONTROL);
+	cp[0] = htole32(XHCI_INCTX_0_DROP_MASK(dci));
+	cp[1] = htole32(0);
+
+	cp = xhci_slot_get_icv(sc, xs, xhci_dci_to_ici(XHCI_DCI_SLOT));
+	cp[0] = htole32(XHCI_SCTX_0_CTX_NUM_SET(dci));
+
+	/* sync input contexts before they are read from memory */
+	usb_syncmem(&xs->xs_ic_dma, 0, sc->sc_pgsz, BUS_DMASYNC_PREWRITE);
+
+	trb.trb_0 = xhci_slot_get_icp(sc, xs, 0);
+	trb.trb_2 = 0;
+	trb.trb_3 = XHCI_TRB_3_SLOT_SET(xs->xs_idx) |
+	    XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_CONFIGURE_EP);
+
+	err = xhci_do_command(sc, &trb, USBD_DEFAULT_TIMEOUT);
+	usb_syncmem(&xs->xs_dc_dma, 0, sc->sc_pgsz, BUS_DMASYNC_POSTREAD);
+
+	return err;
+#else
 #ifdef USB_DEBUG
 	struct xhci_slot * const xs = pipe->device->hci_private;
 #endif
@@ -1042,6 +1162,7 @@ xhci_unconfigure_endpoint(usbd_pipe_hand
 	DPRINTFN(4, "slot %u", xs->xs_idx, 0, 0, 0);
 
 	return USBD_NORMAL_COMPLETION;
+#endif
 }
 
 static usbd_status
@@ -1054,7 +1175,7 @@ xhci_reset_endpoint(usbd_pipe_handle pip
 	usbd_status err;
 
 	XHCIHIST_FUNC(); XHCIHIST_CALLED();
-	DPRINTFN(4, "dci %u", dci, 0, 0, 0);
+	DPRINTFN(4, "slot %u dci %u", xs->xs_idx, dci, 0, 0);
 
 	trb.trb_0 = 0;
 	trb.trb_2 = 0;
@@ -1078,7 +1199,7 @@ xhci_stop_endpoint(usbd_pipe_handle pipe
 	const u_int dci = xhci_ep_get_dci(pipe->endpoint->edesc);
 
 	XHCIHIST_FUNC(); XHCIHIST_CALLED();
-	DPRINTFN(4, "dci %u", dci, 0, 0, 0);
+	DPRINTFN(4, "slot %u dci %u", xs->xs_idx, dci, 0, 0);
 
 	trb.trb_0 = 0;
 	trb.trb_2 = 0;
@@ -1139,8 +1260,7 @@ xhci_open(usbd_pipe_handle pipe)
 		return USBD_IOERROR;
 
 	/* Root Hub */
-	if (dev->depth == 0 && dev->powersrc->portno == 0 &&
-	    dev->speed != USB_SPEED_SUPER) {
+	if (dev->depth == 0 && dev->powersrc->portno == 0) {
 		switch (ed->bEndpointAddress) {
 		case USB_CONTROL_ENDPOINT:
 			pipe->methods = &xhci_root_ctrl_methods;
@@ -1177,7 +1297,7 @@ xhci_open(usbd_pipe_handle pipe)
 	}
 
 	if (ed->bEndpointAddress != USB_CONTROL_ENDPOINT)
-		xhci_configure_endpoint(pipe);
+		return xhci_configure_endpoint(pipe);
 
 	return USBD_NORMAL_COMPLETION;
 }
@@ -1194,13 +1314,30 @@ xhci_rhpsc(struct xhci_softc * const sc,
 	if (xfer == NULL)
 		return;
 
-	if (!(port >= sc->sc_hs_port_start &&
-	    port < sc->sc_hs_port_start + sc->sc_hs_port_count))
-		return;
+#ifdef XHCI_OLD_RH
+	xfer->pipe->device->speed = xhci_xspeed2speed(
+	    XHCI_PS_SPEED_GET(xhci_op_read_4(sc, XHCI_PORTSC(port))));
+#if 1
+	DPRINTFN(4, "port %u status change speed %u xferlen %u\n",
+	    port, xfer->pipe->device->speed, xfer->length, 0);
+#endif
 
-	port -= sc->sc_hs_port_start;
-	port += 1;
-	DPRINTFN(4, "hs port %u status change", port, 0, 0, 0);
+	if (port >= sc->sc_hs_port_start &&
+	    port < sc->sc_hs_port_start + sc->sc_hs_port_count) {
+		port -= sc->sc_hs_port_start;
+		port += 1;
+		DPRINTFN(4, "hs port %u status change", port, 0, 0, 0);
+	} else if (port >= sc->sc_ss_port_start &&
+	    port < sc->sc_ss_port_start + sc->sc_ss_port_count) {
+		port -= sc->sc_ss_port_start;
+		port += 1;
+		DPRINTFN(4, "ss port %u status change", port, 0, 0, 0);
+	} else {
+		/* cannot happen */
+		DPRINTFN(0, "port %u out of range", port, 0, 0, 0);
+		return;
+	}
+#endif /* XHCI_OLD_RH */
 
 	p = KERNADDR(&xfer->dmabuf, 0);
 	memset(p, 0, xfer->length);
@@ -1248,6 +1385,11 @@ xhci_handle_event(struct xhci_softc * co
 			xx = (void *)(uintptr_t)(trb_0 & ~0x3);
 		}
 		xfer = &xx->xx_xfer;
+		if (xfer == NULL) {
+			/* STOP_EP may cause this condition. */ 
+			DPRINTFN(1, "xfer is NULL", 0, 0, 0, 0);
+			break;
+		}
 		DPRINTFN(14, "xfer %p", xfer, 0, 0, 0);
 
 		if ((trb_3 & XHCI_TRB_3_ED_BIT) != 0) {
@@ -1269,7 +1411,10 @@ xhci_handle_event(struct xhci_softc * co
 			xfer->actlen = xfer->length - XHCI_TRB_2_REM_GET(trb_2);
 			err = USBD_NORMAL_COMPLETION;
 		} else if (XHCI_TRB_2_ERROR_GET(trb_2) ==
-		    XHCI_TRB_ERROR_STALL) {
+		    XHCI_TRB_ERROR_STALL ||
+		    XHCI_EPCTX_0_EPSTATE_GET(
+		     le32toh(((uint32_t *)xhci_slot_get_dcv(sc, xs, dci)))[0])
+		    == XHCI_EPSTATE_HALTED) {
 			err = USBD_STALLED;
 			xr->is_halted = true;
 			DPRINTFN(1, "ev: xfer done: err %u slot %u dci %u",
@@ -1468,11 +1613,11 @@ xhci_new_device(device_t parent, usbd_bu
 	usbd_status err;
 	usb_device_descriptor_t *dd;
 	struct usbd_device *hub;
-	struct usbd_device *adev;
+	uint32_t route = 0;
 	int rhport = 0;
 	struct xhci_slot *xs;
 	uint32_t *cp;
-	uint8_t slot;
+	uint8_t slot = 0;
 	uint8_t addr;
 
 	XHCIHIST_FUNC(); XHCIHIST_CALLED();
@@ -1515,28 +1660,36 @@ xhci_new_device(device_t parent, usbd_bu
 	up->device = dev;
 
 	/* Locate root hub port */
-	for (adev = dev, hub = dev;
-	    hub != NULL;
-	    adev = hub, hub = hub->myhub) {
-		DPRINTFN(4, "hub %p", hub, 0, 0, 0);
-	}
-	DPRINTFN(4, "hub %p", hub, 0, 0, 0);
-
-	if (hub != NULL) {
-		for (int p = 0; p < hub->hub->hubdesc.bNbrPorts; p++) {
-			if (hub->hub->ports[p].device == adev) {
-				rhport = p;
-			}
-		}
-	} else {
-		rhport = port;
-	}
-	if (speed == USB_SPEED_SUPER) {
-		rhport += sc->sc_ss_port_start - 1;
-	} else {
-		rhport += sc->sc_hs_port_start - 1;
+	for (hub = dev; hub != NULL; hub = hub->myhub) {
+		uint32_t dep;
+		uint8_t rh_port;
+
+		DPRINTFN(4, "hub %p depth %d upport %p upportno %d",
+		    hub, hub->depth, hub->powersrc,
+		    hub->powersrc ? hub->powersrc->portno : 0);
+
+		if (hub->powersrc == NULL)
+			break;
+		dep = hub->depth;
+		rh_port = hub->powersrc->portno;
+		if (dep == 0 || dep > USB_HUB_MAX_DEPTH)
+			break;
+		if (rh_port > UHD_SS_NPORTS_MAX)
+			rh_port = UHD_SS_NPORTS_MAX;
+
+		route |= rh_port << ((dep - 1) * 4);
 	}
-	DPRINTFN(4, "rhport %d", rhport, 0, 0, 0);
+	rhport = route & 0xf;
+	route = route >> 4;
+
+#ifdef XHCI_OLD_RH
+	if (speed == USB_SPEED_SUPER)
+		rhport = rhport + sc->sc_ss_port_start - 1;
+	else
+		rhport = rhport + sc->sc_hs_port_start - 1;
+#endif
+
+	DPRINTFN(4, "rhport %d Route %05x hub %p", rhport, route, hub, 0);
 
 	dev->speed = speed;
 	dev->langid = USBD_NOLANG;
@@ -1565,7 +1718,7 @@ xhci_new_device(device_t parent, usbd_bu
 		err = xhci_enable_slot(sc, &slot);
 		if (err)
 			return err;
-		err = xhci_init_slot(sc, slot, depth, speed, port, rhport);
+		err = xhci_init_slot(sc, slot, depth, speed, route, rhport);
 		if (err)
 			return err;
 		xs = &sc->sc_slots[slot];
@@ -1617,7 +1770,7 @@ xhci_new_device(device_t parent, usbd_bu
 
 	if ((depth == 0) && (port == 0)) {
 		usbd_attach_roothub(parent, dev);
-		DPRINTFN(1, "root_hub %p", bus->root_hub, 0, 0, 0);
+		DPRINTFN(1, "root_hub attached", 0, 0, 0, 0);
 		return USBD_NORMAL_COMPLETION;
 	}
 
@@ -1844,6 +2006,24 @@ xhci_enable_slot(struct xhci_softc * con
 	return err;
 }
 
+#if 0
+static usbd_status
+xhci_disable_slot(struct xhci_softc * const sc, uint8_t slot)
+{
+	struct xhci_trb trb;
+
+	XHCIHIST_FUNC(); XHCIHIST_CALLED();
+
+	trb.trb_0 = 0;
+	trb.trb_2 = 0;
+	trb.trb_3 = htole32(
+		XHCI_TRB_3_SLOT_SET(slot) |
+		XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_DISABLE_SLOT));
+
+	return xhci_do_command(sc, &trb, USBD_DEFAULT_TIMEOUT);
+}
+#endif
+
 static usbd_status
 xhci_address_device(struct xhci_softc * const sc,
     uint64_t icp, uint8_t slot_id, bool bsr)
@@ -1962,6 +2142,7 @@ xhci_init_slot(struct xhci_softc * const
 	err = usb_allocmem(&sc->sc_bus, sc->sc_pgsz, sc->sc_pgsz,
 	    &xs->xs_ic_dma);
 	if (err)
+		/* free xs_dc_dma */
 		return err;
 	memset(KERNADDR(&xs->xs_ic_dma, 0), 0, sc->sc_pgsz);
 
@@ -1988,6 +2169,7 @@ xhci_init_slot(struct xhci_softc * const
 	cp = xhci_slot_get_icv(sc, xs, xhci_dci_to_ici(XHCI_DCI_SLOT));
 	cp[0] = htole32(
 		XHCI_SCTX_0_CTX_NUM_SET(1) |
+		XHCI_SCTX_0_ROUTE_SET(port) |
 		XHCI_SCTX_0_SPEED_SET(xspeed)
 		);
 	cp[1] = htole32(
@@ -2042,73 +2224,77 @@ xhci_noop(usbd_pipe_handle pipe)
 /* root hub descriptors */
 
 static const usb_device_descriptor_t xhci_devd = {
-	USB_DEVICE_DESCRIPTOR_SIZE,
-	UDESC_DEVICE,		/* type */
-	{0x00, 0x02},		/* USB version */
-	UDCLASS_HUB,		/* class */
-	UDSUBCLASS_HUB,		/* subclass */
-	UDPROTO_HSHUBSTT,	/* protocol */
-	64,			/* max packet */
-	{0},{0},{0x00,0x01},	/* device id */
-	1,2,0,			/* string indexes */
-	1			/* # of configurations */
+	.bLength		= USB_DEVICE_DESCRIPTOR_SIZE,
+	.bDescriptorType	= UDESC_DEVICE,		/* type */
+	.bcdUSB			= {0x00, 0x02},		/* USB version */
+	.bDeviceClass		= UDCLASS_HUB,		/* class */
+	.bDeviceSubClass	= UDSUBCLASS_HUB,	/* subclass */
+	.bDeviceProtocol	= UDPROTO_HSHUBSTT,	/* protocol */
+	.bMaxPacketSize		= 64,			/* max packet */
+	.idVendor		= {0},
+	.idProduct		= {0},
+	.bcdDevice		= {0x00, 0x01},		/* device id */
+	.iManufacturer		= 1,			/* string indexes */
+	.iProduct		= 2,
+	.iSerialNumber		= 0,
+	.bNumConfigurations	= 1		/* # of configurations */
 };
 
 static const usb_device_qualifier_t xhci_odevd = {
-	USB_DEVICE_DESCRIPTOR_SIZE,
-	UDESC_DEVICE_QUALIFIER,	/* type */
-	{0x00, 0x02},		/* USB version */
-	UDCLASS_HUB,		/* class */
-	UDSUBCLASS_HUB,		/* subclass */
-	UDPROTO_FSHUB,		/* protocol */
-	64,                     /* max packet */
-	1,                      /* # of configurations */
-	0
+	.bLength		= USB_DEVICE_DESCRIPTOR_SIZE,
+	.bDescriptorType	= UDESC_DEVICE_QUALIFIER,	/* type */
+	.bcdUSB			= {0x00, 0x02},		/* USB version */
+	.bDeviceClass		= UDCLASS_HUB,		/* class */
+	.bDeviceSubClass	= UDSUBCLASS_HUB,	/* subclass */
+	.bDeviceProtocol	= UDPROTO_FSHUB,	/* protocol */
+	.bMaxPacketSize0	= 64,			/* max packet */
+	.bNumConfigurations	= 1,		/* # of configurations */
+	.bReserved		= 0
 };
 
 static const usb_config_descriptor_t xhci_confd = {
-	USB_CONFIG_DESCRIPTOR_SIZE,
-	UDESC_CONFIG,
-	{USB_CONFIG_DESCRIPTOR_SIZE +
-	 USB_INTERFACE_DESCRIPTOR_SIZE +
-	 USB_ENDPOINT_DESCRIPTOR_SIZE},
-	1,
-	1,
-	0,
-	UC_ATTR_MBO | UC_SELF_POWERED,
-	0                      /* max power */
+	.bLength		= USB_CONFIG_DESCRIPTOR_SIZE,
+	.bDescriptorType	= UDESC_CONFIG,
+	.wTotalLength		= {USB_CONFIG_DESCRIPTOR_SIZE +
+				 USB_INTERFACE_DESCRIPTOR_SIZE +
+				 USB_ENDPOINT_DESCRIPTOR_SIZE},
+	.bNumInterface		= 1,
+	.bConfigurationValue	= 1,
+	.iConfiguration		= 0,
+	.bmAttributes		= UC_ATTR_MBO | UC_SELF_POWERED,
+	.bMaxPower		= 0	/* max current in 2 mA units */
 };
 
 static const usb_interface_descriptor_t xhci_ifcd = {
-	USB_INTERFACE_DESCRIPTOR_SIZE,
-	UDESC_INTERFACE,
-	0,
-	0,
-	1,
-	UICLASS_HUB,
-	UISUBCLASS_HUB,
-	UIPROTO_HSHUBSTT,
-	0
+	.bLength		= USB_INTERFACE_DESCRIPTOR_SIZE,
+	.bDescriptorType	= UDESC_INTERFACE,
+	.bInterfaceNumber	= 0,
+	.bAlternateSetting	= 0,
+	.bNumEndpoints		= 1,
+	.bInterfaceClass	= UICLASS_HUB,
+	.bInterfaceSubClass	= UISUBCLASS_HUB,
+	.bInterfaceProtocol	= UIPROTO_HSHUBSTT,
+	.iInterface		= 0
 };
 
 static const usb_endpoint_descriptor_t xhci_endpd = {
-	USB_ENDPOINT_DESCRIPTOR_SIZE,
-	UDESC_ENDPOINT,
-	UE_DIR_IN | XHCI_INTR_ENDPT,
-	UE_INTERRUPT,
-	{8, 0},                 /* max packet */
-	12
+	.bLength		= USB_ENDPOINT_DESCRIPTOR_SIZE,
+	.bDescriptorType	= UDESC_ENDPOINT,
+	.bEndpointAddress	= UE_DIR_IN | XHCI_INTR_ENDPT,
+	.bmAttributes		= UE_INTERRUPT,
+	.wMaxPacketSize		= {64, 0},	/* max packet */
+	.bInterval		= 12
 };
 
 static const usb_hub_descriptor_t xhci_hubd = {
-	USB_HUB_DESCRIPTOR_SIZE,
-	UDESC_HUB,
-	0,
-	{0,0},
-	0,
-	0,
-	{""},
-	{""},
+	.bDescLength		= USB_HUB_DESCRIPTOR_SIZE,
+	.bDescriptorType	= UDESC_HUB,
+	.bNbrPorts		= 0,
+	.wHubCharacteristics	= {0, 0},
+	.bPwrOn2PwrGood		= 0,		/* delay in 2 ms units */
+	.bHubContrCurrent	= 0,
+	.DeviceRemovable	= {""},		/* max 255 ports */
+	.PortPowerCtrlMask	= {""},		/* deprecated */ 
 };
 
 /* root hub control */
@@ -2144,6 +2330,10 @@ xhci_root_ctrl_start(usbd_xfer_handle xf
 	int len, value, index;
 	int l, totlen = 0;
 	int port, i;
+#ifdef XHCI_OLD_RH
+	int ridx;
+#endif
+	int speed = xfer->pipe->device->speed;
 	uint32_t v;
 
 	XHCIHIST_FUNC(); XHCIHIST_CALLED();
@@ -2290,11 +2480,27 @@ xhci_root_ctrl_start(usbd_xfer_handle xf
 	case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER):
 		DPRINTFN(4, "UR_CLEAR_PORT_FEATURE port=%d feature=%d",
 			     index, value, 0, 0);
-		if (index < 1 || index > sc->sc_hs_port_count) {
+#ifdef XHCI_OLD_RH
+		if (speed == USB_SPEED_SUPER &&
+		    (index < 1 || index > sc->sc_ss_port_count)) {
+			err = USBD_IOERROR;
+			goto ret;
+		} else if (speed != USB_SPEED_SUPER &&
+		    (index < 1 || index > sc->sc_hs_port_count)) {
 			err = USBD_IOERROR;
 			goto ret;
 		}
-		port = XHCI_PORTSC(sc->sc_hs_port_start - 1 + index);
+		if (speed == USB_SPEED_SUPER)
+			port = XHCI_PORTSC(sc->sc_ss_port_start - 1 + index);
+		else
+			port = XHCI_PORTSC(sc->sc_hs_port_start - 1 + index);
+#else
+		if (index < 1 || index > sc->sc_maxports) {
+			err = USBD_IOERROR;
+			goto ret;
+		}
+		port = XHCI_PORTSC(index);
+#endif /* XHCI_OLD_RH */
 		v = xhci_op_read_4(sc, port);
 		DPRINTFN(4, "portsc=0x%08x", v, 0, 0, 0);
 		v &= ~XHCI_PS_CLEAR;
@@ -2335,8 +2541,41 @@ xhci_root_ctrl_start(usbd_xfer_handle xf
 			err = USBD_IOERROR;
 			goto ret;
 		}
+#if 0
+		if (speed == USB_SPEED_SUPER) {
+			usb_hub_ss_descriptor_t hubssd;
+	
+			hubssd = xhci_hubssd;
+			hubssd.bNbrPorts = sc->sc_ss_port_count;
+			/* XXX not defined in SS hub */
+			USETW(hubssd.wHubCharacteristics, UHD_PWR_NO_SWITCH);
+			hubssd.bPwrOn2PwrGood = 200;
+			hubssd.DeviceRemovable[0] = 0;
+			hubssd.DeviceRemovable[1] = 0;
+			l = min(len, hubssd.bLength);
+			totlen = l;
+			memcpy(buf, &hubssd, l);
+		} else {
+			hubd = xhci_hubd;
+			hubd.bNbrPorts = sc->sc_hs_port_count;
+			USETW(hubd.wHubCharacteristics, UHD_PWR_NO_SWITCH);
+			hubd.bPwrOn2PwrGood = 200;
+			for (i = 0, l = sc->sc_hs_port_count;
+			    l > 0; i++, l -= 8)
+				/* XXX can't find out? */
+				hubd.DeviceRemovable[i++] = 0;
+			hubd.bDescLength = USB_HUB_DESCRIPTOR_SIZE + i;
+			l = min(len, hubd.bDescLength);
+			totlen = l;
+			memcpy(buf, &hubd, l);
+		}
+#else
 		hubd = xhci_hubd;
+#ifdef XHCI_OLD_RH
 		hubd.bNbrPorts = sc->sc_hs_port_count;
+#else
+		hubd.bNbrPorts = sc->sc_maxports;
+#endif
 		USETW(hubd.wHubCharacteristics, UHD_PWR_NO_SWITCH);
 		hubd.bPwrOn2PwrGood = 200;
 		for (i = 0, l = sc->sc_maxports; l > 0; i++, l -= 8)
@@ -2345,6 +2584,7 @@ xhci_root_ctrl_start(usbd_xfer_handle xf
 		l = min(len, hubd.bDescLength);
 		totlen = l;
 		memcpy(buf, &hubd, l);
+#endif
 		break;
 	case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE):
 		if (len != 4) {
@@ -2364,10 +2604,20 @@ xhci_root_ctrl_start(usbd_xfer_handle xf
 			err = USBD_IOERROR;
 			goto ret;
 		}
-		v = xhci_op_read_4(sc, XHCI_PORTSC(sc->sc_hs_port_start - 1 +
-		    index));
+#ifdef XHCI_OLD_RH
+		if (speed == USB_SPEED_SUPER) {
+			ridx = sc->sc_ss_port_start - 1 + index;
+		} else {
+			ridx = sc->sc_hs_port_start - 1 + index;
+		}
+		v = xhci_op_read_4(sc, XHCI_PORTSC(ridx));
 		DPRINTFN(4, "READ_CLASS_OTHER GET_STATUS PORTSC %d (%d) %08x",
-		    index, sc->sc_hs_port_start - 1 + index, v, 0);
+		    index, ridx, v, 0);
+#else
+		v = xhci_op_read_4(sc, XHCI_PORTSC(index));
+		DPRINTFN(4, "READ_CLASS_OTHER GET_STATUS PORTSC %d %08x",
+		    index, v, 0, 0);
+#endif /* XHCI_OLD_RH */
 		switch (XHCI_PS_SPEED_GET(v)) {
 		case 1:
 			i = UPS_FULL_SPEED;
@@ -2378,6 +2628,12 @@ xhci_root_ctrl_start(usbd_xfer_handle xf
 		case 3:
 			i = UPS_HIGH_SPEED;
 			break;
+		case 4:
+			if (speed == USB_SPEED_SUPER)
+				i = UPS_SUPER_SPEED;
+			else
+				i = 0;
+			break;
 		default:
 			i = 0;
 			break;
@@ -2394,6 +2650,11 @@ xhci_root_ctrl_start(usbd_xfer_handle xf
 		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 0 /* 3.0 only */
+		if (v & XHCI_PS_WRC)	i |= UPS_C_BH_PORT_RESET;
+		if (v & XHCI_PS_PLC)	i |= UPS_C_PORT_LINK_STATE;
+		if (v & XHCI_PS_CEC)	i |= UPS_C_PORT_CONFIG_ERROR;
+#endif
 		USETW(ps.wPortChange, i);
 		l = min(len, sizeof ps);
 		memcpy(buf, &ps, l);
@@ -2402,14 +2663,32 @@ xhci_root_ctrl_start(usbd_xfer_handle xf
 	case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE):
 		err = USBD_IOERROR;
 		goto ret;
+	case C(UR_SET_HUB_DEPTH, UT_WRITE_CLASS_DEVICE):
+		break;
 	case C(UR_SET_FEATURE, UT_WRITE_CLASS_DEVICE):
 		break;
 	case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER):
-		if (index < 1 || index > sc->sc_hs_port_count) {
+#ifdef XHCI_OLD_RH
+		if (speed == USB_SPEED_SUPER &&
+		    (index < 1 || index > sc->sc_ss_port_count)) {
+			err = USBD_IOERROR;
+			goto ret;
+		} else if (speed != USB_SPEED_SUPER &&
+		    (index < 1 || index > sc->sc_hs_port_count)) {
+			err = USBD_IOERROR;
+			goto ret;
+		}
+		if (speed == USB_SPEED_SUPER)
+			port = XHCI_PORTSC(sc->sc_ss_port_start - 1 + index);
+		else
+			port = XHCI_PORTSC(sc->sc_hs_port_start - 1 + index);
+#else
+		if (index < 1 || index > sc->sc_maxports) {
 			err = USBD_IOERROR;
 			goto ret;
 		}
-		port = XHCI_PORTSC(sc->sc_hs_port_start - 1 + index);
+		port = XHCI_PORTSC(index);
+#endif /* XHCI_OLD_RH */
 		v = xhci_op_read_4(sc, port);
 		DPRINTFN(4, "portsc=0x%08x", v, 0, 0, 0);
 		v &= ~XHCI_PS_CLEAR;
@@ -2708,6 +2987,8 @@ static void
 xhci_device_ctrl_close(usbd_pipe_handle pipe)
 {
 	XHCIHIST_FUNC(); XHCIHIST_CALLED();
+
+	(void)xhci_unconfigure_endpoint(pipe);
 }
 
 /* ----------------- */
@@ -2828,6 +3109,8 @@ static void
 xhci_device_bulk_close(usbd_pipe_handle pipe)
 {
 	XHCIHIST_FUNC(); XHCIHIST_CALLED();
+
+	(void)xhci_unconfigure_endpoint(pipe);
 }
 
 /* --------------- */
--- src/sys/dev/usb/xhcireg.h.orig	2013-09-14 09:40:31.000000000 +0900
+++ src/sys/dev/usb/xhcireg.h	2014-10-11 16:48:19.000000000 +0900
@@ -38,6 +38,11 @@
 #define	 PCI_USBREV_3_0		0x30	/* USB 3.0 */
 #define	PCI_XHCI_FLADJ		0x61	/* RW frame length adjust */
 
+#define	PCI_XHCI_INTEL_XUSB2PR	0xD0    /* Intel USB2 Port Routing */
+#define	PCI_XHCI_INTEL_USB2PRM	0xD4    /* Intel USB2 Port Routing Mask */
+#define	PCI_XHCI_INTEL_USB3_PSSEN 0xD8  /* Intel USB3 Port SuperSpeed Enable */
+#define	PCI_XHCI_INTEL_USB3PRM	0xDC    /* Intel USB3 Port Routing Mask */
+
 /* XHCI capability registers */
 #define XHCI_CAPLENGTH		0x00	/* RO capability */
 #define	XHCI_CAP_CAPLENGTH(x)	((x) & 0xFF)
@@ -188,18 +193,20 @@
 /* XHCI legacy support */
 #define	XHCI_XECP_ID(x)		((x) & 0xFF)
 #define	XHCI_XECP_NEXT(x)	(((x) >> 8) & 0xFF)
-#if 0
 #define	XHCI_XECP_BIOS_SEM	0x0002
 #define	XHCI_XECP_OS_SEM	0x0003
-#endif
 
-/* XHCI capability ID's */
-#define	XHCI_ID_USB_LEGACY	0x0001
-#define	XHCI_ID_PROTOCOLS	0x0002
-#define	XHCI_ID_POWER_MGMT	0x0003
-#define	XHCI_ID_VIRTUALIZATION	0x0004
-#define	XHCI_ID_MSG_IRQ		0x0005
-#define	XHCI_ID_USB_LOCAL_MEM	0x0006
+/* XHCI extended capability ID's */
+#define	XHCI_ID_USB_LEGACY	0x0001	/* USB Legacy Support */
+#define	 XHCI_XECP_USBLESUP	0x0000	/* Legacy Support Capability Reg */
+#define	 XHCI_XECP_USBLEGCTLSTS	0x0004	/* Legacy Support Ctrl & Status Reg */
+#define	XHCI_ID_PROTOCOLS	0x0002	/* Supported Protocol */
+#define	XHCI_ID_POWER_MGMT	0x0003	/* Extended Power Management */
+#define	XHCI_ID_VIRTUALIZATION	0x0004	/* I/O Virtualization */
+#define	XHCI_ID_MSG_IRQ		0x0005	/* Message Interrupt */
+#define	XHCI_ID_USB_LOCAL_MEM	0x0006	/* Local Memory */
+#define	XHCI_ID_USB_DEBUG	0x000A	/* USB Debug Capability */
+#define	XHCI_ID_XMSG_IRQ	0x0011	/* Extended Message Interrupt */
 
 #define XHCI_PAGE_SIZE(sc) ((sc)->sc_pgsz)
 
@@ -243,6 +250,7 @@ struct xhci_trb {
 #define XHCI_TRB_3_TC_BIT               (1U << 1)       /* command ring only */
 #define XHCI_TRB_3_ENT_BIT              (1U << 1)       /* transfer ring only */
 #define XHCI_TRB_3_ISP_BIT              (1U << 2)
+#define XHCI_TRB_3_ED_BIT               (1U << 2)
 #define XHCI_TRB_3_NSNOOP_BIT           (1U << 3)
 #define XHCI_TRB_3_CHAIN_BIT            (1U << 4)
 #define XHCI_TRB_3_IOC_BIT              (1U << 5)
@@ -266,6 +274,8 @@ struct xhci_trb {
 #define XHCI_TRB_3_FRID_SET(x)          (((x) & 0x7FF) << 20)
 #define XHCI_TRB_3_ISO_SIA_BIT          (1U << 31)
 #define XHCI_TRB_3_SUSP_EP_BIT          (1U << 23)
+#define XHCI_TRB_3_VFID_GET(x)          (((x) >> 16) & 0xFF)
+#define XHCI_TRB_3_VFID_SET(x)          (((x) & 0xFF) << 16)
 #define XHCI_TRB_3_SLOT_GET(x)          (((x) >> 24) & 0xFF)
 #define XHCI_TRB_3_SLOT_SET(x)          (((x) & 0xFF) << 24)
 
@@ -375,10 +385,20 @@ struct xhci_trb {
 #define XHCI_SCTX_3_DEV_ADDR_GET(x)             ((x) & 0xFF)
 #define XHCI_SCTX_3_SLOT_STATE_SET(x)           (((x) & 0x1F) << 27)
 #define XHCI_SCTX_3_SLOT_STATE_GET(x)           (((x) >> 27) & 0x1F)
+#define XHCI_SLOTSTATE_DISABLED			0 /* disabled or enabled */
+#define XHCI_SLOTSTATE_ENABLED			0
+#define XHCI_SLOTSTATE_DEFAULT			1
+#define XHCI_SLOTSTATE_ADDRESSED		2
+#define XHCI_SLOTSTATE_CONFIGURED		3
 
 
 #define XHCI_EPCTX_0_EPSTATE_SET(x)             ((x) & 0x7)
 #define XHCI_EPCTX_0_EPSTATE_GET(x)             ((x) & 0x7)
+#define XHCI_EPSTATE_DISABLED			0
+#define XHCI_EPSTATE_RUNNING			1
+#define XHCI_EPSTATE_HALTED			2
+#define XHCI_EPSTATE_STOPPED			3
+#define XHCI_EPSTATE_ERROR			4
 #define XHCI_EPCTX_0_MULT_SET(x)                (((x) & 0x3) << 8)
 #define XHCI_EPCTX_0_MULT_GET(x)                (((x) >> 8) & 0x3)
 #define XHCI_EPCTX_0_MAXP_STREAMS_SET(x)        (((x) & 0x1F) << 10)


Home | Main Index | Thread Index | Old Index