1 /* $NetBSD: usbroothub.c,v 1.2 2016/04/23 10:15:32 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@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 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 static const usb_device_descriptor_t usbroothub_devd2 = { 173 .bLength = sizeof(usb_device_descriptor_t), 174 .bDescriptorType = UDESC_DEVICE, 175 .bcdUSB = {0x00, 0x02}, 176 .bDeviceClass = UDCLASS_HUB, 177 .bDeviceSubClass = UDSUBCLASS_HUB, 178 .bDeviceProtocol = UDPROTO_HSHUBSTT, 179 .bMaxPacketSize = 64, 180 .idVendor = {0}, 181 .idProduct = {0}, 182 .bcdDevice = {0x00, 0x01}, 183 .iManufacturer = 1, 184 .iProduct = 2, 185 .iSerialNumber = 0, 186 .bNumConfigurations = 1 187 }; 188 189 static const usb_device_qualifier_t usbroothub_odevd2 = { 190 .bLength = USB_DEVICE_QUALIFIER_SIZE, 191 .bDescriptorType = UDESC_DEVICE_QUALIFIER, 192 .bcdUSB = {0x00, 0x02}, 193 .bDeviceClass = UDCLASS_HUB, 194 .bDeviceSubClass = UDSUBCLASS_HUB, 195 .bDeviceProtocol = UDPROTO_FSHUB, 196 .bMaxPacketSize0 = 64, 197 .bNumConfigurations = 1, 198 }; 199 200 static const struct usb_roothub_descriptors usbroothub_confd2 = { 201 .urh_confd = { 202 .bLength = USB_CONFIG_DESCRIPTOR_SIZE, 203 .bDescriptorType = UDESC_CONFIG, 204 .wTotalLength = USETWD(sizeof(usbroothub_confd2)), 205 .bNumInterface = 1, 206 .bConfigurationValue = 1, 207 .iConfiguration = 0, 208 .bmAttributes = UC_ATTR_MBO | UC_SELF_POWERED, 209 .bMaxPower = 0, 210 }, 211 .urh_ifcd = { 212 .bLength = USB_INTERFACE_DESCRIPTOR_SIZE, 213 .bDescriptorType = UDESC_INTERFACE, 214 .bInterfaceNumber = 0, 215 .bAlternateSetting = 0, 216 .bNumEndpoints = 1, 217 .bInterfaceClass = UICLASS_HUB, 218 .bInterfaceSubClass = UISUBCLASS_HUB, 219 .bInterfaceProtocol = UIPROTO_HSHUBSTT, 220 .iInterface = 0 221 }, 222 .urh_endpd = { 223 .bLength = USB_ENDPOINT_DESCRIPTOR_SIZE, 224 .bDescriptorType = UDESC_ENDPOINT, 225 .bEndpointAddress = UE_DIR_IN | USBROOTHUB_INTR_ENDPT, 226 .bmAttributes = UE_INTERRUPT, 227 .wMaxPacketSize = USETWD(8), /* max packet */ 228 .bInterval = 12, 229 }, 230 }; 231 232 static const usb_hub_descriptor_t usbroothub_hubd = { 233 .bDescLength = USB_HUB_DESCRIPTOR_SIZE, 234 .bDescriptorType = UDESC_HUB, 235 .bNbrPorts = 1, 236 .wHubCharacteristics = USETWD(UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL), 237 .bPwrOn2PwrGood = 50, 238 .bHubContrCurrent = 0, 239 .DeviceRemovable = {0}, /* port is removable */ 240 }; 241 242 /* 243 * Simulate a hardware hub by handling all the necessary requests. 244 */ 245 usbd_status 246 roothub_ctrl_transfer(struct usbd_xfer *xfer) 247 { 248 struct usbd_pipe *pipe = xfer->ux_pipe; 249 struct usbd_bus *bus = pipe->up_dev->ud_bus; 250 usbd_status err; 251 252 /* Insert last in queue. */ 253 mutex_enter(bus->ub_lock); 254 err = usb_insert_transfer(xfer); 255 mutex_exit(bus->ub_lock); 256 if (err) 257 return err; 258 259 /* Pipe isn't running, start first */ 260 return roothub_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue)); 261 } 262 263 static usbd_status 264 roothub_ctrl_start(struct usbd_xfer *xfer) 265 { 266 struct usbd_pipe *pipe = xfer->ux_pipe; 267 struct usbd_bus *bus = pipe->up_dev->ud_bus; 268 usb_device_request_t *req; 269 usbd_status err = USBD_IOERROR; /* XXX STALL? */ 270 uint16_t len, value; 271 int buflen, actlen; 272 void *buf; 273 274 USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 275 276 KASSERT(xfer->ux_rqflags & URQ_REQUEST); 277 req = &xfer->ux_request; 278 279 USBHIST_LOG(usbdebug, "type=%#2x request=%#2x", req->bmRequestType, 280 req->bRequest, 0, 0); 281 282 len = UGETW(req->wLength); 283 value = UGETW(req->wValue); 284 285 buf = len ? usbd_get_buffer(xfer) : NULL; 286 buflen = 0; 287 288 #define C(x,y) ((x) | ((y) << 8)) 289 switch (C(req->bRequest, req->bmRequestType)) { 290 case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE): 291 case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE): 292 case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT): 293 /* 294 * DEVICE_REMOTE_WAKEUP and ENDPOINT_HALT are no-ops 295 * for the integrated root hub. 296 */ 297 break; 298 case C(UR_GET_CONFIG, UT_READ_DEVICE): 299 if (len > 0) { 300 uint8_t *out = buf; 301 302 *out = bus->ub_rhconf; 303 buflen = sizeof(*out); 304 } 305 break; 306 case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE): 307 USBHIST_LOG(usbdebug, "wValue=%#4x", value, 0, 0, 0); 308 309 if (len == 0) 310 break; 311 switch (value) { 312 case C(0, UDESC_DEVICE): 313 if (bus->ub_revision == USBREV_2_0) { 314 buflen = min(len, sizeof(usbroothub_devd2)); 315 memcpy(buf, &usbroothub_devd2, buflen); 316 } else { 317 buflen = min(len, sizeof(usbroothub_devd1)); 318 memcpy(buf, &usbroothub_devd1, buflen); 319 } 320 break; 321 case C(0, UDESC_CONFIG): 322 if (bus->ub_revision == USBREV_2_0) { 323 buflen = min(len, sizeof(usbroothub_confd2)); 324 memcpy(buf, &usbroothub_confd2, buflen); 325 } else { 326 buflen = min(len, sizeof(usbroothub_confd1)); 327 memcpy(buf, &usbroothub_confd1, buflen); 328 } 329 break; 330 case C(0, UDESC_DEVICE_QUALIFIER): 331 if (bus->ub_revision == USBREV_2_0) { 332 /* 333 * We can't really operate at another speed, 334 * but the spec says we need this descriptor. 335 */ 336 buflen = min(len, sizeof(usbroothub_odevd2)); 337 memcpy(buf, &usbroothub_odevd2, buflen); 338 } else 339 goto fail; 340 break; 341 case C(0, UDESC_OTHER_SPEED_CONFIGURATION): 342 if (bus->ub_revision == USBREV_2_0) { 343 struct usb_roothub_descriptors confd; 344 345 /* 346 * We can't really operate at another speed, 347 * but the spec says we need this descriptor. 348 */ 349 buflen = min(len, sizeof(usbroothub_confd2)); 350 memcpy(&confd, &usbroothub_confd2, buflen); 351 confd.urh_confd.bDescriptorType = 352 UDESC_OTHER_SPEED_CONFIGURATION; 353 memcpy(buf, &confd, buflen); 354 } else 355 goto fail; 356 break; 357 #define sd ((usb_string_descriptor_t *)buf) 358 case C(0, UDESC_STRING): 359 /* Language table */ 360 buflen = usb_makelangtbl(sd, len); 361 break; 362 case C(1, UDESC_STRING): 363 /* Vendor */ 364 buflen = usb_makestrdesc(sd, len, "NetBSD"); 365 break; 366 case C(2, UDESC_STRING): 367 /* Product */ 368 buflen = usb_makestrdesc(sd, len, "Root hub"); 369 break; 370 #undef sd 371 default: 372 /* Default to error */ 373 buflen = -1; 374 } 375 break; 376 case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE): 377 buflen = min(len, sizeof(usbroothub_hubd)); 378 memcpy(buf, &usbroothub_hubd, buflen); 379 break; 380 case C(UR_GET_INTERFACE, UT_READ_INTERFACE): 381 /* Get Interface, 9.4.4 */ 382 if (len > 0) { 383 uint8_t *out = buf; 384 385 *out = 0; 386 buflen = sizeof(*out); 387 } 388 break; 389 case C(UR_GET_STATUS, UT_READ_DEVICE): 390 /* Get Status from device, 9.4.5 */ 391 if (len > 1) { 392 usb_status_t *out = buf; 393 394 USETW(out->wStatus, UDS_SELF_POWERED); 395 buflen = sizeof(*out); 396 } 397 break; 398 case C(UR_GET_STATUS, UT_READ_INTERFACE): 399 case C(UR_GET_STATUS, UT_READ_ENDPOINT): 400 /* Get Status from interface, endpoint, 9.4.5 */ 401 if (len > 1) { 402 usb_status_t *out = buf; 403 404 USETW(out->wStatus, 0); 405 buflen = sizeof(*out); 406 } 407 break; 408 case C(UR_SET_ADDRESS, UT_WRITE_DEVICE): 409 /* Set Address, 9.4.6 */ 410 USBHIST_LOG(usbdebug, "UR_SET_ADDRESS, UT_WRITE_DEVICE: addr %d", 411 value, 0, 0, 0); 412 if (value >= USB_MAX_DEVICES) { 413 goto fail; 414 } 415 bus->ub_rhaddr = value; 416 break; 417 case C(UR_SET_CONFIG, UT_WRITE_DEVICE): 418 /* Set Configuration, 9.4.7 */ 419 if (value != 0 && value != 1) { 420 goto fail; 421 } 422 bus->ub_rhconf = value; 423 break; 424 case C(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE): 425 /* Set Descriptor, 9.4.8, not supported */ 426 break; 427 case C(UR_SET_FEATURE, UT_WRITE_DEVICE): 428 case C(UR_SET_FEATURE, UT_WRITE_INTERFACE): 429 case C(UR_SET_FEATURE, UT_WRITE_ENDPOINT): 430 /* Set Feature, 9.4.9, not supported */ 431 goto fail; 432 case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE): 433 /* Set Interface, 9.4.10, not supported */ 434 break; 435 case C(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT): 436 /* Synch Frame, 9.4.11, not supported */ 437 break; 438 default: 439 /* Default to error */ 440 buflen = -1; 441 break; 442 } 443 444 actlen = bus->ub_methods->ubm_rhctrl(bus, req, buf, buflen); 445 USBHIST_LOG(usbdebug, "xfer %p buflen %d actlen %d", xfer, buflen, 446 actlen, 0); 447 if (actlen < 0) 448 goto fail; 449 450 xfer->ux_actlen = actlen; 451 err = USBD_NORMAL_COMPLETION; 452 453 fail: 454 USBHIST_LOG(usbdebug, "xfer %p err %d", xfer, err, 0, 0); 455 456 xfer->ux_status = err; 457 mutex_enter(bus->ub_lock); 458 usb_transfer_complete(xfer); 459 mutex_exit(bus->ub_lock); 460 461 return USBD_NORMAL_COMPLETION; 462 } 463 464 /* Abort a root control request. */ 465 Static void 466 roothub_ctrl_abort(struct usbd_xfer *xfer) 467 { 468 469 /* Nothing to do, all transfers are synchronous. */ 470 } 471 472 /* Close the root pipe. */ 473 Static void 474 roothub_ctrl_close(struct usbd_pipe *pipe) 475 { 476 477 /* Nothing to do. */ 478 } 479 480 Static void 481 roothub_ctrl_done(struct usbd_xfer *xfer) 482 { 483 484 /* Nothing to do. */ 485 } 486 487 static void 488 roothub_noop(struct usbd_pipe *pipe) 489 { 490 491 } 492