1 /* $FreeBSD$ */ 2 /*- 3 * SPDX-License-Identifier: BSD-2-Clause-NetBSD 4 * 5 * Copyright (c) 1998 The NetBSD Foundation, Inc. All rights reserved. 6 * Copyright (c) 1998 Lennart Augustsson. All rights reserved. 7 * Copyright (c) 2008-2010 Hans Petter Selasky. All rights reserved. 8 * Copyright (c) 2019 Takanori Watanabe. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 /* 33 * USB spec: http://www.usb.org/developers/docs/usbspec.zip 34 */ 35 36 #ifdef USB_GLOBAL_INCLUDE_FILE 37 #include USB_GLOBAL_INCLUDE_FILE 38 #else 39 #include <sys/stdint.h> 40 #include <sys/stddef.h> 41 #include <sys/param.h> 42 #include <sys/queue.h> 43 #include <sys/types.h> 44 #include <sys/systm.h> 45 #include <sys/kernel.h> 46 #include <sys/bus.h> 47 #include <sys/module.h> 48 #include <sys/lock.h> 49 #include <sys/mutex.h> 50 #include <sys/condvar.h> 51 #include <sys/sysctl.h> 52 #include <sys/sx.h> 53 #include <sys/unistd.h> 54 #include <sys/callout.h> 55 #include <sys/malloc.h> 56 #include <sys/priv.h> 57 58 #include <dev/usb/usb.h> 59 #include <dev/usb/usbdi.h> 60 #include <dev/usb/usbdi_util.h> 61 62 #define USB_DEBUG_VAR uhub_debug 63 64 #include <dev/usb/usb_core.h> 65 #include <dev/usb/usb_process.h> 66 #include <dev/usb/usb_device.h> 67 #include <dev/usb/usb_request.h> 68 #include <dev/usb/usb_debug.h> 69 #include <dev/usb/usb_hub.h> 70 #include <dev/usb/usb_util.h> 71 #include <dev/usb/usb_busdma.h> 72 #include <dev/usb/usb_transfer.h> 73 #include <dev/usb/usb_dynamic.h> 74 75 #include <dev/usb/usb_controller.h> 76 #include <dev/usb/usb_bus.h> 77 #endif /* USB_GLOBAL_INCLUDE_FILE */ 78 #include <dev/usb/usb_hub_private.h> 79 #include <contrib/dev/acpica/include/acpi.h> 80 #include <contrib/dev/acpica/include/accommon.h> 81 #include <dev/acpica/acpivar.h> 82 #include <sys/sbuf.h> 83 84 #define ACPI_PLD_SIZE 20 85 struct acpi_uhub_port { 86 ACPI_HANDLE handle; 87 #define ACPI_UPC_CONNECTABLE 0x80000000 88 #define ACPI_UPC_PORTTYPE(x) ((x)&0xff) 89 uint32_t upc; 90 uint8_t pld[ACPI_PLD_SIZE]; 91 }; 92 93 struct acpi_uhub_softc { 94 struct uhub_softc usc; 95 uint8_t nports; 96 ACPI_HANDLE ah; 97 struct acpi_uhub_port *port; 98 }; 99 100 static UINT32 101 acpi_uhub_find_rh_cb(ACPI_HANDLE ah, UINT32 nl, void *ctx, void **status) 102 { 103 ACPI_DEVICE_INFO *devinfo; 104 UINT32 ret; 105 106 *status = NULL; 107 devinfo = NULL; 108 109 ret = AcpiGetObjectInfo(ah, &devinfo); 110 if (ACPI_SUCCESS(ret)) { 111 if ((devinfo->Valid & ACPI_VALID_ADR) && 112 (devinfo->Address == 0)) { 113 ret = AE_CTRL_TERMINATE; 114 *status = ah; 115 } 116 AcpiOsFree(devinfo); 117 } 118 return (ret); 119 } 120 121 static const char * 122 acpi_uhub_upc_type(uint8_t type) 123 { 124 const char *typelist[] = {"TypeA", "MiniAB", "Express", 125 "USB3-A", "USB3-B", "USB-MicroB", 126 "USB3-MicroAB", "USB3-PowerB", 127 "TypeC-USB2", "TypeC-Switch", 128 "TypeC-nonSwitch"}; 129 const int last = sizeof(typelist) / sizeof(typelist[0]); 130 131 if (type == 0xff) { 132 return "Proprietary"; 133 } 134 135 return (type < last) ? typelist[type] : "Unknown"; 136 } 137 138 static int 139 acpi_uhub_parse_upc(device_t dev, unsigned int p, ACPI_HANDLE ah, struct sysctl_oid_list *poid) 140 { 141 ACPI_BUFFER buf; 142 struct acpi_uhub_softc *sc = device_get_softc(dev); 143 struct acpi_uhub_port *port = &sc->port[p - 1]; 144 145 buf.Pointer = NULL; 146 buf.Length = ACPI_ALLOCATE_BUFFER; 147 148 if (AcpiEvaluateObject(ah, "_UPC", NULL, &buf) == AE_OK) { 149 ACPI_OBJECT *obj = buf.Pointer; 150 UINT64 porttypenum, conn; 151 uint8_t *connectable; 152 153 acpi_PkgInt(obj, 0, &conn); 154 acpi_PkgInt(obj, 1, &porttypenum); 155 connectable = conn ? "" : "non"; 156 157 port->upc = porttypenum; 158 port->upc |= (conn) ? (ACPI_UPC_CONNECTABLE) : 0; 159 160 if (usb_debug) 161 device_printf(dev, "Port %u %sconnectable %s\n", 162 p, connectable, 163 acpi_uhub_upc_type(porttypenum)); 164 165 SYSCTL_ADD_U32( 166 device_get_sysctl_ctx(dev), 167 poid, OID_AUTO, 168 "upc", 169 CTLFLAG_RD | CTLFLAG_MPSAFE, 170 SYSCTL_NULL_U32_PTR, port->upc, 171 "UPC value. MSB is visible flag"); 172 } 173 AcpiOsFree(buf.Pointer); 174 175 return (0); 176 } 177 static int 178 acpi_uhub_port_sysctl(SYSCTL_HANDLER_ARGS) 179 { 180 struct acpi_uhub_port *port = oidp->oid_arg1; 181 struct sbuf sb; 182 int error; 183 184 sbuf_new_for_sysctl(&sb, NULL, 256, req); 185 sbuf_printf(&sb, "Handle %s\n", acpi_name(port->handle)); 186 if (port->upc == 0xffffffff) { 187 sbuf_printf(&sb, "\tNo information\n"); 188 goto end; 189 } 190 sbuf_printf(&sb, "\t"); 191 if (port->upc & ACPI_UPC_CONNECTABLE) { 192 sbuf_printf(&sb, "Connectable "); 193 } 194 sbuf_printf(&sb, "%s port\n", acpi_uhub_upc_type(port->upc & 0xff)); 195 196 if ((port->pld[0] & 0x80) == 0) { 197 sbuf_printf(&sb, 198 "\tColor:#%02x%02x%02x\n", 199 port->pld[1], port->pld[2], 200 port->pld[3]); 201 } 202 sbuf_printf(&sb, "\tWidth %d mm Height %d mm\n", 203 port->pld[4] | (port->pld[5] << 8), 204 port->pld[6] | (port->pld[7] << 8)); 205 if (port->pld[8] & 1) { 206 sbuf_printf(&sb, "\tVisible\n"); 207 } 208 if (port->pld[8] & 2) { 209 sbuf_printf(&sb, "\tDock\n"); 210 } 211 if (port->pld[8] & 4) { 212 sbuf_printf(&sb, "\tLid\n"); 213 } { 214 int panelpos = (port->pld[8] >> 3) & 7; 215 const char *panposstr[] = {"Top", "Bottom", "Left", 216 "Right", "Front", "Back", 217 "Unknown", "Invalid"}; 218 const char *shapestr[] = { 219 "Round", "Oval", "Square", "VRect", "HRect", 220 "VTrape", "HTrape", "Unknown", "Chamferd", 221 "Rsvd", "Rsvd", "Rsvd", "Rsvd", 222 "Rsvd", "Rsvd", "Rsvd", "Rsvd"}; 223 224 sbuf_printf(&sb, "\tPanelPosition: %s\n", panposstr[panelpos]); 225 if (panelpos < 6) { 226 const char *posstr[] = {"Upper", "Center", 227 "Lower", "Invalid"}; 228 229 sbuf_printf(&sb, "\tVertPosition: %s\n", 230 posstr[(port->pld[8] >> 6) & 3]); 231 sbuf_printf(&sb, "\tHorizPosition: %s\n", 232 posstr[(port->pld[9]) & 3]); 233 234 235 } 236 sbuf_printf(&sb, "\tShape: %s\n", 237 shapestr[(port->pld[9] >> 2) & 0xf]); 238 sbuf_printf(&sb, "\tGroup Orientation %s\n", 239 ((port->pld[9] >> 6) & 1) ? "Vertical" : 240 "Horizontal"); 241 sbuf_printf(&sb, "\tGroupToken %x\n", 242 ((port->pld[9] >> 7) 243 | (port->pld[10] << 1)) & 0xff); 244 sbuf_printf(&sb, "\tGroupPosition %x\n", 245 ((port->pld[10] >> 7) 246 | (port->pld[11] << 1)) & 0xff); 247 sbuf_printf(&sb, "\t%s %s %s\n", 248 (port->pld[11] & 0x80) ? 249 "Bay" : "", 250 (port->pld[12] & 1) ? "Eject" : "", 251 (port->pld[12] & 2) ? "OSPM" : "" 252 ); 253 } 254 if ((port->pld[0] & 0x7f) >= 2) { 255 sbuf_printf(&sb, "\tVOFF%d mm HOFF %dmm", 256 port->pld[16] | (port->pld[17] << 8), 257 port->pld[18] | (port->pld[19] << 8)); 258 } 259 260 end: 261 error = sbuf_finish(&sb); 262 sbuf_delete(&sb); 263 return (error); 264 } 265 266 static int 267 acpi_uhub_parse_pld(device_t dev, unsigned int p, ACPI_HANDLE ah, struct sysctl_oid_list *tree) 268 { 269 ACPI_BUFFER buf; 270 struct acpi_uhub_softc *sc = device_get_softc(dev); 271 struct acpi_uhub_port *port = &sc->port[p - 1]; 272 273 buf.Pointer = NULL; 274 buf.Length = ACPI_ALLOCATE_BUFFER; 275 276 if (AcpiEvaluateObject(ah, "_PLD", NULL, &buf) == AE_OK) { 277 ACPI_OBJECT *obj; 278 unsigned char *resbuf; 279 int len; 280 281 obj = buf.Pointer; 282 283 if (obj->Type == ACPI_TYPE_PACKAGE 284 && obj->Package.Elements[0].Type == ACPI_TYPE_BUFFER) { 285 ACPI_OBJECT *obj1; 286 287 obj1 = &obj->Package.Elements[0]; 288 len = obj1->Buffer.Length; 289 resbuf = obj1->Buffer.Pointer; 290 } else if (obj->Type == ACPI_TYPE_BUFFER) { 291 len = obj->Buffer.Length; 292 resbuf = obj->Buffer.Pointer; 293 } else { 294 goto skip; 295 } 296 len = (len < ACPI_PLD_SIZE) ? len : ACPI_PLD_SIZE; 297 memcpy(port->pld, resbuf, len); 298 SYSCTL_ADD_OPAQUE( 299 device_get_sysctl_ctx(dev), tree, OID_AUTO, 300 "pldraw", CTLFLAG_RD | CTLFLAG_MPSAFE, 301 port->pld, len, "A", "Raw PLD value"); 302 303 if (usb_debug) { 304 device_printf(dev, "Revision:%d\n", 305 resbuf[0] & 0x7f); 306 if ((resbuf[0] & 0x80) == 0) { 307 device_printf(dev, 308 "Color:#%02x%02x%02x\n", 309 resbuf[1], resbuf[2], 310 resbuf[3]); 311 } 312 device_printf(dev, "Width %d mm Height %d mm\n", 313 resbuf[4] | (resbuf[5] << 8), 314 resbuf[6] | (resbuf[7] << 8)); 315 if (resbuf[8] & 1) { 316 device_printf(dev, "Visible\n"); 317 } 318 if (resbuf[8] & 2) { 319 device_printf(dev, "Dock\n"); 320 } 321 if (resbuf[8] & 4) { 322 device_printf(dev, "Lid\n"); 323 } 324 device_printf(dev, "PanelPosition: %d\n", 325 (resbuf[8] >> 3) & 7); 326 device_printf(dev, "VertPosition: %d\n", 327 (resbuf[8] >> 6) & 3); 328 device_printf(dev, "HorizPosition: %d\n", 329 (resbuf[9]) & 3); 330 device_printf(dev, "Shape: %d\n", 331 (resbuf[9] >> 2) & 0xf); 332 device_printf(dev, "80: %02x, %02x, %02x\n", 333 resbuf[9], resbuf[10], resbuf[11]); 334 device_printf(dev, "96: %02x, %02x, %02x, %02x\n", 335 resbuf[12], resbuf[13], 336 resbuf[14], resbuf[15]); 337 338 if ((resbuf[0] & 0x7f) >= 2) { 339 device_printf(dev, "VOFF%d mm HOFF %dmm", 340 resbuf[16] | (resbuf[17] << 8), 341 resbuf[18] | (resbuf[19] << 8)); 342 } 343 } 344 skip: 345 AcpiOsFree(buf.Pointer); 346 } 347 return (0); 348 } 349 350 static ACPI_STATUS 351 acpi_uhub_find_rh(device_t dev, ACPI_HANDLE *ah) 352 { 353 device_t grand; 354 ACPI_HANDLE gah; 355 356 *ah = NULL; 357 grand = device_get_parent(device_get_parent(dev)); 358 359 if ((gah = acpi_get_handle(grand)) == NULL) 360 return (AE_ERROR); 361 362 return (AcpiWalkNamespace(ACPI_TYPE_DEVICE, gah, 1, 363 acpi_uhub_find_rh_cb, NULL, dev, ah)); 364 } 365 366 static ACPI_STATUS 367 acpi_usb_hub_port_probe_cb(ACPI_HANDLE ah, UINT32 lv, void *ctx, void **rv) 368 { 369 ACPI_DEVICE_INFO *devinfo; 370 device_t dev = ctx; 371 struct acpi_uhub_softc *sc = device_get_softc(dev); 372 UINT32 ret; 373 374 ret = AcpiGetObjectInfo(ah, &devinfo); 375 if (ACPI_SUCCESS(ret)) { 376 if ((devinfo->Valid & ACPI_VALID_ADR) && 377 (devinfo->Address > 0) && 378 (devinfo->Address <= (uint64_t)sc->nports)) { 379 char buf[] = "portXXX"; 380 struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); 381 struct sysctl_oid *oid; 382 struct sysctl_oid_list *tree; 383 384 snprintf(buf, sizeof(buf), "port%ju", 385 (uintmax_t)devinfo->Address); 386 oid = SYSCTL_ADD_NODE(ctx, 387 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 388 OID_AUTO, buf, CTLFLAG_RD | CTLFLAG_MPSAFE, 389 NULL, "port nodes"); 390 tree = SYSCTL_CHILDREN(oid); 391 sc->port[devinfo->Address - 1].handle = ah; 392 sc->port[devinfo->Address - 1].upc = 0xffffffff; 393 acpi_uhub_parse_upc(dev, devinfo->Address, ah, tree); 394 acpi_uhub_parse_pld(dev, devinfo->Address, ah, tree); 395 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), tree, 396 OID_AUTO, "info", 397 CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, 398 &sc->port[devinfo->Address - 1], 0, 399 acpi_uhub_port_sysctl, "A", "Port information"); 400 } 401 AcpiOsFree(devinfo); 402 } 403 return (AE_OK); 404 } 405 406 static ACPI_STATUS 407 acpi_usb_hub_port_probe(device_t dev, ACPI_HANDLE ah) 408 { 409 return (AcpiWalkNamespace(ACPI_TYPE_DEVICE, 410 ah, 1, 411 acpi_usb_hub_port_probe_cb, 412 NULL, dev, NULL)); 413 } 414 415 static int 416 acpi_uhub_root_probe(device_t dev) 417 { 418 ACPI_STATUS status; 419 ACPI_HANDLE ah; 420 421 if (acpi_disabled("usb")) 422 return (ENXIO); 423 424 status = acpi_uhub_find_rh(dev, &ah); 425 if (ACPI_SUCCESS(status) && ah != NULL && 426 uhub_probe(dev) <= 0) { 427 /* success prior than non-ACPI USB HUB */ 428 return (BUS_PROBE_DEFAULT + 1); 429 } 430 return (ENXIO); 431 } 432 433 static int 434 acpi_uhub_probe(device_t dev) 435 { 436 ACPI_HANDLE ah; 437 438 if (acpi_disabled("usb")) 439 return (ENXIO); 440 441 ah = acpi_get_handle(dev); 442 if (ah == NULL) 443 return (ENXIO); 444 445 if (uhub_probe(dev) <= 0) { 446 /* success prior than non-ACPI USB HUB */ 447 return (BUS_PROBE_DEFAULT + 1); 448 } 449 return (ENXIO); 450 } 451 static int 452 acpi_uhub_attach_common(device_t dev) 453 { 454 struct usb_hub *uh; 455 struct acpi_uhub_softc *sc = device_get_softc(dev); 456 ACPI_STATUS status; 457 int ret = ENXIO; 458 459 uh = sc->usc.sc_udev->hub; 460 sc->nports = uh->nports; 461 sc->port = malloc(sizeof(struct acpi_uhub_port) * uh->nports, 462 M_USBDEV, M_WAITOK | M_ZERO); 463 status = acpi_usb_hub_port_probe(dev, sc->ah); 464 465 if (ACPI_SUCCESS(status)){ 466 ret = 0; 467 } 468 469 return (ret); 470 } 471 472 static int 473 acpi_uhub_detach(device_t dev) 474 { 475 struct acpi_uhub_softc *sc = device_get_softc(dev); 476 477 free(sc->port, M_USBDEV); 478 479 return (uhub_detach(dev)); 480 } 481 482 static int 483 acpi_uhub_root_attach(device_t dev) 484 { 485 int ret; 486 struct acpi_uhub_softc *sc = device_get_softc(dev); 487 488 if (ACPI_FAILURE(acpi_uhub_find_rh(dev, &sc->ah)) || 489 (sc->ah == NULL)) { 490 return (ENXIO); 491 } 492 if ((ret = uhub_attach(dev)) != 0) { 493 return (ret); 494 } 495 496 if ((ret = acpi_uhub_attach_common(dev)) != 0) { 497 acpi_uhub_detach(dev); 498 } 499 return ret; 500 } 501 502 static int 503 acpi_uhub_attach(device_t dev) 504 { 505 int ret; 506 struct acpi_uhub_softc *sc = device_get_softc(dev); 507 508 sc->ah = acpi_get_handle(dev); 509 510 if (sc->ah == NULL) { 511 return (ENXIO); 512 } 513 if ((ret = uhub_attach(dev)) != 0) { 514 return (ret); 515 } 516 517 if ((ret = acpi_uhub_attach_common(dev)) != 0) { 518 acpi_uhub_detach(dev); 519 } 520 521 return (ret); 522 } 523 524 static int 525 acpi_uhub_read_ivar(device_t dev, device_t child, int idx, uintptr_t *res) 526 { 527 struct hub_result hres; 528 struct acpi_uhub_softc *sc = device_get_softc(dev); 529 ACPI_HANDLE ah; 530 531 mtx_lock(&Giant); 532 uhub_find_iface_index(sc->usc.sc_udev->hub, child, &hres); 533 mtx_unlock(&Giant); 534 535 if ((idx == ACPI_IVAR_HANDLE) && 536 (hres.portno > 0) && 537 (hres.portno <= sc->nports) && 538 (ah = sc->port[hres.portno - 1].handle)) { 539 *res = (uintptr_t)ah; 540 return (0); 541 } 542 return (ENXIO); 543 } 544 545 static int 546 acpi_uhub_child_location_string(device_t parent, device_t child, 547 char *buf, size_t buflen) 548 { 549 ACPI_HANDLE ah; 550 551 uhub_child_location_string(parent, child, buf, buflen); 552 553 ah = acpi_get_handle(child); 554 if (ah != NULL) { 555 strlcat(buf, " handle=", buflen); 556 strlcat(buf, acpi_name(ah), buflen); 557 } 558 return (0); 559 } 560 561 562 static device_method_t acpi_uhub_methods[] = { 563 DEVMETHOD(device_probe, acpi_uhub_probe), 564 DEVMETHOD(device_attach, acpi_uhub_attach), 565 DEVMETHOD(device_detach, acpi_uhub_detach), 566 DEVMETHOD(bus_child_location_str, acpi_uhub_child_location_string), 567 DEVMETHOD(bus_read_ivar, acpi_uhub_read_ivar), 568 DEVMETHOD_END 569 570 }; 571 572 static device_method_t acpi_uhub_root_methods[] = { 573 DEVMETHOD(device_probe, acpi_uhub_root_probe), 574 DEVMETHOD(device_attach, acpi_uhub_root_attach), 575 DEVMETHOD(device_detach, acpi_uhub_detach), 576 DEVMETHOD(bus_read_ivar, acpi_uhub_read_ivar), 577 DEVMETHOD(bus_child_location_str, acpi_uhub_child_location_string), 578 DEVMETHOD_END 579 }; 580 581 static devclass_t uhub_devclass; 582 extern driver_t uhub_driver; 583 static kobj_class_t uhub_baseclasses[] = {&uhub_driver, NULL}; 584 585 static driver_t acpi_uhub_driver = { 586 .name = "uhub", 587 .methods = acpi_uhub_methods, 588 .size = sizeof(struct acpi_uhub_softc), 589 .baseclasses = uhub_baseclasses, 590 }; 591 592 static driver_t acpi_uhub_root_driver = { 593 .name = "uhub", 594 .methods = acpi_uhub_root_methods, 595 .size = sizeof(struct acpi_uhub_softc), 596 .baseclasses = uhub_baseclasses, 597 }; 598 599 DRIVER_MODULE(uacpi, uhub, acpi_uhub_driver, uhub_devclass, 0, 0); 600 DRIVER_MODULE(uacpi, usbus, acpi_uhub_root_driver, uhub_devclass, 0, 0); 601 602 MODULE_DEPEND(uacpi, acpi, 1, 1, 1); 603 MODULE_DEPEND(uacpi, usb, 1, 1, 1); 604 605 MODULE_VERSION(uacpi, 1); 606