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