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