Module Name:    src
Committed By:   skrll
Date:           Thu Dec  4 08:04:32 UTC 2014

Modified Files:
        src/sys/arch/mips/adm5120/dev [nick-nhusb]: ahci.c
        src/sys/arch/mips/conf [nick-nhusb]: files.adm5120
        src/sys/dev/ic [nick-nhusb]: sl811hs.c sl811hsvar.h
        src/sys/dev/usb [nick-nhusb]: ehci.c ehcivar.h motg.c motgvar.h ohci.c
            ohcivar.h uhci.c uhcivar.h usbdivar.h usbroothub.c usbroothub.h
            xhci.c xhcivar.h
        src/sys/external/bsd/dwc2 [nick-nhusb]: dwc2.c dwc2var.h
        src/sys/rump/dev/lib/libugenhc [nick-nhusb]: ugenhc.c

Log Message:
Rework roothub control transfers so that much of the code is shared
across HCDs.

I have retained the vendor/product reporting for each HCD for now,
but it maybe get removed later.

ahci(4) now reports a language table and uses the usb_makestrdesc
function instead of rolling its own version.


To generate a diff of this commit:
cvs rdiff -u -r1.12.6.9 -r1.12.6.10 src/sys/arch/mips/adm5120/dev/ahci.c
cvs rdiff -u -r1.3 -r1.3.32.1 src/sys/arch/mips/conf/files.adm5120
cvs rdiff -u -r1.47.6.9 -r1.47.6.10 src/sys/dev/ic/sl811hs.c
cvs rdiff -u -r1.11 -r1.11.6.1 src/sys/dev/ic/sl811hsvar.h
cvs rdiff -u -r1.234.2.12 -r1.234.2.13 src/sys/dev/usb/ehci.c
cvs rdiff -u -r1.42.14.3 -r1.42.14.4 src/sys/dev/usb/ehcivar.h
cvs rdiff -u -r1.12.2.8 -r1.12.2.9 src/sys/dev/usb/motg.c
cvs rdiff -u -r1.4.2.2 -r1.4.2.3 src/sys/dev/usb/motgvar.h
cvs rdiff -u -r1.254.2.11 -r1.254.2.12 src/sys/dev/usb/ohci.c
cvs rdiff -u -r1.55.6.2 -r1.55.6.3 src/sys/dev/usb/ohcivar.h
cvs rdiff -u -r1.264.4.11 -r1.264.4.12 src/sys/dev/usb/uhci.c
cvs rdiff -u -r1.52.14.2 -r1.52.14.3 src/sys/dev/usb/uhcivar.h
cvs rdiff -u -r1.109.2.6 -r1.109.2.7 src/sys/dev/usb/usbdivar.h
cvs rdiff -u -r1.1.2.1 -r1.1.2.2 src/sys/dev/usb/usbroothub.c \
    src/sys/dev/usb/usbroothub.h
cvs rdiff -u -r1.28.2.11 -r1.28.2.12 src/sys/dev/usb/xhci.c
cvs rdiff -u -r1.4.12.1 -r1.4.12.2 src/sys/dev/usb/xhcivar.h
cvs rdiff -u -r1.32.2.8 -r1.32.2.9 src/sys/external/bsd/dwc2/dwc2.c
cvs rdiff -u -r1.3.12.2 -r1.3.12.3 src/sys/external/bsd/dwc2/dwc2var.h
cvs rdiff -u -r1.22.4.6 -r1.22.4.7 src/sys/rump/dev/lib/libugenhc/ugenhc.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/arch/mips/adm5120/dev/ahci.c
diff -u src/sys/arch/mips/adm5120/dev/ahci.c:1.12.6.9 src/sys/arch/mips/adm5120/dev/ahci.c:1.12.6.10
--- src/sys/arch/mips/adm5120/dev/ahci.c:1.12.6.9	Wed Dec  3 22:40:54 2014
+++ src/sys/arch/mips/adm5120/dev/ahci.c	Thu Dec  4 08:04:31 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: ahci.c,v 1.12.6.9 2014/12/03 22:40:54 skrll Exp $	*/
+/*	$NetBSD: ahci.c,v 1.12.6.10 2014/12/04 08:04:31 skrll Exp $	*/
 
 /*-
  * Copyright (c) 2007 Ruslan Ermilov and Vsevolod Lobko.
@@ -64,7 +64,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ahci.c,v 1.12.6.9 2014/12/03 22:40:54 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ahci.c,v 1.12.6.10 2014/12/04 08:04:31 skrll Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -81,6 +81,7 @@ __KERNEL_RCSID(0, "$NetBSD: ahci.c,v 1.1
 #include <dev/usb/usbdivar.h>
 #include <dev/usb/usb_mem.h>
 #include <dev/usb/usbdevs.h>
+#include <dev/usb/usbroothub.h>
 
 #include <mips/adm5120/include/adm5120reg.h>
 #include <mips/adm5120/include/adm5120var.h>
@@ -98,14 +99,8 @@ static usbd_xfer_handle ahci_allocx(stru
 static void		ahci_freex(struct usbd_bus *, usbd_xfer_handle);
 
 static void		ahci_get_lock(struct usbd_bus *, kmutex_t **);
-
-static int		ahci_str(usb_string_descriptor_t *, int, const char *);
-
-static usbd_status	ahci_root_ctrl_transfer(usbd_xfer_handle);
-static usbd_status	ahci_root_ctrl_start(usbd_xfer_handle);
-static void		ahci_root_ctrl_abort(usbd_xfer_handle);
-static void		ahci_root_ctrl_close(usbd_pipe_handle);
-static void		ahci_root_ctrl_done(usbd_xfer_handle);
+static int		ahci_roothub_ctrl(struct usbd_bus *, usb_device_request_t *,
+    void *, int);
 
 static usbd_status	ahci_root_intr_transfer(usbd_xfer_handle);
 static usbd_status	ahci_root_intr_start(usbd_xfer_handle);
@@ -150,9 +145,6 @@ int ahci_dummy;
 
 #define AHCI_DEBUG
 
-/* For root hub */
-#define AHCI_INTR_ENDPT	(1)
-
 #ifdef AHCI_DEBUG
 #define D_TRACE	(0x0001)	/* function trace */
 #define D_MSG	(0x0002)	/* debug messages */
@@ -177,15 +169,7 @@ struct usbd_bus_methods ahci_bus_methods
 	.ubm_allocx = ahci_allocx,
 	.ubm_freex = ahci_freex,
 	.ubm_getlock = ahci_get_lock,
-};
-
-struct usbd_pipe_methods ahci_root_ctrl_methods = {
-	.upm_transfer = ahci_root_ctrl_transfer,
-	.upm_start = ahci_root_ctrl_start,
-	.upm_abort = ahci_root_ctrl_abort,
-	.upm_close = ahci_root_ctrl_close,
-	.upm_cleartoggle = ahci_noop,
-	.upm_done = ahci_root_ctrl_done,
+	.ubm_rhctrl = ahci_roothub_ctrl,
 };
 
 struct usbd_pipe_methods ahci_root_intr_methods = {
@@ -368,21 +352,21 @@ usbd_status
 ahci_open(usbd_pipe_handle pipe)
 {
 	usbd_device_handle dev = pipe->up_dev;
-	struct ahci_softc *sc = (struct ahci_softc *)dev->ud_bus;
 	struct ahci_pipe *apipe = (struct ahci_pipe *)pipe;
 	usb_endpoint_descriptor_t *ed = pipe->up_endpoint->ue_edesc;
+	uint8_t rhaddr = dev->ud_bus->ub_rhaddr;
 
 	DPRINTF(D_TRACE, ("ahci_open(addr=%d,ep=%d,scaddr=%d)",
-		dev->ud_addr, ed->bEndpointAddress, sc->sc_addr));
+		dev->ud_addr, ed->bEndpointAddress, rhaddr));
 
 	apipe->toggle=0;
 
-	if (dev->ud_addr == sc->sc_addr) {
+	if (dev->ud_addr == rhaddr) {
 		switch (ed->bEndpointAddress) {
 		case USB_CONTROL_ENDPOINT:
-			pipe->up_methods = &ahci_root_ctrl_methods;
+			pipe->up_methods = &roothub_ctrl_methods;
 			break;
-		case UE_DIR_IN | AHCI_INTR_ENDPT:
+		case UE_DIR_IN | USBROOTHUB_INTR_ENDPT:
 			pipe->up_methods = &ahci_root_intr_methods;
 			break;
 		default:
@@ -531,275 +515,52 @@ ahci_noop(usbd_pipe_handle pipe)
 /*
  * Data structures and routines to emulate the root hub.
  */
-usb_device_descriptor_t ahci_devd = {
-	.bLength = USB_DEVICE_DESCRIPTOR_SIZE,
-	.bDescriptorType = UDESC_DEVICE,
-	.bcdUSB = {0x01, 0x01},
-	.bDeviceClass = UDCLASS_HUB,
-	.bDeviceSubClass = UDSUBCLASS_HUB,
-	.bDeviceProtocol = 0,
-	.bMaxPacketSize = 64,
-	.idVendor = {
-		USB_VENDOR_SCANLOGIC & 0xff,
-		USB_VENDOR_SCANLOGIC >> 8
-	},
-	.idProduct = {0},
-	.bcdDevice = {0},
-	.iManufacturer = 1,
-	.iProduct = 2,
-	.iSerialNumber = 0,
-	.bNumConfigurations = 1
-};
-
-usb_config_descriptor_t ahci_confd = {
-	.bLength = USB_CONFIG_DESCRIPTOR_SIZE,
-	.bDescriptorType = UDESC_CONFIG,
-	.wTotalLength = USETWD(
-	    USB_CONFIG_DESCRIPTOR_SIZE +
-	    USB_INTERFACE_DESCRIPTOR_SIZE +
-	    USB_ENDPOINT_DESCRIPTOR_SIZE),
-	.bNumInterface = 1,
-	.bConfigurationValue = 1,
-	.iConfiguration = 0,
-	.bmAttributes = UC_SELF_POWERED,
-	.bMaxPower = 250
-};
-
-usb_interface_descriptor_t ahci_ifcd = {
-	.bLength = USB_INTERFACE_DESCRIPTOR_SIZE,
-	.bDescriptorType = UDESC_INTERFACE,
-	.bInterfaceNumber = 0,
-	.bAlternateSetting = 0,
-	.bNumEndpoints = 1,
-	.bInterfaceClass = UICLASS_HUB,
-	.bInterfaceSubClass = UISUBCLASS_HUB,
-	.bInterfaceProtocol = 0,
-	.iInterface = 0
-};
-
-usb_endpoint_descriptor_t ahci_endpd = {
-	.bLength = USB_ENDPOINT_DESCRIPTOR_SIZE,
-	.bDescriptorType = UDESC_ENDPOINT,
-	.bEndpointAddress = UE_DIR_IN | AHCI_INTR_ENDPT,
-	.bmAttributes = UE_INTERRUPT,
-	.wMaxPacketSize = USETWD(8),
-	.bInterval = 255
-};
-
-usb_hub_descriptor_t ahci_hubd = {
-	.bDescLength = USB_HUB_DESCRIPTOR_SIZE,
-	.bDescriptorType = UDESC_HUB,
-	.bNbrPorts = 2,
-	.wHubCharacteristics = USETWD(0),
-	.bPwrOn2PwrGood = 0,
-	.bHubContrCurrent = 0,
-	.DeviceRemovable = { 0x00 },
-	.PortPowerCtrlMask = { 0x00 }
-};
 
 static int
-ahci_str(usb_string_descriptor_t *p, int l, const char *s)
-{
-	int i;
-
-	if (l == 0)
-		return 0;
-	p->bLength = 2 * strlen(s) + 2;
-	if (l == 1)
-		return 1;
-	p->bDescriptorType = UDESC_STRING;
-	l -= 2;
-	for (i = 0; s[i] && l > 1; i++, l -= 2)
-		USETW2(p->bString[i], 0, s[i]);
-	return 2 * i + 2;
-}
-
-usbd_status
-ahci_root_ctrl_transfer(usbd_xfer_handle xfer)
-{
-	struct ahci_softc *sc = (struct ahci_softc *)xfer->ux_pipe->up_dev->ud_bus;
-	usbd_status error;
-
-	DPRINTF(D_TRACE, ("SLRCtrans "));
-
-	/* Insert last in queue */
-	mutex_enter(&sc->sc_lock);
-	error = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (error) {
-		DPRINTF(D_MSG, ("usb_insert_transfer returns err! "));
-		return error;
-	}
-
-	/*
-	 * Pipe isn't running (otherwise error would be USBD_INPROG),
-	 * so start it first.
-	 */
-	return ahci_root_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
-}
-
-usbd_status
-ahci_root_ctrl_start(usbd_xfer_handle xfer)
+ahci_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req,
+    void *buf, int buflen)
 {
-	struct ahci_softc *sc = (struct ahci_softc *)xfer->ux_pipe->up_dev->ud_bus;
-	usb_device_request_t *req;
-	int len, value, index, l, status;
-	int totlen = 0;
-	void *buf = NULL;
+	struct ahci_softc *sc = bus->ub_hcpriv;
+	uint16_t len, value, index;
 	usb_port_status_t ps;
-	usbd_status error;
-
+	int totlen = 0;
+	int status;
 
 	DPRINTF(D_TRACE, ("SLRCstart "));
 
-	req = &xfer->ux_request;
-
 	len = UGETW(req->wLength);
 	value = UGETW(req->wValue);
 	index = UGETW(req->wIndex);
 
-	if (len)
-		buf = KERNADDR(&xfer->ux_dmabuf, 0);
-
-#ifdef AHCI_DEBUG
-	if ((ahci_debug & D_TRACE))
-		print_req_hub(req);
-#endif
-
 #define C(x,y) ((x) | ((y) << 8))
 	switch (C(req->bRequest, req->bmRequestType)) {
-	case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE):
-		DPRINTF(D_MSG, ("UR_CLEAR_FEATURE(DEVICE)XXX "));
-		break;
-	case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE):
-		DPRINTF(D_MSG, ("UR_CLEAR_FEATURE(INTERFACE)XXX "));
-		break;
-	case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT):
-		DPRINTF(D_MSG, ("UR_CLEAR_FEATURE(ENDPOINT)XXX "));
-		break;
-	case C(UR_GET_CONFIG, UT_READ_DEVICE):
-		DPRINTF(D_MSG, ("UR_GET_CONFIG "));
-		if (len > 0) {
-			*(uint8_t *)buf = sc->sc_conf;
-			totlen = 1;
-		}
-		break;
 	case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE):
-		switch (value >> 8) {
-		case UDESC_DEVICE:
+		switch (value) {
+		case C(0, UDESC_DEVICE): {
+			usb_device_descriptor_t devd;
+
 			DPRINTF(D_MSG, ("UDESC_DEVICE "));
-			if ((value & 0xff) != 0) {
-				error = USBD_IOERROR;
-				goto ret;
-			}
-			totlen = l = min(len, USB_DEVICE_DESCRIPTOR_SIZE);
-			memcpy(buf, &ahci_devd, l);
-			break;
-		case UDESC_CONFIG:
-			DPRINTF(D_MSG, ("UDESC_CONFIG "));
-			if ((value & 0xff) != 0) {
-				error = USBD_IOERROR;
-				goto ret;
-			}
-			totlen = l = min(len, USB_CONFIG_DESCRIPTOR_SIZE);
-			memcpy(buf, &ahci_confd, l);
-			buf = (char *)buf + l;
-			len -= l;
-
-			l = min(len, USB_INTERFACE_DESCRIPTOR_SIZE);
-			totlen += l;
-			memcpy(buf, &ahci_ifcd, l);
-			buf = (char *)buf + l;
-			len -= l;
-
-			l = min(len, USB_ENDPOINT_DESCRIPTOR_SIZE);
-			totlen += l;
-			memcpy(buf, &ahci_endpd, l);
-			break;
-		case UDESC_STRING:
-			DPRINTF(D_MSG, ("UDESC_STR "));
-			if (len == 0)
-				break;
-			*(uint8_t *)buf = 0;
-			totlen = 1;
-			switch (value & 0xff) {
-			case 0:
-				break;
-			case 1:	/* Vendor */
-				totlen = ahci_str(buf, len, "ADMTek");
-				break;
-			case 2:	/* Product */
-				totlen = ahci_str(buf, len, "ADM5120 root hub");
-				break;
-			default:
-				printf("strerr%d ", value & 0xff);
-				break;
-			}
+			totlen = min(buflen, sizeof(devd));
+			memcpy(&devd, buf, totlen);
+			USETW(devd.idVendor, USB_VENDOR_SCANLOGIC);
+			memcpy(buf, &devd, totlen);
+			break;
+		}
+#define sd ((usb_string_descriptor_t *)buf)
+		case C(1, UDESC_STRING):
+			/* Vendor */
+			totlen = usb_makestrdesc(sd, len, "ADMTek");
+			break;
+		case C(2, UDESC_STRING):
+			/* Product */
+			totlen = usb_makestrdesc(sd, len, "ADM5120 root hub");
 			break;
 		default:
 			printf("unknownGetDescriptor=%x", value);
-			error = USBD_IOERROR;
-			break;
-		}
-		break;
-	case C(UR_GET_INTERFACE, UT_READ_INTERFACE):
-		/* Get Interface, 9.4.4 */
-		if (len > 0) {
-			*(uint8_t *)buf = 0;
-			totlen = 1;
-		}
-		break;
-	case C(UR_GET_STATUS, UT_READ_DEVICE):
-		/* Get Status from device, 9.4.5 */
-		if (len > 1) {
-			USETW(((usb_status_t *)buf)->wStatus, UDS_SELF_POWERED);
-			totlen = 2;
-		}
-		break;
-	case C(UR_GET_STATUS, UT_READ_INTERFACE):
-	case C(UR_GET_STATUS, UT_READ_ENDPOINT):
-		/* Get Status from interface, endpoint, 9.4.5 */
-		if (len > 1) {
-			USETW(((usb_status_t *)buf)->wStatus, 0);
-			totlen = 2;
-		}
-		break;
-	case C(UR_SET_ADDRESS, UT_WRITE_DEVICE):
-		/* Set Address, 9.4.6 */
-		DPRINTF(D_MSG, ("UR_SET_ADDRESS "));
-		if (value >= USB_MAX_DEVICES) {
-			error = USBD_IOERROR;
-			goto ret;
+			/* default from usbroothub */
+			return buflen;
 		}
-		sc->sc_addr = value;
-		break;
-	case C(UR_SET_CONFIG, UT_WRITE_DEVICE):
-		/* Set Configuration, 9.4.7 */
-		DPRINTF(D_MSG, ("UR_SET_CONFIG "));
-		if (value != 0 && value != 1) {
-			error = USBD_IOERROR;
-			goto ret;
-		}
-		sc->sc_conf = value;
-		break;
-	case C(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE):
-		/* Set Descriptor, 9.4.8, not supported */
-		DPRINTF(D_MSG, ("UR_SET_DESCRIPTOR,WRITE_DEVICE not supported\n"));
 		break;
-	case C(UR_SET_FEATURE, UT_WRITE_DEVICE):
-	case C(UR_SET_FEATURE, UT_WRITE_INTERFACE):
-	case C(UR_SET_FEATURE, UT_WRITE_ENDPOINT):
-		/* Set Feature, 9.4.9, not supported */
-		DPRINTF(D_MSG, ("UR_SET_FEATURE not supported\n"));
-		error = USBD_IOERROR;
-		break;
-	case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE):
-		/* Set Interface, 9.4.10, not supported */
-		break;
-	case C(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT):
-		/* Synch Frame, 9.4.11, not supported */
-		break;
-
 	/*
 	 * Hub specific requests
 	 */
