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