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