@@ -812,8 +573,7 @@ ahci_root_ctrl_start(usbd_xfer_handle xf
 #define WPS(x) REG_WRITE(ADMHCD_REG_PORTSTATUS0+(index-1)*4, (x))
 		/* Clear Port Feature, 11.16.2.2 */
 		if (index != 1 && index != 2 ) {
-			error = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
 		switch (value) {
 		case UHF_PORT_POWER:
@@ -845,8 +605,7 @@ ahci_root_ctrl_start(usbd_xfer_handle xf
 			break;
 		default:
 			printf("ClrPortFeatERR:value=0x%x ", value);
-			error = USBD_IOERROR;
-			break;
+			return -1;
 		}
 		//DPRINTF(D_XFER, ("CH=%04x ", sc->sc_change));
 #undef WPS
@@ -859,19 +618,22 @@ ahci_root_ctrl_start(usbd_xfer_handle xf
 		/* Get Hub Descriptor, 11.16.2.4 */
 		DPRINTF(D_MSG, ("UR_GET_DESCRIPTOR RCD"));
 		if ((value&0xff) != 0) {
-			error = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
-		l = min(len, USB_HUB_DESCRIPTOR_SIZE);
-		totlen = l;
-		memcpy(buf, &ahci_hubd, l);
+		usb_hub_descriptor_t hubd;
+
+		totlen = min(buflen, sizeof(hubd));
+		memcpy(&hubd, buf, totlen);
+		hubd.bNbrPorts = 2;
+		USETW(hubd.wHubCharacteristics, 0);
+		hubd.bPwrOn2PwrGood = 0;
+		memcpy(buf, &hubd, totlen);
 		break;
 	case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE):
 		/* Get Hub Status, 11.16.2.5 */
 		DPRINTF(D_MSG, ("UR_GET_STATUS RCD"));
 		if (len != 4) {
-			error = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
 		memset(buf, 0, len);
 		totlen = len;
@@ -880,8 +642,7 @@ ahci_root_ctrl_start(usbd_xfer_handle xf
 		/* Get Port Status, 11.16.2.6 */
 		if ((index != 1 && index != 2)  || len != 4) {
 			printf("index=%d,len=%d ", index, len);
-			error = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
 		status = REG_READ(ADMHCD_REG_PORTSTATUS0+(index-1)*4);
 		DPRINTF(D_MSG, ("UR_GET_STATUS RCO=%x ", status));
@@ -889,15 +650,13 @@ ahci_root_ctrl_start(usbd_xfer_handle xf
 		//DPRINTF(D_XFER, ("ST=%04x,CH=%04x ", status, sc->sc_change));
 		USETW(ps.wPortStatus, status  & (UPS_CURRENT_CONNECT_STATUS|UPS_PORT_ENABLED|UPS_SUSPEND|UPS_OVERCURRENT_INDICATOR|UPS_RESET|UPS_PORT_POWER|UPS_LOW_SPEED));
 		USETW(ps.wPortChange, (status>>16) & (UPS_C_CONNECT_STATUS|UPS_C_PORT_ENABLED|UPS_C_SUSPEND|UPS_C_OVERCURRENT_INDICATOR|UPS_C_PORT_RESET));
-		l = min(len, sizeof(ps));
-		memcpy(buf, &ps, l);
-		totlen = l;
+		totlen = min(len, sizeof(ps));
+		memcpy(buf, &ps, totlen);
 		break;
 	case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE):
 		/* Set Hub Descriptor, 11.16.2.7, not supported */
 		/* STALL ? */
-		error = USBD_IOERROR;
-		break;
+		return -1;
 	case C(UR_SET_FEATURE, UT_WRITE_CLASS_DEVICE):
 		/* Set Hub Feature, 11.16.2.8, not supported */
 		break;
@@ -906,8 +665,7 @@ ahci_root_ctrl_start(usbd_xfer_handle xf
 		/* Set Port Feature, 11.16.2.9 */
 		if ((index != 1) && (index !=2)) {
 			printf("index=%d ", index);
-			error = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
 		switch (value) {
 		case UHF_PORT_RESET:
@@ -924,43 +682,18 @@ ahci_root_ctrl_start(usbd_xfer_handle xf
 			break;
 		default:
 			printf("SetPortFeatERR=0x%x ", value);
-			error = USBD_IOERROR;
-			break;
+			return -1;
 		}
 #undef WPS
 		break;
 	default:
 		DPRINTF(D_MSG, ("ioerr(UR=%02x,UT=%02x) ",
 			req->bRequest, req->bmRequestType));
-		error = USBD_IOERROR;
-		goto ret;
+		/* default from usbroothub */
+		return buflen;
 	}
-	xfer->ux_actlen = totlen;
-	error = USBD_NORMAL_COMPLETION;
- ret:
-	xfer->ux_status = error;
-	mutex_enter(&sc->sc_lock);
-	usb_transfer_complete(xfer);
-	mutex_exit(&sc->sc_lock);
-	return USBD_IN_PROGRESS;
-}
-
-void
-ahci_root_ctrl_abort(usbd_xfer_handle xfer)
-{
-	DPRINTF(D_TRACE, ("SLRCabort "));
-}
 
-void
-ahci_root_ctrl_close(usbd_pipe_handle pipe)
-{
-	DPRINTF(D_TRACE, ("SLRCclose "));
-}
-
-void
-ahci_root_ctrl_done(usbd_xfer_handle xfer)
-{
-	DPRINTF(D_TRACE, ("SLRCdone\n"));
+	return totlen;
 }
 
 static usbd_status

Index: src/sys/arch/mips/conf/files.adm5120
diff -u src/sys/arch/mips/conf/files.adm5120:1.3 src/sys/arch/mips/conf/files.adm5120:1.3.32.1
--- src/sys/arch/mips/conf/files.adm5120:1.3	Mon Apr  4 20:01:14 2011
+++ src/sys/arch/mips/conf/files.adm5120	Thu Dec  4 08:04:31 2014
@@ -1,4 +1,4 @@
-#	$NetBSD: files.adm5120,v 1.3 2011/04/04 20:01:14 dyoung Exp $
+#	$NetBSD: files.adm5120,v 1.3.32.1 2014/12/04 08:04:31 skrll Exp $
 
 file	arch/mips/adm5120/adm5120_intr.c
 
@@ -44,6 +44,6 @@ attach	wdc at extio with wdc_extio
 file	arch/mips/adm5120/dev/wdc_extio.c		wdc_extio
 
 # On-chip USB controller
-device	ahci: usbus, usb_dma
+device	ahci: usbus, usbroothub, usb_dma
 attach	ahci at obio
 file	arch/mips/adm5120/dev/ahci.c			ahci

Index: src/sys/dev/ic/sl811hs.c
diff -u src/sys/dev/ic/sl811hs.c:1.47.6.9 src/sys/dev/ic/sl811hs.c:1.47.6.10
--- src/sys/dev/ic/sl811hs.c:1.47.6.9	Wed Dec  3 23:05:06 2014
+++ src/sys/dev/ic/sl811hs.c	Thu Dec  4 08:04:31 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: sl811hs.c,v 1.47.6.9 2014/12/03 23:05:06 skrll Exp $	*/
+/*	$NetBSD: sl811hs.c,v 1.47.6.10 2014/12/04 08:04:31 skrll Exp $	*/
 
 /*
  * Not (c) 2007 Matthew Orgass
@@ -68,7 +68,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sl811hs.c,v 1.47.6.9 2014/12/03 23:05:06 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sl811hs.c,v 1.47.6.10 2014/12/04 08:04:31 skrll Exp $");
 
 #include "opt_slhci.h"
 
@@ -252,9 +252,6 @@ static const struct timeval overflow_war
 #endif
 const int slhci_wait_time = SLHCI_WAIT_TIME;
 
-/* Root hub intr endpoint */
-#define ROOT_INTR_ENDPT        1
-
 #ifndef SLHCI_MAX_RETRIES
 #define SLHCI_MAX_RETRIES 3
 #endif
@@ -432,6 +429,9 @@ usbd_status slhci_start(struct usbd_xfer
 usbd_status slhci_root_start(struct usbd_xfer *);
 usbd_status slhci_open(struct usbd_pipe *);
 
+static int slhci_roothub_ctrl(struct usbd_bus *, usb_device_request_t *,
+    void *, int);
+
 /*
  * slhci_supported_rev, slhci_preinit, slhci_attach, slhci_detach,
  * slhci_activate
@@ -684,6 +684,7 @@ const struct usbd_bus_methods slhci_bus_
 	.ubm_allocx = slhci_allocx,
 	.ubm_freex = slhci_freex,
 	.ubm_getlock = slhci_get_lock,
+	.ubm_rhctrl = slhci_roothub_ctrl,
 };
 
 const struct usbd_pipe_methods slhci_pipe_methods = {
@@ -992,17 +993,17 @@ slhci_open(struct usbd_pipe *pipe)
 	struct slhci_softc *sc;
 	struct slhci_pipe *spipe;
 	usb_endpoint_descriptor_t *ed;
-	struct slhci_transfers *t;
 	unsigned int max_packet, pmaxpkt;
+	uint8_t rhaddr;
 
 	dev = pipe->up_dev;
 	sc = dev->ud_bus->ub_hcpriv;
 	spipe = (struct slhci_pipe *)pipe;
 	ed = pipe->up_endpoint->ue_edesc;
-	t = &sc->sc_transfers;
+	rhaddr = dev->ud_bus->ub_rhaddr;
 
 	DLOG(D_TRACE, "slhci_open(addr=%d,ep=%d,rootaddr=%d)",
-		dev->ud_addr, ed->bEndpointAddress, t->rootaddr, 0);
+		dev->ud_addr, ed->bEndpointAddress, rhaddr, 0);
 
 	spipe->pflags = 0;
 	spipe->frame = 0;
@@ -1024,7 +1025,7 @@ slhci_open(struct usbd_pipe *pipe)
 
 	if (dev->ud_speed == USB_SPEED_LOW) {
 		spipe->pflags |= PF_LS;
-		if (dev->ud_myhub->ud_addr != t->rootaddr) {
+		if (dev->ud_myhub->ud_addr != rhaddr) {
 			spipe->pflags |= PF_PREAMBLE;
 			if (!slhci_try_lsvh)
 				return slhci_lock_call(sc, &slhci_lsvh_warn,
@@ -1040,15 +1041,17 @@ slhci_open(struct usbd_pipe *pipe)
 		return USBD_INVAL;
 	}
 
-	if (dev->ud_addr == t->rootaddr) {
+	if (dev->ud_addr == rhaddr) {
 		switch (ed->bEndpointAddress) {
 		case USB_CONTROL_ENDPOINT:
 			spipe->ptype = PT_ROOT_CTRL;
 			pipe->up_interval = 0;
+			pipe->up_methods = &roothub_ctrl_methods;
 			break;
-		case UE_DIR_IN | ROOT_INTR_ENDPT:
+		case UE_DIR_IN | USBROOTHUB_INTR_ENDPT:
 			spipe->ptype = PT_ROOT_INTR;
 			pipe->up_interval = 1;
+			pipe->up_methods = &slhci_root_methods;
 			break;
 		default:
 			printf("%s: Invalid root endpoint!\n", SC_NAME(sc));
@@ -1056,7 +1059,6 @@ slhci_open(struct usbd_pipe *pipe)
 			    0,0,0);
 			return USBD_INVAL;
 		}
-		pipe->up_methods = __UNCONST(&slhci_root_methods);
 		return USBD_NORMAL_COMPLETION;
 	} else {
 		switch (ed->bmAttributes & UE_XFERTYPE) {
@@ -2929,64 +2931,6 @@ slhci_insert(struct slhci_softc *sc)
 /*
  * Data structures and routines to emulate the root hub.
  */
-static const usb_device_descriptor_t slhci_devd = {
-	.bLength = USB_DEVICE_DESCRIPTOR_SIZE,
-	.bDescriptorType = UDESC_DEVICE,
-	.bcdUSB = {0x01, 0x01},
-	.bDeviceClass = UDCLASS_HUB,
-	.bDeviceSubClass = UDSUBCLASS_HUB,
-	.bDeviceProtocol = 0,
-	.bMaxPacketSize = 64,
-	.idVendor = {
-		USB_VENDOR_SCANLOGIC & 0xff,	/* vendor ID (low)  */
-	 	USB_VENDOR_SCANLOGIC >> 8
-	},
-	.idProduct = {0},
-	.bcdDevice = {0},
-	.iManufacturer = 1,
-	.iProduct = 2,
-	.iSerialNumber = 0,
-	.bNumConfigurations = 1
-};
-
-static const struct slhci_confd_t {
-	const usb_config_descriptor_t confd;
-	const usb_interface_descriptor_t ifcd;
-	const usb_endpoint_descriptor_t endpd;
-} UPACKED slhci_confd = {
-	.confd = {
-		.bLength = USB_CONFIG_DESCRIPTOR_SIZE,
-		.bDescriptorType = UDESC_CONFIG,
-		.wTotalLength = USETWD(
-		    USB_CONFIG_DESCRIPTOR_SIZE +
-		    USB_INTERFACE_DESCRIPTOR_SIZE +
-		    USB_ENDPOINT_DESCRIPTOR_SIZE),
-		.bNumInterface = 1,
-		.bConfigurationValue = 1,
-		.iConfiguration = 0,
-		.bmAttributes = UC_SELF_POWERED,
-		.bMaxPower = 0
-	},
-	.ifcd = {
-		.bLength = USB_INTERFACE_DESCRIPTOR_SIZE,
-		.bDescriptorType = UDESC_INTERFACE,
-		.bInterfaceNumber = 0,
-		.bAlternateSetting = 0,
-		.bNumEndpoints = 1,
-		.bInterfaceClass = UICLASS_HUB,	
-		.bInterfaceSubClass = UISUBCLASS_HUB,
-		.bInterfaceProtocol = 0,
-		.iInterface = 0
-	},
-	.endpd = {
-		.bLength = USB_ENDPOINT_DESCRIPTOR_SIZE,
-		.bDescriptorType = UDESC_ENDPOINT,
-		.bEndpointAddress = UE_DIR_IN | ROOT_INTR_ENDPT,
-		.bmAttributes = UE_INTERRUPT,
-		.wMaxPacketSize = USETWD(240),
-		.bInterval = 255
-	}
-};
 
 static const usb_hub_descriptor_t slhci_hubd = {
 	.bDescLength = USB_HUB_DESCRIPTOR_SIZE,
@@ -3149,13 +3093,8 @@ slhci_root(struct slhci_softc *sc, struc
     *xfer)
 {
 	struct slhci_transfers *t;
-	usb_device_request_t *req;
-	unsigned int len, value, index, actlen, type;
-	uint8_t *buf;
-	usbd_status error;
 
 	t = &sc->sc_transfers;
-	buf = NULL;
 
 	LK_SLASSERT(spipe != NULL && xfer != NULL, sc, spipe, xfer, return
 	    USBD_CANCELLED);
@@ -3163,18 +3102,25 @@ slhci_root(struct slhci_softc *sc, struc
 	DLOG(D_TRACE, "%s start", pnames(SLHCI_XFER_TYPE(xfer)), 0,0,0);
 	KASSERT(mutex_owned(&sc->sc_intr_lock));
 
-	if (spipe->ptype == PT_ROOT_INTR) {
-		LK_SLASSERT(t->rootintr == NULL, sc, spipe, xfer, return
-		    USBD_CANCELLED);
-		t->rootintr = xfer;
-		if (t->flags & F_CHANGE)
-			t->flags |= F_ROOTINTR;
-		return USBD_IN_PROGRESS;
-	}
+	KASSERT(spipe->ptype == PT_ROOT_INTR);
+	LK_SLASSERT(t->rootintr == NULL, sc, spipe, xfer, return
+	    USBD_CANCELLED);
+	t->rootintr = xfer;
+	if (t->flags & F_CHANGE)
+		t->flags |= F_ROOTINTR;
+	return USBD_IN_PROGRESS;
+}
 
-	error = USBD_IOERROR; /* XXX should be STALL */
-	actlen = 0;
-	req = &xfer->ux_request;
+static int
+slhci_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req,
+    void *buf, int buflen)
+{
+	struct slhci_softc *sc = bus->ub_hcpriv;
+	struct slhci_transfers *t = &sc->sc_transfers;
+	usbd_status error = USBD_IOERROR; /* XXX should be STALL */
+	uint16_t len, value, index;
+	uint8_t type;
+	int actlen = 0;
 
 	len = UGETW(req->wLength);
 	value = UGETW(req->wValue);
@@ -3182,9 +3128,6 @@ slhci_root(struct slhci_softc *sc, struc
 
 	type = req->bmRequestType;
 
-	if (len)
-		buf = xfer->ux_buf;
-
 	SLHCI_DEXEC(D_TRACE, slhci_log_req_hub(req));
 
 	/*
@@ -3244,24 +3187,7 @@ slhci_root(struct slhci_softc *sc, struc
 			    "ENDPOINT_HALT or DEVICE_REMOTE_WAKEUP "
 			    "not supported", 0,0,0,0);
 		break;
-	case UR_SET_ADDRESS:
-		if (type == UT_WRITE_DEVICE) {
-			DLOG(D_ROOT, "Set Address %#.4x", value, 0,0,0);
-			if (value < USB_MAX_DEVICES) {
-				t->rootaddr = value;
-				error = USBD_NORMAL_COMPLETION;
-			}
-		}
-		break;
-	case UR_SET_CONFIG:
-		if (type == UT_WRITE_DEVICE) {
-			DLOG(D_ROOT, "Set Config %#.4x", value, 0,0,0);
-			if (value == 0 || value == 1) {
-				t->rootconf = value;
-				error = USBD_NORMAL_COMPLETION;
-			}
-		}
-		break;
+
 	/* Read Requests */
 	case UR_GET_STATUS:
 		if (type == UT_READ_CLASS_OTHER) {
@@ -3284,57 +3210,29 @@ slhci_root(struct slhci_softc *sc, struc
 			} else
 				DLOG(D_ROOT, "Get Hub Status bad len %#.4x",
 				    len, 0,0,0);
-		} else if (type == UT_READ_DEVICE) {
-			if (len >= 2) {
-				USETW(((usb_status_t *)buf)->wStatus, UDS_SELF_POWERED);
-				actlen = 2;
-				error = USBD_NORMAL_COMPLETION;
-			}
-		} else if (type == (UT_READ_INTERFACE|UT_READ_ENDPOINT)) {
-			if (len >= 2) {
-				USETW(((usb_status_t *)buf)->wStatus, 0);
-				actlen = 2;
-				error = USBD_NORMAL_COMPLETION;
-			}
-		}
-		break;
-	case UR_GET_CONFIG:
-		if (type == UT_READ_DEVICE) {
-			DLOG(D_ROOT, "Get Config", 0,0,0,0);
-			if (len > 0) {
-				*buf = t->rootconf;
-				actlen = 1;
-				error = USBD_NORMAL_COMPLETION;
-			}
-		}
-		break;
-	case UR_GET_INTERFACE:
-		if (type == UT_READ_INTERFACE) {
-			if (len > 0) {
-				*buf = 0;
-				actlen = 1;
-				error = USBD_NORMAL_COMPLETION;
-			}
 		}
 		break;
 	case UR_GET_DESCRIPTOR:
 		if (type == UT_READ_DEVICE) {
 			/* value is type (&0xff00) and index (0xff) */
 			if (value == (UDESC_DEVICE<<8)) {
-				actlen = min(len, sizeof(slhci_devd));
-				memcpy(buf, &slhci_devd, actlen);
+				usb_device_descriptor_t devd;
+
+				actlen = min(buflen, sizeof(devd));
+				memcpy(&devd, buf, actlen);
+				USETW(devd.idVendor, USB_VENDOR_SCANLOGIC);
+				memcpy(buf, &devd, actlen);
 				error = USBD_NORMAL_COMPLETION;
 			} else if (value == (UDESC_CONFIG<<8)) {
-				actlen = min(len, sizeof(slhci_confd));
-				memcpy(buf, &slhci_confd, actlen);
-				if (actlen > offsetof(usb_config_descriptor_t,
-				    bMaxPower))
-					((usb_config_descriptor_t *)
-					    buf)->bMaxPower = t->max_current;
-					    /* 2 mA units */
+				struct usb_roothub_descriptors confd;
+
+				actlen = min(buflen, sizeof(confd));
+				memcpy(&confd, buf, actlen);
+
+				/* 2 mA units */
+				confd.urh_confd.bMaxPower = t->max_current;
+				memcpy(buf, &confd, actlen);
 				error = USBD_NORMAL_COMPLETION;
-			} else if (value == (UDESC_STRING<<8)) {
-				/* language table XXX */
 			} else if (value == ((UDESC_STRING<<8)|1)) {
 				/* Vendor */
 				actlen = usb_makestrdesc((usb_string_descriptor_t *)
@@ -3351,29 +3249,28 @@ slhci_root(struct slhci_softc *sc, struc
 		} else if (type == UT_READ_CLASS_DEVICE) {
 			/* Descriptor number is 0 */
 			if (value == (UDESC_HUB<<8)) {
-				actlen = min(len, sizeof(slhci_hubd));
-				memcpy(buf, &slhci_hubd, actlen);
-				if (actlen > offsetof(usb_config_descriptor_t,
-				    bMaxPower))
-					((usb_hub_descriptor_t *)
-					    buf)->bHubContrCurrent = 500 -
-					    t->max_current;
+				usb_hub_descriptor_t hubd;
+
+				actlen = min(buflen, sizeof(hubd));
+				memcpy(&hubd, buf, actlen);
+				hubd.bHubContrCurrent =
+				    500 - t->max_current;
+				memcpy(buf, &hubd, actlen);
 				error = USBD_NORMAL_COMPLETION;
 			} else
 				DDOLOG("Unknown Get Hub Descriptor %#.4x",
 				    value, 0,0,0);
 		}
 		break;
+	default:
+		/* default from usbroothub */
+		return buflen;
 	}
 
 	if (error == USBD_NORMAL_COMPLETION)
-		xfer->ux_actlen = actlen;
-	xfer->ux_status = error;
-	KASSERT(spipe->xfer == NULL);
-	spipe->xfer = xfer;
-	enter_callback(t, spipe);
+		return actlen;
 
-	return USBD_IN_PROGRESS;
+	return -1;
 }
 
 /* End in lock functions. Start debug functions. */

Index: src/sys/dev/ic/sl811hsvar.h
diff -u src/sys/dev/ic/sl811hsvar.h:1.11 src/sys/dev/ic/sl811hsvar.h:1.11.6.1
--- src/sys/dev/ic/sl811hsvar.h:1.11	Wed Oct  2 22:55:04 2013
+++ src/sys/dev/ic/sl811hsvar.h	Thu Dec  4 08:04:31 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: sl811hsvar.h,v 1.11 2013/10/02 22:55:04 skrll Exp $	*/
+/*	$NetBSD: sl811hsvar.h,v 1.11.6.1 2014/12/04 08:04:31 skrll Exp $	*/
 
 /*
  * Not (c) 2007 Matthew Orgass
@@ -36,8 +36,6 @@ struct slhci_transfers {
 	int16_t len[2];		     	/* length of transfer or -1 if none */
 	uint8_t current_tregs[2][4]; 	/* ab, ADR, LEN, PID, DEV */
 	uint8_t copyin[2]; 		/* copyin ADR, LEN */
-	uint8_t rootaddr;		/* device address of root hub */
-	uint8_t rootconf;		/* root configuration */
 	uint8_t max_current;		/* max current / 2 */
 	uint8_t sltype;			/* revision */
 };

Index: src/sys/dev/usb/ehci.c
diff -u src/sys/dev/usb/ehci.c:1.234.2.12 src/sys/dev/usb/ehci.c:1.234.2.13
--- src/sys/dev/usb/ehci.c:1.234.2.12	Wed Dec  3 23:05:06 2014
+++ src/sys/dev/usb/ehci.c	Thu Dec  4 08:04:31 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: ehci.c,v 1.234.2.12 2014/12/03 23:05:06 skrll Exp $ */
+/*	$NetBSD: ehci.c,v 1.234.2.13 2014/12/04 08:04:31 skrll Exp $ */
 
 /*
  * Copyright (c) 2004-2012 The NetBSD Foundation, Inc.
@@ -53,7 +53,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ehci.c,v 1.234.2.12 2014/12/03 23:05:06 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ehci.c,v 1.234.2.13 2014/12/04 08:04:31 skrll Exp $");
 
 #include "ohci.h"
 #include "uhci.h"
@@ -81,10 +81,10 @@ __KERNEL_RCSID(0, "$NetBSD: ehci.c,v 1.2
 #include <dev/usb/usbhist.h>
 #include <dev/usb/usb_mem.h>
 #include <dev/usb/usb_quirks.h>
-#include <dev/usb/usbroothub.h>
 
 #include <dev/usb/ehcireg.h>
 #include <dev/usb/ehcivar.h>
+#include <dev/usb/usbroothub.h>
 
 
 #ifdef USB_DEBUG
@@ -173,12 +173,8 @@ Static void		ehci_pcd(void *);
 Static usbd_xfer_handle	ehci_allocx(struct usbd_bus *);
 Static void		ehci_freex(struct usbd_bus *, usbd_xfer_handle);
 Static void		ehci_get_lock(struct usbd_bus *, kmutex_t **);
-
-Static usbd_status	ehci_root_ctrl_transfer(usbd_xfer_handle);
-Static usbd_status	ehci_root_ctrl_start(usbd_xfer_handle);
-Static void		ehci_root_ctrl_abort(usbd_xfer_handle);
-Static void		ehci_root_ctrl_close(usbd_pipe_handle);
-Static void		ehci_root_ctrl_done(usbd_xfer_handle);
+Static int		ehci_roothub_ctrl(struct usbd_bus *,
+    usb_device_request_t *, void *, int);
 
 Static usbd_status	ehci_root_intr_transfer(usbd_xfer_handle);
 Static usbd_status	ehci_root_intr_start(usbd_xfer_handle);
@@ -276,8 +272,6 @@ Static void		ehci_dump_exfer(struct ehci
 
 #define EHCI_NULL htole32(EHCI_LINK_TERMINATE)
 
-#define EHCI_INTR_ENDPT 1
-
 #define ehci_add_intr_list(sc, ex) \
 	TAILQ_INSERT_TAIL(&(sc)->sc_intrhead, (ex), inext);
 #define ehci_del_intr_list(sc, ex) \
@@ -294,16 +288,7 @@ Static const struct usbd_bus_methods ehc
 	.ubm_allocx =	ehci_allocx,
 	.ubm_freex =	ehci_freex,
 	.ubm_getlock =	ehci_get_lock,
-	.ubm_newdev =	NULL,
-};
-
-Static const struct usbd_pipe_methods ehci_root_ctrl_methods = {
-	.upm_transfer =	ehci_root_ctrl_transfer,
-	.upm_start =	ehci_root_ctrl_start,
-	.upm_abort =	ehci_root_ctrl_abort,
-	.upm_close =	ehci_root_ctrl_close,
-	.upm_cleartoggle =	ehci_noop,
-	.upm_done =		ehci_root_ctrl_done,
+	.ubm_rhctrl =	ehci_roothub_ctrl,
 };
 
 Static const struct usbd_pipe_methods ehci_root_intr_methods = {
@@ -1840,6 +1825,7 @@ ehci_open(usbd_pipe_handle pipe)
 	usbd_device_handle dev = pipe->up_dev;
 	ehci_softc_t *sc = dev->ud_bus->ub_hcpriv;
 	usb_endpoint_descriptor_t *ed = pipe->up_endpoint->ue_edesc;
+	uint8_t rhaddr = dev->ud_bus->ub_rhaddr;
 	uint8_t addr = dev->ud_addr;
 	uint8_t xfertype = UE_GET_XFERTYPE(ed->bmAttributes);
 	struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
@@ -1851,7 +1837,7 @@ ehci_open(usbd_pipe_handle pipe)
 	USBHIST_FUNC(); USBHIST_CALLED(ehcidebug);
 
 	USBHIST_LOG(ehcidebug, "pipe=%p, addr=%d, endpt=%d (%d)",
-	    pipe, addr, ed->bEndpointAddress, sc->sc_addr);
+	    pipe, addr, ed->bEndpointAddress, rhaddr);
 
 	if (dev->ud_myhsport) {
 		/*
@@ -1860,7 +1846,7 @@ ehci_open(usbd_pipe_handle pipe)
 		 * address to 0 (us).
 		 */
 		if (!(sc->sc_flags & EHCIF_ETTF)
-		    || (dev->ud_myhsport->up_parent->ud_addr != sc->sc_addr)) {
+		    || (dev->ud_myhsport->up_parent->ud_addr != rhaddr)) {
 			hshubaddr = dev->ud_myhsport->up_parent->ud_addr;
 		} else {
 			hshubaddr = 0;
@@ -1877,12 +1863,12 @@ ehci_open(usbd_pipe_handle pipe)
 	/* toggle state needed for bulk endpoints */
 	epipe->nexttoggle = pipe->up_endpoint->ue_toggle;
 
-	if (addr == sc->sc_addr) {
+	if (addr == rhaddr) {
 		switch (ed->bEndpointAddress) {
 		case USB_CONTROL_ENDPOINT:
-			pipe->up_methods = &ehci_root_ctrl_methods;
+			pipe->up_methods = &roothub_ctrl_methods;
 			break;
-		case UE_DIR_IN | EHCI_INTR_ENDPT:
+		case UE_DIR_IN | USBROOTHUB_INTR_ENDPT:
 			pipe->up_methods = &ehci_root_intr_methods;
 			break;
 		default:
@@ -2248,131 +2234,24 @@ ehci_rem_free_sitd_chain(ehci_softc_t *s
 	exfer->sitdend = NULL;
 }
 
-
 /***********/
 
-/*
- * Data structures and routines to emulate the root hub.
- */
-Static usb_device_descriptor_t ehci_devd = {
-	.bLength = USB_DEVICE_DESCRIPTOR_SIZE,
-	.bDescriptorType = UDESC_DEVICE,
-	.bcdUSB = {0x00, 0x02},
-	.bDeviceClass = UDCLASS_HUB,
-	.bDeviceSubClass = UDSUBCLASS_HUB,
-	.bDeviceProtocol = UDPROTO_HSHUBSTT,
-	.bMaxPacketSize = 64,
-	.idVendor = {0},
-	.idProduct = {0},
-	.bcdDevice = {0x00,0x01},
-	.iManufacturer = 1,
-	.iProduct = 2,
-	.iSerialNumber = 0,
-	.bNumConfigurations = 1
-};
-
-Static const usb_device_qualifier_t ehci_odevd = {
-	.bLength = USB_DEVICE_DESCRIPTOR_SIZE,
-	.bDescriptorType = UDESC_DEVICE_QUALIFIER,
-	.bcdUSB = {0x00, 0x02},
-	.bDeviceClass = UDCLASS_HUB,
-	.bDeviceSubClass = UDSUBCLASS_HUB,
-	.bDeviceProtocol = UDPROTO_FSHUB,
-	.bMaxPacketSize0 = 64,
-	.bNumConfigurations = 1,
-	0
-};
-
-Static const usb_config_descriptor_t ehci_confd = {
-	.bLength = USB_CONFIG_DESCRIPTOR_SIZE,
-	.bDescriptorType = UDESC_CONFIG,
-	.wTotalLength = USETWD(
-		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
-};
-
-Static const usb_interface_descriptor_t ehci_ifcd = {
-	.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 ehci_endpd = {
-	.bLength = USB_ENDPOINT_DESCRIPTOR_SIZE,
-	.bDescriptorType = UDESC_ENDPOINT,
-	.bEndpointAddress = UE_DIR_IN | EHCI_INTR_ENDPT,
-	.bmAttributes = UE_INTERRUPT,
-	.wMaxPacketSize = USETWD(8),
-	.bInterval = 12
-};
-
-Static const usb_hub_descriptor_t ehci_hubd = {
-	.bDescLength = USB_HUB_DESCRIPTOR_SIZE,
-	.bDescriptorType = UDESC_HUB,
-	.bNbrPorts = 0,
-	.wHubCharacteristics = USETWD(0),
-	.bPwrOn2PwrGood = 0,
-	.bHubContrCurrent = 0,
-	.DeviceRemovable = {""},
-	.PortPowerCtrlMask = {""},
-};
-
-/*
- * Simulate a hardware hub by handling all the necessary requests.
- */
-Static usbd_status
-ehci_root_ctrl_transfer(usbd_xfer_handle xfer)
-{
-	ehci_softc_t *sc = xfer->ux_pipe->up_dev->ud_bus->ub_hcpriv;
-	usbd_status err;
-
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return (err);
-
-	/* Pipe isn't running, start first */
-	return (ehci_root_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue)));
-}
-
-Static usbd_status
-ehci_root_ctrl_start(usbd_xfer_handle xfer)
+Static int
+ehci_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req,
+    void *buf, int buflen)
 {
-	ehci_softc_t *sc = xfer->ux_pipe->up_dev->ud_bus->ub_hcpriv;
-	usb_device_request_t *req;
-	void *buf = NULL;
-	int port, i;
-	int len, value, index, l, totlen = 0;
-	usb_port_status_t ps;
+	ehci_softc_t *sc = bus->ub_hcpriv;
 	usb_hub_descriptor_t hubd;
-	usbd_status err;
+	usb_port_status_t ps;
+	uint16_t len, value, index;
+	int l, totlen = 0;
+	int port, i;
 	uint32_t v;
 
 	USBHIST_FUNC(); USBHIST_CALLED(ehcidebug);
 
 	if (sc->sc_dying)
-		return (USBD_IOERROR);
-
-#ifdef DIAGNOSTIC
-	if (!(xfer->ux_rqflags & URQ_REQUEST))
-		/* XXX panic */
-		return (USBD_INVAL);
-#endif
-	req = &xfer->ux_request;
+		return -1;
 
 	USBHIST_LOG(ehcidebug, "type=0x%02x request=%02x",
 		    req->bmRequestType, req->bRequest, 0, 0);
@@ -2381,142 +2260,37 @@ ehci_root_ctrl_start(usbd_xfer_handle xf
 	value = UGETW(req->wValue);
 	index = UGETW(req->wIndex);
 
-	if (len != 0)
-		buf = xfer->ux_buf;
-
 #define C(x,y) ((x) | ((y) << 8))
-	switch(C(req->bRequest, req->bmRequestType)) {
-	case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE):
-	case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE):
-	case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT):
-		/*
-		 * DEVICE_REMOTE_WAKEUP and ENDPOINT_HALT are no-ops
-		 * for the integrated root hub.
-		 */
-		break;
-	case C(UR_GET_CONFIG, UT_READ_DEVICE):
-		if (len > 0) {
-			*(uint8_t *)buf = sc->sc_conf;
-			totlen = 1;
-		}
-		break;
+	switch (C(req->bRequest, req->bmRequestType)) {
 	case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE):
-		USBHIST_LOG(ehcidebug, "wValue=0x%04x", value, 0, 0, 0);
 		if (len == 0)
 			break;
-		switch(value >> 8) {
-		case UDESC_DEVICE:
-			if ((value & 0xff) != 0) {
-				err = USBD_IOERROR;
-				goto ret;
-			}
-			totlen = l = min(len, USB_DEVICE_DESCRIPTOR_SIZE);
-			USETW(ehci_devd.idVendor, sc->sc_id_vendor);
-			memcpy(buf, &ehci_devd, l);
-			break;
-		/*
-		 * We can't really operate at another speed, but the spec says
-		 * we need this descriptor.
-		 */
-		case UDESC_DEVICE_QUALIFIER:
-			if ((value & 0xff) != 0) {
-				err = USBD_IOERROR;
-				goto ret;
-			}
-			totlen = l = min(len, USB_DEVICE_DESCRIPTOR_SIZE);
-			memcpy(buf, &ehci_odevd, l);
-			break;
-		/*
-		 * We can't really operate at another speed, but the spec says
-		 * we need this descriptor.
-		 */
-		case UDESC_OTHER_SPEED_CONFIGURATION:
-		case UDESC_CONFIG:
-			if ((value & 0xff) != 0) {
-				err = USBD_IOERROR;
-				goto ret;
-			}
-			totlen = l = min(len, USB_CONFIG_DESCRIPTOR_SIZE);
-			memcpy(buf, &ehci_confd, l);
-			((usb_config_descriptor_t *)buf)->bDescriptorType =
-				value >> 8;
-			buf = (char *)buf + l;
-			len -= l;
-			l = min(len, USB_INTERFACE_DESCRIPTOR_SIZE);
-			totlen += l;
-			memcpy(buf, &ehci_ifcd, l);
-			buf = (char *)buf + l;
-			len -= l;
-			l = min(len, USB_ENDPOINT_DESCRIPTOR_SIZE);
-			totlen += l;
-			memcpy(buf, &ehci_endpd, l);
+		switch (value) {
+		case C(0, UDESC_DEVICE): {
+			usb_device_descriptor_t devd;
+			totlen = min(buflen, sizeof(devd));
+			memcpy(&devd, buf, totlen);
+			USETW(devd.idVendor, sc->sc_id_vendor);
+			memcpy(buf, &devd, totlen);
 			break;
-		case UDESC_STRING:
+		
+		}
 #define sd ((usb_string_descriptor_t *)buf)
-			switch (value & 0xff) {
-			case 0: /* Language table */
-				totlen = usb_makelangtbl(sd, len);
-				break;
-			case 1: /* Vendor */
-				totlen = usb_makestrdesc(sd, len,
-							 sc->sc_vendor);
-				break;
-			case 2: /* Product */
-				totlen = usb_makestrdesc(sd, len,
-							 "EHCI root hub");
-				break;
-			}
-#undef sd
+		case C(1, UDESC_STRING):
+			/* Vendor */
+			totlen = usb_makestrdesc(sd, len, sc->sc_vendor);
+			break;
+		case C(2, UDESC_STRING):
+			/* Product */
+			totlen = usb_makestrdesc(sd, len, "EHCI root hub");
 			break;
+#undef sd
 		default:
-			err = USBD_IOERROR;
-			goto ret;
-		}
-		break;
-	case C(UR_GET_INTERFACE, UT_READ_INTERFACE):
-		if (len > 0) {
-			*(uint8_t *)buf = 0;
-			totlen = 1;
-		}
-		break;
-	case C(UR_GET_STATUS, UT_READ_DEVICE):
-		if (len > 1) {
-			USETW(((usb_status_t *)buf)->wStatus,UDS_SELF_POWERED);
-			totlen = 2;
-		}
-		break;
-	case C(UR_GET_STATUS, UT_READ_INTERFACE):
-	case C(UR_GET_STATUS, UT_READ_ENDPOINT):
-		if (len > 1) {
-			USETW(((usb_status_t *)buf)->wStatus, 0);
-			totlen = 2;
-		}
-		break;
-	case C(UR_SET_ADDRESS, UT_WRITE_DEVICE):
-		if (value >= USB_MAX_DEVICES) {
-			err = USBD_IOERROR;
-			goto ret;
+			/* default from usbroothub */
+			return buflen;
 		}
-		sc->sc_addr = value;
-		break;
-	case C(UR_SET_CONFIG, UT_WRITE_DEVICE):
-		if (value != 0 && value != 1) {
-			err = USBD_IOERROR;
-			goto ret;
-		}
-		sc->sc_conf = value;
-		break;
-	case C(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE):
-		break;
-	case C(UR_SET_FEATURE, UT_WRITE_DEVICE):
-	case C(UR_SET_FEATURE, UT_WRITE_INTERFACE):
-	case C(UR_SET_FEATURE, UT_WRITE_ENDPOINT):
-		err = USBD_IOERROR;
-		goto ret;
-	case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE):
-		break;
-	case C(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT):
 		break;
+
 	/* Hub requests */
 	case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_DEVICE):
 		break;
@@ -2525,14 +2299,13 @@ ehci_root_ctrl_start(usbd_xfer_handle xf
 		    "UR_CLEAR_PORT_FEATURE port=%d feature=%d", index, value,
 		    0, 0);
 		if (index < 1 || index > sc->sc_noport) {
-			err = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
 		port = EHCI_PORTSC(index);
 		v = EOREAD4(sc, port);
 		USBHIST_LOG(ehcidebug, "portsc=0x%08x", v, 0, 0, 0);
 		v &= ~EHCI_PS_CLEAR;
-		switch(value) {
+		switch (value) {
 		case UHF_PORT_ENABLE:
 			EOWRITE4(sc, port, v &~ EHCI_PS_PE);
 			break;
@@ -2580,8 +2353,7 @@ ehci_root_ctrl_start(usbd_xfer_handle xf
 			sc->sc_isreset[index] = 0;
 			break;
 		default:
-			err = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
 #if 0
 		switch(value) {
@@ -2599,10 +2371,10 @@ ehci_root_ctrl_start(usbd_xfer_handle xf
 		if (len == 0)
 			break;
 		if ((value & 0xff) != 0) {
-			err = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
-		hubd = ehci_hubd;
+		totlen = min(buflen, sizeof(hubd));
+		memcpy(&hubd, buf, totlen);
 		hubd.bNbrPorts = sc->sc_noport;
 		v = EOREAD4(sc, EHCI_HCSPARAMS);
 		USETW(hubd.wHubCharacteristics,
@@ -2613,14 +2385,12 @@ ehci_root_ctrl_start(usbd_xfer_handle xf
 		for (i = 0, l = sc->sc_noport; l > 0; i++, l -= 8, v >>= 8)
 			hubd.DeviceRemovable[i++] = 0; /* XXX can't find out? */
 		hubd.bDescLength = USB_HUB_DESCRIPTOR_SIZE + i;
-		l = min(len, hubd.bDescLength);
-		totlen = l;
-		memcpy(buf, &hubd, l);
+		totlen = min(totlen, hubd.bDescLength);
+		memcpy(buf, &hubd, totlen);
 		break;
 	case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE):
 		if (len != 4) {
-			err = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
 		memset(buf, 0, len); /* ? XXX */
 		totlen = len;
@@ -2628,12 +2398,10 @@ ehci_root_ctrl_start(usbd_xfer_handle xf
 	case C(UR_GET_STATUS, UT_READ_CLASS_OTHER):
 		USBHIST_LOG(ehcidebug, "get port status i=%d", index, 0, 0, 0);
 		if (index < 1 || index > sc->sc_noport) {
-			err = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
 		if (len != 4) {
-			err = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
 		v = EOREAD4(sc, EHCI_PORTSC(index));
 		USBHIST_LOG(ehcidebug, "port status=0x%04x", v, 0, 0, 0);
@@ -2663,19 +2431,16 @@ ehci_root_ctrl_start(usbd_xfer_handle xf
 		if (v & EHCI_PS_OCC)	i |= UPS_C_OVERCURRENT_INDICATOR;
 		if (sc->sc_isreset[index]) i |= UPS_C_PORT_RESET;
 		USETW(ps.wPortChange, i);
-		l = min(len, sizeof ps);
-		memcpy(buf, &ps, l);
-		totlen = l;
+		totlen = min(len, sizeof(ps));
+		memcpy(buf, &ps, totlen);
 		break;
 	case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE):
-		err = USBD_IOERROR;
-		goto ret;
+		return -1;
 	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_noport) {
-			err = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
 		port = EHCI_PORTSC(index);
 		v = EOREAD4(sc, port);
@@ -2706,8 +2471,7 @@ ehci_root_ctrl_start(usbd_xfer_handle xf
 			/* Wait for reset to complete. */
 			usb_delay_ms(&sc->sc_bus, USB_PORT_ROOT_RESET_DELAY);
 			if (sc->sc_dying) {
-				err = USBD_IOERROR;
-				goto ret;
+				return -1;
 			}
 			/*
 			 * An embedded transaction translator will automatically
@@ -2722,8 +2486,7 @@ ehci_root_ctrl_start(usbd_xfer_handle xf
 				usb_delay_ms(&sc->sc_bus,
 				    EHCI_PORT_RESET_COMPLETE);
 				if (sc->sc_dying) {
-					err = USBD_IOERROR;
-					goto ret;
+					return -1;
 				}
 			}
 
@@ -2762,8 +2525,7 @@ ehci_root_ctrl_start(usbd_xfer_handle xf
 			EOWRITE4(sc, port, v | EHCI_PS_PIC);
 			break;
 		default:
-			err = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
 		break;
 	case C(UR_CLEAR_TT_BUFFER, UT_WRITE_CLASS_OTHER):
@@ -2772,17 +2534,11 @@ ehci_root_ctrl_start(usbd_xfer_handle xf
 	case C(UR_STOP_TT, UT_WRITE_CLASS_OTHER):
 		break;
 	default:
-		err = USBD_IOERROR;
-		goto ret;
+		/* default from usbroothub */
+		return buflen;
 	}
-	xfer->ux_actlen = totlen;
-	err = USBD_NORMAL_COMPLETION;
- ret:
-	mutex_enter(&sc->sc_lock);
-	xfer->ux_status = err;
-	usb_transfer_complete(xfer);
-	mutex_exit(&sc->sc_lock);
-	return (USBD_IN_PROGRESS);
+
+	return totlen;
 }
 
 Static void
@@ -2815,27 +2571,6 @@ ehci_disown(ehci_softc_t *sc, int index,
 	EOWRITE4(sc, port, v | EHCI_PS_PO);
 }
 
-/* Abort a root control request. */
-Static void
-ehci_root_ctrl_abort(usbd_xfer_handle xfer)
-{
-	/* Nothing to do, all transfers are synchronous. */
-}
-
-/* Close the root pipe. */
-Static void
-ehci_root_ctrl_close(usbd_pipe_handle pipe)
-{
-	USBHIST_FUNC(); USBHIST_CALLED(ehcidebug);
-	/* Nothing to do. */
-}
-
-Static void
-ehci_root_ctrl_done(usbd_xfer_handle xfer)
-{
-	xfer->ux_hcpriv = NULL;
-}
-
 Static usbd_status
 ehci_root_intr_transfer(usbd_xfer_handle xfer)
 {

Index: src/sys/dev/usb/ehcivar.h
diff -u src/sys/dev/usb/ehcivar.h:1.42.14.3 src/sys/dev/usb/ehcivar.h:1.42.14.4
--- src/sys/dev/usb/ehcivar.h:1.42.14.3	Tue Dec  2 09:00:33 2014
+++ src/sys/dev/usb/ehcivar.h	Thu Dec  4 08:04:31 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: ehcivar.h,v 1.42.14.3 2014/12/02 09:00:33 skrll Exp $ */
+/*	$NetBSD: ehcivar.h,v 1.42.14.4 2014/12/04 08:04:31 skrll Exp $ */
 
 /*
  * Copyright (c) 2001 The NetBSD Foundation, Inc.
@@ -170,8 +170,6 @@ typedef struct ehci_softc {
 
 	int sc_noport;
 	uint8_t sc_hasppc;		/* has Port Power Control */
-	uint8_t sc_addr;		/* device address */
-	uint8_t sc_conf;		/* device configuration */
 	usbd_xfer_handle sc_intrxfer;
 	char sc_isreset[EHCI_MAX_PORTS];
 	char sc_softwake;

Index: src/sys/dev/usb/motg.c
diff -u src/sys/dev/usb/motg.c:1.12.2.8 src/sys/dev/usb/motg.c:1.12.2.9
--- src/sys/dev/usb/motg.c:1.12.2.8	Wed Dec  3 23:05:06 2014
+++ src/sys/dev/usb/motg.c	Thu Dec  4 08:04:31 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: motg.c,v 1.12.2.8 2014/12/03 23:05:06 skrll Exp $	*/
+/*	$NetBSD: motg.c,v 1.12.2.9 2014/12/04 08:04:31 skrll Exp $	*/
 
 /*
  * Copyright (c) 1998, 2004, 2011, 2012, 2014 The NetBSD Foundation, Inc.
@@ -42,7 +42,7 @@
 #include "opt_motg.h"
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: motg.c,v 1.12.2.8 2014/12/03 23:05:06 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: motg.c,v 1.12.2.9 2014/12/04 08:04:31 skrll Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -101,11 +101,6 @@ int motgdebug = 0;
 #define NAK_TO_BULK_HIGH 0
 
 static void 		motg_hub_change(struct motg_softc *);
-static usbd_status	motg_root_ctrl_transfer(usbd_xfer_handle);
-static usbd_status	motg_root_ctrl_start(usbd_xfer_handle);
-static void		motg_root_ctrl_abort(usbd_xfer_handle);
-static void		motg_root_ctrl_close(usbd_pipe_handle);
-static void		motg_root_ctrl_done(usbd_xfer_handle);
 
 static usbd_status	motg_root_intr_transfer(usbd_xfer_handle);
 static usbd_status	motg_root_intr_start(usbd_xfer_handle);
@@ -119,6 +114,9 @@ static void		motg_softintr(void *);
 static usbd_xfer_handle	motg_allocx(struct usbd_bus *);
 static void		motg_freex(struct usbd_bus *, usbd_xfer_handle);
 static void		motg_get_lock(struct usbd_bus *, kmutex_t **);
+static int		motg_roothub_ctrl(struct usbd_bus *, usb_device_request_t *,
+    void *, int);
+
 static void		motg_noop(usbd_pipe_handle pipe);
 static usbd_status	motg_portreset(struct motg_softc*);
 
@@ -148,7 +146,6 @@ static void		motg_waitintr(struct motg_s
 static void		motg_device_clear_toggle(usbd_pipe_handle);
 static void		motg_device_xfer_abort(usbd_xfer_handle);
 
-#define MOTG_INTR_ENDPT 1
 #define UBARR(sc) bus_space_barrier((sc)->sc_iot, (sc)->sc_ioh, 0, (sc)->sc_size, \
 			BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE)
 #define UWRITE1(sc, r, x) \
@@ -207,16 +204,7 @@ const struct usbd_bus_methods motg_bus_m
 	.ubm_allocx =	motg_allocx,
 	.ubm_freex =	motg_freex,
 	.ubm_getlock =	motg_get_lock,
-	.ubm_newdev =	NULL,
-};
-
-const struct usbd_pipe_methods motg_root_ctrl_methods = {
-	.upm_transfer =	motg_root_ctrl_transfer,
-	.upm_start =	motg_root_ctrl_start,
-	.upm_abort =	motg_root_ctrl_abort,
-	.upm_close =	motg_root_ctrl_close,
-	.upm_cleartoggle =	motg_noop,
-	.upm_done =	motg_root_ctrl_done,
+	.ubm_rhctrl =	motg_roothub_ctrl,
 };
 
 const struct usbd_pipe_methods motg_root_intr_methods = {
@@ -496,10 +484,11 @@ motg_open(usbd_pipe_handle pipe)
 	struct motg_softc *sc = pipe->up_dev->ud_bus->ub_hcpriv;
 	struct motg_pipe *otgpipe = (struct motg_pipe *)pipe;
 	usb_endpoint_descriptor_t *ed = pipe->up_endpoint->ue_edesc;
+	uint8_t rhaddr = pipe->up_dev->ud_bus->ub_rhaddr;
 
 	DPRINTF(("motg_open: pipe=%p, addr=%d, endpt=%d (%d)\n",
 		     pipe, pipe->up_dev->ud_addr,
-		     ed->bEndpointAddress, sc->sc_root_addr));
+		     ed->bEndpointAddress, rhaddr));
 
 	if (sc->sc_dying)
 		return USBD_IOERROR;
@@ -507,12 +496,12 @@ motg_open(usbd_pipe_handle pipe)
 	/* toggle state needed for bulk endpoints */
 	otgpipe->nexttoggle = pipe->up_endpoint->ue_toggle;
 
-	if (pipe->up_dev->ud_addr == sc->sc_root_addr) {
+	if (pipe->up_dev->ud_addr == rhaddr) {
 		switch (ed->bEndpointAddress) {
 		case USB_CONTROL_ENDPOINT:
-			pipe->up_methods = &motg_root_ctrl_methods;
+			pipe->up_methods = &roothub_ctrl_methods;
 			break;
-		case UE_DIR_IN | MOTG_INTR_ENDPT:
+		case UE_DIR_IN | USBROOTHUB_INTR_ENDPT:
 			pipe->up_methods = &motg_root_intr_methods;
 			break;
 		default:
@@ -756,250 +745,69 @@ motg_get_lock(struct usbd_bus *bus, kmut
 }
 
 /*
- * Data structures and routines to emulate the root hub.
- */
-usb_device_descriptor_t motg_devd = {
-	.bLength = USB_DEVICE_DESCRIPTOR_SIZE,
-	.bDescriptorType = UDESC_DEVICE,
-	.bcdUSB = {0x00, 0x01},
-	.bDeviceClass = UDCLASS_HUB,
-	.bDeviceSubClass = UDSUBCLASS_HUB,
-	.bDeviceProtocol = UDPROTO_FSHUB,
-	.bMaxPacketSize = 64,
-	.idVendor = {0},
-	.idProduct = {0},
-	.bcdDevice = {0x00,0x01},
-	.iManufacturer = 1,
-	.iProduct = 2,
-	.iSerialNumber = 0,
-	.bNumConfigurations = 1
-};
-
-const usb_config_descriptor_t motg_confd = {
-	.bLength = USB_CONFIG_DESCRIPTOR_SIZE,
-	.bDescriptorType = UDESC_CONFIG,
-	.wTotalLength = USETWD(
-		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
-};
-
-const usb_interface_descriptor_t motg_ifcd = {
-	.bLength = USB_INTERFACE_DESCRIPTOR_SIZE,
-	.bDescriptorType = UDESC_INTERFACE,
-	.bInterfaceNumber = 0,
-	.bAlternateSetting = 0,
-	.bNumEndpoints = 1,
-	.bInterfaceClass = UICLASS_HUB,
-	.bInterfaceSubClass = UISUBCLASS_HUB,
-	.bInterfaceProtocol = 	UIPROTO_FSHUB,
-};
-
-const usb_endpoint_descriptor_t motg_endpd = {
-	.bLength = USB_ENDPOINT_DESCRIPTOR_SIZE,
-	.bDescriptorType = UDESC_ENDPOINT,
-	.bEndpointAddress = UE_DIR_IN | MOTG_INTR_ENDPT,
-	.bmAttributes = UE_INTERRUPT,
-	.wMaxPacketSize = USETWD(8),
-	.bInterval = 255
-};
-
-const usb_hub_descriptor_t motg_hubd = {
-	.bDescLength = USB_HUB_DESCRIPTOR_SIZE,
-	.bDescriptorType = UDESC_HUB,
-	.bNbrPorts = 1,
-	.wHubCharacteristics = USETWD(UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL),
-	.bPwrOn2PwrGood = 50,
-	.bHubContrCurrent = 0,
-	.DeviceRemovable = { 0 },
-	.PortPowerCtrlMask = { 0 },
-};
-
-/*
- * Simulate a hardware hub by handling all the necessary requests.
+ * Routines to emulate the root hub.
  */
-usbd_status
-motg_root_ctrl_transfer(usbd_xfer_handle xfer)
-{
-	struct motg_softc *sc = xfer->ux_pipe->up_dev->ud_bus->ub_hcpriv;
-	usbd_status err;
-
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return (err);
-
-	/*
-	 * Pipe isn't running (otherwise err would be USBD_INPROG),
-	 * so start it first.
-	 */
-	return (motg_root_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue)));
-}
-
-usbd_status
-motg_root_ctrl_start(usbd_xfer_handle xfer)
+Static int
+motg_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req,
+    void *buf, int buflen)
 {
-	struct motg_softc *sc = xfer->ux_pipe->up_dev->ud_bus->ub_hcpriv;
-	usb_device_request_t *req;
-	void *buf = NULL;
-	int len, value, index, status, change, l, totlen = 0;
+	struct motg_softc *sc = bus->ub_hcpriv;
+	int status, change, totlen = 0;
+	uint16_t len, value, index;
 	usb_port_status_t ps;
 	usbd_status err;
 	uint32_t val;
 
 	if (sc->sc_dying)
-		return (USBD_IOERROR);
+		return -1;
 
-#ifdef DIAGNOSTIC
-	if (!(xfer->ux_rqflags & URQ_REQUEST))
-		panic("motg_root_ctrl_start: not a request");
-#endif
-	req = &xfer->ux_request;
-
-	DPRINTFN(MD_ROOT,("motg_root_ctrl_control type=0x%02x request=%02x\n",
+	DPRINTFN(MD_ROOT,("%s type=0x%02x request=%02x\n", __func__,
 		    req->bmRequestType, req->bRequest));
 
 	len = UGETW(req->wLength);
 	value = UGETW(req->wValue);
 	index = UGETW(req->wIndex);
 
-	if (len != 0)
-		buf = xfer->ux_buf;
-
 #define C(x,y) ((x) | ((y) << 8))
-	switch(C(req->bRequest, req->bmRequestType)) {
-	case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE):
-	case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE):
-	case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT):
-		/*
-		 * DEVICE_REMOTE_WAKEUP and ENDPOINT_HALT are no-ops
-		 * for the integrated root hub.
-		 */
-		break;
-	case C(UR_GET_CONFIG, UT_READ_DEVICE):
-		if (len > 0) {
-			*(uint8_t *)buf = sc->sc_root_conf;
-			totlen = 1;
-		}
-		break;
+	switch (C(req->bRequest, req->bmRequestType)) {
 	case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE):
-		DPRINTFN(MD_ROOT,("motg_root_ctrl_control wValue=0x%04x\n", value));
-		if (len == 0)
+		DPRINTFN(MD_ROOT,("%s wValue=0x%04x\n", __func__, value));
+		switch (value) {
+		case C(0, UDESC_DEVICE): {
+			usb_device_descriptor_t devd;
+
+			totlen = min(buflen, sizeof(devd));
+			memcpy(&devd, buf, totlen);
+			USETW(devd.idVendor, sc->sc_id_vendor);
+			memcpy(buf, &devd, totlen);
 			break;
-		switch(value >> 8) {
-		case UDESC_DEVICE:
-			if ((value & 0xff) != 0) {
-				err = USBD_IOERROR;
-				goto ret;
-			}
-			totlen = l = min(len, USB_DEVICE_DESCRIPTOR_SIZE);
-			USETW(motg_devd.idVendor, sc->sc_id_vendor);
-			memcpy(buf, &motg_devd, l);
-			break;
-		case UDESC_CONFIG:
-			if ((value & 0xff) != 0) {
-				err = USBD_IOERROR;
-				goto ret;
-			}
-			totlen = l = min(len, USB_CONFIG_DESCRIPTOR_SIZE);
-			memcpy(buf, &motg_confd, l);
-			buf = (char *)buf + l;
-			len -= l;
-			l = min(len, USB_INTERFACE_DESCRIPTOR_SIZE);
-			totlen += l;
-			memcpy(buf, &motg_ifcd, l);
-			buf = (char *)buf + l;
-			len -= l;
-			l = min(len, USB_ENDPOINT_DESCRIPTOR_SIZE);
-			totlen += l;
-			memcpy(buf, &motg_endpd, l);
-			break;
-		case UDESC_STRING:
+		}
+		case C(1, UDESC_STRING):
 #define sd ((usb_string_descriptor_t *)buf)
-			switch (value & 0xff) {
-			case 0: /* Language table */
-				totlen = usb_makelangtbl(sd, len);
-				break;
-			case 1: /* Vendor */
-				totlen = usb_makestrdesc(sd, len,
-							 sc->sc_vendor);
-				break;
-			case 2: /* Product */
-				totlen = usb_makestrdesc(sd, len,
-							 "MOTG root hub");
-				break;
-			}
-#undef sd
+			/* Vendor */
+			totlen = usb_makestrdesc(sd, len, sc->sc_vendor);
 			break;
+		case C(2, UDESC_STRING):
+			/* Product */
+			totlen = usb_makestrdesc(sd, len, "MOTG root hub");
+			break;
+#undef sd
 		default:
-			err = USBD_IOERROR;
-			goto ret;
-		}
-		break;
-	case C(UR_GET_INTERFACE, UT_READ_INTERFACE):
-		if (len > 0) {
-			*(uint8_t *)buf = 0;
-			totlen = 1;
-		}
-		break;
-	case C(UR_GET_STATUS, UT_READ_DEVICE):
-		if (len > 1) {
-			USETW(((usb_status_t *)buf)->wStatus,UDS_SELF_POWERED);
-			totlen = 2;
+			/* default from usbroothub */
+			return buflen;
 		}
 		break;
-	case C(UR_GET_STATUS, UT_READ_INTERFACE):
-	case C(UR_GET_STATUS, UT_READ_ENDPOINT):
-		if (len > 1) {
-			USETW(((usb_status_t *)buf)->wStatus, 0);
-			totlen = 2;
-		}
-		break;
-	case C(UR_SET_ADDRESS, UT_WRITE_DEVICE):
-		if (value >= USB_MAX_DEVICES) {
-			err = USBD_IOERROR;
-			goto ret;
-		}
-		sc->sc_root_addr = value;
-		break;
-	case C(UR_SET_CONFIG, UT_WRITE_DEVICE):
-		if (value != 0 && value != 1) {
-			err = USBD_IOERROR;
-			goto ret;
-		}
-		sc->sc_root_conf = value;
-		break;
-	case C(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE):
-		break;
-	case C(UR_SET_FEATURE, UT_WRITE_DEVICE):
-	case C(UR_SET_FEATURE, UT_WRITE_INTERFACE):
-	case C(UR_SET_FEATURE, UT_WRITE_ENDPOINT):
-		err = USBD_IOERROR;
-		goto ret;
-	case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE):
-		break;
-	case C(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT):
-		break;
 	/* Hub requests */
 	case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_DEVICE):
 		break;
 	case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER):
 		DPRINTFN(MD_ROOT,
-		    ("motg_root_ctrl_control: UR_CLEAR_PORT_FEATURE "
-			     "port=%d feature=%d\n",
-			     index, value));
+		    ("%s: UR_CLEAR_PORT_FEATURE port=%d feature=%d\n",
+		    __func__, index, value));
 		if (index != 1) {
-			err = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
-		switch(value) {
+		switch (value) {
 		case UHF_PORT_ENABLE:
 			sc->sc_port_enabled = 0;
 			break;
@@ -1028,8 +836,7 @@ motg_root_ctrl_start(usbd_xfer_handle xf
 			break;
 		case UHF_C_PORT_RESET:
 			sc->sc_isreset = 0;
-			err = USBD_NORMAL_COMPLETION;
-			goto ret;
+			break;
 		case UHF_PORT_POWER:
 			/* XXX todo */
 			break;
@@ -1038,40 +845,32 @@ motg_root_ctrl_start(usbd_xfer_handle xf
 		case UHF_PORT_LOW_SPEED:
 		case UHF_C_PORT_SUSPEND:
 		default:
-			err = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
 		break;
 	case C(UR_GET_BUS_STATE, UT_READ_CLASS_OTHER):
-		err = USBD_IOERROR;
-		goto ret;
+		return -1;
 	case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE):
 		if (len == 0)
 			break;
 		if ((value & 0xff) != 0) {
-			err = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
-		l = min(len, USB_HUB_DESCRIPTOR_SIZE);
-		totlen = l;
-		memcpy(buf, &motg_hubd, l);
+		totlen = buflen;
 		break;
 	case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE):
 		if (len != 4) {
-			err = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
 		memset(buf, 0, len);
 		totlen = len;
 		break;
 	case C(UR_GET_STATUS, UT_READ_CLASS_OTHER):
 		if (index != 1) {
-			err = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
 		if (len != 4) {
-			err = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
 		status = change = 0;
 		if (sc->sc_connected)
@@ -1095,19 +894,16 @@ motg_root_ctrl_start(usbd_xfer_handle xf
 			change |= UPS_C_PORT_RESET;
 		USETW(ps.wPortStatus, status);
 		USETW(ps.wPortChange, change);
-		l = min(len, sizeof ps);
-		memcpy(buf, &ps, l);
-		totlen = l;
+		totlen = min(len, sizeof(ps));
+		memcpy(buf, &ps, totlen);
 		break;
 	case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE):
-		err = USBD_IOERROR;
-		goto ret;
+		return -1;
 	case C(UR_SET_FEATURE, UT_WRITE_CLASS_DEVICE):
 		break;
 	case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER):
 		if (index != 1) {
-			err = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
 		switch(value) {
 		case UHF_PORT_ENABLE:
@@ -1126,11 +922,12 @@ motg_root_ctrl_start(usbd_xfer_handle xf
 			break;
 		case UHF_PORT_RESET:
 			err = motg_portreset(sc);
-			goto ret;
+			if (err != USBD_NORMAL_COMPLETION)
+				return -1;
+			return 0;
 		case UHF_PORT_POWER:
 			/* XXX todo */
-			err = USBD_NORMAL_COMPLETION;
-			goto ret;
+			return 0;
 		case UHF_C_PORT_CONNECTION:
 		case UHF_C_PORT_ENABLE:
 		case UHF_C_PORT_OVER_CURRENT:
@@ -1140,41 +937,15 @@ motg_root_ctrl_start(usbd_xfer_handle xf
 		case UHF_C_PORT_SUSPEND:
 		case UHF_C_PORT_RESET:
 		default:
-			err = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
 		break;
 	default:
-		err = USBD_IOERROR;
-		goto ret;
+		/* default from usbroothub */
+		return buflen;
 	}
-	xfer->ux_actlen = totlen;
-	err = USBD_NORMAL_COMPLETION;
- ret:
-	xfer->ux_status = err;
-	mutex_enter(&sc->sc_lock);
-	usb_transfer_complete(xfer);
-	mutex_exit(&sc->sc_lock);
-	return (USBD_IN_PROGRESS);
-}
 
-/* Abort a root control request. */
-void
-motg_root_ctrl_abort(usbd_xfer_handle xfer)
-{
-	/* Nothing to do, all transfers are synchronous. */
-}
-
-/* Close the root pipe. */
-void
-motg_root_ctrl_close(usbd_pipe_handle pipe)
-{
-	DPRINTFN(MD_ROOT, ("motg_root_ctrl_close\n"));
-}
-
-void
-motg_root_ctrl_done(usbd_xfer_handle xfer)
-{
+	return totlen;
 }
 
 /* Abort a root interrupt request. */

Index: src/sys/dev/usb/motgvar.h
diff -u src/sys/dev/usb/motgvar.h:1.4.2.2 src/sys/dev/usb/motgvar.h:1.4.2.3
--- src/sys/dev/usb/motgvar.h:1.4.2.2	Tue Dec  2 09:00:33 2014
+++ src/sys/dev/usb/motgvar.h	Thu Dec  4 08:04:31 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: motgvar.h,v 1.4.2.2 2014/12/02 09:00:33 skrll Exp $	*/
+/*	$NetBSD: motgvar.h,v 1.4.2.3 2014/12/04 08:04:31 skrll Exp $	*/
 
 /*
  * Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -93,8 +93,6 @@ struct motg_softc {
 
 	/* Info for the root hub interrupt "pipe". */
 	usbd_xfer_handle sc_intr_xfer;	/* root hub interrupt transfer */
-	uint8_t sc_root_addr;		/* address of the root hub */
-	uint8_t sc_root_conf;		/* configuration of the root hub */
 
 	char sc_vendor[32];		/* vendor string for root hub */
 	int sc_id_vendor;		/* vendor ID for root hub */

Index: src/sys/dev/usb/ohci.c
diff -u src/sys/dev/usb/ohci.c:1.254.2.11 src/sys/dev/usb/ohci.c:1.254.2.12
--- src/sys/dev/usb/ohci.c:1.254.2.11	Wed Dec  3 23:05:06 2014
+++ src/sys/dev/usb/ohci.c	Thu Dec  4 08:04:31 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: ohci.c,v 1.254.2.11 2014/12/03 23:05:06 skrll Exp $	*/
+/*	$NetBSD: ohci.c,v 1.254.2.12 2014/12/04 08:04:31 skrll Exp $	*/
 
 /*
  * Copyright (c) 1998, 2004, 2005, 2012 The NetBSD Foundation, Inc.
@@ -41,7 +41,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ohci.c,v 1.254.2.11 2014/12/03 23:05:06 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ohci.c,v 1.254.2.12 2014/12/04 08:04:31 skrll Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -130,12 +130,8 @@ Static void		ohci_device_isoc_enter(usbd
 Static usbd_xfer_handle	ohci_allocx(struct usbd_bus *);
 Static void		ohci_freex(struct usbd_bus *, usbd_xfer_handle);
 Static void		ohci_get_lock(struct usbd_bus *, kmutex_t **);
-
-Static usbd_status	ohci_root_ctrl_transfer(usbd_xfer_handle);
-Static usbd_status	ohci_root_ctrl_start(usbd_xfer_handle);
-Static void		ohci_root_ctrl_abort(usbd_xfer_handle);
-Static void		ohci_root_ctrl_close(usbd_pipe_handle);
-Static void		ohci_root_ctrl_done(usbd_xfer_handle);
+Static int		ohci_roothub_ctrl(struct usbd_bus *, 
+    usb_device_request_t *, void *, int);
 
 Static usbd_status	ohci_root_intr_transfer(usbd_xfer_handle);
 Static usbd_status	ohci_root_intr_start(usbd_xfer_handle);
@@ -245,8 +241,6 @@ struct ohci_pipe {
 	} u;
 };
 
-#define OHCI_INTR_ENDPT 1
-
 Static const struct usbd_bus_methods ohci_bus_methods = {
 	.ubm_open =	ohci_open,
 	.ubm_softint =	ohci_softintr,
@@ -254,16 +248,7 @@ Static const struct usbd_bus_methods ohc
 	.ubm_allocx =	ohci_allocx,
 	.ubm_freex =	ohci_freex,
 	.ubm_getlock =	ohci_get_lock,
-	.ubm_newdev =	NULL,
-};
-
-Static const struct usbd_pipe_methods ohci_root_ctrl_methods = {
-	.upm_transfer =	ohci_root_ctrl_transfer,
-	.upm_start =	ohci_root_ctrl_start,
-	.upm_abort =	ohci_root_ctrl_abort,
-	.upm_close =	ohci_root_ctrl_close,
-	.upm_cleartoggle =	ohci_noop,
-	.upm_done =	ohci_root_ctrl_done,
+	.ubm_rhctrl =	ohci_roothub_ctrl,
 };
 
 Static const struct usbd_pipe_methods ohci_root_intr_methods = {
@@ -1588,11 +1573,6 @@ ohci_root_intr_done(usbd_xfer_handle xfe
 {
 }
 
-void
-ohci_root_ctrl_done(usbd_xfer_handle xfer)
-{
-}
-
 /*
  * Wait here until controller claims to have an interrupt.
  * Then call ohci_intr and return.  Use timeout to avoid waiting
@@ -2076,6 +2056,7 @@ usbd_status
 ohci_open(usbd_pipe_handle pipe)
 {
 	usbd_device_handle dev = pipe->up_dev;
+	struct usbd_bus *bus = dev->ud_bus;
 	ohci_softc_t *sc = dev->ud_bus->ub_hcpriv;
 	usb_endpoint_descriptor_t *ed = pipe->up_endpoint->ue_edesc;
 	struct ohci_pipe *opipe = (struct ohci_pipe *)pipe;
@@ -2090,7 +2071,7 @@ ohci_open(usbd_pipe_handle pipe)
 	int ival;
 
 	DPRINTFN(1, ("ohci_open: pipe=%p, addr=%d, endpt=%d (%d)\n",
-		     pipe, addr, ed->bEndpointAddress, sc->sc_addr));
+		     pipe, addr, ed->bEndpointAddress, bus->ub_rhaddr));
 
 	if (sc->sc_dying) {
 		return USBD_IOERROR;
@@ -2099,12 +2080,12 @@ ohci_open(usbd_pipe_handle pipe)
 	std = NULL;
 	sed = NULL;
 
-	if (addr == sc->sc_addr) {
+	if (addr == bus->ub_rhaddr) {
 		switch (ed->bEndpointAddress) {
 		case USB_CONTROL_ENDPOINT:
-			pipe->up_methods = &ohci_root_ctrl_methods;
+			pipe->up_methods = &roothub_ctrl_methods;
 			break;
-		case UE_DIR_IN | OHCI_INTR_ENDPT:
+		case UE_DIR_IN | USBROOTHUB_INTR_ENDPT:
 			pipe->up_methods = &ohci_root_intr_methods;
 			break;
 		default:
@@ -2394,240 +2375,68 @@ done:
 /*
  * Data structures and routines to emulate the root hub.
  */
-Static usb_device_descriptor_t ohci_devd = {
-	.bLength = USB_DEVICE_DESCRIPTOR_SIZE,
-	.bDescriptorType = UDESC_DEVICE,
-	.bcdUSB = {0x00, 0x01},
-	.bDeviceClass = UDCLASS_HUB,
-	.bDeviceSubClass = UDSUBCLASS_HUB,
-	.bDeviceProtocol = UDPROTO_FSHUB,
-	.bMaxPacketSize = 64,
-	.idVendor = {0},
-	.idProduct = {0},
-	.bcdDevice = {0x00,0x01},
-	.iManufacturer = 1,
-	.iProduct = 2,
-	.iSerialNumber = 0,
-	.bNumConfigurations = 1
-};
-
-Static const usb_config_descriptor_t ohci_confd = {
-	.bLength = USB_CONFIG_DESCRIPTOR_SIZE,
-	.bDescriptorType = UDESC_CONFIG,
-	.wTotalLength = USETWD(
-	    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
-};
-
-Static const usb_interface_descriptor_t ohci_ifcd = {
-	.bLength = USB_INTERFACE_DESCRIPTOR_SIZE,
-	.bDescriptorType = UDESC_INTERFACE,
-	.bInterfaceNumber = 0,
-	.bAlternateSetting = 0,
-	.bNumEndpoints = 1,
-	.bInterfaceClass = UICLASS_HUB,
-	.bInterfaceSubClass = UISUBCLASS_HUB,
-	.bInterfaceProtocol = UIPROTO_FSHUB,
-	.iInterface = 0
-};
-
-Static const usb_endpoint_descriptor_t ohci_endpd = {
-	.bLength = USB_ENDPOINT_DESCRIPTOR_SIZE,
-	.bDescriptorType = UDESC_ENDPOINT,
-	.bEndpointAddress = UE_DIR_IN | OHCI_INTR_ENDPT,
-	.bmAttributes = UE_INTERRUPT,
-	.wMaxPacketSize = USETWD(8),
-	.bInterval = 255,
-};
-
-Static const usb_hub_descriptor_t ohci_hubd = {
-	.bDescLength = USB_HUB_DESCRIPTOR_SIZE,
-	.bDescriptorType = UDESC_HUB,
-};
-
-/*
- * Simulate a hardware hub by handling all the necessary requests.
- */
-Static usbd_status
-ohci_root_ctrl_transfer(usbd_xfer_handle xfer)
-{
-	ohci_softc_t *sc = xfer->ux_pipe->up_dev->ud_bus->ub_hcpriv;
-	usbd_status err;
-
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return (err);
-
-	/* Pipe isn't running, start first */
-	return (ohci_root_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue)));
-}
-
-Static usbd_status
-ohci_root_ctrl_start(usbd_xfer_handle xfer)
+Static int
+ohci_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req,
+    void *buf, int buflen)
 {
-	ohci_softc_t *sc = xfer->ux_pipe->up_dev->ud_bus->ub_hcpriv;
-	usb_device_request_t *req;
-	void *buf = NULL;
-	int port, i;
-	int len, value, index, l, totlen = 0;
+	ohci_softc_t *sc = bus->ub_hcpriv;
 	usb_port_status_t ps;
-	usb_hub_descriptor_t hubd;
-	usbd_status err;
+	uint16_t len, value, index;
+	int l, totlen = 0;
+	int port, i;
 	uint32_t v;
 
 	if (sc->sc_dying)
-		return (USBD_IOERROR);
-
-#ifdef DIAGNOSTIC
-	if (!(xfer->ux_rqflags & URQ_REQUEST))
-		/* XXX panic */
-		return (USBD_INVAL);
-#endif
-	req = &xfer->ux_request;
+		return -1;
 
-	DPRINTFN(4,("ohci_root_ctrl_control type=0x%02x request=%02x\n",
-		    req->bmRequestType, req->bRequest));
+	DPRINTFN(4,("%s: type=0x%02x request=%02x\n", __func__,
+	    req->bmRequestType, req->bRequest));
 
 	len = UGETW(req->wLength);
 	value = UGETW(req->wValue);
 	index = UGETW(req->wIndex);
 
-	if (len != 0)
-		buf = xfer->ux_buf;
-
 #define C(x,y) ((x) | ((y) << 8))
-	switch(C(req->bRequest, req->bmRequestType)) {
-	case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE):
-	case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE):
-	case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT):
-		/*
-		 * DEVICE_REMOTE_WAKEUP and ENDPOINT_HALT are no-ops
-		 * for the integrated root hub.
-		 */
-		break;
-	case C(UR_GET_CONFIG, UT_READ_DEVICE):
-		if (len > 0) {
-			*(uint8_t *)buf = sc->sc_conf;
-			totlen = 1;
-		}
-		break;
+	switch (C(req->bRequest, req->bmRequestType)) {
 	case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE):
-		DPRINTFN(8,("ohci_root_ctrl_control wValue=0x%04x\n", value));
+		DPRINTFN(8,("%s: wValue=0x%04x\n", __func__, value));
 		if (len == 0)
 			break;
-		switch(value >> 8) {
-		case UDESC_DEVICE:
-			if ((value & 0xff) != 0) {
-				err = USBD_IOERROR;
-				goto ret;
-			}
-			totlen = l = min(len, USB_DEVICE_DESCRIPTOR_SIZE);
-			USETW(ohci_devd.idVendor, sc->sc_id_vendor);
-			memcpy(buf, &ohci_devd, l);
-			break;
-		case UDESC_CONFIG:
-			if ((value & 0xff) != 0) {
-				err = USBD_IOERROR;
-				goto ret;
-			}
-			totlen = l = min(len, USB_CONFIG_DESCRIPTOR_SIZE);
-			memcpy(buf, &ohci_confd, l);
-			buf = (char *)buf + l;
-			len -= l;
-			l = min(len, USB_INTERFACE_DESCRIPTOR_SIZE);
-			totlen += l;
-			memcpy(buf, &ohci_ifcd, l);
-			buf = (char *)buf + l;
-			len -= l;
-			l = min(len, USB_ENDPOINT_DESCRIPTOR_SIZE);
-			totlen += l;
-			memcpy(buf, &ohci_endpd, l);
+		switch (value) {
+		case C(0, UDESC_DEVICE): {
+			usb_device_descriptor_t devd;
+
+			totlen = min(buflen, sizeof(devd));
+			memcpy(&devd, buf, totlen);
+			USETW(devd.idVendor, sc->sc_id_vendor);
+			memcpy(buf, &devd, totlen);
 			break;
-		case UDESC_STRING:
+		}
+		case C(1, UDESC_STRING):
 #define sd ((usb_string_descriptor_t *)buf)
-			switch (value & 0xff) {
-			case 0: /* Language table */
-				totlen = usb_makelangtbl(sd, len);
-				break;
-			case 1: /* Vendor */
-				totlen = usb_makestrdesc(sd, len,
-							 sc->sc_vendor);
-				break;
-			case 2: /* Product */
-				totlen = usb_makestrdesc(sd, len,
-							 "OHCI root hub");
-				break;
-			}
-#undef sd
+			/* Vendor */
+			totlen = usb_makestrdesc(sd, len, sc->sc_vendor);
+			break;
+		case C(2, UDESC_STRING):
+			/* Product */
+			totlen = usb_makestrdesc(sd, len, "OHCI root hub");
 			break;
+#undef sd
 		default:
-			err = USBD_IOERROR;
-			goto ret;
-		}
-		break;
-	case C(UR_GET_INTERFACE, UT_READ_INTERFACE):
-		if (len > 0) {
-			*(uint8_t *)buf = 0;
-			totlen = 1;
-		}
-		break;
-	case C(UR_GET_STATUS, UT_READ_DEVICE):
-		if (len > 1) {
-			USETW(((usb_status_t *)buf)->wStatus,UDS_SELF_POWERED);
-			totlen = 2;
-		}
-		break;
-	case C(UR_GET_STATUS, UT_READ_INTERFACE):
-	case C(UR_GET_STATUS, UT_READ_ENDPOINT):
-		if (len > 1) {
-			USETW(((usb_status_t *)buf)->wStatus, 0);
-			totlen = 2;
-		}
-		break;
-	case C(UR_SET_ADDRESS, UT_WRITE_DEVICE):
-		if (value >= USB_MAX_DEVICES) {
-			err = USBD_IOERROR;
-			goto ret;
-		}
-		sc->sc_addr = value;
-		break;
-	case C(UR_SET_CONFIG, UT_WRITE_DEVICE):
-		if (value != 0 && value != 1) {
-			err = USBD_IOERROR;
-			goto ret;
+			/* default from usbroothub */
+			return buflen;
 		}
-		sc->sc_conf = value;
-		break;
-	case C(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE):
-		break;
-	case C(UR_SET_FEATURE, UT_WRITE_DEVICE):
-	case C(UR_SET_FEATURE, UT_WRITE_INTERFACE):
-	case C(UR_SET_FEATURE, UT_WRITE_ENDPOINT):
-		err = USBD_IOERROR;
-		goto ret;
-	case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE):
-		break;
-	case C(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT):
 		break;
+
 	/* Hub requests */
 	case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_DEVICE):
 		break;
 	case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER):
-		DPRINTFN(8, ("ohci_root_ctrl_control: UR_CLEAR_PORT_FEATURE "
-			     "port=%d feature=%d\n",
+		DPRINTFN(8, ("%s: UR_CLEAR_PORT_FEATURE "
+			     "port=%d feature=%d\n", __func__,
 			     index, value));
 		if (index < 1 || index > sc->sc_noport) {
-			err = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
 		port = OHCI_RH_PORT_STATUS(index);
 		switch(value) {
@@ -2657,8 +2466,7 @@ ohci_root_ctrl_start(usbd_xfer_handle xf
 			OWRITE4(sc, port, UPS_C_PORT_RESET << 16);
 			break;
 		default:
-			err = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
 		switch(value) {
 		case UHF_C_PORT_CONNECTION:
@@ -2678,11 +2486,14 @@ ohci_root_ctrl_start(usbd_xfer_handle xf
 		if (len == 0)
 			break;
 		if ((value & 0xff) != 0) {
-			err = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
+		usb_hub_descriptor_t hubd;
+
+		totlen = min(buflen, sizeof(hubd));
+		memcpy(&hubd, buf, totlen);
+
 		v = OREAD4(sc, OHCI_RH_DESCRIPTOR_A);
-		hubd = ohci_hubd;
 		hubd.bNbrPorts = sc->sc_noport;
 		USETW(hubd.wHubCharacteristics,
 		      (v & OHCI_NPS ? UHD_PWR_NO_SWITCH :
@@ -2694,47 +2505,40 @@ ohci_root_ctrl_start(usbd_xfer_handle xf
 		for (i = 0, l = sc->sc_noport; l > 0; i++, l -= 8, v >>= 8)
 			hubd.DeviceRemovable[i++] = (uint8_t)v;
 		hubd.bDescLength = USB_HUB_DESCRIPTOR_SIZE + i;
-		l = min(len, hubd.bDescLength);
-		totlen = l;
-		memcpy(buf, &hubd, l);
+		totlen = min(totlen, hubd.bDescLength);
+		memcpy(buf, &hubd, totlen);
 		break;
 	case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE):
 		if (len != 4) {
-			err = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
 		memset(buf, 0, len); /* ? XXX */
 		totlen = len;
 		break;
 	case C(UR_GET_STATUS, UT_READ_CLASS_OTHER):
-		DPRINTFN(8,("ohci_root_ctrl_transfer: get port status i=%d\n",
+		DPRINTFN(8,("%s: get port status i=%d\n", __func__,
 			    index));
 		if (index < 1 || index > sc->sc_noport) {
-			err = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
 		if (len != 4) {
-			err = USBD_IOERROR;
-			goto ret;
-		}
+			return -1;
+			}
 		v = OREAD4(sc, OHCI_RH_PORT_STATUS(index));
-		DPRINTFN(8,("ohci_root_ctrl_transfer: port status=0x%04x\n",
+		DPRINTFN(8,("%s: port status=0x%04x\n", __func__,
 			    v));
 		USETW(ps.wPortStatus, v);
 		USETW(ps.wPortChange, v >> 16);
-		l = min(len, sizeof ps);
-		memcpy(buf, &ps, l);
-		totlen = l;
+		totlen = min(len, sizeof(ps));
+		memcpy(buf, &ps, totlen);
 		break;
 	case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE):
-		err = USBD_IOERROR;
-		goto ret;
+		return -1;
 	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_noport) {
-			err = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
 		port = OHCI_RH_PORT_STATUS(index);
 		switch(value) {
@@ -2745,15 +2549,14 @@ ohci_root_ctrl_start(usbd_xfer_handle xf
 			OWRITE4(sc, port, UPS_SUSPEND);
 			break;
 		case UHF_PORT_RESET:
-			DPRINTFN(5,("ohci_root_ctrl_transfer: reset port %d\n",
+			DPRINTFN(5,("%s: reset port %d\n", __func__,
 				    index));
 			OWRITE4(sc, port, UPS_RESET);
 			for (i = 0; i < 5; i++) {
 				usb_delay_ms(&sc->sc_bus,
 					     USB_PORT_ROOT_RESET_DELAY);
 				if (sc->sc_dying) {
-					err = USBD_IOERROR;
-					goto ret;
+					return -1;
 				}
 				if ((OREAD4(sc, port) & UPS_RESET) == 0)
 					break;
@@ -2762,42 +2565,20 @@ ohci_root_ctrl_start(usbd_xfer_handle xf
 				    index, OREAD4(sc, port)));
 			break;
 		case UHF_PORT_POWER:
-			DPRINTFN(2,("ohci_root_ctrl_transfer: set port power "
-				    "%d\n", index));
+			DPRINTFN(2,("%s: set port power "
+				    "%d\n", __func__, index));
 			OWRITE4(sc, port, UPS_PORT_POWER);
 			break;
 		default:
-			err = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
 		break;
 	default:
-		err = USBD_IOERROR;
-		goto ret;
+		/* default from usbroothub */
+		return buflen;
 	}
-	xfer->ux_actlen = totlen;
-	err = USBD_NORMAL_COMPLETION;
- ret:
-	xfer->ux_status = err;
-	mutex_enter(&sc->sc_lock);
-	usb_transfer_complete(xfer);
-	mutex_exit(&sc->sc_lock);
-	return (USBD_IN_PROGRESS);
-}
-
-/* Abort a root control request. */
-Static void
-ohci_root_ctrl_abort(usbd_xfer_handle xfer)
-{
-	/* Nothing to do, all transfers are synchronous. */
-}
 
-/* Close the root pipe. */
-Static void
-ohci_root_ctrl_close(usbd_pipe_handle pipe)
-{
-	DPRINTF(("ohci_root_ctrl_close\n"));
-	/* Nothing to do. */
+	return totlen;
 }
 
 Static usbd_status

Index: src/sys/dev/usb/ohcivar.h
diff -u src/sys/dev/usb/ohcivar.h:1.55.6.2 src/sys/dev/usb/ohcivar.h:1.55.6.3
--- src/sys/dev/usb/ohcivar.h:1.55.6.2	Tue Dec  2 09:00:33 2014
+++ src/sys/dev/usb/ohcivar.h	Thu Dec  4 08:04:31 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: ohcivar.h,v 1.55.6.2 2014/12/02 09:00:33 skrll Exp $	*/
+/*	$NetBSD: ohcivar.h,v 1.55.6.3 2014/12/04 08:04:31 skrll Exp $	*/
 
 /*
  * Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -109,8 +109,6 @@ typedef struct ohci_softc {
 	LIST_HEAD(, ohci_soft_itd) sc_hash_itds[OHCI_HASH_SIZE];
 
 	int sc_noport;
-	uint8_t sc_addr;		/* device address */
-	uint8_t sc_conf;		/* device configuration */
 
 	int sc_endian;
 #define	OHCI_LITTLE_ENDIAN	0	/* typical (uninitialized default) */

Index: src/sys/dev/usb/uhci.c
diff -u src/sys/dev/usb/uhci.c:1.264.4.11 src/sys/dev/usb/uhci.c:1.264.4.12
--- src/sys/dev/usb/uhci.c:1.264.4.11	Wed Dec  3 23:05:06 2014
+++ src/sys/dev/usb/uhci.c	Thu Dec  4 08:04:31 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: uhci.c,v 1.264.4.11 2014/12/03 23:05:06 skrll Exp $	*/
+/*	$NetBSD: uhci.c,v 1.264.4.12 2014/12/04 08:04:31 skrll Exp $	*/
 
 /*
  * Copyright (c) 1998, 2004, 2011, 2012 The NetBSD Foundation, Inc.
@@ -42,7 +42,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uhci.c,v 1.264.4.11 2014/12/03 23:05:06 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uhci.c,v 1.264.4.12 2014/12/04 08:04:31 skrll Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -168,6 +168,8 @@ Static void		uhci_device_isoc_enter(usbd
 Static usbd_xfer_handle	uhci_allocx(struct usbd_bus *);
 Static void		uhci_freex(struct usbd_bus *, usbd_xfer_handle);
 Static void		uhci_get_lock(struct usbd_bus *, kmutex_t **);
+Static int		uhci_roothub_ctrl(struct usbd_bus *, 
+    usb_device_request_t *, void *, int);
 
 Static usbd_status	uhci_device_ctrl_transfer(usbd_xfer_handle);
 Static usbd_status	uhci_device_ctrl_start(usbd_xfer_handle);
@@ -193,12 +195,6 @@ Static void		uhci_device_isoc_abort(usbd
 Static void		uhci_device_isoc_close(usbd_pipe_handle);
 Static void		uhci_device_isoc_done(usbd_xfer_handle);
 
-Static usbd_status	uhci_root_ctrl_transfer(usbd_xfer_handle);
-Static usbd_status	uhci_root_ctrl_start(usbd_xfer_handle);
-Static void		uhci_root_ctrl_abort(usbd_xfer_handle);
-Static void		uhci_root_ctrl_close(usbd_pipe_handle);
-Static void		uhci_root_ctrl_done(usbd_xfer_handle);
-
 Static usbd_status	uhci_root_intr_transfer(usbd_xfer_handle);
 Static usbd_status	uhci_root_intr_start(usbd_xfer_handle);
 Static void		uhci_root_intr_abort(usbd_xfer_handle);
@@ -277,8 +273,6 @@ UREAD4(uhci_softc_t *sc, bus_size_t r)
 
 #define UHCI_CURFRAME(sc) (UREAD2(sc, UHCI_FRNUM) & UHCI_FRNUM_MASK)
 
-#define UHCI_INTR_ENDPT 1
-
 const struct usbd_bus_methods uhci_bus_methods = {
 	.ubm_open =	uhci_open,
 	.ubm_softint =	uhci_softintr,
@@ -286,16 +280,7 @@ const struct usbd_bus_methods uhci_bus_m
 	.ubm_allocx =	uhci_allocx,
 	.ubm_freex =	uhci_freex,
 	.ubm_getlock =	uhci_get_lock,
-	.ubm_newdev =	NULL,
-};
-
-const struct usbd_pipe_methods uhci_root_ctrl_methods = {
-	.upm_transfer =	uhci_root_ctrl_transfer,
-	.upm_start =	uhci_root_ctrl_start,
-	.upm_abort =	uhci_root_ctrl_abort,
-	.upm_close =	uhci_root_ctrl_close,
-	.upm_cleartoggle =	uhci_noop,
-	.upm_done =	uhci_root_ctrl_done,
+	.ubm_rhctrl =	uhci_roothub_ctrl,
 };
 
 const struct usbd_pipe_methods uhci_root_intr_methods = {
@@ -969,11 +954,6 @@ uhci_root_intr_done(usbd_xfer_handle xfe
 {
 }
 
-void
-uhci_root_ctrl_done(usbd_xfer_handle xfer)
-{
-}
-
 /*
  * Let the last QH loop back to the high speed control transfer QH.
  * This is what intel calls "bandwidth reclamation" and improves
@@ -3245,6 +3225,7 @@ usbd_status
 uhci_open(usbd_pipe_handle pipe)
 {
 	uhci_softc_t *sc = pipe->up_dev->ud_bus->ub_hcpriv;
+	struct usbd_bus *bus = pipe->up_dev->ud_bus;
 	struct uhci_pipe *upipe = (struct uhci_pipe *)pipe;
 	usb_endpoint_descriptor_t *ed = pipe->up_endpoint->ue_edesc;
 	usbd_status err = USBD_NOMEM;
@@ -3252,7 +3233,7 @@ uhci_open(usbd_pipe_handle pipe)
 
 	DPRINTFN(1, ("uhci_open: pipe=%p, addr=%d, endpt=%d (%d)\n",
 		     pipe, pipe->up_dev->ud_addr,
-		     ed->bEndpointAddress, sc->sc_addr));
+		     ed->bEndpointAddress, bus->ub_rhaddr));
 
 	if (sc->sc_dying)
 		return USBD_IOERROR;
@@ -3261,12 +3242,12 @@ uhci_open(usbd_pipe_handle pipe)
 	/* toggle state needed for bulk endpoints */
 	upipe->nexttoggle = pipe->up_endpoint->ue_toggle;
 
-	if (pipe->up_dev->ud_addr == sc->sc_addr) {
+	if (pipe->up_dev->ud_addr == bus->ub_rhaddr) {
 		switch (ed->bEndpointAddress) {
 		case USB_CONTROL_ENDPOINT:
-			pipe->up_methods = &uhci_root_ctrl_methods;
+			pipe->up_methods = &roothub_ctrl_methods;
 			break;
-		case UE_DIR_IN | UHCI_INTR_ENDPT:
+		case UE_DIR_IN | USBROOTHUB_INTR_ENDPT:
 			pipe->up_methods = &uhci_root_intr_methods;
 			break;
 		default:
@@ -3326,69 +3307,6 @@ uhci_open(usbd_pipe_handle pipe)
 /*
  * Data structures and routines to emulate the root hub.
  */
-usb_device_descriptor_t uhci_devd = {
-	.bLength = USB_DEVICE_DESCRIPTOR_SIZE,
-	.bDescriptorType = UDESC_DEVICE,
-	.bcdUSB = {0x00, 0x01},
-	.bDeviceClass = UDCLASS_HUB,
-	.bDeviceSubClass = UDSUBCLASS_HUB,
-	.bDeviceProtocol = UDPROTO_FSHUB,
-	.bMaxPacketSize = 64,
-	.idVendor = {0},
-	.idProduct = {0},
-	.bcdDevice = {0x00,0x01},
-	.iManufacturer = 1,
-	.iProduct = 2,
-	.iSerialNumber = 0,
-	.bNumConfigurations = 1
-};
-
-const usb_config_descriptor_t uhci_confd = {
-	.bLength = USB_CONFIG_DESCRIPTOR_SIZE,
-	.bDescriptorType = UDESC_CONFIG,
-	.wTotalLength = USETWD(
-	    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
-};
-
-const usb_interface_descriptor_t uhci_ifcd = {
-	.bLength = USB_INTERFACE_DESCRIPTOR_SIZE,
-	.bDescriptorType = UDESC_INTERFACE,
-	.bInterfaceNumber = 0,
-	.bAlternateSetting = 0,
-	.bNumEndpoints = 1,
-	.bInterfaceClass = UICLASS_HUB,
-	.bInterfaceSubClass = UISUBCLASS_HUB,
-	.bInterfaceProtocol = UIPROTO_FSHUB,
-	.iInterface = 0
-};
-
-const usb_endpoint_descriptor_t uhci_endpd = {
-	.bLength = USB_ENDPOINT_DESCRIPTOR_SIZE,
-	.bDescriptorType = UDESC_ENDPOINT,
-	.bEndpointAddress = UE_DIR_IN | UHCI_INTR_ENDPT,
-	.bmAttributes = UE_INTERRUPT,
-	.wMaxPacketSize = USETWD(8),
-	.bInterval = 255
-};
-
-const usb_hub_descriptor_t uhci_hubd_piix = {
-	.bDescLength = USB_HUB_DESCRIPTOR_SIZE,
-	.bDescriptorType = UDESC_HUB,
-	.bNbrPorts = 2,
-	.wHubCharacteristics = USETWD(UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL),
-	.bPwrOn2PwrGood = 50,
-	.bHubContrCurrent = 0,
-	.DeviceRemovable = { 0x00 },
-	.PortPowerCtrlMask = { 0 },
-};
-
 /*
  * The USB hub protocol requires that SET_FEATURE(PORT_RESET) also
  * enables the port, and also states that SET_FEATURE(PORT_ENABLE)
@@ -3484,187 +3402,72 @@ uhci_portreset(uhci_softc_t *sc, int ind
 	return (USBD_NORMAL_COMPLETION);
 }
 
-/*
- * Simulate a hardware hub by handling all the necessary requests.
- */
-usbd_status
-uhci_root_ctrl_transfer(usbd_xfer_handle xfer)
+Static int
+uhci_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req,
+    void *buf, int buflen)
 {
-	uhci_softc_t *sc = xfer->ux_pipe->up_dev->ud_bus->ub_hcpriv;
-	usbd_status err;
-
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return (err);
-
-	/*
-	 * Pipe isn't running (otherwise err would be USBD_INPROG),
-	 * so start it first.
-	 */
-	return (uhci_root_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue)));
-}
-
-usbd_status
-uhci_root_ctrl_start(usbd_xfer_handle xfer)
-{
-	uhci_softc_t *sc = xfer->ux_pipe->up_dev->ud_bus->ub_hcpriv;
-	usb_device_request_t *req;
-	void *buf = NULL;
+	uhci_softc_t *sc = bus->ub_hcpriv;
 	int port, x;
-	int len, value, index, status, change, l, totlen = 0;
+	int status, change, totlen = 0;
+	uint16_t len, value, index;
 	usb_port_status_t ps;
 	usbd_status err;
 
 	if (sc->sc_dying)
-		return (USBD_IOERROR);
-
-#ifdef DIAGNOSTIC
-	if (!(xfer->ux_rqflags & URQ_REQUEST))
-		panic("uhci_root_ctrl_start: not a request");
-#endif
-	req = &xfer->ux_request;
+		return -1;
 
-	DPRINTFN(2,("uhci_root_ctrl_control type=0x%02x request=%02x\n",
-		    req->bmRequestType, req->bRequest));
+	DPRINTFN(2,("%s: type=0x%02x request=%02x\n", __func__,
+	    req->bmRequestType, req->bRequest));
 
 	len = UGETW(req->wLength);
 	value = UGETW(req->wValue);
 	index = UGETW(req->wIndex);
 
-	if (len != 0)
-		buf = xfer->ux_buf;
-
 #define C(x,y) ((x) | ((y) << 8))
-	switch(C(req->bRequest, req->bmRequestType)) {
-	case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE):
-	case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE):
-	case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT):
-		/*
-		 * DEVICE_REMOTE_WAKEUP and ENDPOINT_HALT are no-ops
-		 * for the integrated root hub.
-		 */
-		break;
-	case C(UR_GET_CONFIG, UT_READ_DEVICE):
-		if (len > 0) {
-			*(uint8_t *)buf = sc->sc_conf;
-			totlen = 1;
-		}
-		break;
+	switch (C(req->bRequest, req->bmRequestType)) {
 	case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE):
-		DPRINTFN(2,("uhci_root_ctrl_control wValue=0x%04x\n", value));
+		DPRINTFN(2,("%s: wValue=0x%04x\n", __func__, value));
 		if (len == 0)
 			break;
-		switch(value >> 8) {
-		case UDESC_DEVICE:
-			if ((value & 0xff) != 0) {
-				err = USBD_IOERROR;
-				goto ret;
-			}
-			totlen = l = min(len, USB_DEVICE_DESCRIPTOR_SIZE);
-			USETW(uhci_devd.idVendor, sc->sc_id_vendor);
-			memcpy(buf, &uhci_devd, l);
-			break;
-		case UDESC_CONFIG:
-			if ((value & 0xff) != 0) {
-				err = USBD_IOERROR;
-				goto ret;
-			}
-			totlen = l = min(len, USB_CONFIG_DESCRIPTOR_SIZE);
-			memcpy(buf, &uhci_confd, l);
-			buf = (char *)buf + l;
-			len -= l;
-			l = min(len, USB_INTERFACE_DESCRIPTOR_SIZE);
-			totlen += l;
-			memcpy(buf, &uhci_ifcd, l);
-			buf = (char *)buf + l;
-			len -= l;
-			l = min(len, USB_ENDPOINT_DESCRIPTOR_SIZE);
-			totlen += l;
-			memcpy(buf, &uhci_endpd, l);
+		switch (value) {
+		case C(0, UDESC_DEVICE): {
+			usb_device_descriptor_t devd;
+
+			totlen = min(buflen, sizeof(devd));
+			memcpy(&devd, buf, totlen);
+			USETW(devd.idVendor, sc->sc_id_vendor);
+			memcpy(buf, &devd, totlen);
 			break;
-		case UDESC_STRING:
+		}
+		case C(1, UDESC_STRING):
 #define sd ((usb_string_descriptor_t *)buf)
-			switch (value & 0xff) {
-			case 0: /* Language table */
-				totlen = usb_makelangtbl(sd, len);
-				break;
-			case 1: /* Vendor */
-				totlen = usb_makestrdesc(sd, len,
-							 sc->sc_vendor);
-				break;
-			case 2: /* Product */
-				totlen = usb_makestrdesc(sd, len,
-							 "UHCI root hub");
-				break;
-			}
-#undef sd
+			/* Vendor */
+			totlen = usb_makestrdesc(sd, len, sc->sc_vendor);
+			break;
+		case C(2, UDESC_STRING):
+			/* Product */
+			totlen = usb_makestrdesc(sd, len, "UHCI root hub");
 			break;
+#undef sd
 		default:
-			err = USBD_IOERROR;
-			goto ret;
-		}
-		break;
-	case C(UR_GET_INTERFACE, UT_READ_INTERFACE):
-		if (len > 0) {
-			*(uint8_t *)buf = 0;
-			totlen = 1;
+			/* default from usbroothub */
+			return buflen;
 		}
 		break;
-	case C(UR_GET_STATUS, UT_READ_DEVICE):
-		if (len > 1) {
-			USETW(((usb_status_t *)buf)->wStatus,UDS_SELF_POWERED);
-			totlen = 2;
-		}
-		break;
-	case C(UR_GET_STATUS, UT_READ_INTERFACE):
-	case C(UR_GET_STATUS, UT_READ_ENDPOINT):
-		if (len > 1) {
-			USETW(((usb_status_t *)buf)->wStatus, 0);
-			totlen = 2;
-		}
-		break;
-	case C(UR_SET_ADDRESS, UT_WRITE_DEVICE):
-		if (value >= USB_MAX_DEVICES) {
-			err = USBD_IOERROR;
-			goto ret;
-		}
-		sc->sc_addr = value;
-		break;
-	case C(UR_SET_CONFIG, UT_WRITE_DEVICE):
-		if (value != 0 && value != 1) {
-			err = USBD_IOERROR;
-			goto ret;
-		}
-		sc->sc_conf = value;
-		break;
-	case C(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE):
-		break;
-	case C(UR_SET_FEATURE, UT_WRITE_DEVICE):
-	case C(UR_SET_FEATURE, UT_WRITE_INTERFACE):
-	case C(UR_SET_FEATURE, UT_WRITE_ENDPOINT):
-		err = USBD_IOERROR;
-		goto ret;
-	case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE):
-		break;
-	case C(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT):
-		break;
+
 	/* Hub requests */
 	case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_DEVICE):
 		break;
 	case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER):
-		DPRINTFN(3, ("uhci_root_ctrl_control: UR_CLEAR_PORT_FEATURE "
-			     "port=%d feature=%d\n",
+		DPRINTFN(3, ("%s: UR_CLEAR_PORT_FEATURE "
+			     "port=%d feature=%d\n", __func__,
 			     index, value));
 		if (index == 1)
 			port = UHCI_PORTSC1;
 		else if (index == 2)
 			port = UHCI_PORTSC2;
 		else {
-			err = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
 		switch(value) {
 		case UHF_PORT_ENABLE:
@@ -3699,16 +3502,14 @@ uhci_root_ctrl_start(usbd_xfer_handle xf
 			break;
 		case UHF_C_PORT_RESET:
 			sc->sc_isreset = 0;
-			err = USBD_NORMAL_COMPLETION;
-			goto ret;
+			return -1;
 		case UHF_PORT_CONNECTION:
 		case UHF_PORT_OVER_CURRENT:
 		case UHF_PORT_POWER:
 		case UHF_PORT_LOW_SPEED:
 		case UHF_C_PORT_SUSPEND:
 		default:
-			err = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
 		break;
 	case C(UR_GET_BUS_STATE, UT_READ_CLASS_OTHER):
@@ -3717,8 +3518,7 @@ uhci_root_ctrl_start(usbd_xfer_handle xf
 		else if (index == 2)
 			port = UHCI_PORTSC2;
 		else {
-			err = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
 		if (len > 0) {
 			*(uint8_t *)buf =
@@ -3731,17 +3531,18 @@ uhci_root_ctrl_start(usbd_xfer_handle xf
 		if (len == 0)
 			break;
 		if ((value & 0xff) != 0) {
-			err = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
-		l = min(len, USB_HUB_DESCRIPTOR_SIZE);
-		totlen = l;
-		memcpy(buf, &uhci_hubd_piix, l);
+		usb_hub_descriptor_t hubd;
+
+		totlen = min(buflen, sizeof(hubd));
+		memcpy(&hubd, buf, totlen);
+		hubd.bNbrPorts = 2;
+		memcpy(buf, &hubd, totlen);
 		break;
 	case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE):
 		if (len != 4) {
-			err = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
 		memset(buf, 0, len);
 		totlen = len;
@@ -3752,12 +3553,10 @@ uhci_root_ctrl_start(usbd_xfer_handle xf
 		else if (index == 2)
 			port = UHCI_PORTSC2;
 		else {
-			err = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
 		if (len != 4) {
-			err = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
 		x = UREAD2(sc, port);
 		status = change = 0;
@@ -3782,13 +3581,11 @@ uhci_root_ctrl_start(usbd_xfer_handle xf
 			change |= UPS_C_PORT_RESET;
 		USETW(ps.wPortStatus, status);
 		USETW(ps.wPortChange, change);
-		l = min(len, sizeof ps);
-		memcpy(buf, &ps, l);
-		totlen = l;
+		totlen = min(len, sizeof(ps));
+		memcpy(buf, &ps, totlen);
 		break;
 	case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE):
-		err = USBD_IOERROR;
-		goto ret;
+		return -1;
 	case C(UR_SET_FEATURE, UT_WRITE_CLASS_DEVICE):
 		break;
 	case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER):
@@ -3797,8 +3594,7 @@ uhci_root_ctrl_start(usbd_xfer_handle xf
 		else if (index == 2)
 			port = UHCI_PORTSC2;
 		else {
-			err = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
 		switch(value) {
 		case UHF_PORT_ENABLE:
@@ -3811,11 +3607,12 @@ uhci_root_ctrl_start(usbd_xfer_handle xf
 			break;
 		case UHF_PORT_RESET:
 			err = uhci_portreset(sc, index);
-			goto ret;
+			if (err != USBD_NORMAL_COMPLETION)
+				return -1;
+			return 0;
 		case UHF_PORT_POWER:
 			/* Pretend we turned on power */
-			err = USBD_NORMAL_COMPLETION;
-			goto ret;
+			return 0;
 		case UHF_C_PORT_CONNECTION:
 		case UHF_C_PORT_ENABLE:
 		case UHF_C_PORT_OVER_CURRENT:
@@ -3825,36 +3622,15 @@ uhci_root_ctrl_start(usbd_xfer_handle xf
 		case UHF_C_PORT_SUSPEND:
 		case UHF_C_PORT_RESET:
 		default:
-			err = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
 		break;
 	default:
-		err = USBD_IOERROR;
-		goto ret;
+		/* default from usbroothub */
+		return buflen;
 	}
-	xfer->ux_actlen = totlen;
-	err = USBD_NORMAL_COMPLETION;
- ret:
-	xfer->ux_status = err;
-	mutex_enter(&sc->sc_lock);
-	usb_transfer_complete(xfer);
-	mutex_exit(&sc->sc_lock);
-	return (USBD_IN_PROGRESS);
-}
 
-/* Abort a root control request. */
-void
-uhci_root_ctrl_abort(usbd_xfer_handle xfer)
-{
-	/* Nothing to do, all transfers are synchronous. */
-}
-
-/* Close the root pipe. */
-void
-uhci_root_ctrl_close(usbd_pipe_handle pipe)
-{
-	DPRINTF(("uhci_root_ctrl_close\n"));
+	return totlen;
 }
 
 /* Abort a root interrupt request. */

Index: src/sys/dev/usb/uhcivar.h
diff -u src/sys/dev/usb/uhcivar.h:1.52.14.2 src/sys/dev/usb/uhcivar.h:1.52.14.3
--- src/sys/dev/usb/uhcivar.h:1.52.14.2	Tue Dec  2 09:00:34 2014
+++ src/sys/dev/usb/uhcivar.h	Thu Dec  4 08:04:31 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: uhcivar.h,v 1.52.14.2 2014/12/02 09:00:34 skrll Exp $	*/
+/*	$NetBSD: uhcivar.h,v 1.52.14.3 2014/12/04 08:04:31 skrll Exp $	*/
 
 /*
  * Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -159,9 +159,6 @@ typedef struct uhci_softc {
 
 	pool_cache_t sc_xferpool;	/* free xfer pool */
 
-	uint8_t sc_addr;		/* device address */
-	uint8_t sc_conf;		/* device configuration */
-
 	uint8_t sc_saved_sof;
 	uint16_t sc_saved_frnum;
 

Index: src/sys/dev/usb/usbdivar.h
diff -u src/sys/dev/usb/usbdivar.h:1.109.2.6 src/sys/dev/usb/usbdivar.h:1.109.2.7
--- src/sys/dev/usb/usbdivar.h:1.109.2.6	Wed Dec  3 22:19:50 2014
+++ src/sys/dev/usb/usbdivar.h	Thu Dec  4 08:04:31 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: usbdivar.h,v 1.109.2.6 2014/12/03 22:19:50 skrll Exp $	*/
+/*	$NetBSD: usbdivar.h,v 1.109.2.7 2014/12/04 08:04:31 skrll Exp $	*/
 
 /*
  * Copyright (c) 1998, 2012 The NetBSD Foundation, Inc.
@@ -98,6 +98,9 @@ struct usbd_bus_methods {
 	void		      (*ubm_getlock)(struct usbd_bus *, kmutex_t **);
 	usbd_status	      (*ubm_newdev)(device_t, usbd_bus_handle, int,
 					    int, int, struct usbd_port *);
+
+	int			(*ubm_rhctrl)(struct usbd_bus *,
+				    usb_device_request_t *, void *, int);
 };
 
 struct usbd_pipe_methods {
@@ -159,6 +162,8 @@ struct usbd_bus {
 	/* Filled by usb driver */
 	kmutex_t		*ub_lock;
 	struct usbd_device      *ub_roothub;
+	uint8_t			ub_rhaddr;	/* roothub address */
+	uint8_t			ub_rhconf;	/* roothub configuration */
 	usbd_device_handle	ub_devices[USB_MAX_DEVICES];
 	kcondvar_t              ub_needsexplore_cv;
 	char			ub_needsexplore;/* a hub a signalled a change */

Index: src/sys/dev/usb/usbroothub.c
diff -u src/sys/dev/usb/usbroothub.c:1.1.2.1 src/sys/dev/usb/usbroothub.c:1.1.2.2
--- src/sys/dev/usb/usbroothub.c:1.1.2.1	Wed Dec  3 23:05:06 2014
+++ src/sys/dev/usb/usbroothub.c	Thu Dec  4 08:04:31 2014
@@ -1,5 +1,36 @@
-/* $NetBSD: usbroothub.c,v 1.1.2.1 2014/12/03 23:05:06 skrll Exp $ */
+/* $NetBSD: usbroothub.c,v 1.1.2.2 2014/12/04 08:04:31 skrll Exp $ */
 
+/*-
+ * Copyright (c) 1998, 2004, 2011, 2012 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Lennart Augustsson ([email protected]) at
+ * Carlstedt Research & Technology, Jared D. McNeill ([email protected]),
+ * Matthew R. Green ([email protected]) and Nick Hudson.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+ 
 /*
  * Copyright (c) 2008
  *	Matthias Drochner.  All rights reserved.
@@ -27,10 +58,42 @@
  */
 
 #include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdivar.h>
 #include <dev/usb/usbroothub.h>
 
+#ifdef USB_DEBUG
+#define	DPRINTFN(n,fmt,...) do {		\
+	if (usbdebug >= (n)) {			\
+		printf("%s: " fmt,		\
+		__FUNCTION__,## __VA_ARGS__);	\
+	}					\
+} while (0)
+#define	DPRINTF(...)	DPRINTFN(1, __VA_ARGS__)
+extern int usbdebug;
+#else
+#define	DPRINTF(...) do { } while (0)
+#define	DPRINTFN(...) do { } while (0)
+#endif
+
 /* helper functions for USB root hub emulation */
 
+static usbd_status	roothub_ctrl_transfer(usbd_xfer_handle);
+static usbd_status	roothub_ctrl_start(usbd_xfer_handle);
+static void		roothub_ctrl_abort(usbd_xfer_handle);
+static void		roothub_ctrl_close(usbd_pipe_handle);
+static void		roothub_ctrl_done(usbd_xfer_handle);
+static void		roothub_noop(usbd_pipe_handle pipe);
+
+const struct usbd_pipe_methods roothub_ctrl_methods = {
+	.upm_transfer =	roothub_ctrl_transfer,
+	.upm_start =	roothub_ctrl_start,
+	.upm_abort =	roothub_ctrl_abort,
+	.upm_close =	roothub_ctrl_close,
+	.upm_cleartoggle =	roothub_noop,
+	.upm_done =	roothub_ctrl_done,
+};
+
 int
 usb_makestrdesc(usb_string_descriptor_t *p, int l, const char *s)
 {
@@ -59,8 +122,378 @@ usb_makelangtbl(usb_string_descriptor_t 
 	if (l == 1)
 		return (1);
 	p->bDescriptorType = UDESC_STRING;
-	if (l <  4)
+	if (l < 4)
 		return (2);
 	USETW(p->bString[0], 0x0409); /* english/US */
 	return (4);
 }
+
+/*
+ * Data structures and routines to emulate the root hub.
+ */
+static const usb_device_descriptor_t usbroothub_devd1 = {
+	.bLength = sizeof(usb_device_descriptor_t),
+	.bDescriptorType = UDESC_DEVICE,
+	.bcdUSB = {0x00, 0x01},
+	.bDeviceClass = UDCLASS_HUB,
+	.bDeviceSubClass = UDSUBCLASS_HUB,
+	.bDeviceProtocol = UDPROTO_FSHUB,
+	.bMaxPacketSize = 64,
+	.idVendor = {0},
+	.idProduct = {0},
+	.bcdDevice = {0x00, 0x01},
+	.iManufacturer = 1,
+	.iProduct = 2,
+	.iSerialNumber = 0,
+	.bNumConfigurations = 1
+};
+
+static const struct usb_roothub_descriptors usbroothub_confd1 = {
+	.urh_confd = {
+		.bLength = USB_CONFIG_DESCRIPTOR_SIZE,
+		.bDescriptorType = UDESC_CONFIG,
+		.wTotalLength = USETWD(sizeof(usbroothub_confd1)),
+		.bNumInterface = 1,
+		.bConfigurationValue = 1,
+		.iConfiguration = 0,
+		.bmAttributes = UC_ATTR_MBO | UC_SELF_POWERED,
+		.bMaxPower = 0,
+	},
+	.urh_ifcd = {
+		.bLength = USB_INTERFACE_DESCRIPTOR_SIZE,
+		.bDescriptorType = UDESC_INTERFACE,
+		.bInterfaceNumber = 0,
+		.bAlternateSetting = 0,
+		.bNumEndpoints = 1,
+		.bInterfaceClass = UICLASS_HUB,
+		.bInterfaceSubClass = UISUBCLASS_HUB,
+		.bInterfaceProtocol = UIPROTO_FSHUB,
+		.iInterface = 0
+	},
+	.urh_endpd = {
+		.bLength = USB_ENDPOINT_DESCRIPTOR_SIZE,
+		.bDescriptorType = UDESC_ENDPOINT,
+		.bEndpointAddress = UE_DIR_IN | USBROOTHUB_INTR_ENDPT,
+		.bmAttributes = UE_INTERRUPT,
+		.wMaxPacketSize = USETWD(8),			/* max packet */
+		.bInterval = 255,
+	},
+};
+
+static const usb_device_descriptor_t usbroothub_devd2 = {
+	.bLength = sizeof(usb_device_descriptor_t),
+	.bDescriptorType = UDESC_DEVICE,
+	.bcdUSB = {0x00, 0x02},
+	.bDeviceClass = UDCLASS_HUB,
+	.bDeviceSubClass = UDSUBCLASS_HUB,
+	.bDeviceProtocol = UDPROTO_HSHUBSTT,
+	.bMaxPacketSize = 64,
+	.idVendor = {0},
+	.idProduct = {0},
+	.bcdDevice = {0x00, 0x01},
+	.iManufacturer = 1,
+	.iProduct = 2,
+	.iSerialNumber = 0,
+	.bNumConfigurations = 1
+};
+
+static const usb_device_qualifier_t usbroothub_odevd2 = {
+	.bLength = USB_DEVICE_QUALIFIER_SIZE,
+	.bDescriptorType = UDESC_DEVICE_QUALIFIER,
+	.bcdUSB = {0x00, 0x02},
+	.bDeviceClass = UDCLASS_HUB,
+	.bDeviceSubClass = UDSUBCLASS_HUB,
+	.bDeviceProtocol = UDPROTO_FSHUB,
+	.bMaxPacketSize0 = 64,
+	.bNumConfigurations = 1,
+};
+
+static const struct usb_roothub_descriptors usbroothub_confd2 = {
+	.urh_confd = {
+		.bLength = USB_CONFIG_DESCRIPTOR_SIZE,
+		.bDescriptorType = UDESC_CONFIG,
+		.wTotalLength = USETWD(sizeof(usbroothub_confd2)),
+		.bNumInterface = 1,
+		.bConfigurationValue = 1,
+		.iConfiguration = 0,
+		.bmAttributes = UC_ATTR_MBO | UC_SELF_POWERED,
+		.bMaxPower = 0,
+	},
+	.urh_ifcd = {
+		.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
+	},
+	.urh_endpd = {
+		.bLength = USB_ENDPOINT_DESCRIPTOR_SIZE,
+		.bDescriptorType = UDESC_ENDPOINT,
+		.bEndpointAddress = UE_DIR_IN | USBROOTHUB_INTR_ENDPT,
+		.bmAttributes = UE_INTERRUPT,
+		.wMaxPacketSize = USETWD(8),			/* max packet */
+		.bInterval = 12,
+	},
+};
+
+static const usb_hub_descriptor_t usbroothub_hubd = {
+	.bDescLength = USB_HUB_DESCRIPTOR_SIZE,
+	.bDescriptorType = UDESC_HUB,
+	.bNbrPorts = 1,
+	.wHubCharacteristics = USETWD(UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL),
+	.bPwrOn2PwrGood = 50,
+	.bHubContrCurrent = 0,
+	.DeviceRemovable = {0},		/* port is removable */
+};
+  
+/*
+ * Simulate a hardware hub by handling all the necessary requests.
+ */
+usbd_status
+roothub_ctrl_transfer(usbd_xfer_handle xfer)
+{
+	usbd_pipe_handle pipe = xfer->ux_pipe;
+	struct usbd_bus *bus = pipe->up_dev->ud_bus;
+	usbd_status err;
+
+	/* Insert last in queue. */
+	mutex_enter(bus->ub_lock);
+	err = usb_insert_transfer(xfer);
+	mutex_exit(bus->ub_lock);
+	if (err)
+		return (err);
+
+	/* Pipe isn't running, start first */
+	return roothub_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
+}
+
+static usbd_status
+roothub_ctrl_start(usbd_xfer_handle xfer)
+{
+	usbd_pipe_handle pipe = xfer->ux_pipe;
+	struct usbd_bus *bus = pipe->up_dev->ud_bus;
+	usb_device_request_t *req;
+	usbd_status err = USBD_IOERROR;		/* XXX STALL? */
+	uint16_t len, value;
+	int buflen, actlen;
+	void *buf;
+
+	KASSERT(xfer->ux_rqflags & URQ_REQUEST);
+	req = &xfer->ux_request;
+
+	DPRINTFN(4, "type=%#2x request=%#2x\n",
+	    req->bmRequestType, req->bRequest);
+
+	len = UGETW(req->wLength);
+	value = UGETW(req->wValue);
+
+	buf = len ? usbd_get_buffer(xfer) : NULL;
+	buflen = 0;
+
+#define C(x,y) ((x) | ((y) << 8))
+	switch (C(req->bRequest, req->bmRequestType)) {
+	case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE):
+	case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE):
+	case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT):
+		/*
+		 * DEVICE_REMOTE_WAKEUP and ENDPOINT_HALT are no-ops
+		 * for the integrated root hub.
+		 */
+		break;
+	case C(UR_GET_CONFIG, UT_READ_DEVICE):
+		if (len > 0) {
+			uint8_t *out = buf;
+
+			*out = bus->ub_rhconf;
+			buflen = sizeof(*out);
+		}
+		break;
+	case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE):
+		DPRINTFN(8, "wValue=%#4x\n", value);
+
+		if (len == 0)
+			break;
+		switch (value) {
+		case C(0, UDESC_DEVICE):
+			if (bus->ub_revision == USBREV_2_0) {
+				buflen = min(len, sizeof(usbroothub_devd2));
+				memcpy(buf, &usbroothub_devd2, buflen);
+			} else {
+				buflen = min(len, sizeof(usbroothub_devd1));
+				memcpy(buf, &usbroothub_devd1, buflen);
+			}
+			break;
+		case C(0, UDESC_CONFIG):
+			if (bus->ub_revision == USBREV_2_0) {
+				buflen = min(len, sizeof(usbroothub_confd2));
+				memcpy(buf, &usbroothub_confd2, buflen);
+			} else {
+				buflen = min(len, sizeof(usbroothub_confd1));
+				memcpy(buf, &usbroothub_confd1, buflen);
+			}
+			break;
+		case C(0, UDESC_DEVICE_QUALIFIER):
+			if (bus->ub_revision == USBREV_2_0) {
+				/*
+				 * We can't really operate at another speed,
+				 * but the spec says we need this descriptor.
+				 */
+				buflen = min(len, sizeof(usbroothub_odevd2));
+				memcpy(buf, &usbroothub_odevd2, buflen);
+			} else
+				goto fail;
+			break;
+		case C(0, UDESC_OTHER_SPEED_CONFIGURATION):
+			if (bus->ub_revision == USBREV_2_0) {
+				struct usb_roothub_descriptors confd;
+
+				/*
+				 * We can't really operate at another speed,
+				 * but the spec says we need this descriptor.
+				 */
+				buflen = min(len, sizeof(usbroothub_confd2));
+				memcpy(&confd, &usbroothub_confd2, buflen);
+				confd.urh_confd.bDescriptorType =
+				    UDESC_OTHER_SPEED_CONFIGURATION;
+				memcpy(buf, &confd, buflen);
+			} else 
+				goto fail;
+			break;
+#define sd ((usb_string_descriptor_t *)buf)
+		case C(0, UDESC_STRING):
+			/* Language table */
+			buflen = usb_makelangtbl(sd, len);
+			break;
+		case C(1, UDESC_STRING):
+			/* Vendor */
+			buflen = usb_makestrdesc(sd, len, "NetBSD");
+			break;
+		case C(2, UDESC_STRING):
+			/* Product */
+			buflen = usb_makestrdesc(sd, len, "Root hub");
+			break;
+#undef sd
+		default:
+			/* Default to error */
+			buflen = -1;
+		}
+		break;
+	case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE):
+		buflen = min(len, sizeof(usbroothub_hubd));
+		memcpy(buf, &usbroothub_hubd, buflen);
+		break;
+	case C(UR_GET_INTERFACE, UT_READ_INTERFACE):
+		/* Get Interface, 9.4.4 */
+		if (len > 0) {
+			uint8_t *out = buf;
+
+			*out = 0;
+			buflen = sizeof(*out);
+		}
+		break;
+	case C(UR_GET_STATUS, UT_READ_DEVICE):
+		/* Get Status from device, 9.4.5 */
+		if (len > 1) {
+			usb_status_t *out = buf;
+
+			USETW(out->wStatus, UDS_SELF_POWERED);
+			buflen = sizeof(*out);
+		}
+		break;
+	case C(UR_GET_STATUS, UT_READ_INTERFACE):
+	case C(UR_GET_STATUS, UT_READ_ENDPOINT):
+		/* Get Status from interface, endpoint, 9.4.5 */
+		if (len > 1) {
+			usb_status_t *out = buf;
+
+			USETW(out->wStatus, 0);
+			buflen = sizeof(*out);
+		}
+		break;
+	case C(UR_SET_ADDRESS, UT_WRITE_DEVICE):
+		/* Set Address, 9.4.6 */
+		DPRINTF("UR_SET_ADDRESS, UT_WRITE_DEVICE: addr %d\n",
+		    value);
+		if (value >= USB_MAX_DEVICES) {
+			goto fail;
+		}
+		bus->ub_rhaddr = value;
+		break;
+	case C(UR_SET_CONFIG, UT_WRITE_DEVICE):
+		/* Set Configuration, 9.4.7 */
+		if (value != 0 && value != 1) {
+			goto fail;
+		}
+		bus->ub_rhconf = value;
+		break;
+	case C(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE):
+		/* Set Descriptor, 9.4.8, not supported */
+		break;
+	case C(UR_SET_FEATURE, UT_WRITE_DEVICE):
+	case C(UR_SET_FEATURE, UT_WRITE_INTERFACE):
+	case C(UR_SET_FEATURE, UT_WRITE_ENDPOINT):
+		/* Set Feature, 9.4.9, not supported */
+		goto fail;
+	case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE):
+		/* Set Interface, 9.4.10, not supported */
+		break;
+	case C(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT):
+		/* Synch Frame, 9.4.11, not supported */
+		break;
+	default:
+		/* Default to error */
+		buflen = -1;
+		break;
+	}
+
+	actlen = bus->ub_methods->ubm_rhctrl(bus, req, buf, buflen);
+	if (actlen < 0)
+		goto fail;
+
+	xfer->ux_actlen = actlen;
+	err = USBD_NORMAL_COMPLETION;
+
+ fail:
+	xfer->ux_status = err;
+	mutex_enter(bus->ub_lock);
+	usb_transfer_complete(xfer);
+	mutex_exit(bus->ub_lock);
+
+	return USBD_IN_PROGRESS;
+}
+
+/* Abort a root control request. */
+Static void
+roothub_ctrl_abort(usbd_xfer_handle xfer)
+{
+
+	DPRINTF("\n");
+	/* Nothing to do, all transfers are synchronous. */
+}
+
+/* Close the root pipe. */
+Static void
+roothub_ctrl_close(usbd_pipe_handle pipe)
+{
+
+	DPRINTF("\n");
+	/* Nothing to do. */
+}
+
+Static void
+roothub_ctrl_done(usbd_xfer_handle xfer)
+{
+
+	DPRINTF("\n");
+	/* Nothing to do. */
+}
+
+static void
+roothub_noop(usbd_pipe_handle pipe)
+{
+
+}
Index: src/sys/dev/usb/usbroothub.h
diff -u src/sys/dev/usb/usbroothub.h:1.1.2.1 src/sys/dev/usb/usbroothub.h:1.1.2.2
--- src/sys/dev/usb/usbroothub.h:1.1.2.1	Wed Dec  3 23:05:06 2014
+++ src/sys/dev/usb/usbroothub.h	Thu Dec  4 08:04:31 2014
@@ -1,4 +1,43 @@
-/* $NetBSD: usbroothub.h,v 1.1.2.1 2014/12/03 23:05:06 skrll Exp $ */
+/* $NetBSD: usbroothub.h,v 1.1.2.2 2014/12/04 08:04:31 skrll Exp $ */
+
+/*-
+ * Copyright (c) 2014 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Nick Hudson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
 
 int usb_makestrdesc(usb_string_descriptor_t *, int, const char *);
 int usb_makelangtbl(usb_string_descriptor_t *, int);
+
+struct usb_roothub_descriptors {
+	usb_config_descriptor_t urh_confd;
+	usb_interface_descriptor_t urh_ifcd;
+	usb_endpoint_descriptor_t urh_endpd;
+};
+
+#define	USBROOTHUB_INTR_ENDPT	1
+
+extern const struct usbd_pipe_methods roothub_ctrl_methods;

Index: src/sys/dev/usb/xhci.c
diff -u src/sys/dev/usb/xhci.c:1.28.2.11 src/sys/dev/usb/xhci.c:1.28.2.12
--- src/sys/dev/usb/xhci.c:1.28.2.11	Wed Dec  3 23:05:06 2014
+++ src/sys/dev/usb/xhci.c	Thu Dec  4 08:04:31 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: xhci.c,v 1.28.2.11 2014/12/03 23:05:06 skrll Exp $	*/
+/*	$NetBSD: xhci.c,v 1.28.2.12 2014/12/04 08:04:31 skrll Exp $	*/
 
 /*
  * Copyright (c) 2013 Jonathan A. Kollasch
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.28.2.11 2014/12/03 23:05:06 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.28.2.12 2014/12/04 08:04:31 skrll Exp $");
 
 #include "opt_usb.h"
 
@@ -108,7 +108,6 @@ struct xhci_pipe {
 	struct usbd_pipe xp_pipe;
 };
 
-#define XHCI_INTR_ENDPT 1
 #define XHCI_COMMAND_RING_TRBS 256
 #define XHCI_EVENT_RING_TRBS 256
 #define XHCI_EVENT_RING_SEGMENTS 1
@@ -123,6 +122,8 @@ static void xhci_freex(struct usbd_bus *
 static void xhci_get_lock(struct usbd_bus *, kmutex_t **);
 static usbd_status xhci_new_device(device_t, usbd_bus_handle, int, int, int,
     struct usbd_port *);
+static int xhci_roothub_ctrl(struct usbd_bus *, usb_device_request_t *,
+    void *, int);
 
 static usbd_status xhci_configure_endpoint(usbd_pipe_handle);
 static usbd_status xhci_unconfigure_endpoint(usbd_pipe_handle);
@@ -147,12 +148,6 @@ static void xhci_ring_free(struct xhci_s
 
 static void xhci_noop(usbd_pipe_handle);
 
-static usbd_status xhci_root_ctrl_transfer(usbd_xfer_handle);
-static usbd_status xhci_root_ctrl_start(usbd_xfer_handle);
-static void xhci_root_ctrl_abort(usbd_xfer_handle);
-static void xhci_root_ctrl_close(usbd_pipe_handle);
-static void xhci_root_ctrl_done(usbd_xfer_handle);
-
 static usbd_status xhci_root_intr_transfer(usbd_xfer_handle);
 static usbd_status xhci_root_intr_start(usbd_xfer_handle);
 static void xhci_root_intr_abort(usbd_xfer_handle);
@@ -188,15 +183,7 @@ static const struct usbd_bus_methods xhc
 	.ubm_freex = xhci_freex,
 	.ubm_getlock = xhci_get_lock,
 	.ubm_newdev = xhci_new_device,
-};
-
-static const struct usbd_pipe_methods xhci_root_ctrl_methods = {
-	.upm_transfer = xhci_root_ctrl_transfer,
-	.upm_start = xhci_root_ctrl_start,
-	.upm_abort = xhci_root_ctrl_abort,
-	.upm_close = xhci_root_ctrl_close,
-	.upm_cleartoggle = xhci_noop,
-	.upm_done = xhci_root_ctrl_done,
+	.ubm_rhctrl = xhci_roothub_ctrl,
 };
 
 static const struct usbd_pipe_methods xhci_root_intr_methods = {
@@ -1138,9 +1125,9 @@ xhci_open(usbd_pipe_handle pipe)
 	    dev->ud_speed != USB_SPEED_SUPER) {
 		switch (ed->bEndpointAddress) {
 		case USB_CONTROL_ENDPOINT:
-			pipe->up_methods = &xhci_root_ctrl_methods;
+			pipe->up_methods = &roothub_ctrl_methods;
 			break;
-		case UE_DIR_IN | XHCI_INTR_ENDPT:
+		case UE_DIR_IN | USBROOTHUB_INTR_ENDPT:
 			pipe->up_methods = &xhci_root_intr_methods;
 			break;
 		default:
@@ -1997,255 +1984,47 @@ xhci_noop(usbd_pipe_handle pipe)
 	XHCIHIST_FUNC(); XHCIHIST_CALLED();
 }
 
-/* root hub descriptors */
-
-static const usb_device_descriptor_t xhci_devd = {
-	.bLength = USB_DEVICE_DESCRIPTOR_SIZE,
-	.bDescriptorType = UDESC_DEVICE,
-	.bcdUSB = {0x00, 0x02},
-	.bDeviceClass = UDCLASS_HUB,
-	.bDeviceSubClass = UDSUBCLASS_HUB,
-	.bDeviceProtocol = UDPROTO_HSHUBSTT,
-	.bMaxPacketSize = 64,
-	.idVendor = {0},
-	.idProduct = {0},
-	.bcdDevice = {0x00,0x01},
-	.iManufacturer = 1,
-	.iProduct = 2,
-	.iSerialNumber = 0,
-	.bNumConfigurations = 1
-};
-
-static const usb_device_qualifier_t xhci_odevd = {
-	.bLength = USB_DEVICE_DESCRIPTOR_SIZE,
-	.bDescriptorType = UDESC_DEVICE_QUALIFIER,
-	.bcdUSB = {0x00, 0x02},
-	.bDeviceClass = UDCLASS_HUB,
-	.bDeviceSubClass = UDSUBCLASS_HUB,
-	.bDeviceProtocol = UDPROTO_FSHUB,
-	.bMaxPacketSize0 = 64,
-	.bNumConfigurations = 1,
-};
-
-static const usb_config_descriptor_t xhci_confd = {
-	.bLength = USB_CONFIG_DESCRIPTOR_SIZE,
-	.bDescriptorType = UDESC_CONFIG,
-	.wTotalLength = USETWD(
-	    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
-};
-
-static const usb_interface_descriptor_t xhci_ifcd = {
-	.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 = {
-	.bLength = USB_ENDPOINT_DESCRIPTOR_SIZE,
-	.bDescriptorType = UDESC_ENDPOINT,
-	.bEndpointAddress = UE_DIR_IN | XHCI_INTR_ENDPT,
-	.bmAttributes = UE_INTERRUPT,
-	.wMaxPacketSize = USETWD(8),
-	.bInterval = 12
-};
-
-static const usb_hub_descriptor_t xhci_hubd = {
-	.bDescLength = USB_HUB_DESCRIPTOR_SIZE,
-	.bDescriptorType = UDESC_HUB,
-	.bNbrPorts = 0,
-	.wHubCharacteristics = USETWD(0),
-	.bPwrOn2PwrGood = 0,
-	.bHubContrCurrent = 0,
-	.DeviceRemovable = {""},
-	.PortPowerCtrlMask = {""},
-};
-
-/* root hub control */
-
-static usbd_status
-xhci_root_ctrl_transfer(usbd_xfer_handle xfer)
+static int xhci_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req,
+    void *buf, int buflen)
 {
-	struct xhci_softc * const sc = xfer->ux_pipe->up_dev->ud_bus->ub_hcpriv;
-	usbd_status err;
-
-	XHCIHIST_FUNC(); XHCIHIST_CALLED();
-
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
-
-	/* Pipe isn't running, start first */
-	return (xhci_root_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue)));
-}
-
-static usbd_status
-xhci_root_ctrl_start(usbd_xfer_handle xfer)
-{
-	struct xhci_softc * const sc = xfer->ux_pipe->up_dev->ud_bus->ub_hcpriv;
+	struct xhci_softc * const sc = bus->ub_hcpriv;
 	usb_port_status_t ps;
-	usb_device_request_t *req;
-	void *buf = NULL;
-	usb_hub_descriptor_t hubd;
-	usbd_status err;
-	int len, value, index;
 	int l, totlen = 0;
+	uint16_t len, value, index;
 	int port, i;
 	uint32_t v;
 
 	XHCIHIST_FUNC(); XHCIHIST_CALLED();
 
 	if (sc->sc_dying)
-		return USBD_IOERROR;
-
-	req = &xfer->ux_request;
+		return -1;
 
+	len = UGETW(req->wLength);
 	value = UGETW(req->wValue);
 	index = UGETW(req->wIndex);
-	len = UGETW(req->wLength);
-
-	if (len != 0)
-		buf = xfer->ux_buf;
 
 	DPRINTFN(12, "rhreq: %04x %04x %04x %04x",
 	    req->bmRequestType | (req->bRequest << 8), value, index, len);
 
 #define C(x,y) ((x) | ((y) << 8))
-	switch(C(req->bRequest, req->bmRequestType)) {
-	case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE):
-	case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE):
-	case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT):
-		/*
-		 * DEVICE_REMOTE_WAKEUP and ENDPOINT_HALT are no-ops
-		 * for the integrated root hub.
-		 */
-		break;
-	case C(UR_GET_CONFIG, UT_READ_DEVICE):
-		if (len > 0) {
-			*(uint8_t *)buf = sc->sc_conf;
-			totlen = 1;
-		}
-		break;
+	switch (C(req->bRequest, req->bmRequestType)) {
 	case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE):
 		DPRINTFN(8, "getdesc: wValue=0x%04x", value, 0, 0, 0);
 		if (len == 0)
 			break;
-		switch(value >> 8) {
-		case UDESC_DEVICE:
-			if ((value & 0xff) != 0) {
-				err = USBD_IOERROR;
-				goto ret;
-			}
-			totlen = l = min(len, USB_DEVICE_DESCRIPTOR_SIZE);
-			memcpy(buf, &xhci_devd, min(l, sizeof(xhci_devd)));
-			break;
-		case UDESC_DEVICE_QUALIFIER:
-			if ((value & 0xff) != 0) {
-			}
-			totlen = l = min(len, USB_DEVICE_DESCRIPTOR_SIZE);
-			memcpy(buf, &xhci_odevd, min(l, sizeof(xhci_odevd)));
-			break;
-		case UDESC_OTHER_SPEED_CONFIGURATION:
-		case UDESC_CONFIG:
-			if ((value & 0xff) != 0) {
-				err = USBD_IOERROR;
-				goto ret;
-			}
-			totlen = l = min(len, USB_CONFIG_DESCRIPTOR_SIZE);
-			memcpy(buf, &xhci_confd, min(l, sizeof(xhci_confd)));
-			((usb_config_descriptor_t *)buf)->bDescriptorType =
-			    value >> 8;
-			buf = (char *)buf + l;
-			len -= l;
-			l = min(len, USB_INTERFACE_DESCRIPTOR_SIZE);
-			totlen += l;
-			memcpy(buf, &xhci_ifcd, min(l, sizeof(xhci_ifcd)));
-			buf = (char *)buf + l;
-			len -= l;
-			l = min(len, USB_ENDPOINT_DESCRIPTOR_SIZE);
-			totlen += l;
-			memcpy(buf, &xhci_endpd, min(l, sizeof(xhci_endpd)));
-			break;
-		case UDESC_STRING:
+		switch (value) {
 #define sd ((usb_string_descriptor_t *)buf)
-			switch (value & 0xff) {
-			case 0: /* Language table */
-				totlen = usb_makelangtbl(sd, len);
-				break;
-			case 1: /* Vendor */
-				totlen = usb_makestrdesc(sd, len, "NetBSD");
-				break;
-			case 2: /* Product */
-				totlen = usb_makestrdesc(sd, len,
-				    "xHCI Root Hub");
-				break;
-			}
-#undef sd
+		case C(2, UDESC_STRING):
+			/* Product */
+			totlen = usb_makestrdesc(sd, len, "xHCI Root Hub");
 			break;
+#undef sd
 		default:
-			err = USBD_IOERROR;
-			goto ret;
-		}
-		break;
-	case C(UR_GET_INTERFACE, UT_READ_INTERFACE):
-		if (len > 0) {
-			*(uint8_t *)buf = 0;
-			totlen = 1;
-		}
-		break;
-	case C(UR_GET_STATUS, UT_READ_DEVICE):
-		if (len > 1) {
-			USETW(((usb_status_t *)buf)->wStatus,UDS_SELF_POWERED);
-			totlen = 2;
-		}
-		break;
-	case C(UR_GET_STATUS, UT_READ_INTERFACE):
-	case C(UR_GET_STATUS, UT_READ_ENDPOINT):
-		if (len > 1) {
-			USETW(((usb_status_t *)buf)->wStatus, 0);
-			totlen = 2;
-		}
-		break;
-	case C(UR_SET_ADDRESS, UT_WRITE_DEVICE):
-		if (value >= USB_MAX_DEVICES) {
-			err = USBD_IOERROR;
-			goto ret;
-		}
-		//sc->sc_addr = value;
-		break;
-	case C(UR_SET_CONFIG, UT_WRITE_DEVICE):
-		if (value != 0 && value != 1) {
-			err = USBD_IOERROR;
-			goto ret;
+			/* default from usbroothub */
+			return buflen;
 		}
-		sc->sc_conf = value;
-		break;
-	case C(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE):
-		break;
-	case C(UR_SET_FEATURE, UT_WRITE_DEVICE):
-	case C(UR_SET_FEATURE, UT_WRITE_INTERFACE):
-	case C(UR_SET_FEATURE, UT_WRITE_ENDPOINT):
-		err = USBD_IOERROR;
-		goto ret;
-	case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE):
-		break;
-	case C(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT):
 		break;
+
 	/* Hub requests */
 	case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_DEVICE):
 		break;
@@ -2253,8 +2032,7 @@ xhci_root_ctrl_start(usbd_xfer_handle xf
 		DPRINTFN(4, "UR_CLEAR_PORT_FEATURE port=%d feature=%d",
 			     index, value, 0, 0);
 		if (index < 1 || index > sc->sc_hs_port_count) {
-			err = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
 		port = XHCI_PORTSC(sc->sc_hs_port_start - 1 + index);
 		v = xhci_op_read_4(sc, port);
@@ -2265,53 +2043,48 @@ xhci_root_ctrl_start(usbd_xfer_handle xf
 			xhci_op_write_4(sc, port, v &~ XHCI_PS_PED);
 			break;
 		case UHF_PORT_SUSPEND:
-			err = USBD_IOERROR;
-			goto ret;
+			return -1;
 		case UHF_PORT_POWER:
 			break;
 		case UHF_PORT_TEST:
 		case UHF_PORT_INDICATOR:
-			err = USBD_IOERROR;
-			goto ret;
+			return -1;
 		case UHF_C_PORT_CONNECTION:
 			xhci_op_write_4(sc, port, v | XHCI_PS_CSC);
 			break;
 		case UHF_C_PORT_ENABLE:
 		case UHF_C_PORT_SUSPEND:
 		case UHF_C_PORT_OVER_CURRENT:
-			err = USBD_IOERROR;
-			goto ret;
+			return -1;
 		case UHF_C_PORT_RESET:
 			xhci_op_write_4(sc, port, v | XHCI_PS_PRC);
 			break;
 		default:
-			err = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
-
 		break;
 	case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE):
 		if (len == 0)
 			break;
 		if ((value & 0xff) != 0) {
-			err = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
-		hubd = xhci_hubd;
+		usb_hub_descriptor_t hubd;
+
+		totlen = min(buflen, sizeof(hubd));
+		memcpy(&hubd, buf, totlen);
 		hubd.bNbrPorts = sc->sc_hs_port_count;
 		USETW(hubd.wHubCharacteristics, UHD_PWR_NO_SWITCH);
 		hubd.bPwrOn2PwrGood = 200;
 		for (i = 0, l = sc->sc_maxports; l > 0; i++, l -= 8)
 			hubd.DeviceRemovable[i++] = 0; /* XXX can't find out? */
 		hubd.bDescLength = USB_HUB_DESCRIPTOR_SIZE + i;
-		l = min(len, hubd.bDescLength);
-		totlen = l;
-		memcpy(buf, &hubd, l);
+		totlen = min(totlen, hubd.bDescLength);
+		memcpy(buf, &hubd, totlen);
 		break;
 	case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE):
 		if (len != 4) {
-			err = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
 		memset(buf, 0, len); /* ? XXX */
 		totlen = len;
@@ -2319,12 +2092,10 @@ xhci_root_ctrl_start(usbd_xfer_handle xf
 	case C(UR_GET_STATUS, UT_READ_CLASS_OTHER):
 		DPRINTFN(8, "get port status i=%d", index, 0, 0, 0);
 		if (index < 1 || index > sc->sc_maxports) {
-			err = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
 		if (len != 4) {
-			err = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
 		v = xhci_op_read_4(sc, XHCI_PORTSC(sc->sc_hs_port_start - 1 +
 		    index));
@@ -2357,19 +2128,16 @@ xhci_root_ctrl_start(usbd_xfer_handle xf
 		if (v & XHCI_PS_OCC)    i |= UPS_C_OVERCURRENT_INDICATOR;
 		if (v & XHCI_PS_PRC)	i |= UPS_C_PORT_RESET;
 		USETW(ps.wPortChange, i);
-		l = min(len, sizeof ps);
-		memcpy(buf, &ps, l);
-		totlen = l;
+		totlen = min(len, sizeof(ps));
+		memcpy(buf, &ps, totlen);
 		break;
 	case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE):
-		err = USBD_IOERROR;
-		goto ret;
+		return -1;
 	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) {
-			err = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
 		port = XHCI_PORTSC(sc->sc_hs_port_start - 1 + index);
 		v = xhci_op_read_4(sc, port);
@@ -2388,8 +2156,7 @@ xhci_root_ctrl_start(usbd_xfer_handle xf
 			/* Wait for reset to complete. */
 			usb_delay_ms(&sc->sc_bus, USB_PORT_ROOT_RESET_DELAY);
 			if (sc->sc_dying) {
-				err = USBD_IOERROR;
-				goto ret;
+				return -1;
 			}
 			v = xhci_op_read_4(sc, port);
 			if (v & XHCI_PS_PR) {
@@ -2406,8 +2173,7 @@ xhci_root_ctrl_start(usbd_xfer_handle xf
 			xhci_op_write_4(sc, port, v | XHCI_PS_PRC);
 			break;
 		default:
-			err = USBD_IOERROR;
-			goto ret;
+			return -1;
 		}
 		break;
 	case C(UR_CLEAR_TT_BUFFER, UT_WRITE_CLASS_OTHER):
@@ -2416,44 +2182,14 @@ xhci_root_ctrl_start(usbd_xfer_handle xf
 	case C(UR_STOP_TT, UT_WRITE_CLASS_OTHER):
 		break;
 	default:
-		err = USBD_IOERROR;
-		goto ret;
+		/* default from usbroothub */
+		return buflen;
 	}
-	xfer->ux_actlen = totlen;
-	err = USBD_NORMAL_COMPLETION;
-ret:
-	xfer->ux_status = err;
-	mutex_enter(&sc->sc_lock);
-	usb_transfer_complete(xfer);
-	mutex_exit(&sc->sc_lock);
-	return USBD_IN_PROGRESS;
-}
-
-
-static void
-xhci_root_ctrl_abort(usbd_xfer_handle xfer)
-{
-	XHCIHIST_FUNC(); XHCIHIST_CALLED();
-	/* Nothing to do, all transfers are synchronous. */
-}
-
-
-static void
-xhci_root_ctrl_close(usbd_pipe_handle pipe)
-{
-	XHCIHIST_FUNC(); XHCIHIST_CALLED();
-	/* Nothing to do. */
-}
 
-static void
-xhci_root_ctrl_done(usbd_xfer_handle xfer)
-{
-	XHCIHIST_FUNC(); XHCIHIST_CALLED();
-
-	xfer->ux_hcpriv = NULL;
+	return totlen;
 }
 
-/* root hub interrupt */
+/* root hub intrerrupt */
 
 static usbd_status
 xhci_root_intr_transfer(usbd_xfer_handle xfer)

Index: src/sys/dev/usb/xhcivar.h
diff -u src/sys/dev/usb/xhcivar.h:1.4.12.1 src/sys/dev/usb/xhcivar.h:1.4.12.2
--- src/sys/dev/usb/xhcivar.h:1.4.12.1	Thu Dec  4 06:57:29 2014
+++ src/sys/dev/usb/xhcivar.h	Thu Dec  4 08:04:32 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: xhcivar.h,v 1.4.12.1 2014/12/04 06:57:29 skrll Exp $	*/
+/*	$NetBSD: xhcivar.h,v 1.4.12.2 2014/12/04 08:04:32 skrll Exp $	*/
 
 /*
  * Copyright (c) 2013 Jonathan A. Kollasch
@@ -109,9 +109,6 @@ struct xhci_softc {
 
 	bool sc_ac64;
 	bool sc_dying;
-
-	uint8_t sc_addr;
-	uint8_t sc_conf;
 };
 
 int	xhci_init(struct xhci_softc *);

Index: src/sys/external/bsd/dwc2/dwc2.c
diff -u src/sys/external/bsd/dwc2/dwc2.c:1.32.2.8 src/sys/external/bsd/dwc2/dwc2.c:1.32.2.9
--- src/sys/external/bsd/dwc2/dwc2.c:1.32.2.8	Wed Dec  3 23:05:06 2014
+++ src/sys/external/bsd/dwc2/dwc2.c	Thu Dec  4 08:04:32 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: dwc2.c,v 1.32.2.8 2014/12/03 23:05:06 skrll Exp $	*/
+/*	$NetBSD: dwc2.c,v 1.32.2.9 2014/12/04 08:04:32 skrll Exp $	*/
 
 /*-
  * Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: dwc2.c,v 1.32.2.8 2014/12/03 23:05:06 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: dwc2.c,v 1.32.2.9 2014/12/04 08:04:32 skrll Exp $");
 
 #include "opt_usb.h"
 
@@ -50,7 +50,6 @@ __KERNEL_RCSID(0, "$NetBSD: dwc2.c,v 1.3
 #include <dev/usb/usbdi.h>
 #include <dev/usb/usbdivar.h>
 #include <dev/usb/usb_mem.h>
-
 #include <dev/usb/usbroothub.h>
 
 #include <dwc2/dwc2.h>
@@ -88,12 +87,8 @@ Static void		dwc2_waitintr(struct dwc2_s
 Static usbd_xfer_handle	dwc2_allocx(struct usbd_bus *);
 Static void		dwc2_freex(struct usbd_bus *, usbd_xfer_handle);
 Static void		dwc2_get_lock(struct usbd_bus *, kmutex_t **);
-
-Static usbd_status	dwc2_root_ctrl_transfer(usbd_xfer_handle);
-Static usbd_status	dwc2_root_ctrl_start(usbd_xfer_handle);
-Static void		dwc2_root_ctrl_abort(usbd_xfer_handle);
-Static void		dwc2_root_ctrl_close(usbd_pipe_handle);
-Static void		dwc2_root_ctrl_done(usbd_xfer_handle);
+Static int		dwc2_roothub_ctrl(struct usbd_bus *, usb_device_request_t *,
+    void *, int);
 
 Static usbd_status	dwc2_root_intr_transfer(usbd_xfer_handle);
 Static usbd_status	dwc2_root_intr_start(usbd_xfer_handle);
@@ -153,8 +148,6 @@ dwc2_free_bus_bandwidth(struct dwc2_hsot
 {
 }
 
-#define DWC2_INTR_ENDPT 1
-
 Static const struct usbd_bus_methods dwc2_bus_methods = {
 	.ubm_open =	dwc2_open,
 	.ubm_softint =	dwc2_softintr,
@@ -162,15 +155,7 @@ Static const struct usbd_bus_methods dwc
 	.ubm_allocx =	dwc2_allocx,
 	.ubm_freex =	dwc2_freex,
 	.ubm_getlock =	dwc2_get_lock,
-};
-
-Static const struct usbd_pipe_methods dwc2_root_ctrl_methods = {
-	.upm_transfer =	dwc2_root_ctrl_transfer,
-	.upm_start =	dwc2_root_ctrl_start,
-	.upm_abort =	dwc2_root_ctrl_abort,
-	.upm_close =	dwc2_root_ctrl_close,
-	.upm_cleartoggle =	dwc2_noop,
-	.upm_done =	dwc2_root_ctrl_done,
+	.ubm_rhctrl =	dwc2_roothub_ctrl,
 };
 
 Static const struct usbd_pipe_methods dwc2_root_intr_methods = {
@@ -421,12 +406,12 @@ dwc2_open(usbd_pipe_handle pipe)
 		return USBD_IOERROR;
 	}
 
-	if (addr == sc->sc_addr) {
+	if (addr == dev->ud_bus->ub_rhaddr) {
 		switch (ed->bEndpointAddress) {
 		case USB_CONTROL_ENDPOINT:
-			pipe->up_methods = &dwc2_root_ctrl_methods;
+			pipe->up_methods = &roothub_ctrl_methods;
 			break;
-		case UE_DIR_IN | DWC2_INTR_ENDPT:
+		case UE_DIR_IN | USBROOTHUB_INTR_ENDPT:
 			pipe->up_methods = &dwc2_root_intr_methods;
 			break;
 		default:
@@ -577,104 +562,17 @@ dwc2_device_clear_toggle(usbd_pipe_handl
 
 /***********************************************************************/
 
-/*
- * Data structures and routines to emulate the root hub.
- */
-
-Static const usb_device_descriptor_t dwc2_devd = {
-	.bLength = sizeof(usb_device_descriptor_t),
-	.bDescriptorType = UDESC_DEVICE,
-	.bcdUSB = {0x00, 0x02},
-	.bDeviceClass = UDCLASS_HUB,
-	.bDeviceSubClass = UDSUBCLASS_HUB,
-	.bDeviceProtocol = UDPROTO_HSHUBSTT,
-	.bMaxPacketSize = 64,
-	.bcdDevice = {0x00, 0x01},
-	.iManufacturer = 1,
-	.iProduct = 2,
-	.bNumConfigurations = 1,
-};
-
-struct dwc2_config_desc {
-	usb_config_descriptor_t confd;
-	usb_interface_descriptor_t ifcd;
-	usb_endpoint_descriptor_t endpd;
-} __packed;
-
-Static const struct dwc2_config_desc dwc2_confd = {
-	.confd = {
-		.bLength = USB_CONFIG_DESCRIPTOR_SIZE,
-		.bDescriptorType = UDESC_CONFIG,
-		.wTotalLength = USETWD(sizeof(dwc2_confd)),
-		.bNumInterface = 1,
-		.bConfigurationValue = 1,
-		.iConfiguration = 0,
-		.bmAttributes = UC_SELF_POWERED,
-		.bMaxPower = 0,
-	},
-	.ifcd = {
-		.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
-	},
-	.endpd = {
-		.bLength = USB_ENDPOINT_DESCRIPTOR_SIZE,
-		.bDescriptorType = UDESC_ENDPOINT,
-		.bEndpointAddress = UE_DIR_IN | DWC2_INTR_ENDPT,
-		.bmAttributes = UE_INTERRUPT,
-		.wMaxPacketSize = USETWD(8),			/* max packet */
-		.bInterval = 255,
-	},
-};
-
-#if 0
-/* appears to be unused */
-Static const usb_hub_descriptor_t dwc2_hubd = {
-	.bDescLength = USB_HUB_DESCRIPTOR_SIZE,
-	.bDescriptorType = UDESC_HUB,
-	.bNbrPorts = 1,
-	.wHubCharacteristics = USETWD(UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL),
-	.bPwrOn2PwrGood = 50,
-	.bHubContrCurrent = 0,
-	.DeviceRemovable = {0},		/* port is removable */
-};
-#endif
-
-Static usbd_status
-dwc2_root_ctrl_transfer(usbd_xfer_handle xfer)
+Static int
+dwc2_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req,
+    void *buf, int buflen)
 {
-	struct dwc2_softc *sc = DWC2_XFER2SC(xfer);
-	usbd_status err;
-
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
-
-	return dwc2_root_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
-}
-
-Static usbd_status
-dwc2_root_ctrl_start(usbd_xfer_handle xfer)
-{
-	struct dwc2_softc *sc = DWC2_XFER2SC(xfer);
-	usb_device_request_t *req;
-	uint8_t *buf;
-	uint16_t len;
-	int value, index, l, totlen;
+	struct dwc2_softc *sc = bus->ub_hcpriv;
 	usbd_status err = USBD_IOERROR;
+	uint16_t len, value, index;
+	int totlen = 0;
 
 	if (sc->sc_dying)
-		return USBD_IOERROR;
-
-	req = &xfer->ux_request;
+		return -1;
 
 	DPRINTFN(4, "type=0x%02x request=%02x\n",
 	    req->bmRequestType, req->bRequest);
@@ -683,153 +581,41 @@ dwc2_root_ctrl_start(usbd_xfer_handle xf
 	value = UGETW(req->wValue);
 	index = UGETW(req->wIndex);
 
-	buf = len ? KERNADDR(&xfer->ux_dmabuf, 0) : NULL;
-
-	totlen = 0;
-
 #define C(x,y) ((x) | ((y) << 8))
 	switch (C(req->bRequest, req->bmRequestType)) {
-	case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE):
-	case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE):
-	case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT):
-		/*
-		 * DEVICE_REMOTE_WAKEUP and ENDPOINT_HALT are no-ops
-		 * for the integrated root hub.
-		 */
-		break;
-	case C(UR_GET_CONFIG, UT_READ_DEVICE):
-		if (len > 0) {
-			*buf = sc->sc_conf;
-			totlen = 1;
-		}
-		break;
 	case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE):
 		DPRINTFN(8, "wValue=0x%04x\n", value);
 
 		if (len == 0)
 			break;
 		switch (value) {
-		case C(0, UDESC_DEVICE):
-			l = min(len, USB_DEVICE_DESCRIPTOR_SIZE);
-// 			USETW(dwc2_devd.idVendor, sc->sc_id_vendor);
-			memcpy(buf, &dwc2_devd, l);
-			buf += l;
-			len -= l;
-			totlen += l;
-
-			break;
-		case C(0, UDESC_CONFIG):
-			l = min(len, sizeof(dwc2_confd));
-			memcpy(buf, &dwc2_confd, l);
-			buf += l;
-			len -= l;
-			totlen += l;
-
-			break;
 #define sd ((usb_string_descriptor_t *)buf)
-		case C(0, UDESC_STRING):
-			totlen = usb_makelangtbl(sd, len);
-			break;
 		case C(1, UDESC_STRING):
-			totlen = usb_makestrdesc(sd, len, sc->sc_vendor);
+			/* Vendor */
+			//totlen = usb_makestrdesc(sd, len, sc->sc_vendor);
 			break;
 		case C(2, UDESC_STRING):
+			/* Product */
 			totlen = usb_makestrdesc(sd, len, "DWC2 root hub");
 			break;
 #undef sd
 		default:
-			goto fail;
-		}
-		break;
-	case C(UR_GET_INTERFACE, UT_READ_INTERFACE):
-		if (len > 0) {
-			*buf = 0;
-			totlen = 1;
-		}
-		break;
-	case C(UR_GET_STATUS, UT_READ_DEVICE):
-		if (len > 1) {
-			USETW(((usb_status_t *)buf)->wStatus,UDS_SELF_POWERED);
-			totlen = 2;
+			/* default from usbroothub */
+			return buflen;
 		}
 		break;
-	case C(UR_GET_STATUS, UT_READ_INTERFACE):
-	case C(UR_GET_STATUS, UT_READ_ENDPOINT):
-		if (len > 1) {
-			USETW(((usb_status_t *)buf)->wStatus, 0);
-			totlen = 2;
-		}
-		break;
-	case C(UR_SET_ADDRESS, UT_WRITE_DEVICE):
-		DPRINTF("UR_SET_ADDRESS, UT_WRITE_DEVICE: addr %d\n",
-		    value);
-		if (value >= USB_MAX_DEVICES)
-			goto fail;
-
-		sc->sc_addr = value;
-		break;
-	case C(UR_SET_CONFIG, UT_WRITE_DEVICE):
-		if (value != 0 && value != 1)
-			goto fail;
-
-		sc->sc_conf = value;
-		break;
-	case C(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE):
-		break;
-	case C(UR_SET_FEATURE, UT_WRITE_DEVICE):
-	case C(UR_SET_FEATURE, UT_WRITE_INTERFACE):
-	case C(UR_SET_FEATURE, UT_WRITE_ENDPOINT):
-		err = USBD_IOERROR;
-		goto fail;
-	case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE):
-		break;
-	case C(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT):
-		break;
 	default:
-	    	/* Hub requests - XXXNH len check? */
+		/* Hub requests */
 		err = dwc2_hcd_hub_control(sc->sc_hsotg,
 		    C(req->bRequest, req->bmRequestType), value, index,
 		    buf, len);
 		if (err) {
-			err = USBD_IOERROR;
-			goto fail;
+			return -1;
 		}
 		totlen = len;
 	}
-	xfer->ux_actlen = totlen;
-	err = USBD_NORMAL_COMPLETION;
-
-fail:
-	mutex_enter(&sc->sc_lock);
-	xfer->ux_status = err;
-	usb_transfer_complete(xfer);
-	mutex_exit(&sc->sc_lock);
-
-	return USBD_IN_PROGRESS;
-}
-
-Static void
-dwc2_root_ctrl_abort(usbd_xfer_handle xfer)
-{
-	DPRINTFN(10, "\n");
-
-	/* Nothing to do, all transfers are synchronous. */
-}
-
-Static void
-dwc2_root_ctrl_close(usbd_pipe_handle pipe)
-{
-	DPRINTFN(10, "\n");
-
-	/* Nothing to do. */
-}
-
-Static void
-dwc2_root_ctrl_done(usbd_xfer_handle xfer)
-{
-	DPRINTFN(10, "\n");
 
-	/* Nothing to do. */
+	return totlen;
 }
 
 Static usbd_status

Index: src/sys/external/bsd/dwc2/dwc2var.h
diff -u src/sys/external/bsd/dwc2/dwc2var.h:1.3.12.2 src/sys/external/bsd/dwc2/dwc2var.h:1.3.12.3
--- src/sys/external/bsd/dwc2/dwc2var.h:1.3.12.2	Wed Dec  3 12:52:07 2014
+++ src/sys/external/bsd/dwc2/dwc2var.h	Thu Dec  4 08:04:32 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: dwc2var.h,v 1.3.12.2 2014/12/03 12:52:07 skrll Exp $	*/
+/*	$NetBSD: dwc2var.h,v 1.3.12.3 2014/12/04 08:04:32 skrll Exp $	*/
 
 /*-
  * Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -95,13 +95,8 @@ typedef struct dwc2_softc {
 	device_t sc_child;		/* /dev/usb# device */
 	char sc_dying;
 
-	char sc_vendor[32];		/* vendor string for root hub */
-	int sc_id_vendor;		/* vendor ID for root hub */
-
 	TAILQ_HEAD(, dwc2_xfer) sc_complete;	/* complete transfers */
 
-	uint8_t sc_addr;		/* device address */
-	uint8_t sc_conf;		/* device configuration */
 
 	pool_cache_t sc_xferpool;
 	pool_cache_t sc_qhpool;

Index: src/sys/rump/dev/lib/libugenhc/ugenhc.c
diff -u src/sys/rump/dev/lib/libugenhc/ugenhc.c:1.22.4.6 src/sys/rump/dev/lib/libugenhc/ugenhc.c:1.22.4.7
--- src/sys/rump/dev/lib/libugenhc/ugenhc.c:1.22.4.6	Wed Dec  3 23:05:07 2014
+++ src/sys/rump/dev/lib/libugenhc/ugenhc.c	Thu Dec  4 08:04:32 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: ugenhc.c,v 1.22.4.6 2014/12/03 23:05:07 skrll Exp $	*/
+/*	$NetBSD: ugenhc.c,v 1.22.4.7 2014/12/04 08:04:32 skrll Exp $	*/
 
 /*
  * Copyright (c) 2009, 2010 Antti Kantee.  All Rights Reserved.
@@ -61,7 +61,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ugenhc.c,v 1.22.4.6 2014/12/03 23:05:07 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ugenhc.c,v 1.22.4.7 2014/12/04 08:04:32 skrll Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -99,8 +99,6 @@ struct ugenhc_softc {
 
 	int sc_port_status;
 	int sc_port_change;
-	int sc_addr;
-	int sc_conf;
 
 	struct lwp *sc_rhintr;
 	usbd_xfer_handle sc_intrxfer;
@@ -130,144 +128,45 @@ makeugendevstr(int devnum, int endpoint,
 	snprintf(buf, len, "%s%d.%02d", UGENDEV_BASESTR, devnum, endpoint);
 }
 
-/*
- * Our fictional hubbie.
- */
-
-static const usb_device_descriptor_t rumphub_udd = {
-	.bLength		= USB_DEVICE_DESCRIPTOR_SIZE,
-	.bDescriptorType	= UDESC_DEVICE,
-	.bDeviceClass		= UDCLASS_HUB,
-	.bDeviceSubClass	= UDSUBCLASS_HUB,
-	.bDeviceProtocol	= UDPROTO_FSHUB,
-	.bMaxPacketSize		= 64,
-	.idVendor		= { 0x75, 0x72 },
-	.idProduct		= { 0x70, 0x6d },
-	.bNumConfigurations	= 1,
-};
-
-static const usb_config_descriptor_t rumphub_ucd = {
-	.bLength		= USB_CONFIG_DESCRIPTOR_SIZE,
-	.bDescriptorType	= UDESC_CONFIG,
-	.wTotalLength		= USETWD(
-	    USB_CONFIG_DESCRIPTOR_SIZE +
-	    USB_INTERFACE_DESCRIPTOR_SIZE +
-	    USB_ENDPOINT_DESCRIPTOR_SIZE),
-	.bNumInterface		= 1,
-	.bmAttributes		= UC_SELF_POWERED | UC_ATTR_MBO,
-};
-
-static const usb_interface_descriptor_t rumphub_uid = {
-	.bLength		= USB_INTERFACE_DESCRIPTOR_SIZE,
-	.bDescriptorType	= UDESC_INTERFACE,
-	.bInterfaceNumber	= 0,
-	.bNumEndpoints		= 1,
-	.bInterfaceClass	= UICLASS_HUB,
-	.bInterfaceSubClass	= UISUBCLASS_HUB,
-	.bInterfaceProtocol	= UIPROTO_FSHUB,
-};
-
-static const usb_endpoint_descriptor_t rumphub_epd = {
-	.bLength		= USB_ENDPOINT_DESCRIPTOR_SIZE,
-	.bDescriptorType	= UDESC_ENDPOINT,
-	.bmAttributes		= UE_INTERRUPT,
-	.wMaxPacketSize		= USETWD(64),
-};
-
-static const usb_hub_descriptor_t rumphub_hdd = {
-	.bDescLength		= USB_HUB_DESCRIPTOR_SIZE,
-	.bDescriptorType	= UDESC_HUB,
-	.bNbrPorts		= 1,
-};
-
-static usbd_status
-rumpusb_root_ctrl_start(usbd_xfer_handle xfer)
+static int
+ugenhc_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req,
+    void *buf, int buflen)
 {
-	usb_device_request_t *req = &xfer->ux_request;
-	struct ugenhc_softc *sc = xfer->ux_pipe->up_dev->ud_bus->ub_hcpriv;
-	int len, totlen, value, curlen, err;
-	uint8_t *buf = NULL;
+	struct ugenhc_softc *sc = bus->ub_hcpriv;
+	int totlen = 0;
+	uint16_t len, value;
 
-	len = totlen = UGETW(req->wLength);
-	if (len)
-		buf = KERNADDR(&xfer->ux_dmabuf, 0);
+	len = UGETW(req->wLength);
 	value = UGETW(req->wValue);
 
 #define C(x,y) ((x) | ((y) << 8))
-	switch(C(req->bRequest, req->bmRequestType)) {
-
-	case C(UR_GET_CONFIG, UT_READ_DEVICE):
-		if (len > 0) {
-			*buf = sc->sc_conf;
-			totlen = 1;
-		}
-		break;
-
+	switch (C(req->bRequest, req->bmRequestType)) {
 	case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE):
-		switch (value >> 8) {
-		case UDESC_DEVICE:
-			totlen = min(len, USB_DEVICE_DESCRIPTOR_SIZE);
-			memcpy(buf, &rumphub_udd, totlen);
-			break;
+		switch (value) {
+		case C(0, UDESC_DEVICE): {
+			usb_device_descriptor_t devd;
 
-		case UDESC_CONFIG:
-			totlen = 0;
-			curlen = min(len, USB_CONFIG_DESCRIPTOR_SIZE);
-			memcpy(buf, &rumphub_ucd, curlen);
-			len -= curlen;
-			buf += curlen;
-			totlen += curlen;
-
-			curlen = min(len, USB_INTERFACE_DESCRIPTOR_SIZE);
-			memcpy(buf, &rumphub_uid, curlen);
-			len -= curlen;
-			buf += curlen;
-			totlen += curlen;
-
-			curlen = min(len, USB_ENDPOINT_DESCRIPTOR_SIZE);
-			memcpy(buf, &rumphub_epd, curlen);
-			len -= curlen;
-			buf += curlen;
-			totlen += curlen;
+			totlen = min(buflen, sizeof(devd));
+			memcpy(&devd, buf, totlen);
+			USETW(devd.idVendor, 0x7275);
+			USETW(devd.idProduct, 0x6d72);
+			memcpy(buf, &devd, totlen);
 			break;
-
-		case UDESC_STRING:
+		}
 #define sd ((usb_string_descriptor_t *)buf)
-			switch (value & 0xff) {
-			case 0: /* Language table */
-				totlen = usb_makelangtbl(sd, len);
-				break;
-			case 1: /* Vendor */
-				totlen = usb_makestrdesc(sd, len, "rod nevada");
-				break;
-			case 2: /* Product */
-				totlen = usb_makestrdesc(sd, len,
-				    "RUMPUSBHC root hub");
-				break;
-			}
-#undef sd
+		case C(1, UDESC_STRING):
+			/* Vendor */
+			totlen = usb_makestrdesc(sd, len, "rod nevada");
+			break;
+		case C(2, UDESC_STRING):
+			/* Product */
+			totlen = usb_makestrdesc(sd, len, "RUMPUSBHC root hub");
 			break;
-
+#undef sd
 		default:
-			panic("unhandled read device request");
-			break;
-		}
-		break;
-
-	case C(UR_SET_ADDRESS, UT_WRITE_DEVICE):
-		if (value >= USB_MAX_DEVICES) {
-			err = USBD_IOERROR;
-			goto ret;
-		}
-		sc->sc_addr = value;
-		break;
-
-	case C(UR_SET_CONFIG, UT_WRITE_DEVICE):
-		if (value != 0 && value != 1) {
-			err = USBD_IOERROR;
-			goto ret;
+			/* default from usbroothub */
+			return buflen;
 		}
-		sc->sc_conf = value;
 		break;
 
 	case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER):
@@ -278,7 +177,7 @@ rumpusb_root_ctrl_start(usbd_xfer_handle
 		case UHF_PORT_POWER:
 			break;
 		default:
-			panic("unhandled");
+			return -1;
 		}
 		break;
 
@@ -287,8 +186,7 @@ rumpusb_root_ctrl_start(usbd_xfer_handle
 		break;
 
 	case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE):
-		totlen = min(len, USB_HUB_DESCRIPTOR_SIZE);
-		memcpy(buf, &rumphub_hdd, totlen);
+		totlen = buflen;
 		break;
 
 	case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE):
@@ -297,8 +195,7 @@ rumpusb_root_ctrl_start(usbd_xfer_handle
 		totlen = len;
 		break;
 
-	case C(UR_GET_STATUS, UT_READ_CLASS_OTHER):
-		{
+	case C(UR_GET_STATUS, UT_READ_CLASS_OTHER): {
 		usb_port_status_t ps;
 
 		USETW(ps.wPortStatus, sc->sc_port_status);
@@ -306,73 +203,16 @@ rumpusb_root_ctrl_start(usbd_xfer_handle
 		totlen = min(len, sizeof(ps));
 		memcpy(buf, &ps, totlen);
 		break;
-		}
-
+	}
 	default:
-		panic("unhandled request");
-		break;
+		/* default from usbroothub */
+		return buflen;
 	}
-	err = USBD_NORMAL_COMPLETION;
-	xfer->ux_actlen = totlen;
 
-ret:
-	xfer->ux_status = err;
-	mutex_enter(&sc->sc_lock);
-	usb_transfer_complete(xfer);
-	mutex_exit(&sc->sc_lock);
-
-	return (USBD_IN_PROGRESS);
+	return totlen;
 }
 
 static usbd_status
-rumpusb_root_ctrl_transfer(usbd_xfer_handle xfer)
-{
-	struct ugenhc_softc *sc = xfer->ux_pipe->up_dev->ud_bus->ub_hcpriv;
-	usbd_status err;
-
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return (err);
-
-	return (rumpusb_root_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue)));
-}
-
-static void
-rumpusb_root_ctrl_abort(usbd_xfer_handle xfer)
-{
-
-}
-
-static void
-rumpusb_root_ctrl_close(usbd_pipe_handle pipe)
-{
-
-}
-
-static void
-rumpusb_root_ctrl_cleartoggle(usbd_pipe_handle pipe)
-{
-
-}
-
-static void
-rumpusb_root_ctrl_done(usbd_xfer_handle xfer)
-{
-
-}
-
-static const struct usbd_pipe_methods rumpusb_root_ctrl_methods = {
-	.upm_transfer =	rumpusb_root_ctrl_transfer,
-	.upm_start =	rumpusb_root_ctrl_start,
-	.upm_abort =	rumpusb_root_ctrl_abort,
-	.upm_close =	rumpusb_root_ctrl_close,
-	.upm_cleartoggle =	rumpusb_root_ctrl_cleartoggle,
-	.upm_done =	rumpusb_root_ctrl_done,
-};
-
-static usbd_status
 rumpusb_device_ctrl_start(usbd_xfer_handle xfer)
 {
 	usb_device_request_t *req = &xfer->ux_request;
@@ -385,7 +225,7 @@ rumpusb_device_ctrl_start(usbd_xfer_hand
 
 	len = totlen = UGETW(req->wLength);
 	if (len)
-		buf = KERNADDR(&xfer->ux_dmabuf, 0);
+		buf = xfer->ux_buf;
 	value = UGETW(req->wValue);
 
 #define C(x,y) ((x) | ((y) << 8))
@@ -955,16 +795,17 @@ ugenhc_open(struct usbd_pipe *pipe)
 	usbd_device_handle dev = pipe->up_dev;
 	struct ugenhc_softc *sc = dev->ud_bus->ub_hcpriv;
 	usb_endpoint_descriptor_t *ed = pipe->up_endpoint->ue_edesc;
+	uint8_t rhaddr = dev->ud_bus->ub_rhaddr;
 	uint8_t addr = dev->ud_addr;
 	uint8_t xfertype = ed->bmAttributes & UE_XFERTYPE;
 	char buf[UGENDEV_BUFSIZE];
 	int endpt, oflags, error;
 	int fd, val;
 
-	if (addr == sc->sc_addr) {
+	if (addr == rhaddr) {
 		switch (xfertype) {
 		case UE_CONTROL:
-			pipe->up_methods = &rumpusb_root_ctrl_methods;
+			pipe->up_methods = &roothub_ctrl_methods;
 			break;
 		case UE_INTERRUPT:
 			pipe->up_methods = &rumpusb_root_intr_methods;
@@ -1077,7 +918,8 @@ static const struct usbd_bus_methods uge
 	.ubm_dopoll =	ugenhc_poll,
 	.ubm_allocx = 	ugenhc_allocx,
 	.ubm_freex =	ugenhc_freex,
-	.ubm_getlock =	ugenhc_getlock
+	.ubm_getlock =	ugenhc_getlock,
+	.ubm_rhctrl =	ugenhc_roothub_ctrl,
 };
 
 static int

Reply via email to