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