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