Home | History | Annotate | Line # | Download | only in usb
usbroothub.c revision 1.4
      1 /* $NetBSD: usbroothub.c,v 1.4 2017/11/28 07:36:08 skrll Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 1998, 2004, 2011, 2012 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Lennart Augustsson (lennart (at) augustsson.net) at
      9  * Carlstedt Research & Technology, Jared D. McNeill (jmcneill (at) invisible.ca),
     10  * Matthew R. Green (mrg (at) eterna.com.au) and Nick Hudson.
     11  *
     12  * Redistribution and use in source and binary forms, with or without
     13  * modification, are permitted provided that the following conditions
     14  * are met:
     15  * 1. Redistributions of source code must retain the above copyright
     16  *    notice, this list of conditions and the following disclaimer.
     17  * 2. Redistributions in binary form must reproduce the above copyright
     18  *    notice, this list of conditions and the following disclaimer in the
     19  *    documentation and/or other materials provided with the distribution.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     23  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     24  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     25  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     31  * POSSIBILITY OF SUCH DAMAGE.
     32  */
     33 
     34 /*
     35  * Copyright (c) 2008
     36  *	Matthias Drochner.  All rights reserved.
     37  *
     38  * Redistribution and use in source and binary forms, with or without
     39  * modification, are permitted provided that the following conditions
     40  * are met:
     41  * 1. Redistributions of source code must retain the above copyright
     42  *    notice, this list of conditions and the following disclaimer.
     43  * 2. Redistributions in binary form must reproduce the above copyright
     44  *    notice, this list of conditions and the following disclaimer in the
     45  *    documentation and/or other materials provided with the distribution.
     46  *
     47  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     48  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     49  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     50  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     51  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     52  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     53  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     54  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     55  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     56  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     57  *
     58  */
     59 
     60 #include <dev/usb/usb.h>
     61 #include <dev/usb/usbdi.h>
     62 #include <dev/usb/usbdivar.h>
     63 #include <dev/usb/usbroothub.h>
     64 #include <dev/usb/usbhist.h>
     65 
     66 extern int usbdebug;
     67 
     68 /* helper functions for USB root hub emulation */
     69 
     70 static usbd_status	roothub_ctrl_transfer(struct usbd_xfer *);
     71 static usbd_status	roothub_ctrl_start(struct usbd_xfer *);
     72 static void		roothub_ctrl_abort(struct usbd_xfer *);
     73 static void		roothub_ctrl_close(struct usbd_pipe *);
     74 static void		roothub_ctrl_done(struct usbd_xfer *);
     75 static void		roothub_noop(struct usbd_pipe *pipe);
     76 
     77 const struct usbd_pipe_methods roothub_ctrl_methods = {
     78 	.upm_transfer =	roothub_ctrl_transfer,
     79 	.upm_start =	roothub_ctrl_start,
     80 	.upm_abort =	roothub_ctrl_abort,
     81 	.upm_close =	roothub_ctrl_close,
     82 	.upm_cleartoggle =	roothub_noop,
     83 	.upm_done =	roothub_ctrl_done,
     84 };
     85 
     86 int
     87 usb_makestrdesc(usb_string_descriptor_t *p, int l, const char *s)
     88 {
     89 	int i;
     90 
     91 	if (l == 0)
     92 		return 0;
     93 	p->bLength = 2 * strlen(s) + 2;
     94 	if (l == 1)
     95 		return 1;
     96 	p->bDescriptorType = UDESC_STRING;
     97 	l -= 2;
     98 	/* poor man's utf-16le conversion */
     99 	for (i = 0; s[i] && l > 1; i++, l -= 2)
    100 		USETW2(p->bString[i], 0, s[i]);
    101 	return 2 * i + 2;
    102 }
    103 
    104 int
    105 usb_makelangtbl(usb_string_descriptor_t *p, int l)
    106 {
    107 
    108 	if (l == 0)
    109 		return 0;
    110 	p->bLength = 4;
    111 	if (l == 1)
    112 		return 1;
    113 	p->bDescriptorType = UDESC_STRING;
    114 	if (l < 4)
    115 		return 2;
    116 	USETW(p->bString[0], 0x0409); /* english/US */
    117 	return 4;
    118 }
    119 
    120 /*
    121  * Data structures and routines to emulate the root hub.
    122  */
    123 static const usb_device_descriptor_t usbroothub_devd1 = {
    124 	.bLength = sizeof(usb_device_descriptor_t),
    125 	.bDescriptorType = UDESC_DEVICE,
    126 	.bcdUSB = {0x00, 0x01},
    127 	.bDeviceClass = UDCLASS_HUB,
    128 	.bDeviceSubClass = UDSUBCLASS_HUB,
    129 	.bDeviceProtocol = UDPROTO_FSHUB,
    130 	.bMaxPacketSize = 64,
    131 	.idVendor = {0},
    132 	.idProduct = {0},
    133 	.bcdDevice = {0x00, 0x01},
    134 	.iManufacturer = 1,
    135 	.iProduct = 2,
    136 	.iSerialNumber = 0,
    137 	.bNumConfigurations = 1
    138 };
    139 
    140 static const struct usb_roothub_descriptors usbroothub_confd1 = {
    141 	.urh_confd = {
    142 		.bLength = USB_CONFIG_DESCRIPTOR_SIZE,
    143 		.bDescriptorType = UDESC_CONFIG,
    144 		.wTotalLength = USETWD(sizeof(usbroothub_confd1)),
    145 		.bNumInterface = 1,
    146 		.bConfigurationValue = 1,
    147 		.iConfiguration = 0,
    148 		.bmAttributes = UC_ATTR_MBO | UC_SELF_POWERED,
    149 		.bMaxPower = 0,
    150 	},
    151 	.urh_ifcd = {
    152 		.bLength = USB_INTERFACE_DESCRIPTOR_SIZE,
    153 		.bDescriptorType = UDESC_INTERFACE,
    154 		.bInterfaceNumber = 0,
    155 		.bAlternateSetting = 0,
    156 		.bNumEndpoints = 1,
    157 		.bInterfaceClass = UICLASS_HUB,
    158 		.bInterfaceSubClass = UISUBCLASS_HUB,
    159 		.bInterfaceProtocol = UIPROTO_FSHUB,
    160 		.iInterface = 0
    161 	},
    162 	.urh_endpd = {
    163 		.bLength = USB_ENDPOINT_DESCRIPTOR_SIZE,
    164 		.bDescriptorType = UDESC_ENDPOINT,
    165 		.bEndpointAddress = UE_DIR_IN | USBROOTHUB_INTR_ENDPT,
    166 		.bmAttributes = UE_INTERRUPT,
    167 		.wMaxPacketSize = USETWD(8),			/* max packet */
    168 		.bInterval = 255,
    169 	},
    170 };
    171 
    172 /* USB 3.0 10.15.1 */
    173 static const usb_device_descriptor_t usbroothub_devd3 = {
    174 	.bLength = sizeof(usb_device_descriptor_t),
    175 	.bDescriptorType = UDESC_DEVICE,
    176 	.bcdUSB = {0x00, 0x03},
    177 	.bDeviceClass = UDCLASS_HUB,
    178 	.bDeviceSubClass = UDSUBCLASS_HUB,
    179 	.bDeviceProtocol = UDPROTO_SSHUB,
    180 	.bMaxPacketSize = 9,
    181 	.idVendor = {0},
    182 	.idProduct = {0},
    183 	.bcdDevice = {0x00, 0x01},
    184 	.iManufacturer = 1,
    185 	.iProduct = 2,
    186 	.iSerialNumber = 0,
    187 	.bNumConfigurations = 1
    188 };
    189 
    190 static const usb_device_descriptor_t usbroothub_devd2 = {
    191 	.bLength = sizeof(usb_device_descriptor_t),
    192 	.bDescriptorType = UDESC_DEVICE,
    193 	.bcdUSB = {0x00, 0x02},
    194 	.bDeviceClass = UDCLASS_HUB,
    195 	.bDeviceSubClass = UDSUBCLASS_HUB,
    196 	.bDeviceProtocol = UDPROTO_HSHUBSTT,
    197 	.bMaxPacketSize = 64,
    198 	.idVendor = {0},
    199 	.idProduct = {0},
    200 	.bcdDevice = {0x00, 0x01},
    201 	.iManufacturer = 1,
    202 	.iProduct = 2,
    203 	.iSerialNumber = 0,
    204 	.bNumConfigurations = 1
    205 };
    206 
    207 static const usb_device_qualifier_t usbroothub_odevd2 = {
    208 	.bLength = USB_DEVICE_QUALIFIER_SIZE,
    209 	.bDescriptorType = UDESC_DEVICE_QUALIFIER,
    210 	.bcdUSB = {0x00, 0x02},
    211 	.bDeviceClass = UDCLASS_HUB,
    212 	.bDeviceSubClass = UDSUBCLASS_HUB,
    213 	.bDeviceProtocol = UDPROTO_FSHUB,
    214 	.bMaxPacketSize0 = 64,
    215 	.bNumConfigurations = 1,
    216 };
    217 
    218 static const struct usb_roothub_descriptors usbroothub_confd2 = {
    219 	.urh_confd = {
    220 		.bLength = USB_CONFIG_DESCRIPTOR_SIZE,
    221 		.bDescriptorType = UDESC_CONFIG,
    222 		.wTotalLength = USETWD(sizeof(usbroothub_confd2)),
    223 		.bNumInterface = 1,
    224 		.bConfigurationValue = 1,
    225 		.iConfiguration = 0,
    226 		.bmAttributes = UC_ATTR_MBO | UC_SELF_POWERED,
    227 		.bMaxPower = 0,
    228 	},
    229 	.urh_ifcd = {
    230 		.bLength = USB_INTERFACE_DESCRIPTOR_SIZE,
    231 		.bDescriptorType = UDESC_INTERFACE,
    232 		.bInterfaceNumber = 0,
    233 		.bAlternateSetting = 0,
    234 		.bNumEndpoints = 1,
    235 		.bInterfaceClass = UICLASS_HUB,
    236 		.bInterfaceSubClass = UISUBCLASS_HUB,
    237 		.bInterfaceProtocol = UIPROTO_HSHUBSTT,
    238 		.iInterface = 0
    239 	},
    240 	.urh_endpd = {
    241 		.bLength = USB_ENDPOINT_DESCRIPTOR_SIZE,
    242 		.bDescriptorType = UDESC_ENDPOINT,
    243 		.bEndpointAddress = UE_DIR_IN | USBROOTHUB_INTR_ENDPT,
    244 		.bmAttributes = UE_INTERRUPT,
    245 		.wMaxPacketSize = USETWD(8),			/* max packet */
    246 		.bInterval = 12,
    247 	},
    248 };
    249 
    250 static const struct usb3_roothub_descriptors usbroothub_confd3 = {
    251 	.urh_confd = {
    252 		.bLength = USB_CONFIG_DESCRIPTOR_SIZE,
    253 		.bDescriptorType = UDESC_CONFIG,
    254 		.wTotalLength = USETWD(sizeof(usbroothub_confd3)),
    255 		.bNumInterface = 1,
    256 		.bConfigurationValue = 1,
    257 		.iConfiguration = 0,
    258 		.bmAttributes = UC_SELF_POWERED,		/* 10.13.1 */
    259 		.bMaxPower = 0,
    260 	},
    261 	.urh_ifcd = {
    262 		.bLength = USB_INTERFACE_DESCRIPTOR_SIZE,
    263 		.bDescriptorType = UDESC_INTERFACE,
    264 		.bInterfaceNumber = 0,
    265 		.bAlternateSetting = 0,
    266 		.bNumEndpoints = 1,
    267 		.bInterfaceClass = UICLASS_HUB,
    268 		.bInterfaceSubClass = UISUBCLASS_HUB,
    269 		.bInterfaceProtocol = 0,			/* UIPROTO_SSHUB ??? */
    270 		.iInterface = 0
    271 	},
    272 	.urh_endpd = {
    273 		.bLength = USB_ENDPOINT_DESCRIPTOR_SIZE,
    274 		.bDescriptorType = UDESC_ENDPOINT,
    275 		.bEndpointAddress = UE_DIR_IN | USBROOTHUB_INTR_ENDPT,
    276 		.bmAttributes = UE_INTERRUPT,
    277 		.wMaxPacketSize = USETWD(2),			/* max packet */
    278 		.bInterval = 8,
    279 	},
    280 	.urh_endpssd = {
    281 		.bLength = USB_ENDPOINT_SS_COMP_DESCRIPTOR_SIZE,
    282 		.bDescriptorType = UDESC_ENDPOINT_SS_COMP,
    283 		.bMaxBurst = 0,
    284 		.bmAttributes = 0,
    285 		.wBytesPerInterval = USETWD(2)
    286 	},
    287 };
    288 
    289 static const struct usb3_roothub_bos_descriptors usbroothub_bosd3 = {
    290 	.urh_bosd = {
    291 		.bLength = USB_BOS_DESCRIPTOR_SIZE,
    292 		.bDescriptorType = UDESC_BOS,
    293 		.wTotalLength = USETWD(sizeof(usbroothub_bosd3)),
    294 		.bNumDeviceCaps = 3,
    295 	},
    296 	/* 9.6.2.1 USB 2.0 Extension */
    297 	.urh_usb2extd = {
    298 		.bLength = USB_DEVCAP_USB2EXT_DESCRIPTOR_SIZE,
    299 		.bDescriptorType = 1,
    300 		.bDevCapabilityType = 2,
    301 		.bmAttributes[0] = 2,
    302 	},
    303 	/* 9.6.2.2 Superspeed device capability */
    304 	.urh_ssd = {
    305 		.bLength = USB_DEVCAP_SS_DESCRIPTOR_SIZE,
    306 		.bDescriptorType = UDESC_DEVICE_CAPABILITY,
    307 		.bDevCapabilityType = USB_DEVCAP_SUPER_SPEED,
    308 		.bmAttributes = 0,	/* USB_DEVCAP_SS_LTM */
    309 		.wSpeedsSupported = USETWD(
    310 		    USB_DEVCAP_SS_SPEED_LS | USB_DEVCAP_SS_SPEED_FS |
    311 		    USB_DEVCAP_SS_SPEED_HS | USB_DEVCAP_SS_SPEED_SS),
    312 		.bFunctionalitySupport = 8,		/* SS is 3, i.e. 1 << 3? */
    313 		.bU1DevExitLat = 255,		/* Dummy... 0? */
    314 		.wU2DevExitLat = USETWD(8),	/* Also dummy... 0? */
    315 	},
    316 	/* 9.6.2.3 Container ID  - see RFC 4122 */
    317 	.urh_containerd = {
    318 		.bLength = USB_DEVCAP_CONTAINER_ID_DESCRIPTOR_SIZE,
    319 		.bDescriptorType = 1,
    320 		.bDevCapabilityType = 4,
    321 		.bReserved = 0,
    322 		// ContainerID will be zero
    323 	},
    324 };
    325 
    326 static const usb_hub_descriptor_t usbroothub_hubd = {
    327 	.bDescLength = USB_HUB_DESCRIPTOR_SIZE,
    328 	.bDescriptorType = UDESC_HUB,
    329 	.bNbrPorts = 1,
    330 	.wHubCharacteristics = USETWD(UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL),
    331 	.bPwrOn2PwrGood = 50,
    332 	.bHubContrCurrent = 0,
    333 	.DeviceRemovable = {0},		/* port is removable */
    334 };
    335 
    336 /*
    337  * Simulate a hardware hub by handling all the necessary requests.
    338  */
    339 usbd_status
    340 roothub_ctrl_transfer(struct usbd_xfer *xfer)
    341 {
    342 	struct usbd_pipe *pipe = xfer->ux_pipe;
    343 	struct usbd_bus *bus = pipe->up_dev->ud_bus;
    344 	usbd_status err;
    345 
    346 	/* Insert last in queue. */
    347 	mutex_enter(bus->ub_lock);
    348 	err = usb_insert_transfer(xfer);
    349 	mutex_exit(bus->ub_lock);
    350 	if (err)
    351 		return err;
    352 
    353 	/* Pipe isn't running, start first */
    354 	return roothub_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
    355 }
    356 
    357 static usbd_status
    358 roothub_ctrl_start(struct usbd_xfer *xfer)
    359 {
    360 	struct usbd_pipe *pipe = xfer->ux_pipe;
    361 	struct usbd_bus *bus = pipe->up_dev->ud_bus;
    362 	usb_device_request_t *req;
    363 	usbd_status err = USBD_IOERROR;		/* XXX STALL? */
    364 	uint16_t len, value;
    365 	int buflen, actlen;
    366 	void *buf;
    367 
    368 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
    369 
    370 	KASSERT(xfer->ux_rqflags & URQ_REQUEST);
    371 	req = &xfer->ux_request;
    372 
    373 	USBHIST_LOG(usbdebug, "type=%#2jx request=%#2jx", req->bmRequestType,
    374 	    req->bRequest, 0, 0);
    375 
    376 	len = UGETW(req->wLength);
    377 	value = UGETW(req->wValue);
    378 
    379 	buf = len ? usbd_get_buffer(xfer) : NULL;
    380 	buflen = 0;
    381 
    382 #define C(x,y) ((x) | ((y) << 8))
    383 	switch (C(req->bRequest, req->bmRequestType)) {
    384 	case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE):
    385 	case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE):
    386 	case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT):
    387 		/*
    388 		 * DEVICE_REMOTE_WAKEUP and ENDPOINT_HALT are no-ops
    389 		 * for the integrated root hub.
    390 		 */
    391 		break;
    392 	case C(UR_GET_CONFIG, UT_READ_DEVICE):
    393 		if (len > 0) {
    394 			uint8_t *out = buf;
    395 
    396 			*out = bus->ub_rhconf;
    397 			buflen = sizeof(*out);
    398 		}
    399 		break;
    400 	case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE):
    401 		USBHIST_LOG(usbdebug, "wValue=%#4jx", value, 0, 0, 0);
    402 
    403 		if (len == 0)
    404 			break;
    405 		switch (value) {
    406 		case C(0, UDESC_DEVICE):
    407 			if (bus->ub_revision >= USBREV_3_0) {
    408 				buflen = min(len, sizeof(usbroothub_devd3));
    409 				memcpy(buf, &usbroothub_devd3, buflen);
    410 			} else if (bus->ub_revision == USBREV_2_0) {
    411 				buflen = min(len, sizeof(usbroothub_devd2));
    412 				memcpy(buf, &usbroothub_devd2, buflen);
    413 			} else {
    414 				buflen = min(len, sizeof(usbroothub_devd1));
    415 				memcpy(buf, &usbroothub_devd1, buflen);
    416 			}
    417 			break;
    418 		case C(0, UDESC_CONFIG):
    419 			if (bus->ub_revision >= USBREV_3_0) {
    420 				buflen = min(len, sizeof(usbroothub_confd3));
    421 				memcpy(buf, &usbroothub_confd3, buflen);
    422 			} else if (bus->ub_revision == USBREV_2_0) {
    423 				buflen = min(len, sizeof(usbroothub_confd2));
    424 				memcpy(buf, &usbroothub_confd2, buflen);
    425 			} else {
    426 				buflen = min(len, sizeof(usbroothub_confd1));
    427 				memcpy(buf, &usbroothub_confd1, buflen);
    428 			}
    429 			break;
    430 		case C(0, UDESC_DEVICE_QUALIFIER):
    431 			if (bus->ub_revision == USBREV_2_0) {
    432 				/*
    433 				 * We can't really operate at another speed,
    434 				 * but the spec says we need this descriptor.
    435 				 */
    436 				buflen = min(len, sizeof(usbroothub_odevd2));
    437 				memcpy(buf, &usbroothub_odevd2, buflen);
    438 			} else
    439 				goto fail;
    440 			break;
    441 		case C(0, UDESC_OTHER_SPEED_CONFIGURATION):
    442 			if (bus->ub_revision == USBREV_2_0) {
    443 				struct usb_roothub_descriptors confd;
    444 
    445 				/*
    446 				 * We can't really operate at another speed,
    447 				 * but the spec says we need this descriptor.
    448 				 */
    449 				buflen = min(len, sizeof(usbroothub_confd2));
    450 				memcpy(&confd, &usbroothub_confd2, buflen);
    451 				confd.urh_confd.bDescriptorType =
    452 				    UDESC_OTHER_SPEED_CONFIGURATION;
    453 				memcpy(buf, &confd, buflen);
    454 			} else
    455 				goto fail;
    456 			break;
    457 		case C(0, UDESC_BOS):
    458 			if (bus->ub_revision >= USBREV_3_0) {
    459 				buflen = min(len, sizeof(usbroothub_bosd3));
    460 				memcpy(buf, &usbroothub_bosd3, buflen);
    461 			} else
    462 				goto fail;
    463 			break;
    464 #define sd ((usb_string_descriptor_t *)buf)
    465 		case C(0, UDESC_STRING):
    466 			/* Language table */
    467 			buflen = usb_makelangtbl(sd, len);
    468 			break;
    469 		case C(1, UDESC_STRING):
    470 			/* Vendor */
    471 			buflen = usb_makestrdesc(sd, len, "NetBSD");
    472 			break;
    473 		case C(2, UDESC_STRING):
    474 			/* Product */
    475 			buflen = usb_makestrdesc(sd, len, "Root hub");
    476 			break;
    477 #undef sd
    478 		default:
    479 			/* Default to error */
    480 			buflen = -1;
    481 		}
    482 		break;
    483 	case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE):
    484 		buflen = min(len, sizeof(usbroothub_hubd));
    485 		memcpy(buf, &usbroothub_hubd, buflen);
    486 		break;
    487 	case C(UR_GET_INTERFACE, UT_READ_INTERFACE):
    488 		/* Get Interface, 9.4.4 */
    489 		if (len > 0) {
    490 			uint8_t *out = buf;
    491 
    492 			*out = 0;
    493 			buflen = sizeof(*out);
    494 		}
    495 		break;
    496 	case C(UR_GET_STATUS, UT_READ_DEVICE):
    497 		/* Get Status from device, 9.4.5 */
    498 		if (len > 1) {
    499 			usb_status_t *out = buf;
    500 
    501 			USETW(out->wStatus, UDS_SELF_POWERED);
    502 			buflen = sizeof(*out);
    503 		}
    504 		break;
    505 	case C(UR_GET_STATUS, UT_READ_INTERFACE):
    506 	case C(UR_GET_STATUS, UT_READ_ENDPOINT):
    507 		/* Get Status from interface, endpoint, 9.4.5 */
    508 		if (len > 1) {
    509 			usb_status_t *out = buf;
    510 
    511 			USETW(out->wStatus, 0);
    512 			buflen = sizeof(*out);
    513 		}
    514 		break;
    515 	case C(UR_SET_ADDRESS, UT_WRITE_DEVICE):
    516 		/* Set Address, 9.4.6 */
    517 		USBHIST_LOG(usbdebug, "UR_SET_ADDRESS, UT_WRITE_DEVICE: "
    518 		    "addr %jd", value, 0, 0, 0);
    519 		if (value >= USB_MAX_DEVICES) {
    520 			goto fail;
    521 		}
    522 		bus->ub_rhaddr = value;
    523 		break;
    524 	case C(UR_SET_CONFIG, UT_WRITE_DEVICE):
    525 		/* Set Configuration, 9.4.7 */
    526 		if (value != 0 && value != 1) {
    527 			goto fail;
    528 		}
    529 		bus->ub_rhconf = value;
    530 		break;
    531 	case C(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE):
    532 		/* Set Descriptor, 9.4.8, not supported */
    533 		break;
    534 	case C(UR_SET_FEATURE, UT_WRITE_DEVICE):
    535 	case C(UR_SET_FEATURE, UT_WRITE_INTERFACE):
    536 	case C(UR_SET_FEATURE, UT_WRITE_ENDPOINT):
    537 		/* Set Feature, 9.4.9, not supported */
    538 		goto fail;
    539 	case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE):
    540 		/* Set Interface, 9.4.10, not supported */
    541 		break;
    542 	case C(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT):
    543 		/* Synch Frame, 9.4.11, not supported */
    544 		break;
    545 	default:
    546 		/* Default to error */
    547 		buflen = -1;
    548 		break;
    549 	}
    550 
    551 	actlen = bus->ub_methods->ubm_rhctrl(bus, req, buf, buflen);
    552 	USBHIST_LOG(usbdebug, "xfer %#jx buflen %jd actlen %jd",
    553 	    (uintptr_t)xfer, buflen, actlen, 0);
    554 	if (actlen < 0)
    555 		goto fail;
    556 
    557 	xfer->ux_actlen = actlen;
    558 	err = USBD_NORMAL_COMPLETION;
    559 
    560  fail:
    561 	USBHIST_LOG(usbdebug, "xfer %#jx err %jd", (uintptr_t)xfer, err, 0, 0);
    562 
    563 	xfer->ux_status = err;
    564 	mutex_enter(bus->ub_lock);
    565 	usb_transfer_complete(xfer);
    566 	mutex_exit(bus->ub_lock);
    567 
    568 	return USBD_NORMAL_COMPLETION;
    569 }
    570 
    571 /* Abort a root control request. */
    572 Static void
    573 roothub_ctrl_abort(struct usbd_xfer *xfer)
    574 {
    575 
    576 	/* Nothing to do, all transfers are synchronous. */
    577 }
    578 
    579 /* Close the root pipe. */
    580 Static void
    581 roothub_ctrl_close(struct usbd_pipe *pipe)
    582 {
    583 
    584 	/* Nothing to do. */
    585 }
    586 
    587 Static void
    588 roothub_ctrl_done(struct usbd_xfer *xfer)
    589 {
    590 
    591 	/* Nothing to do. */
    592 }
    593 
    594 static void
    595 roothub_noop(struct usbd_pipe *pipe)
    596 {
    597 
    598 }
    599