1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright (c) 2018, Joyent, Inc. 14 */ 15 16 /* 17 * The purpose of this module is to build topology information for USB devices. 18 * USB devices are more complicated to build topology information for, as there 19 * are multiple sources of information needed to correctly understand the 20 * topology, and the way they present themselves is not always straightforward. 21 * 22 * We enumerate two different types of devices: 23 * 24 * o USB ports 25 * o USB devices 26 * 27 * A USB port represents a logical port, while a USB device represents an actual 28 * device that's been plugged in. If a device is a hub, then we'll enumerate 29 * that device as well. 30 * 31 * Now, some basics. There are several different USB controllers that exist in 32 * the system. Some are part of the chipset, while others may be present via 33 * add-on cards. The system interfaces initially with USB devices through a host 34 * controller. Prior to USB 3.0/xhci, a single controller only supported a 35 * single protocol. With USB 3.0, it is possible for a port to share wiring with 36 * both USB 2.0 devices and USB 3.0 devices. However, to the host controller 37 * this appears as two different logical ports. 38 * 39 * To make matters worse, during the transition to USB 3, the ports that were 40 * controlled could be routed to and from a USB 2 controller to a USB 3 41 * controller. This means that there are a lot of ways for ports to overlap. 42 * 43 * In the first case, controllers define a way to perform this mapping by 44 * leveraging ACPI information. Of course, this only helps us if the platform 45 * provides ACPI information, which it may not. When we do know that two ports 46 * are actually the same port, either because of ACPI or because of a 47 * product-specific mapping file, then we'll use that to say two ports are the 48 * same. Otherwise, we'll enumerate them as two separate logical ports. 49 * 50 * To perform the actual enumeration, the first time we're asked to enumerate a 51 * node, we go through and put together an entire picture of all of the USB 52 * devices in the system. This is done so we can make sure to enumerate devices 53 * under specific devices. The actual topology is determined in a few different 54 * passes. 55 * 56 * Before we walk any trees, we look to see if we have a topo USB metadata file 57 * and if present, load it. However, we do not apply any information from it. 58 * 59 * The first pass uses the devinfo tree to determine all of the USB controllers 60 * and devices that are in the system. We use properties in the devices tree to 61 * identify whether items are a root hub. When a root hub is found, we walk all 62 * of its children and make a note of all of the logical ports under it. 63 * 64 * Next, we walk the information provided by ACPI to try and reduplicate 65 * information about the ports on the system. If the USB topology metadata tells 66 * us that we should not skip ACPI, then we use it. This is done by walking the 67 * /devices/fw tree, looking for USB nodes and then linking them to their 68 * corresponding entries found from the first devinfo walk. 69 * 70 * Finally, we go back and apply metadata to ports that match. 71 * 72 * 73 * To logically keep track of all of this, we have several different structures: 74 * 75 * topo_usb_controller_t - Represents a physical controller. 76 * topo_usb_port_t - Represents a physical port. This is a synthetic 77 * construct that we put together based on ACPI 78 * information. 79 * topo_usb_lport_t - Represents a logical port. This is what the OS 80 * actually detects and sees. Each logical port 81 * belongs to a corresponding topo_usb_port_t. 82 * topo_usb_t - Represents the overall topology enumeration state. 83 * 84 * 85 * This topo module is invoked at three different points by the surrounding code 86 * and logic. Specifically: 87 * 88 * * Dynamically by the pcibus enumerator when we encounter PCI add on cards 89 * which are present in a physical slot. Traditional chipset devices are not 90 * considered a part of this. 91 * 92 * * Statically under the motherboard. All ports that don't belong to a PCI 93 * device are assumed to belong under the motherboard, unless a 94 * platform-specific topology map maps them under the chassis. 95 * 96 * * Statically under the chassis. Ports are only placed under the chassis if 97 * a platform-specific topology file indicates that the port is a part of 98 * the chassis. 99 */ 100 101 #include <libdevinfo.h> 102 #include <strings.h> 103 #include <sys/types.h> 104 #include <sys/stat.h> 105 #include <fcntl.h> 106 #include <dirent.h> 107 #include <sys/debug.h> 108 #include <unistd.h> 109 110 #include <sys/fm/protocol.h> 111 #include <fm/topo_mod.h> 112 #include <fm/topo_list.h> 113 #include <fm/topo_method.h> 114 115 #include <topo_port.h> 116 117 #include "topo_usb.h" 118 #include "topo_usb_int.h" 119 120 typedef enum topo_usb_type { 121 TOPO_USB_PCI, 122 TOPO_USB_MOBO, 123 TOPO_USB_CHASSIS 124 } topo_usb_type_t; 125 126 typedef enum topo_usb_cdrv { 127 TOPO_USB_D_UNKNOWN, 128 TOPO_USB_D_UHCI, 129 TOPO_USB_D_OHCI, 130 TOPO_USB_D_EHCI, 131 TOPO_USB_D_XHCI 132 } topo_usb_cdrv_t; 133 134 typedef enum topo_usb_protocol { 135 TOPO_USB_P_UNKNOWN, 136 TOPO_USB_P_1x, 137 TOPO_USB_P_20, 138 TOPO_USB_P_30, 139 TOPO_USB_P_31 140 } topo_usb_protocol_t; 141 142 typedef enum topo_usb_port_connected { 143 TOPO_USB_C_UNKNOWN, 144 TOPO_USB_C_DISCONNECTED, 145 TOPO_USB_C_CONNECTED 146 } topo_usb_port_connected_t; 147 148 typedef struct topo_usb_port { 149 topo_list_t tup_link; 150 uint_t tup_nlports; 151 topo_list_t tup_lports; 152 boolean_t tup_pld_valid; 153 acpi_pld_info_t tup_pld; 154 uint_t tup_port_type; 155 topo_usb_port_connected_t tup_port_connected; 156 topo_usb_meta_port_t *tup_meta; 157 } topo_usb_port_t; 158 159 typedef struct topo_usb_lport { 160 topo_list_t tul_link; 161 uint_t tul_portno; 162 topo_usb_protocol_t tul_protocol; 163 di_node_t tul_device; 164 di_node_t tul_acpi_device; 165 topo_usb_port_t *tul_port; 166 uint_t tul_nhubd_ports; 167 uint_t tul_nports; 168 topo_list_t tul_ports; 169 char tul_name[PATH_MAX]; 170 const char *tul_acpi_name; 171 } topo_usb_lport_t; 172 173 typedef struct topo_usb_controller { 174 topo_list_t tuc_link; 175 di_node_t tuc_devinfo; 176 char *tuc_path; 177 char *tuc_acpi_path; 178 char tuc_name[PATH_MAX]; 179 topo_usb_cdrv_t tuc_driver; 180 /* 181 * Number of actual ports we've created (some of the logical ports are 182 * deduped). 183 */ 184 uint_t tuc_nports; 185 topo_list_t tuc_ports; 186 /* 187 * Total number of logical ports we expect to exist on this controller. 188 * This may be greater than the number of actual ports we've created 189 * under it because some physical ports represent more than one logical 190 * port (xhci with USB2/3). 191 */ 192 uint_t tuc_nhubd_ports; 193 /* 194 * Keep track of port number and offset information. This is only done 195 * for xhci. 196 */ 197 uint_t tuc_nusb20; 198 uint_t tuc_fusb20; 199 uint_t tuc_nusb30; 200 uint_t tuc_fusb30; 201 uint_t tuc_nusb31; 202 uint_t tuc_fusb31; 203 boolean_t tuc_enumed; 204 } topo_usb_controller_t; 205 206 typedef struct topo_usb { 207 topo_list_t tu_controllers; 208 boolean_t tu_enum_done; 209 di_node_t tu_devinfo; 210 topo_list_t tu_metadata; 211 topo_usb_meta_flags_t tu_meta_flags; 212 topo_list_t tu_chassis_ports; 213 uint_t tu_nchassis_ports; 214 } topo_usb_t; 215 216 typedef struct topo_usb_devcfg_arg { 217 topo_usb_t *tda_usb; 218 topo_mod_t *tda_mod; 219 boolean_t tda_fatal; 220 } topo_usb_devcfg_arg_t; 221 222 static const topo_pgroup_info_t topo_usb_port_pgroup = { 223 TOPO_PGROUP_USB_PORT, 224 TOPO_STABILITY_PRIVATE, 225 TOPO_STABILITY_PRIVATE, 226 1 227 }; 228 229 static const topo_pgroup_info_t topo_io_pgroup = { 230 TOPO_PGROUP_IO, 231 TOPO_STABILITY_PRIVATE, 232 TOPO_STABILITY_PRIVATE, 233 1 234 }; 235 236 static const topo_pgroup_info_t topo_binding_pgroup = { 237 TOPO_PGROUP_BINDING, 238 TOPO_STABILITY_PRIVATE, 239 TOPO_STABILITY_PRIVATE, 240 1 241 }; 242 243 static const topo_pgroup_info_t topo_usb_props_pgroup = { 244 TOPO_PGROUP_USB_PROPS, 245 TOPO_STABILITY_PRIVATE, 246 TOPO_STABILITY_PRIVATE, 247 1 248 }; 249 250 /* Required forwards */ 251 static int topo_usb_enum_device(topo_mod_t *, tnode_t *, topo_usb_port_t *); 252 253 /* 254 * Defines the maximum number of USB ports that can exist. Ports are basically 255 * defined by a uint8_t, meaning that we can go up to UINT8_MAX inclusively. 256 */ 257 #define USB_TOPO_PORT_MAX 256 258 259 /* 260 * Default value to indicate that a USB port has no valid type. 261 */ 262 #define USB_TOPO_PORT_TYPE_DEFAULT 0xff 263 264 /* 265 * These come from the ACPI 6.2 / Table 9-290 UPC Return Package Values. 266 */ 267 static const char * 268 topo_usb_port_type_to_string(int type) 269 { 270 switch (type) { 271 case 0x00: 272 return ("Type A connector"); 273 case 0x01: 274 return ("Mini-AB connector"); 275 case 0x02: 276 return ("ExpressCard"); 277 case 0x03: 278 return ("USB 3 Standard-A connector"); 279 case 0x04: 280 return ("USB 3 Standard-B connector"); 281 case 0x05: 282 return ("USB 3 Micro-B connector"); 283 case 0x06: 284 return ("USB 3 Micro-AB connector"); 285 case 0x07: 286 return ("USB 3 Power-B connector"); 287 case 0x08: 288 return ("Type C connector - USB2-only"); 289 case 0x09: 290 return ("Type C connector - USB2 and SS with Switch"); 291 case 0x0A: 292 return ("Type C connector - USB2 and SS without Switch"); 293 /* 0x0B->0xFE are reserved. Treat them like 0xFF */ 294 case 0xFF: 295 default: 296 return ("Unknown"); 297 } 298 } 299 300 /* 301 * Searches the list of ports at a given layer (not recursively) for the 302 * specific port id. 303 */ 304 static topo_usb_lport_t * 305 topo_usb_lport_find(topo_list_t *plist, uint_t logid) 306 { 307 topo_usb_port_t *p; 308 309 for (p = topo_list_next(plist); p != NULL; p = topo_list_next(p)) { 310 topo_usb_lport_t *l; 311 312 for (l = topo_list_next(&p->tup_lports); l != NULL; 313 l = topo_list_next(l)) { 314 if (l->tul_portno == logid) 315 return (l); 316 } 317 } 318 return (NULL); 319 } 320 321 /* 322 * Create an instance of a controller and seed the basic information. 323 */ 324 static topo_usb_controller_t * 325 topo_usb_controller_create(topo_mod_t *mod, topo_usb_t *usb, di_node_t node) 326 { 327 int *pcount, inst; 328 char *drvname, *acpi; 329 topo_usb_controller_t *c; 330 331 /* 332 * If we can't get the port count or the driver, then this node is 333 * uninteresting. 334 */ 335 if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "usb-port-count", 336 &pcount) != 1) { 337 return (NULL); 338 } 339 340 if ((drvname = di_driver_name(node)) == NULL || 341 (inst = di_instance(node) == -1)) 342 return (NULL); 343 344 if ((c = topo_mod_zalloc(mod, sizeof (topo_usb_controller_t))) == 345 NULL || *pcount <= 0) { 346 return (NULL); 347 } 348 349 if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, "acpi-namespace", 350 &acpi) == 1) { 351 c->tuc_acpi_path = acpi; 352 } 353 354 c->tuc_nhubd_ports = (uint_t)*pcount; 355 c->tuc_devinfo = node; 356 c->tuc_path = di_devfs_path(node); 357 (void) snprintf(c->tuc_name, sizeof (c->tuc_name), "%s%d", drvname, 358 inst); 359 if (strcmp(drvname, "xhci") == 0) { 360 int *p; 361 362 c->tuc_driver = TOPO_USB_D_XHCI; 363 364 /* 365 * Grab the properties that we need so we can better do a port 366 * speed mapping. 367 */ 368 if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, 369 "usb2.0-port-count", &p) == 1 && *p > 0) { 370 c->tuc_nusb20 = (uint_t)*p; 371 } 372 373 if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, 374 "usb2.0-first-port", &p) == 1 && *p > 0) { 375 c->tuc_fusb20 = (uint_t)*p; 376 } 377 378 if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, 379 "usb3.0-port-count", &p) == 1 && *p > 0) { 380 c->tuc_nusb30 = (uint_t)*p; 381 } 382 383 if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, 384 "usb3.0-first-port", &p) == 1 && *p > 0) { 385 c->tuc_fusb30 = (uint_t)*p; 386 } 387 388 if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, 389 "usb3.1-port-count", &p) == 1 && *p > 0) { 390 c->tuc_nusb31 = (uint_t)*p; 391 } 392 393 if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, 394 "usb3.1-first-port", &p) == 1 && *p > 0) { 395 c->tuc_fusb31 = (uint_t)*p; 396 } 397 } else if (strcmp(drvname, "ehci") == 0) { 398 c->tuc_driver = TOPO_USB_D_EHCI; 399 } else if (strcmp(drvname, "uhci") == 0) { 400 c->tuc_driver = TOPO_USB_D_UHCI; 401 } else if (strcmp(drvname, "ohci") == 0) { 402 c->tuc_driver = TOPO_USB_D_OHCI; 403 } else { 404 c->tuc_driver = TOPO_USB_D_UNKNOWN; 405 } 406 topo_list_append(&usb->tu_controllers, c); 407 topo_mod_dprintf(mod, "created new USB controller at %s", c->tuc_path); 408 409 return (c); 410 } 411 412 /* 413 * Process this port and any others that might exist. 414 */ 415 static boolean_t 416 topo_usb_gather_acpi_port(topo_mod_t *mod, topo_usb_t *usb, topo_list_t *plist, 417 uint_t *nports, topo_usb_controller_t *tuc, di_node_t portinfo) 418 { 419 int64_t *portno; 420 uchar_t *loc; 421 int loclen, *type; 422 char *acpi; 423 acpi_pld_info_t pld; 424 boolean_t pld_valid = B_FALSE; 425 topo_usb_port_t *port = NULL; 426 topo_usb_lport_t *lport; 427 di_node_t child; 428 429 /* 430 * Get the port's address, it's a required value. Because this is coming 431 * from firmware, we cannot trust the port's value to be correct. 432 */ 433 if (di_prop_lookup_int64(DDI_DEV_T_ANY, portinfo, "acpi-address", 434 &portno) != 1 || *portno < 1 || *portno >= USB_TOPO_PORT_MAX) { 435 return (B_FALSE); 436 } 437 438 if (di_prop_lookup_strings(DDI_DEV_T_ANY, portinfo, "acpi-namespace", 439 &acpi) != 1) { 440 return (B_FALSE); 441 } 442 443 /* 444 * Check to see if we have any ACPI location information. If we do, we 445 * can decode it. 446 */ 447 if ((loclen = di_prop_lookup_bytes(DDI_DEV_T_ANY, portinfo, 448 "acpi-physical-location", &loc)) >= ACPI_PLD_REV1_BUFFER_SIZE && 449 usbtopo_decode_pld(loc, loclen, &pld)) { 450 pld_valid = B_TRUE; 451 } 452 453 /* 454 * Find the corresponding lport. If this node doesn't happen to match 455 * something we've enumerated from the hub. Warn about that fact and 456 * consider this bad data. 457 */ 458 lport = topo_usb_lport_find(plist, (uint_t)*portno); 459 if (lport == NULL) { 460 topo_mod_dprintf(mod, "failed to find physical usb port for " 461 "%s/%u", acpi, (uint_t)*portno); 462 return (B_TRUE); 463 } 464 465 if (lport->tul_acpi_device != DI_NODE_NIL) { 466 topo_mod_dprintf(mod, "logical port already bound to %s, not " 467 "binding to %s", lport->tul_acpi_name, acpi); 468 return (B_FALSE); 469 } 470 471 lport->tul_acpi_device = portinfo; 472 lport->tul_acpi_name = acpi; 473 port = lport->tul_port; 474 475 if (pld_valid) { 476 port->tup_pld_valid = B_TRUE; 477 port->tup_pld = pld; 478 } 479 480 if (di_prop_lookup_ints(DDI_DEV_T_ANY, portinfo, "usb-port-type", 481 &type) == 1 && *type >= 0) { 482 port->tup_port_type = *type; 483 } else { 484 port->tup_port_type = USB_TOPO_PORT_TYPE_DEFAULT; 485 } 486 487 if (di_prop_find(DDI_DEV_T_ANY, portinfo, 488 "usb-port-connectable") != DI_PROP_NIL) { 489 port->tup_port_connected = TOPO_USB_C_CONNECTED; 490 } else { 491 port->tup_port_connected = TOPO_USB_C_DISCONNECTED; 492 } 493 494 for (child = di_child_node(portinfo); child != NULL; 495 child = di_sibling_node(child)) { 496 const char *pname; 497 498 pname = di_node_name(child); 499 if (pname == NULL || strcmp(pname, "port") != 0) { 500 continue; 501 } 502 503 if (!topo_usb_gather_acpi_port(mod, usb, &lport->tul_ports, 504 &lport->tul_nports, tuc, child)) { 505 return (B_FALSE); 506 } 507 } 508 509 topo_mod_dprintf(mod, "discovered %u ACPI usb child ports", 510 lport->tul_nports); 511 512 return (B_TRUE); 513 } 514 515 /* 516 * First, bootstrap all of our information by reading the ACPI information 517 * exposed in the devinfo tree. All of the nodes we care about will be under 518 * /fw/sb@XX/usbrootub@YYY/port@ZZZ 519 */ 520 static boolean_t 521 topo_usb_gather_acpi(topo_mod_t *mod, topo_usb_t *usb) 522 { 523 di_node_t fwroot, sbnode; 524 525 /* 526 * If we can't find the /fw node, that's fine. We may not have any ACPI 527 * information on the system. 528 */ 529 fwroot = di_lookup_node(usb->tu_devinfo, "/fw"); 530 if (fwroot == DI_NODE_NIL) 531 return (B_TRUE); 532 533 for (sbnode = di_child_node(fwroot); sbnode != DI_NODE_NIL; 534 sbnode = di_sibling_node(sbnode)) { 535 const char *sbname; 536 di_node_t hub; 537 538 sbname = di_node_name(sbnode); 539 if (sbname == NULL || strcmp(sbname, "sb") != 0) { 540 continue; 541 } 542 543 for (hub = di_child_node(sbnode); hub != DI_NODE_NIL; 544 hub = di_sibling_node(hub)) { 545 const char *hubname; 546 char *acpi; 547 topo_usb_controller_t *tuc; 548 di_node_t port; 549 550 hubname = di_node_name(hub); 551 if (hubname == NULL || 552 strcmp(hubname, "usbroothub") != 0) { 553 continue; 554 } 555 556 if (di_prop_lookup_strings(DDI_DEV_T_ANY, hub, 557 "acpi-controller-name", &acpi) != 1) { 558 continue; 559 } 560 561 for (tuc = topo_list_next(&usb->tu_controllers); 562 tuc != NULL; 563 tuc = topo_list_next(tuc)) { 564 if (tuc->tuc_acpi_path != NULL && 565 strcmp(acpi, tuc->tuc_acpi_path) == 0) 566 break; 567 } 568 569 if (tuc == NULL) { 570 topo_mod_dprintf(mod, "failed to find USB " 571 "controller for ACPI path %s", acpi); 572 continue; 573 } 574 575 for (port = di_child_node(hub); port != NULL; 576 port = di_sibling_node(port)) { 577 const char *pname; 578 579 pname = di_node_name(port); 580 if (pname == NULL || 581 strcmp(pname, "port") != 0) { 582 continue; 583 } 584 585 if (!topo_usb_gather_acpi_port(mod, usb, 586 &tuc->tuc_ports, &tuc->tuc_nports, tuc, 587 port)) { 588 return (B_FALSE); 589 } 590 } 591 592 topo_mod_dprintf(mod, "found ACPI usb controller %s " 593 "with %d top-level ports", tuc->tuc_path, 594 tuc->tuc_nports); 595 } 596 } 597 598 return (B_TRUE); 599 } 600 601 static topo_usb_port_t * 602 topo_usb_port_create(topo_mod_t *mod, uint_t portno, const char *parent, 603 char sep) 604 { 605 topo_usb_lport_t *l; 606 topo_usb_port_t *p; 607 608 if ((l = topo_mod_zalloc(mod, sizeof (topo_usb_lport_t))) == NULL) { 609 return (NULL); 610 } 611 l->tul_portno = portno; 612 if (snprintf(l->tul_name, sizeof (l->tul_name), "%s%c%u", parent, sep, 613 portno) >= sizeof (l->tul_name)) { 614 topo_mod_free(mod, l, sizeof (topo_usb_lport_t)); 615 return (NULL); 616 } 617 618 if ((p = topo_mod_zalloc(mod, sizeof (topo_usb_port_t))) == NULL) { 619 topo_mod_free(mod, l, sizeof (topo_usb_lport_t)); 620 return (NULL); 621 } 622 l->tul_port = p; 623 p->tup_port_type = USB_TOPO_PORT_TYPE_DEFAULT; 624 topo_list_append(&p->tup_lports, l); 625 p->tup_nlports++; 626 627 return (p); 628 } 629 630 /* 631 * Set the protocol of a port that belongs to a root hub. 632 */ 633 static void 634 topo_usb_set_rhub_port_protocol(topo_mod_t *mod, topo_usb_controller_t *tuc, 635 topo_usb_lport_t *lport) 636 { 637 switch (tuc->tuc_driver) { 638 case TOPO_USB_D_XHCI: 639 break; 640 case TOPO_USB_D_UHCI: 641 case TOPO_USB_D_OHCI: 642 lport->tul_protocol = TOPO_USB_P_1x; 643 return; 644 case TOPO_USB_D_EHCI: 645 lport->tul_protocol = TOPO_USB_P_20; 646 return; 647 case TOPO_USB_D_UNKNOWN: 648 default: 649 lport->tul_protocol = TOPO_USB_P_UNKNOWN; 650 return; 651 } 652 653 /* 654 * The xHCI controller can support multiple different, protocols. It 655 * communicates this information to us via devinfo properties. It's 656 * possible that a port that is within max ports is not within the range 657 * here. If that's the case, we'll set it to unknown. 658 */ 659 if (lport->tul_portno >= tuc->tuc_fusb20 && 660 lport->tul_portno < tuc->tuc_fusb20 + tuc->tuc_nusb20) { 661 lport->tul_protocol = TOPO_USB_P_20; 662 } else if (lport->tul_portno >= tuc->tuc_fusb30 && 663 lport->tul_portno < tuc->tuc_fusb30 + tuc->tuc_nusb30) { 664 lport->tul_protocol = TOPO_USB_P_30; 665 } else if (lport->tul_portno >= tuc->tuc_fusb31 && 666 lport->tul_portno < tuc->tuc_fusb31 + tuc->tuc_nusb31) { 667 lport->tul_protocol = TOPO_USB_P_31; 668 } else { 669 lport->tul_protocol = TOPO_USB_P_UNKNOWN; 670 } 671 } 672 673 /* 674 * We've found a node on the list. Attempt to find its corresponding port. If we 675 * find a hub, then we will descend further down this part of the tree. 676 */ 677 static int 678 topo_usb_gather_devcfg_port(topo_mod_t *mod, topo_usb_controller_t *c, 679 topo_list_t *plist, di_node_t node) 680 { 681 int *vend, *reg, *nports; 682 topo_usb_lport_t *l; 683 char *drvname; 684 685 /* 686 * Look for the presence of the usb-vendor-id property to determine 687 * whether or not this is a usb device node. usba always adds this 688 * to the devices that it enumerates. 689 */ 690 if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "usb-vendor-id", 691 &vend) != 1) { 692 topo_mod_dprintf(mod, "failed to find usb-vendor-id property " 693 "for child"); 694 return (0); 695 } 696 697 /* 698 * For usb-devices, the reg property is one entry long and it has the 699 * logical port that the controller sees. 700 */ 701 if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "reg", ®) != 1 || 702 *reg <= 0) { 703 topo_mod_dprintf(mod, "got bad \"reg\" property"); 704 return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM)); 705 } 706 707 if ((l = topo_usb_lport_find(plist, (uint_t)*reg)) == NULL) { 708 topo_mod_dprintf(mod, "failed to find topo_usb_lport_t for " 709 "port %d", *reg); 710 return (topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM)); 711 } 712 713 l->tul_device = node; 714 715 /* 716 * Check to see if we have a hub and if so, process it. 717 */ 718 if ((drvname = di_driver_name(node)) != NULL && 719 strcmp(drvname, "hubd") == 0 && 720 di_prop_lookup_ints(DDI_DEV_T_ANY, node, "usb-port-count", 721 &nports) == 1 && *nports >= 1) { 722 di_node_t child; 723 724 /* 725 * First go through and try and discover and create all the 726 * logical ports that exist. It is possible that these ports 727 * already exist and that we have ACPI information about them. 728 * This would happen when a root port is connected into a set of 729 * hubs that are built-in. 730 */ 731 l->tul_nhubd_ports = (uint_t)*nports; 732 for (uint_t i = 1; i <= l->tul_nhubd_ports; i++) { 733 topo_usb_lport_t *clport; 734 topo_usb_port_t *cport; 735 736 if ((cport = topo_usb_port_create(mod, i, l->tul_name, 737 '.')) == NULL) { 738 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 739 } 740 741 clport = topo_list_next(&cport->tup_lports); 742 topo_list_append(&l->tul_ports, cport); 743 l->tul_nports++; 744 745 clport->tul_protocol = l->tul_protocol; 746 } 747 748 /* 749 * Now go through and discover its children. 750 */ 751 for (child = di_child_node(node); child != NULL; 752 child = di_sibling_node(child)) { 753 int ret; 754 755 if ((ret = topo_usb_gather_devcfg_port(mod, c, 756 &l->tul_ports, child)) != 0) { 757 return (-1); 758 } 759 } 760 } 761 762 return (0); 763 } 764 765 static int 766 topo_usb_gather_devcfg_cb(di_node_t node, void *arg) 767 { 768 uint_t i; 769 topo_usb_controller_t *tuc; 770 di_prop_t prop = DI_PROP_NIL; 771 boolean_t rh = B_FALSE, pc = B_FALSE; 772 topo_usb_devcfg_arg_t *tda = arg; 773 topo_usb_t *usb = tda->tda_usb; 774 topo_mod_t *mod = tda->tda_mod; 775 di_node_t child; 776 777 while ((prop = di_prop_next(node, prop)) != DI_PROP_NIL) { 778 const char *name = di_prop_name(prop); 779 int *ports; 780 781 if (strcmp(name, "root-hub") == 0 && 782 di_prop_type(prop) == DI_PROP_TYPE_BOOLEAN) { 783 rh = B_TRUE; 784 } else if (strcmp(name, "usb-port-count") == 0 && 785 di_prop_ints(prop, &ports) == 1 && *ports > 0 && 786 *ports < USB_TOPO_PORT_MAX) { 787 pc = B_TRUE; 788 } 789 } 790 791 if (!rh || !pc) 792 return (DI_WALK_CONTINUE); 793 794 if ((tuc = topo_usb_controller_create(mod, usb, node)) == NULL) { 795 tda->tda_fatal = B_TRUE; 796 return (DI_WALK_TERMINATE); 797 } 798 799 /* 800 * Check to make sure that every logical port exists at this level and 801 * that we have its speed information filled in. If it does not exist, 802 * create it. 803 */ 804 for (i = 1; i <= tuc->tuc_nhubd_ports; i++) { 805 topo_usb_lport_t *l; 806 topo_usb_port_t *p; 807 808 topo_mod_dprintf(mod, "attempting to discover lport %u on " 809 "controller %s", i, tuc->tuc_path); 810 811 if ((p = topo_usb_port_create(mod, i, tuc->tuc_name, '@')) == 812 NULL) { 813 topo_mod_dprintf(mod, "failed to create " 814 "port %u", i); 815 tda->tda_fatal = B_TRUE; 816 return (DI_WALK_TERMINATE); 817 } 818 819 topo_list_append(&tuc->tuc_ports, p); 820 tuc->tuc_nports++; 821 l = topo_list_next(&p->tup_lports); 822 823 topo_usb_set_rhub_port_protocol(mod, tuc, l); 824 } 825 826 for (child = di_child_node(tuc->tuc_devinfo); child != NULL; 827 child = di_sibling_node(child)) { 828 int ret; 829 830 if ((ret = topo_usb_gather_devcfg_port(mod, tuc, 831 &tuc->tuc_ports, child)) != 0) { 832 tda->tda_fatal = B_TRUE; 833 return (DI_WALK_TERMINATE); 834 } 835 } 836 837 return (DI_WALK_PRUNECHILD); 838 } 839 840 /* 841 * To find all the controllers in the system, look for device nodes that have 842 * the 'root-hub' property and also a valid usb-port-count property. 843 */ 844 static boolean_t 845 topo_usb_gather_devcfg(topo_mod_t *mod, topo_usb_t *usb) 846 { 847 topo_usb_devcfg_arg_t tda; 848 849 tda.tda_usb = usb; 850 tda.tda_mod = mod; 851 tda.tda_fatal = B_FALSE; 852 853 (void) di_walk_node(usb->tu_devinfo, DI_WALK_CLDFIRST, 854 &tda, topo_usb_gather_devcfg_cb); 855 856 return (!tda.tda_fatal); 857 } 858 859 /* 860 * For more information on the matching logic here, see xHCI r1.1 / Appendix D - 861 * Port to Connector Mapping. 862 */ 863 static boolean_t 864 topo_usb_acpi_pld_match(const acpi_pld_info_t *l, const acpi_pld_info_t *r) 865 { 866 if (l->Panel == r->Panel && 867 l->VerticalPosition == r->VerticalPosition && 868 l->HorizontalPosition == r->HorizontalPosition && 869 l->Shape == r->Shape && 870 l->GroupOrientation == r->GroupOrientation && 871 l->GroupPosition == r->GroupPosition && 872 l->GroupToken == r->GroupToken) { 873 return (B_TRUE); 874 } 875 876 return (B_FALSE); 877 } 878 879 typedef boolean_t (*topo_usb_port_match_f)(topo_usb_port_t *, void *); 880 881 static topo_usb_port_t * 882 topo_usb_port_match_lport(topo_usb_lport_t *lport, boolean_t remove, 883 topo_usb_port_match_f func, void *arg) 884 { 885 topo_usb_port_t *p; 886 887 for (p = topo_list_next(&lport->tul_ports); p != NULL; 888 p = topo_list_next(p)) { 889 topo_usb_lport_t *l; 890 topo_usb_port_t *ret; 891 892 if (func(p, arg)) { 893 if (remove) { 894 topo_list_delete(&lport->tul_ports, p); 895 lport->tul_nports--; 896 } 897 898 return (p); 899 } 900 901 for (l = topo_list_next(&p->tup_lports); l != NULL; 902 l = topo_list_next(l)) { 903 if ((ret = topo_usb_port_match_lport(l, 904 remove, func, arg)) != NULL) { 905 return (ret); 906 } 907 } 908 } 909 910 return (NULL); 911 } 912 913 static topo_usb_port_t * 914 topo_usb_port_match_controller(topo_usb_controller_t *c, boolean_t remove, 915 topo_usb_port_match_f func, void *arg) 916 { 917 topo_usb_port_t *p; 918 919 for (p = topo_list_next(&c->tuc_ports); p != NULL; 920 p = topo_list_next(p)) { 921 topo_usb_lport_t *l; 922 topo_usb_port_t *ret; 923 924 if (func(p, arg)) { 925 if (remove) { 926 topo_list_delete(&c->tuc_ports, p); 927 c->tuc_nports--; 928 } 929 930 return (p); 931 } 932 933 for (l = topo_list_next(&p->tup_lports); l != NULL; 934 l = topo_list_next(l)) { 935 if ((ret = topo_usb_port_match_lport(l, 936 remove, func, arg)) != NULL) { 937 return (ret); 938 } 939 } 940 } 941 942 return (NULL); 943 } 944 945 static topo_usb_port_t * 946 topo_usb_port_match(topo_usb_t *usb, boolean_t remove, 947 topo_usb_port_match_f func, void *arg) 948 { 949 topo_usb_controller_t *c; 950 951 for (c = topo_list_next(&usb->tu_controllers); c != NULL; 952 c = topo_list_next(c)) { 953 topo_usb_port_t *p; 954 955 if ((p = topo_usb_port_match_controller(c, remove, func, 956 arg)) != NULL) 957 return (p); 958 } 959 return (NULL); 960 } 961 962 /* 963 * Merge all of the local ports and information in source, to sink. 964 */ 965 static void 966 topo_usb_port_merge(topo_usb_port_t *sink, topo_usb_port_t *source) 967 { 968 topo_usb_lport_t *l; 969 970 while ((l = topo_list_next(&source->tup_lports)) != NULL) { 971 topo_list_delete(&source->tup_lports, l); 972 source->tup_nlports--; 973 topo_list_append(&sink->tup_lports, l); 974 sink->tup_nlports++; 975 } 976 977 if (sink->tup_port_type == USB_TOPO_PORT_TYPE_DEFAULT) { 978 sink->tup_port_type = source->tup_port_type; 979 } 980 981 if (sink->tup_port_connected == TOPO_USB_C_UNKNOWN) { 982 sink->tup_port_connected = source->tup_port_connected; 983 } 984 } 985 986 static boolean_t 987 topo_usb_acpi_port_match(topo_usb_port_t *port, void *arg) 988 { 989 topo_usb_port_t *target = arg; 990 991 return (port != target && port->tup_pld_valid && 992 topo_usb_acpi_pld_match(&port->tup_pld, &target->tup_pld)); 993 } 994 995 /* 996 * Ports on an xhci controller can match up. If we've been told that we should 997 * do so, attempt to perform that match. We only try to find matches in the top 998 * level ports of an xhci controller as that's what's most common on systems, 999 * though we'll search all the descendants. 1000 */ 1001 static void 1002 topo_usb_acpi_match(topo_mod_t *mod, topo_usb_controller_t *tuc) 1003 { 1004 topo_usb_port_t *p; 1005 1006 for (p = topo_list_next(&tuc->tuc_ports); p != NULL; 1007 p = topo_list_next(p)) { 1008 topo_usb_port_t *match; 1009 1010 if ((match = topo_usb_port_match_controller(tuc, B_TRUE, 1011 topo_usb_acpi_port_match, p)) != NULL) { 1012 VERIFY3P(p, !=, match); 1013 topo_usb_port_merge(p, match); 1014 topo_mod_free(mod, match, sizeof (topo_usb_port_t)); 1015 } 1016 } 1017 } 1018 1019 static boolean_t 1020 topo_usb_metadata_match(topo_usb_port_t *port, void *arg) 1021 { 1022 topo_usb_meta_port_path_t *path = arg; 1023 topo_usb_lport_t *l; 1024 1025 if (path->tmpp_type != TOPO_USB_T_ACPI) 1026 return (B_FALSE); 1027 1028 for (l = topo_list_next(&port->tup_lports); l != NULL; 1029 l = topo_list_next(l)) { 1030 if (l->tul_acpi_name != NULL && strcmp(path->tmpp_path, 1031 l->tul_acpi_name) == 0) { 1032 return (B_TRUE); 1033 } 1034 } 1035 1036 return (B_FALSE); 1037 } 1038 1039 /* 1040 * We've found metadata describing the USB ports. We need to now go through and 1041 * try to match that data up to actual nodes. 1042 */ 1043 static void 1044 topo_usb_apply_metadata(topo_mod_t *mod, topo_usb_t *usb) 1045 { 1046 topo_usb_meta_port_t *m; 1047 1048 for (m = topo_list_next(&usb->tu_metadata); m != NULL; 1049 m = topo_list_next(m)) { 1050 topo_usb_port_t *p, *sink = NULL; 1051 topo_usb_meta_port_path_t *path; 1052 boolean_t remove = B_FALSE; 1053 1054 /* 1055 * If this is a chassis node, we'll remove the port and move it 1056 * to the chassis. 1057 */ 1058 if (m->tmp_flags & TOPO_USB_F_CHASSIS) { 1059 remove = B_TRUE; 1060 } 1061 1062 for (path = topo_list_next(&m->tmp_paths); path != NULL; 1063 path = topo_list_next(path)) { 1064 topo_mod_dprintf(mod, "considering metadata path %s", 1065 path->tmpp_path); 1066 if ((p = topo_usb_port_match(usb, remove, 1067 topo_usb_metadata_match, path)) == NULL) 1068 continue; 1069 topo_mod_dprintf(mod, "matched path to a logical port"); 1070 p->tup_meta = m; 1071 1072 /* 1073 * Check if we can move this to the Chassis. We should 1074 * always do this on the first port in a group. However, 1075 * if it's a match candidate, then it will have already 1076 * been appended. 1077 */ 1078 if ((m->tmp_flags & TOPO_USB_F_CHASSIS) != 0 && 1079 sink == NULL) { 1080 topo_list_append(&usb->tu_chassis_ports, p); 1081 usb->tu_nchassis_ports++; 1082 } 1083 1084 if ((usb->tu_meta_flags & TOPO_USB_M_METADATA_MATCH) != 1085 0) { 1086 if (sink == NULL) { 1087 sink = p; 1088 remove = B_TRUE; 1089 } else { 1090 VERIFY3P(p, !=, sink); 1091 topo_usb_port_merge(sink, p); 1092 topo_mod_free(mod, p, 1093 sizeof (topo_usb_port_t)); 1094 } 1095 continue; 1096 } 1097 1098 break; 1099 } 1100 1101 } 1102 } 1103 1104 static int 1105 topo_usb_gather(topo_mod_t *mod, topo_usb_t *usb, tnode_t *pnode) 1106 { 1107 int ret; 1108 1109 if ((ret = topo_usb_load_metadata(mod, pnode, &usb->tu_metadata, 1110 &usb->tu_meta_flags)) != 0) { 1111 topo_mod_dprintf(mod, "failed to read usb metadata"); 1112 return (-1); 1113 } 1114 topo_mod_dprintf(mod, "loaded metadata flags: %d", usb->tu_meta_flags); 1115 1116 if (!topo_usb_gather_devcfg(mod, usb)) { 1117 topo_mod_dprintf(mod, "encountered fatal error while " 1118 "gathering physical data"); 1119 return (-1); 1120 } 1121 1122 if ((usb->tu_meta_flags & TOPO_USB_M_NO_ACPI) == 0 && 1123 !topo_usb_gather_acpi(mod, usb)) { 1124 topo_mod_dprintf(mod, "encountered fatal error while " 1125 "gathering ACPI data"); 1126 return (-1); 1127 } 1128 1129 if ((usb->tu_meta_flags & TOPO_USB_M_ACPI_MATCH) != 0) { 1130 topo_usb_controller_t *c; 1131 1132 for (c = topo_list_next(&usb->tu_controllers); c != NULL; 1133 c = topo_list_next(c)) { 1134 if (c->tuc_driver == TOPO_USB_D_XHCI) { 1135 topo_usb_acpi_match(mod, c); 1136 } 1137 } 1138 } 1139 1140 topo_usb_apply_metadata(mod, usb); 1141 1142 return (0); 1143 } 1144 1145 static int 1146 topo_usb_port_properties(topo_mod_t *mod, tnode_t *tn, topo_usb_port_t *port) 1147 { 1148 int err; 1149 char **strs = NULL; 1150 uint_t i; 1151 topo_usb_lport_t *l; 1152 char *label; 1153 const char *ptype; 1154 size_t strlen; 1155 1156 strlen = sizeof (char *) * MAX(port->tup_nlports, 1157 TOPO_PROP_USB_PORT_NATTRS); 1158 if ((strs = topo_mod_zalloc(mod, strlen)) == NULL) { 1159 return (-1); 1160 } 1161 1162 label = NULL; 1163 if (port->tup_meta != NULL) { 1164 label = port->tup_meta->tmp_label; 1165 } 1166 1167 if (port->tup_meta != NULL && port->tup_meta->tmp_port_type != 1168 USB_TOPO_PORT_TYPE_DEFAULT) { 1169 ptype = 1170 topo_usb_port_type_to_string(port->tup_meta->tmp_port_type); 1171 } else { 1172 ptype = topo_usb_port_type_to_string(port->tup_port_type); 1173 } 1174 1175 if (topo_pgroup_create(tn, &topo_usb_port_pgroup, &err) != 0) { 1176 topo_mod_dprintf(mod, "failed to create property group %s: " 1177 "%s\n", TOPO_PGROUP_USB_PORT, topo_strerror(err)); 1178 goto error; 1179 1180 } 1181 1182 if (label != NULL && topo_node_label_set(tn, label, &err) != 0) { 1183 topo_mod_dprintf(mod, "failed to set label on port: %s", 1184 topo_strerror(err)); 1185 goto error; 1186 } 1187 1188 if (ptype != NULL && topo_prop_set_string(tn, TOPO_PGROUP_USB_PORT, 1189 TOPO_PROP_USB_PORT_TYPE, TOPO_PROP_IMMUTABLE, ptype, &err) != 0) { 1190 topo_mod_dprintf(mod, "failed to set %s property: %s", 1191 TOPO_PROP_USB_PORT_TYPE, topo_strerror(err)); 1192 goto error; 1193 } 1194 1195 for (i = 0, l = topo_list_next(&port->tup_lports); l != NULL; 1196 l = topo_list_next(l)) { 1197 char *vers; 1198 int j; 1199 1200 switch (l->tul_protocol) { 1201 case TOPO_USB_P_1x: 1202 vers = "1.x"; 1203 break; 1204 case TOPO_USB_P_20: 1205 vers = "2.0"; 1206 break; 1207 case TOPO_USB_P_30: 1208 vers = "3.0"; 1209 break; 1210 case TOPO_USB_P_31: 1211 vers = "3.1"; 1212 break; 1213 default: 1214 continue; 1215 } 1216 1217 /* 1218 * Make sure we don't already have this string. This can happen 1219 * when we have an ehci port and xhci support that both provide 1220 * USB 2.0 service. 1221 */ 1222 for (j = 0; j < i; j++) { 1223 if (strcmp(strs[j], vers) == 0) 1224 break; 1225 } 1226 1227 if (j < i) 1228 continue; 1229 strs[i++] = vers; 1230 } 1231 1232 if (i > 0 && topo_prop_set_string_array(tn, TOPO_PGROUP_USB_PORT, 1233 TOPO_PROP_USB_PORT_VERSIONS, TOPO_PROP_IMMUTABLE, 1234 (const char **)strs, i, &err) != 0) { 1235 topo_mod_dprintf(mod, "failed to set %s property: %s", 1236 TOPO_PROP_USB_PORT_VERSIONS, topo_strerror(err)); 1237 goto error; 1238 } 1239 1240 i = 0; 1241 if (port->tup_pld_valid && port->tup_pld.UserVisible != 0 && 1242 port->tup_port_connected == TOPO_USB_C_CONNECTED) { 1243 strs[i++] = TOPO_PROP_USB_PORT_A_VISIBLE; 1244 } else if (port->tup_port_connected == TOPO_USB_C_CONNECTED) { 1245 strs[i++] = TOPO_PROP_USB_PORT_A_CONNECTED; 1246 } else if (port->tup_port_connected == TOPO_USB_C_DISCONNECTED) { 1247 strs[i++] = TOPO_PROP_USB_PORT_A_DISCONNECTED; 1248 } 1249 1250 if (port->tup_meta != NULL) { 1251 if (port->tup_meta->tmp_flags & TOPO_USB_F_INTERNAL) { 1252 strs[i++] = TOPO_PROP_USB_PORT_A_INTERNAL; 1253 } 1254 1255 if (port->tup_meta->tmp_flags & TOPO_USB_F_EXTERNAL) { 1256 strs[i++] = TOPO_PROP_USB_PORT_A_EXTERNAL; 1257 } 1258 } 1259 1260 if (i > 0 && topo_prop_set_string_array(tn, TOPO_PGROUP_USB_PORT, 1261 TOPO_PROP_USB_PORT_ATTRIBUTES, TOPO_PROP_IMMUTABLE, 1262 (const char **)strs, i, &err) != 0) { 1263 topo_mod_dprintf(mod, "failed to set %s property: %s", 1264 TOPO_PROP_USB_PORT_VERSIONS, topo_strerror(err)); 1265 goto error; 1266 } 1267 1268 for (i = 0, l = topo_list_next(&port->tup_lports); l != NULL; 1269 l = topo_list_next(l)) { 1270 strs[i++] = l->tul_name; 1271 } 1272 1273 if (i > 0 && topo_prop_set_string_array(tn, TOPO_PGROUP_USB_PORT, 1274 TOPO_PROP_USB_PORT_LPORTS, TOPO_PROP_IMMUTABLE, 1275 (const char **)strs, i, &err) != 0) { 1276 topo_mod_dprintf(mod, "failed to set %s propert: %s", 1277 TOPO_PROP_USB_PORT_LPORTS, topo_strerror(err)); 1278 goto error; 1279 } 1280 1281 err = 0; 1282 error: 1283 if (strs != NULL) { 1284 topo_mod_free(mod, strs, strlen); 1285 } 1286 1287 if (err != 0) { 1288 return (topo_mod_seterrno(mod, err)); 1289 } 1290 1291 return (err); 1292 } 1293 1294 /* 1295 * Create a disk node under the scsa2usb node. When we have an scsa2usb node, 1296 * we'll have a child devinfo which is a disk. To successfully enumerate this, 1297 * we need to find the child node (which should be our only direct descendent) 1298 * and get its devfs path. From there we can construct a 'binding' property 1299 * group with the 'occupantpath' property that points to the module. At that 1300 * point we can invoke the disk enumerator. 1301 */ 1302 static int 1303 topo_usb_enum_scsa2usb(topo_mod_t *mod, tnode_t *tn, topo_usb_lport_t *lport) 1304 { 1305 int ret; 1306 di_node_t child; 1307 char *devfs = NULL; 1308 topo_instance_t min = 0, max = 0; 1309 1310 if ((child = di_child_node(lport->tul_device)) == DI_NODE_NIL || 1311 strcmp("disk", di_node_name(child)) != 0) { 1312 return (0); 1313 } 1314 1315 if ((devfs = di_devfs_path(child)) == NULL) { 1316 topo_mod_dprintf(mod, "failed to get USB disk child device " 1317 "devfs path"); 1318 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 1319 } 1320 1321 if (topo_mod_load(mod, DISK, TOPO_VERSION) == NULL) { 1322 topo_mod_dprintf(mod, "failed to load disk module: %s", 1323 topo_mod_errmsg(mod)); 1324 goto error; 1325 } 1326 1327 if (topo_pgroup_create(tn, &topo_binding_pgroup, &ret) != 0) { 1328 topo_mod_dprintf(mod, "failed to create \"binding\" " 1329 "property group: %s", topo_strerror(ret)); 1330 goto error; 1331 } 1332 1333 if (topo_prop_set_string(tn, TOPO_PGROUP_BINDING, 1334 TOPO_BINDING_OCCUPANT, TOPO_PROP_IMMUTABLE, devfs, &ret) != 1335 0) { 1336 topo_mod_dprintf(mod, "failed to create property %s: %s", 1337 TOPO_IO_MODULE, topo_strerror(ret)); 1338 goto error; 1339 } 1340 di_devfs_path_free(devfs); 1341 devfs = NULL; 1342 1343 if (topo_node_range_create(mod, tn, DISK, min, max) != 0) { 1344 topo_mod_dprintf(mod, "failed to create disk node range %s: %s", 1345 devfs, topo_mod_errmsg(mod)); 1346 goto error; 1347 } 1348 1349 if (topo_mod_enumerate(mod, tn, DISK, DISK, min, max, NULL) != 0) { 1350 topo_mod_dprintf(mod, "failed to create disk node %s: %s", 1351 devfs, topo_mod_errmsg(mod)); 1352 goto error; 1353 } 1354 1355 return (0); 1356 1357 error: 1358 di_devfs_path_free(devfs); 1359 return (-1); 1360 } 1361 1362 static int 1363 topo_usb_enum_port_children(topo_mod_t *mod, tnode_t *pn, 1364 topo_usb_lport_t *plport) 1365 { 1366 int ret; 1367 topo_usb_port_t *port; 1368 topo_instance_t min = 0, i; 1369 1370 if ((ret = port_range_create(mod, pn, min, plport->tul_nports)) != 0) { 1371 topo_mod_dprintf(mod, "failed to create port range [%u, %u) " 1372 "for child hub", 0, plport->tul_nports); 1373 return (ret); 1374 } 1375 1376 for (i = 0, port = topo_list_next(&plport->tul_ports); port != NULL; 1377 port = topo_list_next(port)) { 1378 tnode_t *tn; 1379 if ((ret = port_create_usb(mod, pn, i, &tn)) != 0) 1380 return (ret); 1381 1382 if ((ret = topo_usb_port_properties(mod, tn, port)) != 0) { 1383 return (ret); 1384 } 1385 1386 if ((ret = topo_usb_enum_device(mod, tn, port)) != 0) 1387 return (ret); 1388 1389 i++; 1390 } 1391 1392 return (0); 1393 } 1394 1395 /* 1396 * Enumerate the requested device. Depending on the driver associated with it 1397 * (if any), we may have to create child nodes. 1398 */ 1399 static int 1400 topo_usb_enum_lport(topo_mod_t *mod, tnode_t *pn, topo_usb_port_t *port, 1401 topo_usb_lport_t *lport, topo_instance_t topo_inst) 1402 { 1403 int ret, inst; 1404 int *vendid = NULL, *prodid = NULL, *revid = NULL, *release = NULL; 1405 char *vend = NULL, *prod = NULL, *serial = NULL, *speed = NULL; 1406 char *driver, *devfs; 1407 char revbuf[32], relbuf[32]; 1408 tnode_t *tn = NULL; 1409 di_prop_t prop = DI_PROP_NIL; 1410 nvlist_t *auth = NULL, *fmri = NULL, *modnvl = NULL; 1411 1412 /* 1413 * Look up the information we'll need to create the usb-properties. We 1414 * do this first because this information is often part of the FMRI. 1415 */ 1416 for (prop = di_prop_next(lport->tul_device, DI_PROP_NIL); 1417 prop != DI_PROP_NIL; prop = di_prop_next(lport->tul_device, prop)) { 1418 const char *pname = di_prop_name(prop); 1419 1420 if (strcmp(pname, "usb-vendor-id") == 0) { 1421 if (di_prop_ints(prop, &vendid) != 1) 1422 vendid = NULL; 1423 } else if (strcmp(pname, "usb-product-id") == 0) { 1424 if (di_prop_ints(prop, &prodid) != 1) 1425 prodid = NULL; 1426 } else if (strcmp(pname, "usb-revision-id") == 0) { 1427 if (di_prop_ints(prop, &revid) != 1) { 1428 revid = NULL; 1429 } else { 1430 (void) snprintf(revbuf, sizeof (revbuf), "%x", 1431 *revid); 1432 } 1433 } else if (strcmp(pname, "usb-release") == 0) { 1434 if (di_prop_ints(prop, &release) != 1) { 1435 release = NULL; 1436 } else { 1437 (void) snprintf(relbuf, sizeof (relbuf), 1438 "%x.%x", *release >> 8, 1439 (*release >> 4) & 0xf); 1440 } 1441 } else if (strcmp(pname, "usb-vendor-name") == 0) { 1442 if (di_prop_strings(prop, &vend) != 1) 1443 vend = NULL; 1444 } else if (strcmp(pname, "usb-product-name") == 0) { 1445 if (di_prop_strings(prop, &prod) != 1) 1446 prod = NULL; 1447 } else if (strcmp(pname, "usb-serialno") == 0) { 1448 if (di_prop_strings(prop, &serial) != 1) 1449 serial = NULL; 1450 } else if (strcmp(pname, "full-speed") == 0) { 1451 speed = "full-speed"; 1452 } else if (strcmp(pname, "low-speed") == 0) { 1453 speed = "low-speed"; 1454 } else if (strcmp(pname, "high-speed") == 0) { 1455 speed = "high-speed"; 1456 } else if (strcmp(pname, "super-speed") == 0) { 1457 speed = "super-speed"; 1458 } 1459 } 1460 1461 driver = di_driver_name(lport->tul_device); 1462 inst = di_instance(lport->tul_device); 1463 devfs = di_devfs_path(lport->tul_device); 1464 1465 if ((auth = topo_mod_auth(mod, pn)) == NULL) { 1466 topo_mod_dprintf(mod, "failed to get authority for USB device: " 1467 "%s", topo_mod_errmsg(mod)); 1468 goto error; 1469 } 1470 1471 if ((fmri = topo_mod_hcfmri(mod, pn, FM_HC_SCHEME_VERSION, USB_DEVICE, 1472 topo_inst, NULL, auth, prod, revbuf, serial)) == NULL) { 1473 topo_mod_dprintf(mod, "failed to generate fmri for USB " 1474 "device %s: %s", di_devfs_path(lport->tul_device), 1475 topo_mod_errmsg(mod)); 1476 goto error; 1477 } 1478 1479 if ((tn = topo_node_bind(mod, pn, USB_DEVICE, topo_inst, fmri)) == 1480 NULL) { 1481 topo_mod_dprintf(mod, "failed to bind USB device node: %s", 1482 topo_mod_errmsg(mod)); 1483 goto error; 1484 } 1485 1486 /* 1487 * In general, we expect a USB device to be its own FRU. There are some 1488 * exceptions to this, for example, a built-in hub. However, it's hard 1489 * for us to generally know. It may be nice to allow the platform to 1490 * override this in the future. 1491 */ 1492 if (topo_node_fru_set(tn, fmri, 0, &ret) != 0) { 1493 topo_mod_dprintf(mod, "failed to set FRU: %s", 1494 topo_strerror(ret)); 1495 (void) topo_mod_seterrno(mod, ret); 1496 goto error; 1497 } 1498 1499 /* 1500 * Inherit the label from the port on the device. This is intended to 1501 * only go a single way. 1502 */ 1503 if (port->tup_meta != NULL && port->tup_meta->tmp_label != NULL && 1504 topo_node_label_set(tn, port->tup_meta->tmp_label, &ret) != 0) { 1505 topo_mod_dprintf(mod, "failed to set label on device: %s", 1506 topo_strerror(ret)); 1507 goto error; 1508 } 1509 1510 /* 1511 * USB-properties 1512 */ 1513 if (topo_pgroup_create(tn, &topo_usb_props_pgroup, &ret) != 0) { 1514 topo_mod_dprintf(mod, "failed to create \"usb-properties\" " 1515 "property group: %s", topo_strerror(ret)); 1516 goto error; 1517 } 1518 1519 if (topo_prop_set_uint32(tn, TOPO_PGROUP_USB_PROPS, 1520 TOPO_PGROUP_USB_PROPS_PORT, TOPO_PROP_IMMUTABLE, lport->tul_portno, 1521 &ret) != 0) { 1522 topo_mod_dprintf(mod, "failed to create property %s: %s", 1523 TOPO_PGROUP_USB_PROPS_PORT, topo_strerror(ret)); 1524 goto error; 1525 } 1526 1527 if (vendid != NULL && topo_prop_set_int32(tn, TOPO_PGROUP_USB_PROPS, 1528 TOPO_PGROUP_USB_PROPS_VID, TOPO_PROP_IMMUTABLE, *vendid, &ret) != 1529 0) { 1530 topo_mod_dprintf(mod, "failed to create property %s: %s", 1531 TOPO_PGROUP_USB_PROPS_VID, topo_strerror(ret)); 1532 goto error; 1533 } 1534 1535 if (prodid != NULL && topo_prop_set_int32(tn, TOPO_PGROUP_USB_PROPS, 1536 TOPO_PGROUP_USB_PROPS_PID, TOPO_PROP_IMMUTABLE, *prodid, &ret) != 1537 0) { 1538 topo_mod_dprintf(mod, "failed to create property %s: %s", 1539 TOPO_PGROUP_USB_PROPS_PID, topo_strerror(ret)); 1540 goto error; 1541 } 1542 1543 if (revid != NULL && topo_prop_set_string(tn, TOPO_PGROUP_USB_PROPS, 1544 TOPO_PGROUP_USB_PROPS_REV, TOPO_PROP_IMMUTABLE, revbuf, &ret) != 1545 0) { 1546 topo_mod_dprintf(mod, "failed to create property %s: %s", 1547 TOPO_PGROUP_USB_PROPS_REV, topo_strerror(ret)); 1548 goto error; 1549 } 1550 1551 if (release != NULL && topo_prop_set_string(tn, TOPO_PGROUP_USB_PROPS, 1552 TOPO_PGROUP_USB_PROPS_VERSION, TOPO_PROP_IMMUTABLE, relbuf, &ret) != 1553 0) { 1554 topo_mod_dprintf(mod, "failed to create property %s: %s", 1555 TOPO_PGROUP_USB_PROPS_VERSION, topo_strerror(ret)); 1556 goto error; 1557 } 1558 1559 if (vend != NULL && topo_prop_set_string(tn, TOPO_PGROUP_USB_PROPS, 1560 TOPO_PGROUP_USB_PROPS_VNAME, TOPO_PROP_IMMUTABLE, vend, &ret) != 1561 0) { 1562 topo_mod_dprintf(mod, "failed to create property %s: %s", 1563 TOPO_PGROUP_USB_PROPS_VNAME, topo_strerror(ret)); 1564 goto error; 1565 } 1566 1567 if (prod != NULL && topo_prop_set_string(tn, TOPO_PGROUP_USB_PROPS, 1568 TOPO_PGROUP_USB_PROPS_PNAME, TOPO_PROP_IMMUTABLE, prod, &ret) != 1569 0) { 1570 topo_mod_dprintf(mod, "failed to create property %s: %s", 1571 TOPO_PGROUP_USB_PROPS_PNAME, topo_strerror(ret)); 1572 goto error; 1573 } 1574 1575 if (serial != NULL && topo_prop_set_string(tn, TOPO_PGROUP_USB_PROPS, 1576 TOPO_PGROUP_USB_PROPS_SN, TOPO_PROP_IMMUTABLE, serial, &ret) != 1577 0) { 1578 topo_mod_dprintf(mod, "failed to create property %s: %s", 1579 TOPO_PGROUP_USB_PROPS_SN, topo_strerror(ret)); 1580 goto error; 1581 } 1582 1583 if (speed != NULL && topo_prop_set_string(tn, TOPO_PGROUP_USB_PROPS, 1584 TOPO_PGROUP_USB_PROPS_SPEED, TOPO_PROP_IMMUTABLE, speed, &ret) != 1585 0) { 1586 topo_mod_dprintf(mod, "failed to create property %s: %s", 1587 TOPO_PGROUP_USB_PROPS_SPEED, topo_strerror(ret)); 1588 goto error; 1589 } 1590 1591 /* 1592 * I/O pgroup 1593 */ 1594 if (topo_pgroup_create(tn, &topo_io_pgroup, &ret) != 0) { 1595 topo_mod_dprintf(mod, "failed to create \"io\" " 1596 "property group: %s", topo_strerror(ret)); 1597 goto error; 1598 } 1599 1600 if (driver != NULL && topo_prop_set_string(tn, TOPO_PGROUP_IO, 1601 TOPO_IO_DRIVER, TOPO_PROP_IMMUTABLE, driver, &ret) != 1602 0) { 1603 topo_mod_dprintf(mod, "failed to create property %s: %s", 1604 TOPO_IO_DRIVER, topo_strerror(ret)); 1605 goto error; 1606 } 1607 1608 if (inst != -1 && topo_prop_set_uint32(tn, TOPO_PGROUP_IO, 1609 TOPO_IO_INSTANCE, TOPO_PROP_IMMUTABLE, inst, &ret) != 1610 0) { 1611 topo_mod_dprintf(mod, "failed to create property %s: %s", 1612 TOPO_IO_INSTANCE, topo_strerror(ret)); 1613 goto error; 1614 } 1615 1616 if (devfs != NULL && topo_prop_set_string(tn, TOPO_PGROUP_IO, 1617 TOPO_IO_DEV_PATH, TOPO_PROP_IMMUTABLE, devfs, &ret) != 1618 0) { 1619 topo_mod_dprintf(mod, "failed to create property %s: %s", 1620 TOPO_IO_DEV_PATH, topo_strerror(ret)); 1621 goto error; 1622 } 1623 1624 if (driver != NULL && (modnvl = topo_mod_modfmri(mod, 1625 FM_MOD_SCHEME_VERSION, driver)) != NULL && 1626 topo_prop_set_fmri(tn, TOPO_PGROUP_IO, TOPO_IO_MODULE, 1627 TOPO_PROP_IMMUTABLE, modnvl, &ret) != 0) { 1628 topo_mod_dprintf(mod, "failed to create property %s: %s", 1629 TOPO_IO_MODULE, topo_strerror(ret)); 1630 goto error; 1631 } 1632 1633 /* 1634 * Check the drivers to determine special behavior that we should do. 1635 * The following are cases that we want to handle: 1636 * 1637 * o Creating disk nodes for scsa2usb devices 1638 * o Creating children ports and searching them for hubd 1639 */ 1640 if (driver != NULL && strcmp(driver, "scsa2usb") == 0) { 1641 if ((ret = topo_usb_enum_scsa2usb(mod, tn, lport)) != 0) 1642 goto error; 1643 } 1644 1645 if (lport->tul_nports > 0 && driver != NULL && 1646 strcmp(driver, "hubd") == 0) { 1647 if ((ret = topo_usb_enum_port_children(mod, tn, lport)) != 0) 1648 goto error; 1649 } 1650 1651 di_devfs_path_free(devfs); 1652 nvlist_free(fmri); 1653 nvlist_free(auth); 1654 nvlist_free(modnvl); 1655 return (0); 1656 1657 error: 1658 topo_node_unbind(tn); 1659 di_devfs_path_free(devfs); 1660 nvlist_free(fmri); 1661 nvlist_free(auth); 1662 nvlist_free(modnvl); 1663 return (-1); 1664 } 1665 1666 static int 1667 topo_usb_enum_device(topo_mod_t *mod, tnode_t *pn, topo_usb_port_t *port) 1668 { 1669 int ret; 1670 topo_instance_t i, max; 1671 topo_usb_lport_t *l; 1672 1673 max = 0; 1674 for (l = topo_list_next(&port->tup_lports); l != NULL; 1675 l = topo_list_next(l)) { 1676 if (l->tul_device != DI_NODE_NIL) 1677 max++; 1678 } 1679 1680 if (max == 0) { 1681 return (0); 1682 } 1683 1684 if ((ret = topo_node_range_create(mod, pn, USB_DEVICE, 0, max - 1)) != 1685 0) { 1686 return (-1); 1687 } 1688 1689 for (i = 0, l = topo_list_next(&port->tup_lports); l != NULL; 1690 l = topo_list_next(l)) { 1691 if (l->tul_device != DI_NODE_NIL) { 1692 topo_mod_dprintf(mod, "enumerating device on lport " 1693 "%u, log inst %d", l->tul_portno, i); 1694 if ((ret = topo_usb_enum_lport(mod, pn, port, l, 1695 i)) != 0) { 1696 return (ret); 1697 } 1698 i++; 1699 } 1700 } 1701 1702 return (0); 1703 } 1704 1705 static int 1706 topo_usb_enum_controller(topo_mod_t *mod, tnode_t *pnode, 1707 topo_usb_controller_t *c, topo_instance_t base) 1708 { 1709 int ret; 1710 topo_usb_port_t *port; 1711 1712 if (c->tuc_enumed) 1713 return (0); 1714 1715 c->tuc_enumed = B_TRUE; 1716 if (c->tuc_nports == 0) 1717 return (0); 1718 1719 for (port = topo_list_next(&c->tuc_ports); port != NULL; 1720 port = topo_list_next(port)) { 1721 tnode_t *tn; 1722 if ((ret = port_create_usb(mod, pnode, base, &tn)) != 0) 1723 return (ret); 1724 1725 if ((ret = topo_usb_port_properties(mod, tn, port)) != 0) { 1726 return (ret); 1727 } 1728 1729 if ((ret = topo_usb_enum_device(mod, tn, port)) != 0) 1730 return (ret); 1731 1732 base++; 1733 } 1734 1735 return (0); 1736 } 1737 1738 static int 1739 topo_usb_enum_mobo(topo_mod_t *mod, tnode_t *pnode, topo_usb_t *usb) 1740 { 1741 int ret; 1742 topo_usb_controller_t *c; 1743 topo_instance_t inst = 0; 1744 1745 /* 1746 * First count the number of ports, so we can create the right range. 1747 * Then go back and actually create things. Some of the ports here may 1748 * be actually on the chassis, that's OK, we don't mind over counting 1749 * here. 1750 */ 1751 for (c = topo_list_next(&usb->tu_controllers); c != NULL; 1752 c = topo_list_next(c)) { 1753 inst += c->tuc_nports; 1754 } 1755 1756 if ((ret = port_range_create(mod, pnode, 0, inst)) != 0) { 1757 topo_mod_dprintf(mod, "failed to create port range [%u, %u) " 1758 "for mobo", 0, inst); 1759 return (ret); 1760 } 1761 1762 inst = 0; 1763 for (c = topo_list_next(&usb->tu_controllers); c != NULL; 1764 c = topo_list_next(c)) { 1765 if (c->tuc_enumed) 1766 continue; 1767 if ((ret = topo_usb_enum_controller(mod, pnode, c, inst)) != 1768 0) { 1769 return (ret); 1770 } 1771 inst += c->tuc_nports; 1772 } 1773 1774 return (0); 1775 } 1776 1777 static int 1778 topo_usb_enum_pci(topo_mod_t *mod, tnode_t *pnode, topo_usb_t *usb, 1779 di_node_t din) 1780 { 1781 int ret; 1782 topo_usb_controller_t *c; 1783 topo_instance_t min = 0; 1784 1785 for (c = topo_list_next(&usb->tu_controllers); c != NULL; 1786 c = topo_list_next(c)) { 1787 if (din == c->tuc_devinfo) { 1788 break; 1789 } 1790 } 1791 1792 if (c == NULL) { 1793 return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM)); 1794 } 1795 1796 if ((ret = port_range_create(mod, pnode, min, c->tuc_nports)) != 0) { 1797 topo_mod_dprintf(mod, "failed to create port range [%u, %u) " 1798 "for controller %s", min, c->tuc_nports, c->tuc_path); 1799 return (ret); 1800 } 1801 1802 return (topo_usb_enum_controller(mod, pnode, c, min)); 1803 } 1804 1805 static int 1806 topo_usb_enum_chassis(topo_mod_t *mod, tnode_t *pnode, topo_usb_t *usb) 1807 { 1808 int ret; 1809 topo_usb_port_t *p; 1810 topo_instance_t base = 0; 1811 1812 if (usb->tu_nchassis_ports == 0) 1813 return (0); 1814 1815 if ((ret = port_range_create(mod, pnode, 0, usb->tu_nchassis_ports)) != 1816 0) { 1817 topo_mod_dprintf(mod, "failed to create port range [%u, %u) " 1818 "for mobo", 0, usb); 1819 return (ret); 1820 } 1821 1822 for (p = topo_list_next(&usb->tu_chassis_ports); p != NULL; 1823 p = topo_list_next(p)) { 1824 tnode_t *tn; 1825 if ((ret = port_create_usb(mod, pnode, base, &tn)) != 0) 1826 return (ret); 1827 1828 if ((ret = topo_usb_port_properties(mod, tn, p)) != 0) { 1829 return (ret); 1830 } 1831 1832 if ((ret = topo_usb_enum_device(mod, tn, p)) != 0) 1833 return (ret); 1834 1835 base++; 1836 } 1837 1838 return (0); 1839 } 1840 1841 /* ARGSUSED */ 1842 static int 1843 topo_usb_enum(topo_mod_t *mod, tnode_t *pnode, const char *name, 1844 topo_instance_t min, topo_instance_t max, void *modarg, void *data) 1845 { 1846 topo_usb_t *usb; 1847 topo_usb_type_t type; 1848 1849 if (strcmp(name, USB_PCI) == 0) { 1850 type = TOPO_USB_PCI; 1851 } else if (strcmp(name, USB_MOBO) == 0) { 1852 type = TOPO_USB_MOBO; 1853 } else if (strcmp(name, USB_CHASSIS) == 0) { 1854 type = TOPO_USB_CHASSIS; 1855 } else { 1856 topo_mod_dprintf(mod, "usb_enum: asked to enumerate unknown " 1857 "component: %s\n", name); 1858 return (-1); 1859 } 1860 1861 if (type == TOPO_USB_PCI && data == NULL) { 1862 topo_mod_dprintf(mod, "usb_enum: missing argument to " 1863 "PCI controller enum"); 1864 return (-1); 1865 } else if (type != TOPO_USB_PCI && data != NULL) { 1866 topo_mod_dprintf(mod, "extraneous argument to non-controller " 1867 "enum %s", name); 1868 return (-1); 1869 } 1870 1871 if ((usb = topo_mod_getspecific(mod)) == NULL) { 1872 return (-1); 1873 } 1874 1875 if (!usb->tu_enum_done) { 1876 if (topo_usb_gather(mod, usb, pnode) != 0) 1877 return (-1); 1878 usb->tu_enum_done = B_TRUE; 1879 } 1880 1881 /* 1882 * Now that we've built up the topo nodes, enumerate the specific nodes 1883 * based on the requested type. 1884 */ 1885 if (type == TOPO_USB_PCI) { 1886 return (topo_usb_enum_pci(mod, pnode, usb, data)); 1887 } else if (type == TOPO_USB_MOBO) { 1888 return (topo_usb_enum_mobo(mod, pnode, usb)); 1889 } else if (type == TOPO_USB_CHASSIS) { 1890 return (topo_usb_enum_chassis(mod, pnode, usb)); 1891 } 1892 1893 return (0); 1894 } 1895 1896 static const topo_modops_t usb_ops = { 1897 topo_usb_enum, NULL 1898 }; 1899 1900 static topo_modinfo_t usb_mod = { 1901 USB, FM_FMRI_SCHEME_HC, USB_VERSION, &usb_ops 1902 }; 1903 1904 static void 1905 topo_usb_port_free(topo_mod_t *mod, topo_usb_port_t *p) 1906 { 1907 topo_usb_lport_t *lport; 1908 1909 while ((lport = topo_list_next(&p->tup_lports)) != NULL) { 1910 topo_usb_port_t *child; 1911 1912 topo_list_delete(&p->tup_lports, lport); 1913 while ((child = topo_list_next(&lport->tul_ports)) != NULL) { 1914 topo_list_delete(&lport->tul_ports, child); 1915 topo_usb_port_free(mod, child); 1916 } 1917 topo_mod_free(mod, lport, sizeof (topo_usb_lport_t)); 1918 } 1919 1920 topo_mod_free(mod, p, sizeof (topo_usb_port_t)); 1921 } 1922 1923 static void 1924 topo_usb_free(topo_mod_t *mod, topo_usb_t *usb) 1925 { 1926 topo_usb_controller_t *c; 1927 topo_usb_port_t *p; 1928 1929 if (usb == NULL) 1930 return; 1931 1932 while ((p = topo_list_next(&usb->tu_chassis_ports)) != NULL) { 1933 topo_list_delete(&usb->tu_chassis_ports, p); 1934 topo_usb_port_free(mod, p); 1935 } 1936 1937 while ((c = topo_list_next(&usb->tu_controllers)) != NULL) { 1938 1939 topo_list_delete(&usb->tu_controllers, c); 1940 di_devfs_path_free(c->tuc_path); 1941 1942 while ((p = topo_list_next(&c->tuc_ports)) != NULL) { 1943 topo_list_delete(&c->tuc_ports, p); 1944 topo_usb_port_free(mod, p); 1945 } 1946 topo_mod_free(mod, c, sizeof (topo_usb_controller_t)); 1947 } 1948 1949 topo_usb_free_metadata(mod, &usb->tu_metadata); 1950 1951 /* 1952 * The devinfo handle came from fm, don't do anything ourselevs. 1953 */ 1954 usb->tu_devinfo = DI_NODE_NIL; 1955 1956 topo_mod_free(mod, usb, sizeof (topo_usb_t)); 1957 } 1958 1959 static topo_usb_t * 1960 topo_usb_alloc(topo_mod_t *mod) 1961 { 1962 topo_usb_t *usb = NULL; 1963 1964 if ((usb = topo_mod_zalloc(mod, sizeof (topo_usb_t))) == NULL) { 1965 goto free; 1966 } 1967 1968 if ((usb->tu_devinfo = topo_mod_devinfo(mod)) == DI_NODE_NIL) { 1969 goto free; 1970 } 1971 1972 return (usb); 1973 1974 free: 1975 topo_usb_free(mod, usb); 1976 return (NULL); 1977 } 1978 1979 int 1980 _topo_init(topo_mod_t *mod, topo_version_t version) 1981 { 1982 topo_usb_t *usb; 1983 1984 if (getenv("TOPOUSBDEBUG") != NULL) 1985 topo_mod_setdebug(mod); 1986 1987 topo_mod_dprintf(mod, "_mod_init: initializing %s enumerator\n", USB); 1988 1989 if (version != USB_VERSION) { 1990 return (-1); 1991 } 1992 1993 if ((usb = topo_usb_alloc(mod)) == NULL) { 1994 return (-1); 1995 } 1996 1997 if (topo_mod_register(mod, &usb_mod, TOPO_VERSION) != 0) { 1998 topo_usb_free(mod, usb); 1999 return (-1); 2000 } 2001 2002 topo_mod_setspecific(mod, usb); 2003 2004 return (0); 2005 } 2006 2007 void 2008 _topo_fini(topo_mod_t *mod) 2009 { 2010 topo_usb_free(mod, topo_mod_getspecific(mod)); 2011 topo_mod_setspecific(mod, NULL); 2012 } 2013