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 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 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 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 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 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 605 roothub_ctrl_close(struct usbd_pipe *pipe) 606 { 607 608 /* Nothing to do. */ 609 } 610 611 Static void 612 roothub_ctrl_done(struct usbd_xfer *xfer) 613 { 614 615 /* Nothing to do. */ 616 } 617 618 static void 619 roothub_noop(struct usbd_pipe *pipe) 620 { 621 622 } 623