1 /* $OpenBSD: uhub.c,v 1.98 2024/05/23 03:21:09 jsg Exp $ */ 2 /* $NetBSD: uhub.c,v 1.64 2003/02/08 03:32:51 ichiro Exp $ */ 3 /* $FreeBSD: src/sys/dev/usb/uhub.c,v 1.18 1999/11/17 22:33:43 n_hibma Exp $ */ 4 5 /* 6 * Copyright (c) 1998 The NetBSD Foundation, Inc. 7 * All rights reserved. 8 * 9 * This code is derived from software contributed to The NetBSD Foundation 10 * by Lennart Augustsson (lennart@augustsson.net) at 11 * Carlstedt Research & Technology. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 24 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 25 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 * POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/malloc.h> 38 #include <sys/device.h> 39 40 #include <machine/bus.h> 41 42 #include <dev/usb/usb.h> 43 #include <dev/usb/usbdi.h> 44 #include <dev/usb/usbdi_util.h> 45 #include <dev/usb/usbdivar.h> 46 47 #define UHUB_INTR_INTERVAL 255 /* ms */ 48 49 #ifdef UHUB_DEBUG 50 #define DPRINTF(x...) do { printf(x); } while (0) 51 #else 52 #define DPRINTF(x...) 53 #endif 54 55 #define DEVNAME(sc) ((sc)->sc_dev.dv_xname) 56 57 struct uhub_softc { 58 struct device sc_dev; /* base device */ 59 struct usbd_device *sc_hub; /* USB device */ 60 struct usbd_pipe *sc_ipipe; /* interrupt pipe */ 61 62 uint32_t sc_status; /* status from last interrupt */ 63 uint8_t *sc_statusbuf; /* per port status buffer */ 64 size_t sc_statuslen; /* status bufferlen */ 65 66 u_char sc_running; 67 }; 68 #define UHUB_PROTO(sc) ((sc)->sc_hub->ddesc.bDeviceProtocol) 69 #define UHUB_IS_HIGH_SPEED(sc) (UHUB_PROTO(sc) != UDPROTO_FSHUB) 70 #define UHUB_IS_SINGLE_TT(sc) (UHUB_PROTO(sc) == UDPROTO_HSHUBSTT) 71 72 int uhub_explore(struct usbd_device *hub); 73 void uhub_intr(struct usbd_xfer *, void *, usbd_status); 74 int uhub_port_connect(struct uhub_softc *, int, int); 75 76 /* 77 * We need two attachment points: 78 * hub to usb and hub to hub 79 * Every other driver only connects to hubs 80 */ 81 82 int uhub_match(struct device *, void *, void *); 83 void uhub_attach(struct device *, struct device *, void *); 84 int uhub_detach(struct device *, int); 85 86 struct cfdriver uhub_cd = { 87 NULL, "uhub", DV_DULL 88 }; 89 90 const struct cfattach uhub_ca = { 91 sizeof(struct uhub_softc), uhub_match, uhub_attach, uhub_detach 92 }; 93 94 const struct cfattach uhub_uhub_ca = { 95 sizeof(struct uhub_softc), uhub_match, uhub_attach, uhub_detach 96 }; 97 98 int 99 uhub_match(struct device *parent, void *match, void *aux) 100 { 101 struct usb_attach_arg *uaa = aux; 102 usb_device_descriptor_t *dd = usbd_get_device_descriptor(uaa->device); 103 104 if (uaa->iface == NULL) 105 return (UMATCH_NONE); 106 107 /* 108 * The subclass for hubs seems to be 0 for some and 1 for others, 109 * so we just ignore the subclass. 110 */ 111 if (dd->bDeviceClass == UDCLASS_HUB) 112 return (UMATCH_DEVCLASS_DEVSUBCLASS); 113 return (UMATCH_NONE); 114 } 115 116 void 117 uhub_attach(struct device *parent, struct device *self, void *aux) 118 { 119 struct uhub_softc *sc = (struct uhub_softc *)self; 120 struct usb_attach_arg *uaa = aux; 121 struct usbd_device *dev = uaa->device; 122 struct usbd_hub *hub = NULL; 123 union { 124 usb_hub_descriptor_t hs; 125 usb_hub_ss_descriptor_t ss; 126 } hd; 127 int p, port, nports, powerdelay; 128 struct usbd_interface *iface = uaa->iface; 129 usb_endpoint_descriptor_t *ed; 130 struct usbd_tt *tts = NULL; 131 uint8_t ttthink = 0; 132 usbd_status err; 133 #ifdef UHUB_DEBUG 134 int nremov; 135 #endif 136 137 sc->sc_hub = dev; 138 139 if (dev->depth > USB_HUB_MAX_DEPTH) { 140 printf("%s: hub depth (%d) exceeded, hub ignored\n", 141 sc->sc_dev.dv_xname, USB_HUB_MAX_DEPTH); 142 return; 143 } 144 145 /* 146 * Super-Speed hubs need to know their depth to be able to 147 * parse the bits of the route-string that correspond to 148 * their downstream port number. 149 * 150 * This does no apply to root hubs. 151 */ 152 if (dev->depth != 0 && dev->speed == USB_SPEED_SUPER) { 153 if (usbd_set_hub_depth(dev, dev->depth - 1)) { 154 printf("%s: unable to set HUB depth\n", 155 sc->sc_dev.dv_xname); 156 return; 157 } 158 } 159 160 /* Get hub descriptor. */ 161 if (dev->speed == USB_SPEED_SUPER) { 162 err = usbd_get_hub_ss_descriptor(dev, &hd.ss, 1); 163 nports = hd.ss.bNbrPorts; 164 powerdelay = (hd.ss.bPwrOn2PwrGood * UHD_PWRON_FACTOR); 165 if (!err && nports > 7) 166 usbd_get_hub_ss_descriptor(dev, &hd.ss, nports); 167 } else { 168 err = usbd_get_hub_descriptor(dev, &hd.hs, 1); 169 nports = hd.hs.bNbrPorts; 170 powerdelay = (hd.hs.bPwrOn2PwrGood * UHD_PWRON_FACTOR); 171 ttthink = UGETW(hd.hs.wHubCharacteristics) & UHD_TT_THINK; 172 if (!err && nports > 7) 173 usbd_get_hub_descriptor(dev, &hd.hs, nports); 174 } 175 176 if (err) { 177 DPRINTF("%s: getting hub descriptor failed, error=%s\n", 178 sc->sc_dev.dv_xname, usbd_errstr(err)); 179 return; 180 } 181 182 #ifdef UHUB_DEBUG 183 for (nremov = 0, port = 1; port <= nports; port++) { 184 if (dev->speed == USB_SPEED_SUPER) { 185 if (!UHD_NOT_REMOV(&hd.ss, port)) 186 nremov++; 187 } else { 188 if (!UHD_NOT_REMOV(&hd.hs, port)) 189 nremov++; 190 } 191 } 192 193 printf("%s: %d port%s with %d removable, %s powered", 194 sc->sc_dev.dv_xname, nports, nports != 1 ? "s" : "", 195 nremov, dev->self_powered ? "self" : "bus"); 196 197 if (dev->depth > 0 && UHUB_IS_HIGH_SPEED(sc)) { 198 printf(", %s transaction translator%s", 199 UHUB_IS_SINGLE_TT(sc) ? "single" : "multiple", 200 UHUB_IS_SINGLE_TT(sc) ? "" : "s"); 201 } 202 203 printf("\n"); 204 #endif 205 206 if (nports == 0) { 207 printf("%s: no ports, hub ignored\n", sc->sc_dev.dv_xname); 208 goto bad; 209 } 210 211 hub = malloc(sizeof(*hub), M_USBDEV, M_NOWAIT); 212 if (hub == NULL) 213 return; 214 hub->ports = mallocarray(nports, sizeof(struct usbd_port), 215 M_USBDEV, M_NOWAIT); 216 if (hub->ports == NULL) { 217 free(hub, M_USBDEV, sizeof *hub); 218 return; 219 } 220 dev->hub = hub; 221 dev->hub->hubsoftc = sc; 222 hub->explore = uhub_explore; 223 hub->nports = nports; 224 hub->powerdelay = powerdelay; 225 hub->ttthink = ttthink >> 5; 226 hub->multi = UHUB_IS_SINGLE_TT(sc) ? 0 : 1; 227 228 if (!dev->self_powered && dev->powersrc->parent != NULL && 229 !dev->powersrc->parent->self_powered) { 230 printf("%s: bus powered hub connected to bus powered hub, " 231 "ignored\n", sc->sc_dev.dv_xname); 232 goto bad; 233 } 234 235 /* Set up interrupt pipe. */ 236 ed = usbd_interface2endpoint_descriptor(iface, 0); 237 if (ed == NULL) { 238 printf("%s: no endpoint descriptor\n", sc->sc_dev.dv_xname); 239 goto bad; 240 } 241 if (UE_GET_XFERTYPE(ed->bmAttributes) != UE_INTERRUPT) { 242 printf("%s: bad interrupt endpoint\n", sc->sc_dev.dv_xname); 243 goto bad; 244 } 245 246 sc->sc_statuslen = (nports + 1 + 7) / 8; 247 sc->sc_statusbuf = malloc(sc->sc_statuslen, M_USBDEV, M_NOWAIT); 248 if (!sc->sc_statusbuf) 249 goto bad; 250 251 err = usbd_open_pipe_intr(iface, ed->bEndpointAddress, 252 USBD_SHORT_XFER_OK, &sc->sc_ipipe, sc, sc->sc_statusbuf, 253 sc->sc_statuslen, uhub_intr, UHUB_INTR_INTERVAL); 254 if (err) { 255 printf("%s: cannot open interrupt pipe\n", 256 sc->sc_dev.dv_xname); 257 goto bad; 258 } 259 260 /* Wait with power off for a while. */ 261 usbd_delay_ms(dev, USB_POWER_DOWN_TIME); 262 263 /* 264 * To have the best chance of success we do things in the exact same 265 * order as Windoze98. This should not be necessary, but some 266 * devices do not follow the USB specs to the letter. 267 * 268 * These are the events on the bus when a hub is attached: 269 * Get device and config descriptors (see attach code) 270 * Get hub descriptor (see above) 271 * For all ports 272 * turn on power 273 * wait for power to become stable 274 * (all below happens in explore code) 275 * For all ports 276 * clear C_PORT_CONNECTION 277 * For all ports 278 * get port status 279 * if device connected 280 * wait 100 ms 281 * turn on reset 282 * wait 283 * clear C_PORT_RESET 284 * get port status 285 * proceed with device attachment 286 */ 287 288 if (UHUB_IS_HIGH_SPEED(sc)) { 289 tts = mallocarray((UHUB_IS_SINGLE_TT(sc) ? 1 : nports), 290 sizeof(struct usbd_tt), M_USBDEV, M_NOWAIT); 291 if (!tts) 292 goto bad; 293 } 294 /* Set up data structures */ 295 for (p = 0; p < nports; p++) { 296 struct usbd_port *up = &hub->ports[p]; 297 up->device = NULL; 298 up->parent = dev; 299 up->portno = p + 1; 300 if (dev->self_powered) 301 /* Self powered hub, give ports maximum current. */ 302 up->power = USB_MAX_POWER; 303 else 304 up->power = USB_MIN_POWER; 305 up->restartcnt = 0; 306 up->reattach = 0; 307 if (UHUB_IS_HIGH_SPEED(sc)) { 308 up->tt = &tts[UHUB_IS_SINGLE_TT(sc) ? 0 : p]; 309 up->tt->hub = hub; 310 up->tt->hcpriv = NULL; 311 } else { 312 up->tt = NULL; 313 } 314 } 315 316 for (port = 1; port <= nports; port++) { 317 /* Turn the power on. */ 318 err = usbd_set_port_feature(dev, port, UHF_PORT_POWER); 319 if (err) 320 printf("%s: port %d power on failed, %s\n", 321 sc->sc_dev.dv_xname, port, 322 usbd_errstr(err)); 323 /* Make sure we check the port status at least once. */ 324 sc->sc_status |= (1 << port); 325 } 326 327 /* Wait for stable power. */ 328 if (dev->powersrc->parent != NULL) 329 usbd_delay_ms(dev, powerdelay + USB_EXTRA_POWER_UP_TIME); 330 331 /* The usual exploration will finish the setup. */ 332 333 sc->sc_running = 1; 334 335 return; 336 337 bad: 338 free(sc->sc_statusbuf, M_USBDEV, sc->sc_statuslen); 339 if (hub) { 340 free(hub->ports, M_USBDEV, hub->nports * sizeof(*hub->ports)); 341 free(hub, M_USBDEV, sizeof(*hub)); 342 } 343 dev->hub = NULL; 344 } 345 346 int 347 uhub_explore(struct usbd_device *dev) 348 { 349 struct uhub_softc *sc = dev->hub->hubsoftc; 350 struct usbd_port *up; 351 int status, change; 352 int port; 353 354 if (usbd_is_dying(sc->sc_hub)) 355 return (EIO); 356 357 if (!sc->sc_running) 358 return (ENXIO); 359 360 /* Ignore hubs that are too deep. */ 361 if (sc->sc_hub->depth > USB_HUB_MAX_DEPTH) 362 return (EOPNOTSUPP); 363 364 for (port = 1; port <= sc->sc_hub->hub->nports; port++) { 365 up = &sc->sc_hub->hub->ports[port-1]; 366 367 change = 0; 368 status = 0; 369 370 if ((sc->sc_status & (1 << port)) || up->reattach) { 371 sc->sc_status &= ~(1 << port); 372 373 if (usbd_get_port_status(dev, port, &up->status)) 374 continue; 375 376 status = UGETW(up->status.wPortStatus); 377 change = UGETW(up->status.wPortChange); 378 DPRINTF("%s: port %d status=0x%04x change=0x%04x\n", 379 sc->sc_dev.dv_xname, port, status, change); 380 } 381 382 if (up->reattach) { 383 change |= UPS_C_CONNECT_STATUS; 384 up->reattach = 0; 385 } 386 387 if (change & UPS_C_PORT_ENABLED) { 388 usbd_clear_port_feature(sc->sc_hub, port, 389 UHF_C_PORT_ENABLE); 390 if (change & UPS_C_CONNECT_STATUS) { 391 /* Ignore the port error if the device 392 vanished. */ 393 } else if (status & UPS_PORT_ENABLED) { 394 printf("%s: illegal enable change, port %d\n", 395 sc->sc_dev.dv_xname, port); 396 } else { 397 /* Port error condition. */ 398 if (up->restartcnt) /* no message first time */ 399 printf("%s: port error, restarting " 400 "port %d\n", 401 sc->sc_dev.dv_xname, port); 402 403 if (up->restartcnt++ < USBD_RESTART_MAX) 404 change |= UPS_C_CONNECT_STATUS; 405 else 406 printf("%s: port error, giving up " 407 "port %d\n", 408 sc->sc_dev.dv_xname, port); 409 } 410 } 411 412 if (change & UPS_C_PORT_RESET) { 413 usbd_clear_port_feature(sc->sc_hub, port, 414 UHF_C_PORT_RESET); 415 change |= UPS_C_CONNECT_STATUS; 416 } 417 418 if (change & UPS_C_BH_PORT_RESET && 419 sc->sc_hub->speed == USB_SPEED_SUPER) { 420 usbd_clear_port_feature(sc->sc_hub, port, 421 UHF_C_BH_PORT_RESET); 422 } 423 424 if (change & UPS_C_CONNECT_STATUS) { 425 if (uhub_port_connect(sc, port, status)) 426 continue; 427 428 /* The port set up succeeded, reset error count. */ 429 up->restartcnt = 0; 430 } 431 432 if (change & UPS_C_PORT_LINK_STATE) { 433 usbd_clear_port_feature(sc->sc_hub, port, 434 UHF_C_PORT_LINK_STATE); 435 } 436 437 /* Recursive explore. */ 438 if (up->device != NULL && up->device->hub != NULL) 439 up->device->hub->explore(up->device); 440 } 441 442 return (0); 443 } 444 445 /* 446 * Called from process context when the hub is gone. 447 * Detach all devices on active ports. 448 */ 449 int 450 uhub_detach(struct device *self, int flags) 451 { 452 struct uhub_softc *sc = (struct uhub_softc *)self; 453 struct usbd_hub *hub = sc->sc_hub->hub; 454 struct usbd_port *rup; 455 int port; 456 457 if (hub == NULL) /* Must be partially working */ 458 return (0); 459 460 usbd_close_pipe(sc->sc_ipipe); 461 462 for (port = 0; port < hub->nports; port++) { 463 rup = &hub->ports[port]; 464 if (rup->device != NULL) { 465 usbd_detach(rup->device, self); 466 rup->device = NULL; 467 } 468 } 469 470 free(hub->ports[0].tt, M_USBDEV, 471 (UHUB_IS_SINGLE_TT(sc) ? 1 : hub->nports) * sizeof(struct usbd_tt)); 472 free(sc->sc_statusbuf, M_USBDEV, sc->sc_statuslen); 473 free(hub->ports, M_USBDEV, hub->nports * sizeof(*hub->ports)); 474 free(hub, M_USBDEV, sizeof(*hub)); 475 sc->sc_hub->hub = NULL; 476 477 return (0); 478 } 479 480 /* 481 * This is an indication that some port has changed status. Remember 482 * the ports that need attention and notify the USB task thread that 483 * we need to be explored again. 484 */ 485 void 486 uhub_intr(struct usbd_xfer *xfer, void *addr, usbd_status status) 487 { 488 struct uhub_softc *sc = addr; 489 uint32_t stats = 0; 490 int i; 491 492 if (usbd_is_dying(sc->sc_hub)) 493 return; 494 495 DPRINTF("%s: intr status=%d\n", sc->sc_dev.dv_xname, status); 496 497 if (status == USBD_STALLED) 498 usbd_clear_endpoint_stall_async(sc->sc_ipipe); 499 else if (status == USBD_NORMAL_COMPLETION) { 500 for (i = 0; i < xfer->actlen; i++) 501 stats |= (uint32_t)(xfer->buffer[i]) << (i * 8); 502 sc->sc_status |= stats; 503 504 usb_needs_explore(sc->sc_hub, 0); 505 } 506 } 507 508 int 509 uhub_port_connect(struct uhub_softc *sc, int port, int status) 510 { 511 struct usbd_port *up = &sc->sc_hub->hub->ports[port-1]; 512 int speed, change; 513 514 /* We have a connect status change, handle it. */ 515 usbd_clear_port_feature(sc->sc_hub, port, UHF_C_PORT_CONNECTION); 516 517 /* 518 * If there is already a device on the port the change status 519 * must mean that is has disconnected. Looking at the 520 * current connect status is not enough to figure this out 521 * since a new unit may have been connected before we handle 522 * the disconnect. 523 */ 524 if (up->device != NULL) { 525 /* Disconnected */ 526 usbd_detach(up->device, &sc->sc_dev); 527 up->device = NULL; 528 } 529 530 /* Nothing connected, just ignore it. */ 531 if ((status & UPS_CURRENT_CONNECT_STATUS) == 0) 532 return (0); 533 534 /* Connected */ 535 if ((status & (UPS_PORT_POWER|UPS_PORT_POWER_SS)) == 0) { 536 printf("%s: connected port %d has no power\n", DEVNAME(sc), 537 port); 538 return (-1); 539 } 540 541 /* Wait for maximum device power up time. */ 542 usbd_delay_ms(sc->sc_hub, USB_PORT_POWERUP_DELAY); 543 544 /* Reset port, which implies enabling it. */ 545 if (usbd_reset_port(sc->sc_hub, port)) { 546 printf("%s: port %d reset failed\n", DEVNAME(sc), port); 547 return (-1); 548 } 549 /* Get port status again, it might have changed during reset */ 550 if (usbd_get_port_status(sc->sc_hub, port, &up->status)) 551 return (-1); 552 553 status = UGETW(up->status.wPortStatus); 554 change = UGETW(up->status.wPortChange); 555 DPRINTF("%s: port %d status=0x%04x change=0x%04x\n", DEVNAME(sc), 556 port, status, change); 557 558 /* Nothing connected, just ignore it. */ 559 if ((status & UPS_CURRENT_CONNECT_STATUS) == 0) { 560 DPRINTF("%s: port %d, device disappeared after reset\n", 561 DEVNAME(sc), port); 562 return (-1); 563 } 564 565 /* 566 * Figure out device speed. This is a bit tricky because 567 * UPS_PORT_POWER_SS and UPS_LOW_SPEED share the same bit. 568 */ 569 if ((status & UPS_PORT_POWER) == 0) 570 status &= ~UPS_PORT_POWER_SS; 571 572 if (status & UPS_HIGH_SPEED) 573 speed = USB_SPEED_HIGH; 574 else if (status & UPS_LOW_SPEED) 575 speed = USB_SPEED_LOW; 576 else { 577 /* 578 * If there is no power bit set, it is certainly 579 * a Super Speed device, so use the speed of its 580 * parent hub. 581 */ 582 if (status & UPS_PORT_POWER) 583 speed = USB_SPEED_FULL; 584 else 585 speed = sc->sc_hub->speed; 586 } 587 588 /* 589 * Reduce the speed, otherwise we won't setup the proper 590 * transfer methods. 591 */ 592 if (speed > sc->sc_hub->speed) 593 speed = sc->sc_hub->speed; 594 595 /* Get device info and set its address. */ 596 if (usbd_new_device(&sc->sc_dev, sc->sc_hub->bus, sc->sc_hub->depth + 1, 597 speed, port, up)) { 598 /* 599 * The unit refused to accept a new address, or had 600 * some other serious problem. Since we cannot leave 601 * at 0 we have to disable the port instead. 602 */ 603 printf("%s: device problem, disabling port %d\n", DEVNAME(sc), 604 port); 605 usbd_clear_port_feature(sc->sc_hub, port, UHF_PORT_ENABLE); 606 607 return (-1); 608 } 609 610 return (0); 611 } 612