1672fc84aSRobert Mustacchi /*
2672fc84aSRobert Mustacchi  * This file and its contents are supplied under the terms of the
3672fc84aSRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4672fc84aSRobert Mustacchi  * You may only use this file in accordance with the terms of version
5672fc84aSRobert Mustacchi  * 1.0 of the CDDL.
6672fc84aSRobert Mustacchi  *
7672fc84aSRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8672fc84aSRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9672fc84aSRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10672fc84aSRobert Mustacchi  */
11672fc84aSRobert Mustacchi 
12672fc84aSRobert Mustacchi /*
13*0d2006e4SRobert Mustacchi  * Copyright (c) 2019, Joyent, Inc.
14672fc84aSRobert Mustacchi  */
15672fc84aSRobert Mustacchi 
16672fc84aSRobert Mustacchi /*
17672fc84aSRobert Mustacchi  * The purpose of this module is to build topology information for USB devices.
18672fc84aSRobert Mustacchi  * USB devices are more complicated to build topology information for, as there
19672fc84aSRobert Mustacchi  * are multiple sources of information needed to correctly understand the
20672fc84aSRobert Mustacchi  * topology, and the way they present themselves is not always straightforward.
21672fc84aSRobert Mustacchi  *
22672fc84aSRobert Mustacchi  * We enumerate two different types of devices:
23672fc84aSRobert Mustacchi  *
24672fc84aSRobert Mustacchi  *   o USB ports
25672fc84aSRobert Mustacchi  *   o USB devices
26672fc84aSRobert Mustacchi  *
27672fc84aSRobert Mustacchi  * A USB port represents a logical port, while a USB device represents an actual
28672fc84aSRobert Mustacchi  * device that's been plugged in. If a device is a hub, then we'll enumerate
29672fc84aSRobert Mustacchi  * that device as well.
30672fc84aSRobert Mustacchi  *
31672fc84aSRobert Mustacchi  * Now, some basics. There are several different USB controllers that exist in
32672fc84aSRobert Mustacchi  * the system. Some are part of the chipset, while others may be present via
33672fc84aSRobert Mustacchi  * add-on cards. The system interfaces initially with USB devices through a host
34672fc84aSRobert Mustacchi  * controller. Prior to USB 3.0/xhci, a single controller only supported a
35672fc84aSRobert Mustacchi  * single protocol. With USB 3.0, it is possible for a port to share wiring with
36672fc84aSRobert Mustacchi  * both USB 2.0 devices and USB 3.0 devices. However, to the host controller
37672fc84aSRobert Mustacchi  * this appears as two different logical ports.
38672fc84aSRobert Mustacchi  *
39672fc84aSRobert Mustacchi  * To make matters worse, during the transition to USB 3, the ports that were
40672fc84aSRobert Mustacchi  * controlled could be routed to and from a USB 2 controller to a USB 3
41672fc84aSRobert Mustacchi  * controller. This means that there are a lot of ways for ports to overlap.
42672fc84aSRobert Mustacchi  *
43672fc84aSRobert Mustacchi  * In the first case, controllers define a way to perform this mapping by
44672fc84aSRobert Mustacchi  * leveraging ACPI information. Of course, this only helps us if the platform
45672fc84aSRobert Mustacchi  * provides ACPI information, which it may not. When we do know that two ports
46672fc84aSRobert Mustacchi  * are actually the same port, either because of ACPI or because of a
47672fc84aSRobert Mustacchi  * product-specific mapping file, then we'll use that to say two ports are the
48672fc84aSRobert Mustacchi  * same. Otherwise, we'll enumerate them as two separate logical ports.
49672fc84aSRobert Mustacchi  *
50672fc84aSRobert Mustacchi  * To perform the actual enumeration, the first time we're asked to enumerate a
51672fc84aSRobert Mustacchi  * node, we go through and put together an entire picture of all of the USB
52672fc84aSRobert Mustacchi  * devices in the system. This is done so we can make sure to enumerate devices
53672fc84aSRobert Mustacchi  * under specific devices.  The actual topology is determined in a few different
54672fc84aSRobert Mustacchi  * passes.
55672fc84aSRobert Mustacchi  *
56672fc84aSRobert Mustacchi  * Before we walk any trees, we look to see if we have a topo USB metadata file
57672fc84aSRobert Mustacchi  * and if present, load it. However, we do not apply any information from it.
58672fc84aSRobert Mustacchi  *
59672fc84aSRobert Mustacchi  * The first pass uses the devinfo tree to determine all of the USB controllers
60672fc84aSRobert Mustacchi  * and devices that are in the system. We use properties in the devices tree to
61672fc84aSRobert Mustacchi  * identify whether items are a root hub. When a root hub is found, we walk all
62672fc84aSRobert Mustacchi  * of its children and make a note of all of the logical ports under it.
63672fc84aSRobert Mustacchi  *
64672fc84aSRobert Mustacchi  * Next, we walk the information provided by ACPI to try and reduplicate
65672fc84aSRobert Mustacchi  * information about the ports on the system. If the USB topology metadata tells
66672fc84aSRobert Mustacchi  * us that we should not skip ACPI, then we use it. This is done by walking the
67672fc84aSRobert Mustacchi  * /devices/fw tree, looking for USB nodes and then linking them to their
68672fc84aSRobert Mustacchi  * corresponding entries found from the first devinfo walk.
69672fc84aSRobert Mustacchi  *
70672fc84aSRobert Mustacchi  * Finally, we go back and apply metadata to ports that match.
71672fc84aSRobert Mustacchi  *
72672fc84aSRobert Mustacchi  *
73672fc84aSRobert Mustacchi  * To logically keep track of all of this, we have several different structures:
74672fc84aSRobert Mustacchi  *
75672fc84aSRobert Mustacchi  *  topo_usb_controller_t  - Represents a physical controller.
76672fc84aSRobert Mustacchi  *  topo_usb_port_t	   - Represents a physical port. This is a synthetic
77672fc84aSRobert Mustacchi  *			     construct that we put together based on ACPI
78672fc84aSRobert Mustacchi  *			     information.
79672fc84aSRobert Mustacchi  *  topo_usb_lport_t	   - Represents a logical port. This is what the OS
80672fc84aSRobert Mustacchi  *			     actually detects and sees. Each logical port
81672fc84aSRobert Mustacchi  *			     belongs to a corresponding topo_usb_port_t.
82672fc84aSRobert Mustacchi  *  topo_usb_t		   - Represents the overall topology enumeration state.
83672fc84aSRobert Mustacchi  *
84672fc84aSRobert Mustacchi  *
85672fc84aSRobert Mustacchi  * This topo module is invoked at three different points by the surrounding code
86672fc84aSRobert Mustacchi  * and logic. Specifically:
87672fc84aSRobert Mustacchi  *
88672fc84aSRobert Mustacchi  *   * Dynamically by the pcibus enumerator when we encounter PCI add on cards
89672fc84aSRobert Mustacchi  *     which are present in a physical slot. Traditional chipset devices are not
90672fc84aSRobert Mustacchi  *     considered a part of this.
91672fc84aSRobert Mustacchi  *
92672fc84aSRobert Mustacchi  *   * Statically under the motherboard. All ports that don't belong to a PCI
93672fc84aSRobert Mustacchi  *     device are assumed to belong under the motherboard, unless a
94672fc84aSRobert Mustacchi  *     platform-specific topology map maps them under the chassis.
95672fc84aSRobert Mustacchi  *
96672fc84aSRobert Mustacchi  *   * Statically under the chassis. Ports are only placed under the chassis if
97672fc84aSRobert Mustacchi  *     a platform-specific topology file indicates that the port is a part of
98672fc84aSRobert Mustacchi  *     the chassis.
99672fc84aSRobert Mustacchi  */
100672fc84aSRobert Mustacchi 
101672fc84aSRobert Mustacchi #include <libdevinfo.h>
102672fc84aSRobert Mustacchi #include <strings.h>
103672fc84aSRobert Mustacchi #include <sys/types.h>
104672fc84aSRobert Mustacchi #include <sys/stat.h>
105672fc84aSRobert Mustacchi #include <fcntl.h>
106672fc84aSRobert Mustacchi #include <dirent.h>
107672fc84aSRobert Mustacchi #include <sys/debug.h>
108672fc84aSRobert Mustacchi #include <unistd.h>
109672fc84aSRobert Mustacchi 
110672fc84aSRobert Mustacchi #include <sys/fm/protocol.h>
111672fc84aSRobert Mustacchi #include <fm/topo_mod.h>
112672fc84aSRobert Mustacchi #include <fm/topo_list.h>
113672fc84aSRobert Mustacchi #include <fm/topo_method.h>
114672fc84aSRobert Mustacchi 
115672fc84aSRobert Mustacchi #include <topo_port.h>
116672fc84aSRobert Mustacchi 
117672fc84aSRobert Mustacchi #include "topo_usb.h"
118672fc84aSRobert Mustacchi #include "topo_usb_int.h"
119672fc84aSRobert Mustacchi 
120672fc84aSRobert Mustacchi typedef enum topo_usb_type {
121672fc84aSRobert Mustacchi 	TOPO_USB_PCI,
122672fc84aSRobert Mustacchi 	TOPO_USB_MOBO,
123672fc84aSRobert Mustacchi 	TOPO_USB_CHASSIS
124672fc84aSRobert Mustacchi } topo_usb_type_t;
125672fc84aSRobert Mustacchi 
126672fc84aSRobert Mustacchi typedef enum topo_usb_cdrv {
127672fc84aSRobert Mustacchi 	TOPO_USB_D_UNKNOWN,
128672fc84aSRobert Mustacchi 	TOPO_USB_D_UHCI,
129672fc84aSRobert Mustacchi 	TOPO_USB_D_OHCI,
130672fc84aSRobert Mustacchi 	TOPO_USB_D_EHCI,
131672fc84aSRobert Mustacchi 	TOPO_USB_D_XHCI
132672fc84aSRobert Mustacchi } topo_usb_cdrv_t;
133672fc84aSRobert Mustacchi 
134672fc84aSRobert Mustacchi typedef enum topo_usb_protocol {
135672fc84aSRobert Mustacchi 	TOPO_USB_P_UNKNOWN,
136672fc84aSRobert Mustacchi 	TOPO_USB_P_1x,
137672fc84aSRobert Mustacchi 	TOPO_USB_P_20,
138672fc84aSRobert Mustacchi 	TOPO_USB_P_30,
139672fc84aSRobert Mustacchi 	TOPO_USB_P_31
140672fc84aSRobert Mustacchi } topo_usb_protocol_t;
141672fc84aSRobert Mustacchi 
142672fc84aSRobert Mustacchi typedef enum topo_usb_port_connected {
143672fc84aSRobert Mustacchi 	TOPO_USB_C_UNKNOWN,
144672fc84aSRobert Mustacchi 	TOPO_USB_C_DISCONNECTED,
145672fc84aSRobert Mustacchi 	TOPO_USB_C_CONNECTED
146672fc84aSRobert Mustacchi } topo_usb_port_connected_t;
147672fc84aSRobert Mustacchi 
148672fc84aSRobert Mustacchi typedef struct topo_usb_port {
149672fc84aSRobert Mustacchi 	topo_list_t	tup_link;
150672fc84aSRobert Mustacchi 	uint_t		tup_nlports;
151672fc84aSRobert Mustacchi 	topo_list_t	tup_lports;
152672fc84aSRobert Mustacchi 	boolean_t	tup_pld_valid;
153672fc84aSRobert Mustacchi 	acpi_pld_info_t	tup_pld;
154672fc84aSRobert Mustacchi 	uint_t		tup_port_type;
155672fc84aSRobert Mustacchi 	topo_usb_port_connected_t	tup_port_connected;
156672fc84aSRobert Mustacchi 	topo_usb_meta_port_t	*tup_meta;
157672fc84aSRobert Mustacchi } topo_usb_port_t;
158672fc84aSRobert Mustacchi 
159672fc84aSRobert Mustacchi typedef struct topo_usb_lport {
160672fc84aSRobert Mustacchi 	topo_list_t		tul_link;
161672fc84aSRobert Mustacchi 	uint_t			tul_portno;
162672fc84aSRobert Mustacchi 	topo_usb_protocol_t	tul_protocol;
163672fc84aSRobert Mustacchi 	di_node_t		tul_device;
164672fc84aSRobert Mustacchi 	di_node_t		tul_acpi_device;
165672fc84aSRobert Mustacchi 	topo_usb_port_t		*tul_port;
166672fc84aSRobert Mustacchi 	uint_t			tul_nhubd_ports;
167672fc84aSRobert Mustacchi 	uint_t			tul_nports;
168672fc84aSRobert Mustacchi 	topo_list_t		tul_ports;
169672fc84aSRobert Mustacchi 	char			tul_name[PATH_MAX];
170672fc84aSRobert Mustacchi 	const char		*tul_acpi_name;
171672fc84aSRobert Mustacchi } topo_usb_lport_t;
172672fc84aSRobert Mustacchi 
173672fc84aSRobert Mustacchi typedef struct topo_usb_controller {
174672fc84aSRobert Mustacchi 	topo_list_t	tuc_link;
175672fc84aSRobert Mustacchi 	di_node_t	tuc_devinfo;
176672fc84aSRobert Mustacchi 	char		*tuc_path;
177672fc84aSRobert Mustacchi 	char		*tuc_acpi_path;
178672fc84aSRobert Mustacchi 	char		tuc_name[PATH_MAX];
179672fc84aSRobert Mustacchi 	topo_usb_cdrv_t	tuc_driver;
180672fc84aSRobert Mustacchi 	/*
181672fc84aSRobert Mustacchi 	 * Number of actual ports we've created (some of the logical ports are
182672fc84aSRobert Mustacchi 	 * deduped).
183672fc84aSRobert Mustacchi 	 */
184672fc84aSRobert Mustacchi 	uint_t		tuc_nports;
185672fc84aSRobert Mustacchi 	topo_list_t	tuc_ports;
186672fc84aSRobert Mustacchi 	/*
187672fc84aSRobert Mustacchi 	 * Total number of logical ports we expect to exist on this controller.
188672fc84aSRobert Mustacchi 	 * This may be greater than the number of actual ports we've created
189672fc84aSRobert Mustacchi 	 * under it because some physical ports represent more than one logical
190672fc84aSRobert Mustacchi 	 * port (xhci with USB2/3).
191672fc84aSRobert Mustacchi 	 */
192672fc84aSRobert Mustacchi 	uint_t		tuc_nhubd_ports;
193672fc84aSRobert Mustacchi 	/*
194672fc84aSRobert Mustacchi 	 * Keep track of port number and offset information. This is only done
195672fc84aSRobert Mustacchi 	 * for xhci.
196672fc84aSRobert Mustacchi 	 */
197672fc84aSRobert Mustacchi 	uint_t		tuc_nusb20;
198672fc84aSRobert Mustacchi 	uint_t		tuc_fusb20;
199672fc84aSRobert Mustacchi 	uint_t		tuc_nusb30;
200672fc84aSRobert Mustacchi 	uint_t		tuc_fusb30;
201672fc84aSRobert Mustacchi 	uint_t		tuc_nusb31;
202672fc84aSRobert Mustacchi 	uint_t		tuc_fusb31;
203672fc84aSRobert Mustacchi 	boolean_t	tuc_enumed;
204672fc84aSRobert Mustacchi } topo_usb_controller_t;
205672fc84aSRobert Mustacchi 
206672fc84aSRobert Mustacchi typedef struct topo_usb {
207672fc84aSRobert Mustacchi 	topo_list_t	tu_controllers;
208672fc84aSRobert Mustacchi 	boolean_t	tu_enum_done;
209672fc84aSRobert Mustacchi 	di_node_t	tu_devinfo;
210672fc84aSRobert Mustacchi 	topo_list_t	tu_metadata;
211672fc84aSRobert Mustacchi 	topo_usb_meta_flags_t	tu_meta_flags;
212672fc84aSRobert Mustacchi 	topo_list_t	tu_chassis_ports;
213672fc84aSRobert Mustacchi 	uint_t		tu_nchassis_ports;
214672fc84aSRobert Mustacchi } topo_usb_t;
215672fc84aSRobert Mustacchi 
216672fc84aSRobert Mustacchi typedef struct topo_usb_devcfg_arg {
217672fc84aSRobert Mustacchi 	topo_usb_t	*tda_usb;
218672fc84aSRobert Mustacchi 	topo_mod_t	*tda_mod;
219672fc84aSRobert Mustacchi 	boolean_t	tda_fatal;
220672fc84aSRobert Mustacchi } topo_usb_devcfg_arg_t;
221672fc84aSRobert Mustacchi 
222672fc84aSRobert Mustacchi static const topo_pgroup_info_t topo_usb_port_pgroup = {
223672fc84aSRobert Mustacchi 	TOPO_PGROUP_USB_PORT,
224672fc84aSRobert Mustacchi 	TOPO_STABILITY_PRIVATE,
225672fc84aSRobert Mustacchi 	TOPO_STABILITY_PRIVATE,
226672fc84aSRobert Mustacchi 	1
227672fc84aSRobert Mustacchi };
228672fc84aSRobert Mustacchi 
229672fc84aSRobert Mustacchi static const topo_pgroup_info_t topo_io_pgroup = {
230672fc84aSRobert Mustacchi 	TOPO_PGROUP_IO,
231672fc84aSRobert Mustacchi 	TOPO_STABILITY_PRIVATE,
232672fc84aSRobert Mustacchi 	TOPO_STABILITY_PRIVATE,
233672fc84aSRobert Mustacchi 	1
234672fc84aSRobert Mustacchi };
235672fc84aSRobert Mustacchi 
236672fc84aSRobert Mustacchi static const topo_pgroup_info_t topo_binding_pgroup = {
237672fc84aSRobert Mustacchi 	TOPO_PGROUP_BINDING,
238672fc84aSRobert Mustacchi 	TOPO_STABILITY_PRIVATE,
239672fc84aSRobert Mustacchi 	TOPO_STABILITY_PRIVATE,
240672fc84aSRobert Mustacchi 	1
241672fc84aSRobert Mustacchi };
242672fc84aSRobert Mustacchi 
243672fc84aSRobert Mustacchi static const topo_pgroup_info_t topo_usb_props_pgroup = {
244672fc84aSRobert Mustacchi 	TOPO_PGROUP_USB_PROPS,
245672fc84aSRobert Mustacchi 	TOPO_STABILITY_PRIVATE,
246672fc84aSRobert Mustacchi 	TOPO_STABILITY_PRIVATE,
247672fc84aSRobert Mustacchi 	1
248672fc84aSRobert Mustacchi };
249672fc84aSRobert Mustacchi 
250672fc84aSRobert Mustacchi /* Required forwards */
251672fc84aSRobert Mustacchi static int topo_usb_enum_device(topo_mod_t *, tnode_t *, topo_usb_port_t *);
252672fc84aSRobert Mustacchi 
253672fc84aSRobert Mustacchi /*
254672fc84aSRobert Mustacchi  * Defines the maximum number of USB ports that can exist. Ports are basically
255672fc84aSRobert Mustacchi  * defined by a uint8_t, meaning that we can go up to UINT8_MAX inclusively.
256672fc84aSRobert Mustacchi  */
257672fc84aSRobert Mustacchi #define	USB_TOPO_PORT_MAX	256
258672fc84aSRobert Mustacchi 
259672fc84aSRobert Mustacchi /*
260672fc84aSRobert Mustacchi  * Default value to indicate that a USB port has no valid type.
261672fc84aSRobert Mustacchi  */
262672fc84aSRobert Mustacchi #define	USB_TOPO_PORT_TYPE_DEFAULT	0xff
263672fc84aSRobert Mustacchi 
264672fc84aSRobert Mustacchi /*
265672fc84aSRobert Mustacchi  * These come from the ACPI 6.2 / Table 9-290 UPC Return Package Values.
266672fc84aSRobert Mustacchi  */
267672fc84aSRobert Mustacchi static const char *
topo_usb_port_type_to_string(int type)268672fc84aSRobert Mustacchi topo_usb_port_type_to_string(int type)
269672fc84aSRobert Mustacchi {
270672fc84aSRobert Mustacchi 	switch (type) {
271672fc84aSRobert Mustacchi 	case 0x00:
272672fc84aSRobert Mustacchi 		return ("Type A connector");
273672fc84aSRobert Mustacchi 	case 0x01:
274672fc84aSRobert Mustacchi 		return ("Mini-AB connector");
275672fc84aSRobert Mustacchi 	case 0x02:
276672fc84aSRobert Mustacchi 		return ("ExpressCard");
277672fc84aSRobert Mustacchi 	case 0x03:
278672fc84aSRobert Mustacchi 		return ("USB 3 Standard-A connector");
279672fc84aSRobert Mustacchi 	case 0x04:
280672fc84aSRobert Mustacchi 		return ("USB 3 Standard-B connector");
281672fc84aSRobert Mustacchi 	case 0x05:
282672fc84aSRobert Mustacchi 		return ("USB 3 Micro-B connector");
283672fc84aSRobert Mustacchi 	case 0x06:
284672fc84aSRobert Mustacchi 		return ("USB 3 Micro-AB connector");
285672fc84aSRobert Mustacchi 	case 0x07:
286672fc84aSRobert Mustacchi 		return ("USB 3 Power-B connector");
287672fc84aSRobert Mustacchi 	case 0x08:
288672fc84aSRobert Mustacchi 		return ("Type C connector - USB2-only");
289672fc84aSRobert Mustacchi 	case 0x09:
290672fc84aSRobert Mustacchi 		return ("Type C connector - USB2 and SS with Switch");
291672fc84aSRobert Mustacchi 	case 0x0A:
292672fc84aSRobert Mustacchi 		return ("Type C connector - USB2 and SS without Switch");
293672fc84aSRobert Mustacchi 	/* 0x0B->0xFE are reserved. Treat them like 0xFF */
294672fc84aSRobert Mustacchi 	case 0xFF:
295672fc84aSRobert Mustacchi 	default:
296672fc84aSRobert Mustacchi 		return ("Unknown");
297672fc84aSRobert Mustacchi 	}
298672fc84aSRobert Mustacchi }
299672fc84aSRobert Mustacchi 
300672fc84aSRobert Mustacchi /*
301672fc84aSRobert Mustacchi  * Searches the list of ports at a given layer (not recursively) for the
302672fc84aSRobert Mustacchi  * specific port id.
303672fc84aSRobert Mustacchi  */
304672fc84aSRobert Mustacchi static topo_usb_lport_t *
topo_usb_lport_find(topo_list_t * plist,uint_t logid)305672fc84aSRobert Mustacchi topo_usb_lport_find(topo_list_t *plist, uint_t logid)
306672fc84aSRobert Mustacchi {
307672fc84aSRobert Mustacchi 	topo_usb_port_t *p;
308672fc84aSRobert Mustacchi 
309672fc84aSRobert Mustacchi 	for (p = topo_list_next(plist); p != NULL; p = topo_list_next(p)) {
310672fc84aSRobert Mustacchi 		topo_usb_lport_t *l;
311672fc84aSRobert Mustacchi 
312672fc84aSRobert Mustacchi 		for (l = topo_list_next(&p->tup_lports); l != NULL;
313672fc84aSRobert Mustacchi 		    l = topo_list_next(l)) {
314672fc84aSRobert Mustacchi 			if (l->tul_portno == logid)
315672fc84aSRobert Mustacchi 				return (l);
316672fc84aSRobert Mustacchi 		}
317672fc84aSRobert Mustacchi 	}
318672fc84aSRobert Mustacchi 	return (NULL);
319672fc84aSRobert Mustacchi }
320672fc84aSRobert Mustacchi 
321672fc84aSRobert Mustacchi /*
322672fc84aSRobert Mustacchi  * Create an instance of a controller and seed the basic information.
323672fc84aSRobert Mustacchi  */
324672fc84aSRobert Mustacchi static topo_usb_controller_t *
topo_usb_controller_create(topo_mod_t * mod,topo_usb_t * usb,di_node_t node)325672fc84aSRobert Mustacchi topo_usb_controller_create(topo_mod_t *mod, topo_usb_t *usb, di_node_t node)
326672fc84aSRobert Mustacchi {
327672fc84aSRobert Mustacchi 	int *pcount, inst;
328672fc84aSRobert Mustacchi 	char *drvname, *acpi;
329672fc84aSRobert Mustacchi 	topo_usb_controller_t *c;
330672fc84aSRobert Mustacchi 
331672fc84aSRobert Mustacchi 	/*
332672fc84aSRobert Mustacchi 	 * If we can't get the port count or the driver, then this node is
333672fc84aSRobert Mustacchi 	 * uninteresting.
334672fc84aSRobert Mustacchi 	 */
335672fc84aSRobert Mustacchi 	if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "usb-port-count",
336672fc84aSRobert Mustacchi 	    &pcount) != 1) {
337672fc84aSRobert Mustacchi 		return (NULL);
338672fc84aSRobert Mustacchi 	}
339672fc84aSRobert Mustacchi 
340672fc84aSRobert Mustacchi 	if ((drvname = di_driver_name(node)) == NULL ||
341672fc84aSRobert Mustacchi 	    (inst = di_instance(node) == -1))
342672fc84aSRobert Mustacchi 		return (NULL);
343672fc84aSRobert Mustacchi 
344672fc84aSRobert Mustacchi 	if ((c = topo_mod_zalloc(mod, sizeof (topo_usb_controller_t))) ==
345672fc84aSRobert Mustacchi 	    NULL || *pcount <= 0) {
346672fc84aSRobert Mustacchi 		return (NULL);
347672fc84aSRobert Mustacchi 	}
348672fc84aSRobert Mustacchi 
349672fc84aSRobert Mustacchi 	if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, "acpi-namespace",
350672fc84aSRobert Mustacchi 	    &acpi) == 1) {
351672fc84aSRobert Mustacchi 		c->tuc_acpi_path = acpi;
352672fc84aSRobert Mustacchi 	}
353672fc84aSRobert Mustacchi 
354672fc84aSRobert Mustacchi 	c->tuc_nhubd_ports = (uint_t)*pcount;
355672fc84aSRobert Mustacchi 	c->tuc_devinfo = node;
356672fc84aSRobert Mustacchi 	c->tuc_path = di_devfs_path(node);
357672fc84aSRobert Mustacchi 	(void) snprintf(c->tuc_name, sizeof (c->tuc_name), "%s%d", drvname,
358672fc84aSRobert Mustacchi 	    inst);
359672fc84aSRobert Mustacchi 	if (strcmp(drvname, "xhci") == 0) {
360672fc84aSRobert Mustacchi 		int *p;
361672fc84aSRobert Mustacchi 
362672fc84aSRobert Mustacchi 		c->tuc_driver = TOPO_USB_D_XHCI;
363672fc84aSRobert Mustacchi 
364672fc84aSRobert Mustacchi 		/*
365672fc84aSRobert Mustacchi 		 * Grab the properties that we need so we can better do a port
366672fc84aSRobert Mustacchi 		 * speed mapping.
367672fc84aSRobert Mustacchi 		 */
368672fc84aSRobert Mustacchi 		if (di_prop_lookup_ints(DDI_DEV_T_ANY, node,
369672fc84aSRobert Mustacchi 		    "usb2.0-port-count", &p) == 1 && *p > 0) {
370672fc84aSRobert Mustacchi 			c->tuc_nusb20 = (uint_t)*p;
371672fc84aSRobert Mustacchi 		}
372672fc84aSRobert Mustacchi 
373672fc84aSRobert Mustacchi 		if (di_prop_lookup_ints(DDI_DEV_T_ANY, node,
374672fc84aSRobert Mustacchi 		    "usb2.0-first-port", &p) == 1 && *p > 0) {
375672fc84aSRobert Mustacchi 			c->tuc_fusb20 = (uint_t)*p;
376672fc84aSRobert Mustacchi 		}
377672fc84aSRobert Mustacchi 
378672fc84aSRobert Mustacchi 		if (di_prop_lookup_ints(DDI_DEV_T_ANY, node,
379672fc84aSRobert Mustacchi 		    "usb3.0-port-count", &p) == 1 && *p > 0) {
380672fc84aSRobert Mustacchi 			c->tuc_nusb30 = (uint_t)*p;
381672fc84aSRobert Mustacchi 		}
382672fc84aSRobert Mustacchi 
383672fc84aSRobert Mustacchi 		if (di_prop_lookup_ints(DDI_DEV_T_ANY, node,
384672fc84aSRobert Mustacchi 		    "usb3.0-first-port", &p) == 1 && *p > 0) {
385672fc84aSRobert Mustacchi 			c->tuc_fusb30 = (uint_t)*p;
386672fc84aSRobert Mustacchi 		}
387672fc84aSRobert Mustacchi 
388672fc84aSRobert Mustacchi 		if (di_prop_lookup_ints(DDI_DEV_T_ANY, node,
389672fc84aSRobert Mustacchi 		    "usb3.1-port-count", &p) == 1 && *p > 0) {
390672fc84aSRobert Mustacchi 			c->tuc_nusb31 = (uint_t)*p;
391672fc84aSRobert Mustacchi 		}
392672fc84aSRobert Mustacchi 
393672fc84aSRobert Mustacchi 		if (di_prop_lookup_ints(DDI_DEV_T_ANY, node,
394672fc84aSRobert Mustacchi 		    "usb3.1-first-port", &p) == 1 && *p > 0) {
395672fc84aSRobert Mustacchi 			c->tuc_fusb31 = (uint_t)*p;
396672fc84aSRobert Mustacchi 		}
397672fc84aSRobert Mustacchi 	} else if (strcmp(drvname, "ehci") == 0) {
398672fc84aSRobert Mustacchi 		c->tuc_driver = TOPO_USB_D_EHCI;
399672fc84aSRobert Mustacchi 	} else if (strcmp(drvname, "uhci") == 0) {
400672fc84aSRobert Mustacchi 		c->tuc_driver = TOPO_USB_D_UHCI;
401672fc84aSRobert Mustacchi 	} else if (strcmp(drvname, "ohci") == 0) {
402672fc84aSRobert Mustacchi 		c->tuc_driver = TOPO_USB_D_OHCI;
403672fc84aSRobert Mustacchi 	} else {
404672fc84aSRobert Mustacchi 		c->tuc_driver = TOPO_USB_D_UNKNOWN;
405672fc84aSRobert Mustacchi 	}
406672fc84aSRobert Mustacchi 	topo_list_append(&usb->tu_controllers, c);
407672fc84aSRobert Mustacchi 	topo_mod_dprintf(mod, "created new USB controller at %s", c->tuc_path);
408672fc84aSRobert Mustacchi 
409672fc84aSRobert Mustacchi 	return (c);
410672fc84aSRobert Mustacchi }
411672fc84aSRobert Mustacchi 
412672fc84aSRobert Mustacchi /*
413672fc84aSRobert Mustacchi  * Process this port and any others that might exist.
414672fc84aSRobert Mustacchi  */
415672fc84aSRobert Mustacchi static boolean_t
topo_usb_gather_acpi_port(topo_mod_t * mod,topo_usb_t * usb,topo_list_t * plist,uint_t * nports,topo_usb_controller_t * tuc,di_node_t portinfo)416672fc84aSRobert Mustacchi topo_usb_gather_acpi_port(topo_mod_t *mod, topo_usb_t *usb, topo_list_t *plist,
417672fc84aSRobert Mustacchi     uint_t *nports, topo_usb_controller_t *tuc, di_node_t portinfo)
418672fc84aSRobert Mustacchi {
419672fc84aSRobert Mustacchi 	int64_t *portno;
420672fc84aSRobert Mustacchi 	uchar_t *loc;
421672fc84aSRobert Mustacchi 	int loclen, *type;
422672fc84aSRobert Mustacchi 	char *acpi;
423672fc84aSRobert Mustacchi 	acpi_pld_info_t pld;
424672fc84aSRobert Mustacchi 	boolean_t pld_valid = B_FALSE;
425672fc84aSRobert Mustacchi 	topo_usb_port_t *port = NULL;
426672fc84aSRobert Mustacchi 	topo_usb_lport_t *lport;
427672fc84aSRobert Mustacchi 	di_node_t child;
428672fc84aSRobert Mustacchi 
429672fc84aSRobert Mustacchi 	/*
430672fc84aSRobert Mustacchi 	 * Get the port's address, it's a required value. Because this is coming
431672fc84aSRobert Mustacchi 	 * from firmware, we cannot trust the port's value to be correct.
432672fc84aSRobert Mustacchi 	 */
433672fc84aSRobert Mustacchi 	if (di_prop_lookup_int64(DDI_DEV_T_ANY, portinfo, "acpi-address",
434672fc84aSRobert Mustacchi 	    &portno) != 1 || *portno < 1 || *portno >= USB_TOPO_PORT_MAX) {
435672fc84aSRobert Mustacchi 		return (B_FALSE);
436672fc84aSRobert Mustacchi 	}
437672fc84aSRobert Mustacchi 
438672fc84aSRobert Mustacchi 	if (di_prop_lookup_strings(DDI_DEV_T_ANY, portinfo, "acpi-namespace",
439672fc84aSRobert Mustacchi 	    &acpi) != 1) {
440672fc84aSRobert Mustacchi 		return (B_FALSE);
441672fc84aSRobert Mustacchi 	}
442672fc84aSRobert Mustacchi 
443672fc84aSRobert Mustacchi 	/*
444672fc84aSRobert Mustacchi 	 * Check to see if we have any ACPI location information. If we do, we
445672fc84aSRobert Mustacchi 	 * can decode it.
446672fc84aSRobert Mustacchi 	 */
447672fc84aSRobert Mustacchi 	if ((loclen = di_prop_lookup_bytes(DDI_DEV_T_ANY, portinfo,
448672fc84aSRobert Mustacchi 	    "acpi-physical-location", &loc)) >= ACPI_PLD_REV1_BUFFER_SIZE &&
449672fc84aSRobert Mustacchi 	    usbtopo_decode_pld(loc, loclen, &pld)) {
450672fc84aSRobert Mustacchi 		pld_valid = B_TRUE;
451672fc84aSRobert Mustacchi 	}
452672fc84aSRobert Mustacchi 
453672fc84aSRobert Mustacchi 	/*
454672fc84aSRobert Mustacchi 	 * Find the corresponding lport. If this node doesn't happen to match
455672fc84aSRobert Mustacchi 	 * something we've enumerated from the hub. Warn about that fact and
456672fc84aSRobert Mustacchi 	 * consider this bad data.
457672fc84aSRobert Mustacchi 	 */
458672fc84aSRobert Mustacchi 	lport = topo_usb_lport_find(plist, (uint_t)*portno);
459672fc84aSRobert Mustacchi 	if (lport == NULL) {
460672fc84aSRobert Mustacchi 		topo_mod_dprintf(mod, "failed to find physical usb port for "
461672fc84aSRobert Mustacchi 		    "%s/%u", acpi, (uint_t)*portno);
462672fc84aSRobert Mustacchi 		return (B_TRUE);
463672fc84aSRobert Mustacchi 	}
464672fc84aSRobert Mustacchi 
465672fc84aSRobert Mustacchi 	if (lport->tul_acpi_device != DI_NODE_NIL) {
466672fc84aSRobert Mustacchi 		topo_mod_dprintf(mod, "logical port already bound to %s, not "
467672fc84aSRobert Mustacchi 		    "binding to %s", lport->tul_acpi_name, acpi);
468672fc84aSRobert Mustacchi 		return (B_FALSE);
469672fc84aSRobert Mustacchi 	}
470672fc84aSRobert Mustacchi 
471672fc84aSRobert Mustacchi 	lport->tul_acpi_device = portinfo;
472672fc84aSRobert Mustacchi 	lport->tul_acpi_name = acpi;
473672fc84aSRobert Mustacchi 	port = lport->tul_port;
474672fc84aSRobert Mustacchi 
475672fc84aSRobert Mustacchi 	if (pld_valid) {
476672fc84aSRobert Mustacchi 		port->tup_pld_valid = B_TRUE;
477672fc84aSRobert Mustacchi 		port->tup_pld = pld;
478672fc84aSRobert Mustacchi 	}
479672fc84aSRobert Mustacchi 
480672fc84aSRobert Mustacchi 	if (di_prop_lookup_ints(DDI_DEV_T_ANY, portinfo, "usb-port-type",
481672fc84aSRobert Mustacchi 	    &type) == 1 && *type >= 0) {
482672fc84aSRobert Mustacchi 		port->tup_port_type = *type;
483672fc84aSRobert Mustacchi 	} else {
484672fc84aSRobert Mustacchi 		port->tup_port_type = USB_TOPO_PORT_TYPE_DEFAULT;
485672fc84aSRobert Mustacchi 	}
486672fc84aSRobert Mustacchi 
487672fc84aSRobert Mustacchi 	if (di_prop_find(DDI_DEV_T_ANY, portinfo,
488672fc84aSRobert Mustacchi 	    "usb-port-connectable") != DI_PROP_NIL) {
489672fc84aSRobert Mustacchi 		port->tup_port_connected = TOPO_USB_C_CONNECTED;
490672fc84aSRobert Mustacchi 	} else {
491672fc84aSRobert Mustacchi 		port->tup_port_connected = TOPO_USB_C_DISCONNECTED;
492672fc84aSRobert Mustacchi 	}
493672fc84aSRobert Mustacchi 
494672fc84aSRobert Mustacchi 	for (child = di_child_node(portinfo); child != NULL;
495672fc84aSRobert Mustacchi 	    child = di_sibling_node(child)) {
496672fc84aSRobert Mustacchi 		const char *pname;
497672fc84aSRobert Mustacchi 
498672fc84aSRobert Mustacchi 		pname = di_node_name(child);
499672fc84aSRobert Mustacchi 		if (pname == NULL || strcmp(pname, "port") != 0) {
500672fc84aSRobert Mustacchi 			continue;
501672fc84aSRobert Mustacchi 		}
502672fc84aSRobert Mustacchi 
503672fc84aSRobert Mustacchi 		if (!topo_usb_gather_acpi_port(mod, usb, &lport->tul_ports,
504672fc84aSRobert Mustacchi 		    &lport->tul_nports, tuc, child)) {
505672fc84aSRobert Mustacchi 			return (B_FALSE);
506672fc84aSRobert Mustacchi 		}
507672fc84aSRobert Mustacchi 	}
508672fc84aSRobert Mustacchi 
509672fc84aSRobert Mustacchi 	topo_mod_dprintf(mod, "discovered %u ACPI usb child ports",
510672fc84aSRobert Mustacchi 	    lport->tul_nports);
511672fc84aSRobert Mustacchi 
512672fc84aSRobert Mustacchi 	return (B_TRUE);
513672fc84aSRobert Mustacchi }
514672fc84aSRobert Mustacchi 
515672fc84aSRobert Mustacchi /*
516672fc84aSRobert Mustacchi  * First, bootstrap all of our information by reading the ACPI information
517672fc84aSRobert Mustacchi  * exposed in the devinfo tree. All of the nodes we care about will be under
518672fc84aSRobert Mustacchi  * /fw/sb@XX/usbrootub@YYY/port@ZZZ
519672fc84aSRobert Mustacchi  */
520672fc84aSRobert Mustacchi static boolean_t
topo_usb_gather_acpi(topo_mod_t * mod,topo_usb_t * usb)521672fc84aSRobert Mustacchi topo_usb_gather_acpi(topo_mod_t *mod, topo_usb_t *usb)
522672fc84aSRobert Mustacchi {
523672fc84aSRobert Mustacchi 	di_node_t fwroot, sbnode;
524672fc84aSRobert Mustacchi 
525672fc84aSRobert Mustacchi 	/*
526672fc84aSRobert Mustacchi 	 * If we can't find the /fw node, that's fine. We may not have any ACPI
527672fc84aSRobert Mustacchi 	 * information on the system.
528672fc84aSRobert Mustacchi 	 */
529672fc84aSRobert Mustacchi 	fwroot = di_lookup_node(usb->tu_devinfo, "/fw");
530672fc84aSRobert Mustacchi 	if (fwroot == DI_NODE_NIL)
531672fc84aSRobert Mustacchi 		return (B_TRUE);
532672fc84aSRobert Mustacchi 
533672fc84aSRobert Mustacchi 	for (sbnode = di_child_node(fwroot); sbnode != DI_NODE_NIL;
534672fc84aSRobert Mustacchi 	    sbnode = di_sibling_node(sbnode)) {
535672fc84aSRobert Mustacchi 		const char *sbname;
536672fc84aSRobert Mustacchi 		di_node_t hub;
537672fc84aSRobert Mustacchi 
538672fc84aSRobert Mustacchi 		sbname = di_node_name(sbnode);
539672fc84aSRobert Mustacchi 		if (sbname == NULL || strcmp(sbname, "sb") != 0) {
540672fc84aSRobert Mustacchi 			continue;
541672fc84aSRobert Mustacchi 		}
542672fc84aSRobert Mustacchi 
543672fc84aSRobert Mustacchi 		for (hub = di_child_node(sbnode); hub != DI_NODE_NIL;
544672fc84aSRobert Mustacchi 		    hub = di_sibling_node(hub)) {
545672fc84aSRobert Mustacchi 			const char *hubname;
546672fc84aSRobert Mustacchi 			char *acpi;
547672fc84aSRobert Mustacchi 			topo_usb_controller_t *tuc;
548672fc84aSRobert Mustacchi 			di_node_t port;
549672fc84aSRobert Mustacchi 
550672fc84aSRobert Mustacchi 			hubname = di_node_name(hub);
551672fc84aSRobert Mustacchi 			if (hubname == NULL ||
552672fc84aSRobert Mustacchi 			    strcmp(hubname, "usbroothub") != 0) {
553672fc84aSRobert Mustacchi 				continue;
554672fc84aSRobert Mustacchi 			}
555672fc84aSRobert Mustacchi 
556672fc84aSRobert Mustacchi 			if (di_prop_lookup_strings(DDI_DEV_T_ANY, hub,
557672fc84aSRobert Mustacchi 			    "acpi-controller-name", &acpi) != 1) {
558672fc84aSRobert Mustacchi 				continue;
559672fc84aSRobert Mustacchi 			}
560672fc84aSRobert Mustacchi 
561672fc84aSRobert Mustacchi 			for (tuc = topo_list_next(&usb->tu_controllers);
562672fc84aSRobert Mustacchi 			    tuc != NULL;
563672fc84aSRobert Mustacchi 			    tuc = topo_list_next(tuc)) {
564672fc84aSRobert Mustacchi 				if (tuc->tuc_acpi_path != NULL &&
565672fc84aSRobert Mustacchi 				    strcmp(acpi, tuc->tuc_acpi_path) == 0)
566672fc84aSRobert Mustacchi 					break;
567672fc84aSRobert Mustacchi 			}
568672fc84aSRobert Mustacchi 
569672fc84aSRobert Mustacchi 			if (tuc == NULL) {
570672fc84aSRobert Mustacchi 				topo_mod_dprintf(mod, "failed to find USB "
571672fc84aSRobert Mustacchi 				    "controller for ACPI path %s", acpi);
572672fc84aSRobert Mustacchi 				continue;
573672fc84aSRobert Mustacchi 			}
574672fc84aSRobert Mustacchi 
575672fc84aSRobert Mustacchi 			for (port = di_child_node(hub); port != NULL;
576672fc84aSRobert Mustacchi 			    port = di_sibling_node(port)) {
577672fc84aSRobert Mustacchi 				const char *pname;
578672fc84aSRobert Mustacchi 
579672fc84aSRobert Mustacchi 				pname = di_node_name(port);
580672fc84aSRobert Mustacchi 				if (pname == NULL ||
581672fc84aSRobert Mustacchi 				    strcmp(pname, "port") != 0) {
582672fc84aSRobert Mustacchi 					continue;
583672fc84aSRobert Mustacchi 				}
584672fc84aSRobert Mustacchi 
585672fc84aSRobert Mustacchi 				if (!topo_usb_gather_acpi_port(mod, usb,
586672fc84aSRobert Mustacchi 				    &tuc->tuc_ports, &tuc->tuc_nports, tuc,
587672fc84aSRobert Mustacchi 				    port)) {
588672fc84aSRobert Mustacchi 					return (B_FALSE);
589672fc84aSRobert Mustacchi 				}
590672fc84aSRobert Mustacchi 			}
591672fc84aSRobert Mustacchi 
592672fc84aSRobert Mustacchi 			topo_mod_dprintf(mod, "found ACPI usb controller %s "
593672fc84aSRobert Mustacchi 			    "with %d top-level ports", tuc->tuc_path,
594672fc84aSRobert Mustacchi 			    tuc->tuc_nports);
595672fc84aSRobert Mustacchi 		}
596672fc84aSRobert Mustacchi 	}
597672fc84aSRobert Mustacchi 
598672fc84aSRobert Mustacchi 	return (B_TRUE);
599672fc84aSRobert Mustacchi }
600672fc84aSRobert Mustacchi 
601672fc84aSRobert Mustacchi static topo_usb_port_t *
topo_usb_port_create(topo_mod_t * mod,uint_t portno,const char * parent,char sep)602672fc84aSRobert Mustacchi topo_usb_port_create(topo_mod_t *mod, uint_t portno, const char *parent,
603672fc84aSRobert Mustacchi     char sep)
604672fc84aSRobert Mustacchi {
605672fc84aSRobert Mustacchi 	topo_usb_lport_t *l;
606672fc84aSRobert Mustacchi 	topo_usb_port_t *p;
607672fc84aSRobert Mustacchi 
608672fc84aSRobert Mustacchi 	if ((l = topo_mod_zalloc(mod, sizeof (topo_usb_lport_t))) == NULL) {
609672fc84aSRobert Mustacchi 		return (NULL);
610672fc84aSRobert Mustacchi 	}
611672fc84aSRobert Mustacchi 	l->tul_portno = portno;
612672fc84aSRobert Mustacchi 	if (snprintf(l->tul_name, sizeof (l->tul_name), "%s%c%u", parent, sep,
613672fc84aSRobert Mustacchi 	    portno) >= sizeof (l->tul_name)) {
614672fc84aSRobert Mustacchi 		topo_mod_free(mod, l, sizeof (topo_usb_lport_t));
615672fc84aSRobert Mustacchi 		return (NULL);
616672fc84aSRobert Mustacchi 	}
617672fc84aSRobert Mustacchi 
618672fc84aSRobert Mustacchi 	if ((p = topo_mod_zalloc(mod, sizeof (topo_usb_port_t))) == NULL) {
619672fc84aSRobert Mustacchi 		topo_mod_free(mod, l, sizeof (topo_usb_lport_t));
620672fc84aSRobert Mustacchi 		return (NULL);
621672fc84aSRobert Mustacchi 	}
622672fc84aSRobert Mustacchi 	l->tul_port = p;
623672fc84aSRobert Mustacchi 	p->tup_port_type = USB_TOPO_PORT_TYPE_DEFAULT;
624672fc84aSRobert Mustacchi 	topo_list_append(&p->tup_lports, l);
625672fc84aSRobert Mustacchi 	p->tup_nlports++;
626672fc84aSRobert Mustacchi 
627672fc84aSRobert Mustacchi 	return (p);
628672fc84aSRobert Mustacchi }
629672fc84aSRobert Mustacchi 
630672fc84aSRobert Mustacchi /*
631672fc84aSRobert Mustacchi  * Set the protocol of a port that belongs to a root hub.
632672fc84aSRobert Mustacchi  */
633672fc84aSRobert Mustacchi static void
topo_usb_set_rhub_port_protocol(topo_mod_t * mod,topo_usb_controller_t * tuc,topo_usb_lport_t * lport)634672fc84aSRobert Mustacchi topo_usb_set_rhub_port_protocol(topo_mod_t *mod, topo_usb_controller_t *tuc,
635672fc84aSRobert Mustacchi     topo_usb_lport_t *lport)
636672fc84aSRobert Mustacchi {
637672fc84aSRobert Mustacchi 	switch (tuc->tuc_driver) {
638672fc84aSRobert Mustacchi 	case TOPO_USB_D_XHCI:
639672fc84aSRobert Mustacchi 		break;
640672fc84aSRobert Mustacchi 	case TOPO_USB_D_UHCI:
641672fc84aSRobert Mustacchi 	case TOPO_USB_D_OHCI:
642672fc84aSRobert Mustacchi 		lport->tul_protocol = TOPO_USB_P_1x;
643672fc84aSRobert Mustacchi 		return;
644672fc84aSRobert Mustacchi 	case TOPO_USB_D_EHCI:
645672fc84aSRobert Mustacchi 		lport->tul_protocol = TOPO_USB_P_20;
646672fc84aSRobert Mustacchi 		return;
647672fc84aSRobert Mustacchi 	case TOPO_USB_D_UNKNOWN:
648672fc84aSRobert Mustacchi 	default:
649672fc84aSRobert Mustacchi 		lport->tul_protocol = TOPO_USB_P_UNKNOWN;
650672fc84aSRobert Mustacchi 		return;
651672fc84aSRobert Mustacchi 	}
652672fc84aSRobert Mustacchi 
653672fc84aSRobert Mustacchi 	/*
654672fc84aSRobert Mustacchi 	 * The xHCI controller can support multiple different, protocols. It
655672fc84aSRobert Mustacchi 	 * communicates this information to us via devinfo properties. It's
656672fc84aSRobert Mustacchi 	 * possible that a port that is within max ports is not within the range
657672fc84aSRobert Mustacchi 	 * here. If that's the case, we'll set it to unknown.
658672fc84aSRobert Mustacchi 	 */
659672fc84aSRobert Mustacchi 	if (lport->tul_portno >= tuc->tuc_fusb20 &&
660672fc84aSRobert Mustacchi 	    lport->tul_portno < tuc->tuc_fusb20 + tuc->tuc_nusb20) {
661672fc84aSRobert Mustacchi 		lport->tul_protocol = TOPO_USB_P_20;
662672fc84aSRobert Mustacchi 	} else if (lport->tul_portno >= tuc->tuc_fusb30 &&
663672fc84aSRobert Mustacchi 	    lport->tul_portno < tuc->tuc_fusb30 + tuc->tuc_nusb30) {
664672fc84aSRobert Mustacchi 		lport->tul_protocol = TOPO_USB_P_30;
665672fc84aSRobert Mustacchi 	} else if (lport->tul_portno >= tuc->tuc_fusb31 &&
666672fc84aSRobert Mustacchi 	    lport->tul_portno < tuc->tuc_fusb31 + tuc->tuc_nusb31) {
667672fc84aSRobert Mustacchi 		lport->tul_protocol = TOPO_USB_P_31;
668672fc84aSRobert Mustacchi 	} else {
669672fc84aSRobert Mustacchi 		lport->tul_protocol = TOPO_USB_P_UNKNOWN;
670672fc84aSRobert Mustacchi 	}
671672fc84aSRobert Mustacchi }
672672fc84aSRobert Mustacchi 
673672fc84aSRobert Mustacchi /*
674672fc84aSRobert Mustacchi  * We've found a node on the list. Attempt to find its corresponding port. If we
675672fc84aSRobert Mustacchi  * find a hub, then we will descend further down this part of the tree.
676672fc84aSRobert Mustacchi  */
677672fc84aSRobert Mustacchi static int
topo_usb_gather_devcfg_port(topo_mod_t * mod,topo_usb_controller_t * c,topo_list_t * plist,di_node_t node)678672fc84aSRobert Mustacchi topo_usb_gather_devcfg_port(topo_mod_t *mod, topo_usb_controller_t *c,
679672fc84aSRobert Mustacchi     topo_list_t *plist, di_node_t node)
680672fc84aSRobert Mustacchi {
681672fc84aSRobert Mustacchi 	int *vend, *reg, *nports;
682672fc84aSRobert Mustacchi 	topo_usb_lport_t *l;
683672fc84aSRobert Mustacchi 	char *drvname;
684672fc84aSRobert Mustacchi 
685672fc84aSRobert Mustacchi 	/*
686672fc84aSRobert Mustacchi 	 * Look for the presence of the usb-vendor-id property to determine
687672fc84aSRobert Mustacchi 	 * whether or not this is a usb device node. usba always adds this
688672fc84aSRobert Mustacchi 	 * to the devices that it enumerates.
689672fc84aSRobert Mustacchi 	 */
690672fc84aSRobert Mustacchi 	if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "usb-vendor-id",
691672fc84aSRobert Mustacchi 	    &vend) != 1) {
692672fc84aSRobert Mustacchi 		topo_mod_dprintf(mod, "failed to find usb-vendor-id property "
693672fc84aSRobert Mustacchi 		    "for child");
694672fc84aSRobert Mustacchi 		return (0);
695672fc84aSRobert Mustacchi 	}
696672fc84aSRobert Mustacchi 
697672fc84aSRobert Mustacchi 	/*
698672fc84aSRobert Mustacchi 	 * For usb-devices, the reg property is one entry long and it has the
699672fc84aSRobert Mustacchi 	 * logical port that the controller sees.
700672fc84aSRobert Mustacchi 	 */
701672fc84aSRobert Mustacchi 	if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "reg", &reg) != 1 ||
702672fc84aSRobert Mustacchi 	    *reg <= 0) {
703672fc84aSRobert Mustacchi 		topo_mod_dprintf(mod, "got bad \"reg\" property");
704672fc84aSRobert Mustacchi 		return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM));
705672fc84aSRobert Mustacchi 	}
706672fc84aSRobert Mustacchi 
707672fc84aSRobert Mustacchi 	if ((l = topo_usb_lport_find(plist, (uint_t)*reg)) == NULL) {
708672fc84aSRobert Mustacchi 		topo_mod_dprintf(mod, "failed to find topo_usb_lport_t for "
709672fc84aSRobert Mustacchi 		    "port %d", *reg);
710672fc84aSRobert Mustacchi 		return (topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM));
711672fc84aSRobert Mustacchi 	}
712672fc84aSRobert Mustacchi 
713672fc84aSRobert Mustacchi 	l->tul_device = node;
714672fc84aSRobert Mustacchi 
715672fc84aSRobert Mustacchi 	/*
716672fc84aSRobert Mustacchi 	 * Check to see if we have a hub and if so, process it.
717672fc84aSRobert Mustacchi 	 */
718672fc84aSRobert Mustacchi 	if ((drvname = di_driver_name(node)) != NULL &&
719672fc84aSRobert Mustacchi 	    strcmp(drvname, "hubd") == 0 &&
720672fc84aSRobert Mustacchi 	    di_prop_lookup_ints(DDI_DEV_T_ANY, node, "usb-port-count",
721672fc84aSRobert Mustacchi 	    &nports) == 1 && *nports >= 1) {
722672fc84aSRobert Mustacchi 		di_node_t child;
723672fc84aSRobert Mustacchi 
724672fc84aSRobert Mustacchi 		/*
725672fc84aSRobert Mustacchi 		 * First go through and try and discover and create all the
726672fc84aSRobert Mustacchi 		 * logical ports that exist. It is possible that these ports
727672fc84aSRobert Mustacchi 		 * already exist and that we have ACPI information about them.
728672fc84aSRobert Mustacchi 		 * This would happen when a root port is connected into a set of
729672fc84aSRobert Mustacchi 		 * hubs that are built-in.
730672fc84aSRobert Mustacchi 		 */
731672fc84aSRobert Mustacchi 		l->tul_nhubd_ports = (uint_t)*nports;
732672fc84aSRobert Mustacchi 		for (uint_t i = 1; i <= l->tul_nhubd_ports; i++) {
733672fc84aSRobert Mustacchi 			topo_usb_lport_t *clport;
734672fc84aSRobert Mustacchi 			topo_usb_port_t *cport;
735672fc84aSRobert Mustacchi 
736672fc84aSRobert Mustacchi 			if ((cport = topo_usb_port_create(mod, i, l->tul_name,
737672fc84aSRobert Mustacchi 			    '.')) == NULL) {
738672fc84aSRobert Mustacchi 				return (topo_mod_seterrno(mod, EMOD_NOMEM));
739672fc84aSRobert Mustacchi 			}
740672fc84aSRobert Mustacchi 
741672fc84aSRobert Mustacchi 			clport = topo_list_next(&cport->tup_lports);
742672fc84aSRobert Mustacchi 			topo_list_append(&l->tul_ports, cport);
743672fc84aSRobert Mustacchi 			l->tul_nports++;
744672fc84aSRobert Mustacchi 
745672fc84aSRobert Mustacchi 			clport->tul_protocol = l->tul_protocol;
746672fc84aSRobert Mustacchi 		}
747672fc84aSRobert Mustacchi 
748672fc84aSRobert Mustacchi 		/*
749672fc84aSRobert Mustacchi 		 * Now go through and discover its children.