xref: /illumos-gate/usr/src/uts/common/io/usb/usba/usba.c (revision 7c478bd9)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate /*
30*7c478bd9Sstevel@tonic-gate  * USBA: Solaris USB Architecture support
31*7c478bd9Sstevel@tonic-gate  */
32*7c478bd9Sstevel@tonic-gate #define	USBA_FRAMEWORK
33*7c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usba_impl.h>
34*7c478bd9Sstevel@tonic-gate #include <sys/usb/usba/hcdi_impl.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/usb/hubd/hub.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/fs/dv_node.h>
37*7c478bd9Sstevel@tonic-gate 
38*7c478bd9Sstevel@tonic-gate static int usba_str_startcmp(char *, char *);
39*7c478bd9Sstevel@tonic-gate 
40*7c478bd9Sstevel@tonic-gate /*
41*7c478bd9Sstevel@tonic-gate  * USBA private variables and tunables
42*7c478bd9Sstevel@tonic-gate  */
43*7c478bd9Sstevel@tonic-gate static kmutex_t	usba_mutex;
44*7c478bd9Sstevel@tonic-gate 
45*7c478bd9Sstevel@tonic-gate /*
46*7c478bd9Sstevel@tonic-gate  * ddivs forced binding:
47*7c478bd9Sstevel@tonic-gate  *
48*7c478bd9Sstevel@tonic-gate  *    usbc usbc_xhubs usbc_xaddress  node name
49*7c478bd9Sstevel@tonic-gate  *
50*7c478bd9Sstevel@tonic-gate  *	0	x	x	class name or "device"
51*7c478bd9Sstevel@tonic-gate  *
52*7c478bd9Sstevel@tonic-gate  *	1	0	0	ddivs_usbc
53*7c478bd9Sstevel@tonic-gate  *	1	0	>1	ddivs_usbc except device
54*7c478bd9Sstevel@tonic-gate  *				at usbc_xaddress
55*7c478bd9Sstevel@tonic-gate  *	1	1	0	ddivs_usbc except hubs
56*7c478bd9Sstevel@tonic-gate  *	1	1	>1	ddivs_usbc except hubs and
57*7c478bd9Sstevel@tonic-gate  *				device at usbc_xaddress
58*7c478bd9Sstevel@tonic-gate  */
59*7c478bd9Sstevel@tonic-gate uint_t usba_ddivs_usbc;
60*7c478bd9Sstevel@tonic-gate uint_t usba_ddivs_usbc_xhubs;
61*7c478bd9Sstevel@tonic-gate uint_t usba_ddivs_usbc_xaddress;
62*7c478bd9Sstevel@tonic-gate 
63*7c478bd9Sstevel@tonic-gate uint_t usba_ugen_force_binding;
64*7c478bd9Sstevel@tonic-gate 
65*7c478bd9Sstevel@tonic-gate /*
66*7c478bd9Sstevel@tonic-gate  * compatible name handling
67*7c478bd9Sstevel@tonic-gate  */
68*7c478bd9Sstevel@tonic-gate #define	USBA_MAX_COMPAT_NAMES		15
69*7c478bd9Sstevel@tonic-gate #define	USBA_MAX_COMPAT_NAME_LEN	64
70*7c478bd9Sstevel@tonic-gate static char	usba_name[USBA_MAX_COMPAT_NAMES][USBA_MAX_COMPAT_NAME_LEN];
71*7c478bd9Sstevel@tonic-gate static char	*usba_compatible[USBA_MAX_COMPAT_NAMES];
72*7c478bd9Sstevel@tonic-gate 
73*7c478bd9Sstevel@tonic-gate _NOTE(MUTEX_PROTECTS_DATA(usba_mutex, usba_name usba_compatible))
74*7c478bd9Sstevel@tonic-gate 
75*7c478bd9Sstevel@tonic-gate /* double linked list for usba_devices */
76*7c478bd9Sstevel@tonic-gate usba_list_entry_t	usba_device_list;
77*7c478bd9Sstevel@tonic-gate 
78*7c478bd9Sstevel@tonic-gate _NOTE(MUTEX_PROTECTS_DATA(usba_mutex, usba_device_list))
79*7c478bd9Sstevel@tonic-gate 
80*7c478bd9Sstevel@tonic-gate /*
81*7c478bd9Sstevel@tonic-gate  * modload support
82*7c478bd9Sstevel@tonic-gate  */
83*7c478bd9Sstevel@tonic-gate extern struct mod_ops mod_miscops;
84*7c478bd9Sstevel@tonic-gate 
85*7c478bd9Sstevel@tonic-gate struct modlmisc modlmisc	= {
86*7c478bd9Sstevel@tonic-gate 	&mod_miscops,	/* Type	of module */
87*7c478bd9Sstevel@tonic-gate 	"USBA: USB Architecture 2.0 %I%"
88*7c478bd9Sstevel@tonic-gate };
89*7c478bd9Sstevel@tonic-gate 
90*7c478bd9Sstevel@tonic-gate struct modlinkage modlinkage = {
91*7c478bd9Sstevel@tonic-gate 	MODREV_1, (void	*)&modlmisc, NULL
92*7c478bd9Sstevel@tonic-gate };
93*7c478bd9Sstevel@tonic-gate 
94*7c478bd9Sstevel@tonic-gate 
95*7c478bd9Sstevel@tonic-gate static usb_log_handle_t	usba_log_handle;
96*7c478bd9Sstevel@tonic-gate static uint_t		usba_errlevel = USB_LOG_L4;
97*7c478bd9Sstevel@tonic-gate static uint_t		usba_errmask = (uint_t)-1;
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate extern usb_log_handle_t	hubdi_log_handle;
100*7c478bd9Sstevel@tonic-gate 
101*7c478bd9Sstevel@tonic-gate int
102*7c478bd9Sstevel@tonic-gate _init(void)
103*7c478bd9Sstevel@tonic-gate {
104*7c478bd9Sstevel@tonic-gate 	int i, rval;
105*7c478bd9Sstevel@tonic-gate 
106*7c478bd9Sstevel@tonic-gate 	/*
107*7c478bd9Sstevel@tonic-gate 	 * usbai providing log support needs to be init'ed first
108*7c478bd9Sstevel@tonic-gate 	 * and destroyed last
109*7c478bd9Sstevel@tonic-gate 	 */
110*7c478bd9Sstevel@tonic-gate 	usba_usbai_initialization();
111*7c478bd9Sstevel@tonic-gate 	usba_usba_initialization();
112*7c478bd9Sstevel@tonic-gate 	usba_usbai_register_initialization();
113*7c478bd9Sstevel@tonic-gate 	usba_hcdi_initialization();
114*7c478bd9Sstevel@tonic-gate 	usba_hubdi_initialization();
115*7c478bd9Sstevel@tonic-gate 	usba_devdb_initialization();
116*7c478bd9Sstevel@tonic-gate 
117*7c478bd9Sstevel@tonic-gate 	if ((rval = mod_install(&modlinkage)) != 0) {
118*7c478bd9Sstevel@tonic-gate 		usba_devdb_destroy();
119*7c478bd9Sstevel@tonic-gate 		usba_hubdi_destroy();
120*7c478bd9Sstevel@tonic-gate 		usba_hcdi_destroy();
121*7c478bd9Sstevel@tonic-gate 		usba_usbai_register_destroy();
122*7c478bd9Sstevel@tonic-gate 		usba_usba_destroy();
123*7c478bd9Sstevel@tonic-gate 		usba_usbai_destroy();
124*7c478bd9Sstevel@tonic-gate 	}
125*7c478bd9Sstevel@tonic-gate 
126*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < USBA_MAX_COMPAT_NAMES; i++) {
127*7c478bd9Sstevel@tonic-gate 		usba_compatible[i] = usba_name[i];
128*7c478bd9Sstevel@tonic-gate 	}
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate 	return (rval);
131*7c478bd9Sstevel@tonic-gate }
132*7c478bd9Sstevel@tonic-gate 
133*7c478bd9Sstevel@tonic-gate int
134*7c478bd9Sstevel@tonic-gate _fini()
135*7c478bd9Sstevel@tonic-gate {
136*7c478bd9Sstevel@tonic-gate 	int rval;
137*7c478bd9Sstevel@tonic-gate 
138*7c478bd9Sstevel@tonic-gate 	if ((rval = mod_remove(&modlinkage)) == 0) {
139*7c478bd9Sstevel@tonic-gate 		usba_devdb_destroy();
140*7c478bd9Sstevel@tonic-gate 		usba_hubdi_destroy();
141*7c478bd9Sstevel@tonic-gate 		usba_hcdi_destroy();
142*7c478bd9Sstevel@tonic-gate 		usba_usbai_register_destroy();
143*7c478bd9Sstevel@tonic-gate 		usba_usba_destroy();
144*7c478bd9Sstevel@tonic-gate 		usba_usbai_destroy();
145*7c478bd9Sstevel@tonic-gate 	}
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate 	return (rval);
148*7c478bd9Sstevel@tonic-gate }
149*7c478bd9Sstevel@tonic-gate 
150*7c478bd9Sstevel@tonic-gate int
151*7c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
152*7c478bd9Sstevel@tonic-gate {
153*7c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
154*7c478bd9Sstevel@tonic-gate }
155*7c478bd9Sstevel@tonic-gate 
156*7c478bd9Sstevel@tonic-gate 
157*7c478bd9Sstevel@tonic-gate /*
158*7c478bd9Sstevel@tonic-gate  * common bus ctl for hcd, usb_mid, and hubd
159*7c478bd9Sstevel@tonic-gate  */
160*7c478bd9Sstevel@tonic-gate int
161*7c478bd9Sstevel@tonic-gate usba_bus_ctl(dev_info_t	*dip,
162*7c478bd9Sstevel@tonic-gate 	dev_info_t		*rdip,
163*7c478bd9Sstevel@tonic-gate 	ddi_ctl_enum_t		op,
164*7c478bd9Sstevel@tonic-gate 	void			*arg,
165*7c478bd9Sstevel@tonic-gate 	void			*result)
166*7c478bd9Sstevel@tonic-gate {
167*7c478bd9Sstevel@tonic-gate 	dev_info_t		*child_dip = (dev_info_t *)arg;
168*7c478bd9Sstevel@tonic-gate 	usba_device_t		*usba_device;
169*7c478bd9Sstevel@tonic-gate 	usba_hcdi_t		*usba_hcdi;
170*7c478bd9Sstevel@tonic-gate 	usba_hcdi_ops_t		*usba_hcdi_ops;
171*7c478bd9Sstevel@tonic-gate 
172*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, hubdi_log_handle,
173*7c478bd9Sstevel@tonic-gate 	    "usba_bus_ctl: %s%d %s%d op=%d", ddi_node_name(rdip),
174*7c478bd9Sstevel@tonic-gate 	    ddi_get_instance(rdip), ddi_node_name(dip),
175*7c478bd9Sstevel@tonic-gate 	    ddi_get_instance(dip), op);
176*7c478bd9Sstevel@tonic-gate 
177*7c478bd9Sstevel@tonic-gate 	switch (op) {
178*7c478bd9Sstevel@tonic-gate 
179*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_REPORTDEV:
180*7c478bd9Sstevel@tonic-gate 	{
181*7c478bd9Sstevel@tonic-gate 		char *name, compat_name[64], *speed;
182*7c478bd9Sstevel@tonic-gate 		usba_device_t	*hub_usba_device;
183*7c478bd9Sstevel@tonic-gate 		dev_info_t	*hubdip;
184*7c478bd9Sstevel@tonic-gate 
185*7c478bd9Sstevel@tonic-gate 		usba_device = usba_get_usba_device(rdip);
186*7c478bd9Sstevel@tonic-gate 
187*7c478bd9Sstevel@tonic-gate 		/* find the parent hub */
188*7c478bd9Sstevel@tonic-gate 		hubdip = ddi_get_parent(rdip);
189*7c478bd9Sstevel@tonic-gate 		while ((strcmp(ddi_driver_name(hubdip), "hubd") != 0) &&
190*7c478bd9Sstevel@tonic-gate 		    !(usba_is_root_hub(hubdip))) {
191*7c478bd9Sstevel@tonic-gate 			hubdip = ddi_get_parent(hubdip);
192*7c478bd9Sstevel@tonic-gate 		}
193*7c478bd9Sstevel@tonic-gate 
194*7c478bd9Sstevel@tonic-gate 		hub_usba_device = usba_get_usba_device(hubdip);
195*7c478bd9Sstevel@tonic-gate 
196*7c478bd9Sstevel@tonic-gate 		if (usba_device) {
197*7c478bd9Sstevel@tonic-gate 			if (usb_owns_device(rdip)) {
198*7c478bd9Sstevel@tonic-gate 				(void) snprintf(compat_name,
199*7c478bd9Sstevel@tonic-gate 				    sizeof (compat_name),
200*7c478bd9Sstevel@tonic-gate 				    "usb%x,%x",
201*7c478bd9Sstevel@tonic-gate 				    usba_device->usb_dev_descr->idVendor,
202*7c478bd9Sstevel@tonic-gate 				    usba_device->usb_dev_descr->idProduct);
203*7c478bd9Sstevel@tonic-gate 			} else {
204*7c478bd9Sstevel@tonic-gate 				(void) snprintf(compat_name,
205*7c478bd9Sstevel@tonic-gate 				    sizeof (compat_name),
206*7c478bd9Sstevel@tonic-gate 				    "usbif%x,%x.config%x.%x",
207*7c478bd9Sstevel@tonic-gate 				    usba_device->usb_dev_descr->idVendor,
208*7c478bd9Sstevel@tonic-gate 				    usba_device->usb_dev_descr->idProduct,
209*7c478bd9Sstevel@tonic-gate 				    usba_device->usb_cfg_value,
210*7c478bd9Sstevel@tonic-gate 				    usb_get_if_number(rdip));
211*7c478bd9Sstevel@tonic-gate 			}
212*7c478bd9Sstevel@tonic-gate 			switch (usba_device->usb_port_status) {
213*7c478bd9Sstevel@tonic-gate 			case USBA_HIGH_SPEED_DEV:
214*7c478bd9Sstevel@tonic-gate 				speed = "hi speed (USB 2.x)";
215*7c478bd9Sstevel@tonic-gate 
216*7c478bd9Sstevel@tonic-gate 				break;
217*7c478bd9Sstevel@tonic-gate 			case USBA_LOW_SPEED_DEV:
218*7c478bd9Sstevel@tonic-gate 				speed = "low speed (USB 1.x)";
219*7c478bd9Sstevel@tonic-gate 
220*7c478bd9Sstevel@tonic-gate 				break;
221*7c478bd9Sstevel@tonic-gate 			case USBA_FULL_SPEED_DEV:
222*7c478bd9Sstevel@tonic-gate 			default:
223*7c478bd9Sstevel@tonic-gate 				speed = "full speed (USB 1.x)";
224*7c478bd9Sstevel@tonic-gate 
225*7c478bd9Sstevel@tonic-gate 				break;
226*7c478bd9Sstevel@tonic-gate 			}
227*7c478bd9Sstevel@tonic-gate 
228*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT,
229*7c478bd9Sstevel@tonic-gate 			    "?USB %x.%x %s (%s) operating at %s on "
230*7c478bd9Sstevel@tonic-gate 			    "USB %x.%x %s hub: "
231*7c478bd9Sstevel@tonic-gate 			    "%s@%s, %s%d at bus address %d\n",
232*7c478bd9Sstevel@tonic-gate 			    (usba_device->usb_dev_descr->bcdUSB & 0xff00) >> 8,
233*7c478bd9Sstevel@tonic-gate 			    usba_device->usb_dev_descr->bcdUSB & 0xff,
234*7c478bd9Sstevel@tonic-gate 			    (usb_owns_device(rdip) ? "device" : "interface"),
235*7c478bd9Sstevel@tonic-gate 			    compat_name, speed,
236*7c478bd9Sstevel@tonic-gate 			    (hub_usba_device->usb_dev_descr->bcdUSB &
237*7c478bd9Sstevel@tonic-gate 			    0xff00) >> 8,
238*7c478bd9Sstevel@tonic-gate 			    hub_usba_device->usb_dev_descr->bcdUSB & 0xff,
239*7c478bd9Sstevel@tonic-gate 			    usba_is_root_hub(hubdip) ? "root" : "external",
240*7c478bd9Sstevel@tonic-gate 			    ddi_node_name(rdip), ddi_get_name_addr(rdip),
241*7c478bd9Sstevel@tonic-gate 			    ddi_driver_name(rdip),
242*7c478bd9Sstevel@tonic-gate 			    ddi_get_instance(rdip), usba_device->usb_addr);
243*7c478bd9Sstevel@tonic-gate 
244*7c478bd9Sstevel@tonic-gate 			name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
245*7c478bd9Sstevel@tonic-gate 			(void) usba_get_mfg_prod_sn_str(rdip, name, MAXNAMELEN);
246*7c478bd9Sstevel@tonic-gate 			if (name[0] != '\0') {
247*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "?\t%s\n", name);
248*7c478bd9Sstevel@tonic-gate 			}
249*7c478bd9Sstevel@tonic-gate 			kmem_free(name, MAXNAMELEN);
250*7c478bd9Sstevel@tonic-gate 
251*7c478bd9Sstevel@tonic-gate 		} else { /* harden USBA against this case; if it happens */
252*7c478bd9Sstevel@tonic-gate 
253*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT,
254*7c478bd9Sstevel@tonic-gate 			    "?USB-device: %s@%s, %s%d\n",
255*7c478bd9Sstevel@tonic-gate 			    ddi_node_name(rdip), ddi_get_name_addr(rdip),
256*7c478bd9Sstevel@tonic-gate 			    ddi_driver_name(rdip), ddi_get_instance(rdip));
257*7c478bd9Sstevel@tonic-gate 		}
258*7c478bd9Sstevel@tonic-gate 
259*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
260*7c478bd9Sstevel@tonic-gate 	}
261*7c478bd9Sstevel@tonic-gate 
262*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_INITCHILD:
263*7c478bd9Sstevel@tonic-gate 	{
264*7c478bd9Sstevel@tonic-gate 		int			usb_addr;
265*7c478bd9Sstevel@tonic-gate 		uint_t			n;
266*7c478bd9Sstevel@tonic-gate 		char			name[32];
267*7c478bd9Sstevel@tonic-gate 		int			*data;
268*7c478bd9Sstevel@tonic-gate 		int			rval;
269*7c478bd9Sstevel@tonic-gate 		int			len = sizeof (usb_addr);
270*7c478bd9Sstevel@tonic-gate 
271*7c478bd9Sstevel@tonic-gate 		usba_hcdi	= usba_hcdi_get_hcdi(dip);
272*7c478bd9Sstevel@tonic-gate 		usba_hcdi_ops	= usba_hcdi->hcdi_ops;
273*7c478bd9Sstevel@tonic-gate 		ASSERT(usba_hcdi_ops != NULL);
274*7c478bd9Sstevel@tonic-gate 
275*7c478bd9Sstevel@tonic-gate 		/*
276*7c478bd9Sstevel@tonic-gate 		 * as long as the dip exists, it should have
277*7c478bd9Sstevel@tonic-gate 		 * usba_device structure associated with it
278*7c478bd9Sstevel@tonic-gate 		 */
279*7c478bd9Sstevel@tonic-gate 		usba_device = usba_get_usba_device(child_dip);
280*7c478bd9Sstevel@tonic-gate 		if (usba_device == NULL) {
281*7c478bd9Sstevel@tonic-gate 
282*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_USBA, hubdi_log_handle,
283*7c478bd9Sstevel@tonic-gate 			    "usba_bus_ctl: DDI_NOT_WELL_FORMED (%s (0x%p))",
284*7c478bd9Sstevel@tonic-gate 			    ddi_node_name(child_dip), (void *)child_dip);
285*7c478bd9Sstevel@tonic-gate 
286*7c478bd9Sstevel@tonic-gate 			return (DDI_NOT_WELL_FORMED);
287*7c478bd9Sstevel@tonic-gate 		}
288*7c478bd9Sstevel@tonic-gate 
289*7c478bd9Sstevel@tonic-gate 		/* the dip should have an address and reg property */
290*7c478bd9Sstevel@tonic-gate 		if (ddi_prop_op(DDI_DEV_T_NONE, child_dip, PROP_LEN_AND_VAL_BUF,
291*7c478bd9Sstevel@tonic-gate 		    DDI_PROP_DONTPASS |	DDI_PROP_CANSLEEP, "assigned-address",
292*7c478bd9Sstevel@tonic-gate 		    (caddr_t)&usb_addr,	&len) != DDI_SUCCESS) {
293*7c478bd9Sstevel@tonic-gate 
294*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_USBA, hubdi_log_handle,
295*7c478bd9Sstevel@tonic-gate 			    "usba_bus_ctl:\n\t"
296*7c478bd9Sstevel@tonic-gate 			    "%s%d %s%d op=%d rdip = 0x%p dip = 0x%p",
297*7c478bd9Sstevel@tonic-gate 			    ddi_node_name(rdip), ddi_get_instance(rdip),
298*7c478bd9Sstevel@tonic-gate 			    ddi_node_name(dip), ddi_get_instance(dip), op,
299*7c478bd9Sstevel@tonic-gate 			    rdip, dip);
300*7c478bd9Sstevel@tonic-gate 
301*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_USBA, hubdi_log_handle,
302*7c478bd9Sstevel@tonic-gate 			    "usba_bus_ctl: DDI_NOT_WELL_FORMED (%s (0x%p))",
303*7c478bd9Sstevel@tonic-gate 			    ddi_node_name(child_dip), (void *)child_dip);
304*7c478bd9Sstevel@tonic-gate 
305*7c478bd9Sstevel@tonic-gate 			return (DDI_NOT_WELL_FORMED);
306*7c478bd9Sstevel@tonic-gate 		}
307*7c478bd9Sstevel@tonic-gate 
308*7c478bd9Sstevel@tonic-gate 		if ((rval = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child_dip,
309*7c478bd9Sstevel@tonic-gate 		    DDI_PROP_DONTPASS, "reg",
310*7c478bd9Sstevel@tonic-gate 		    &data, &n)) != DDI_SUCCESS) {
311*7c478bd9Sstevel@tonic-gate 
312*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_USBA, hubdi_log_handle,
313*7c478bd9Sstevel@tonic-gate 			    "usba_bus_ctl: %d, DDI_NOT_WELL_FORMED", rval);
314*7c478bd9Sstevel@tonic-gate 
315*7c478bd9Sstevel@tonic-gate 			return (DDI_NOT_WELL_FORMED);
316*7c478bd9Sstevel@tonic-gate 		}
317*7c478bd9Sstevel@tonic-gate 
318*7c478bd9Sstevel@tonic-gate 
319*7c478bd9Sstevel@tonic-gate 		/*
320*7c478bd9Sstevel@tonic-gate 		 * if the configuration is 1, the unit address is
321*7c478bd9Sstevel@tonic-gate 		 * just the interface number
322*7c478bd9Sstevel@tonic-gate 		 */
323*7c478bd9Sstevel@tonic-gate 		if ((n == 1) || ((n > 1) && (data[1] == 1))) {
324*7c478bd9Sstevel@tonic-gate 			(void) sprintf(name, "%x", data[0]);
325*7c478bd9Sstevel@tonic-gate 		} else {
326*7c478bd9Sstevel@tonic-gate 			(void) sprintf(name, "%x,%x", data[0], data[1]);
327*7c478bd9Sstevel@tonic-gate 		}
328*7c478bd9Sstevel@tonic-gate 
329*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(DPRINT_MASK_USBA,
330*7c478bd9Sstevel@tonic-gate 		    hubdi_log_handle, "usba_bus_ctl: name = %s", name);
331*7c478bd9Sstevel@tonic-gate 
332*7c478bd9Sstevel@tonic-gate 		ddi_prop_free(data);
333*7c478bd9Sstevel@tonic-gate 		ddi_set_name_addr(child_dip, name);
334*7c478bd9Sstevel@tonic-gate 
335*7c478bd9Sstevel@tonic-gate 		/*
336*7c478bd9Sstevel@tonic-gate 		 * increment the reference count for each child using this
337*7c478bd9Sstevel@tonic-gate 		 * usba_device structure
338*7c478bd9Sstevel@tonic-gate 		 */
339*7c478bd9Sstevel@tonic-gate 		mutex_enter(&usba_device->usb_mutex);
340*7c478bd9Sstevel@tonic-gate 		usba_device->usb_ref_count++;
341*7c478bd9Sstevel@tonic-gate 
342*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(DPRINT_MASK_USBA, hubdi_log_handle,
343*7c478bd9Sstevel@tonic-gate 		    "usba_bus_ctl: init usba_device = 0x%p ref_count = %d",
344*7c478bd9Sstevel@tonic-gate 		    (void *)usba_device, usba_device->usb_ref_count);
345*7c478bd9Sstevel@tonic-gate 
346*7c478bd9Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
347*7c478bd9Sstevel@tonic-gate 
348*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
349*7c478bd9Sstevel@tonic-gate 	}
350*7c478bd9Sstevel@tonic-gate 
351*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_UNINITCHILD:
352*7c478bd9Sstevel@tonic-gate 	{
353*7c478bd9Sstevel@tonic-gate 		usba_device = usba_get_usba_device(child_dip);
354*7c478bd9Sstevel@tonic-gate 
355*7c478bd9Sstevel@tonic-gate 		if (usba_device != NULL) {
356*7c478bd9Sstevel@tonic-gate 			/*
357*7c478bd9Sstevel@tonic-gate 			 * decrement the reference count for each child
358*7c478bd9Sstevel@tonic-gate 			 * using this  usba_device structure
359*7c478bd9Sstevel@tonic-gate 			 */
360*7c478bd9Sstevel@tonic-gate 			mutex_enter(&usba_device->usb_mutex);
361*7c478bd9Sstevel@tonic-gate 			usba_device->usb_ref_count--;
362*7c478bd9Sstevel@tonic-gate 
363*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L3(DPRINT_MASK_USBA, hubdi_log_handle,
364*7c478bd9Sstevel@tonic-gate 			    "usba_hcdi_bus_ctl: uninit usba_device=0x%p "
365*7c478bd9Sstevel@tonic-gate 			    "ref_count=%d",
366*7c478bd9Sstevel@tonic-gate 			    usba_device, usba_device->usb_ref_count);
367*7c478bd9Sstevel@tonic-gate 
368*7c478bd9Sstevel@tonic-gate 			mutex_exit(&usba_device->usb_mutex);
369*7c478bd9Sstevel@tonic-gate 		}
370*7c478bd9Sstevel@tonic-gate 		ddi_set_name_addr(child_dip, NULL);
371*7c478bd9Sstevel@tonic-gate 
372*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
373*7c478bd9Sstevel@tonic-gate 	}
374*7c478bd9Sstevel@tonic-gate 
375*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_IOMIN:
376*7c478bd9Sstevel@tonic-gate 		/* Do nothing */
377*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
378*7c478bd9Sstevel@tonic-gate 
379*7c478bd9Sstevel@tonic-gate 	/*
380*7c478bd9Sstevel@tonic-gate 	 * These ops correspond	to functions that "shouldn't" be called
381*7c478bd9Sstevel@tonic-gate 	 * by a	USB client driver.  So	we whine when we're called.
382*7c478bd9Sstevel@tonic-gate 	 */
383*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_DMAPMAPC:
384*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_REPORTINT:
385*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_REGSIZE:
386*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_NREGS:
387*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_NINTRS:
388*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_SIDDEV:
389*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_SLAVEONLY:
390*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_AFFINITY:
391*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_INTR_HILEVEL:
392*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_XLATE_INTRS:
393*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_POKE:
394*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_PEEK:
395*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "%s%d:	invalid	op (%d)	from %s%d",
396*7c478bd9Sstevel@tonic-gate 			ddi_node_name(dip), ddi_get_instance(dip),
397*7c478bd9Sstevel@tonic-gate 			op, ddi_node_name(rdip), ddi_get_instance(rdip));
398*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
399*7c478bd9Sstevel@tonic-gate 
400*7c478bd9Sstevel@tonic-gate 	/*
401*7c478bd9Sstevel@tonic-gate 	 * Everything else (e.g. PTOB/BTOP/BTOPR requests) we pass up
402*7c478bd9Sstevel@tonic-gate 	 */
403*7c478bd9Sstevel@tonic-gate 	default:
404*7c478bd9Sstevel@tonic-gate 		return (ddi_ctlops(dip,	rdip, op, arg, result));
405*7c478bd9Sstevel@tonic-gate 	}
406*7c478bd9Sstevel@tonic-gate }
407*7c478bd9Sstevel@tonic-gate 
408*7c478bd9Sstevel@tonic-gate 
409*7c478bd9Sstevel@tonic-gate /*
410*7c478bd9Sstevel@tonic-gate  * initialize and destroy USBA module
411*7c478bd9Sstevel@tonic-gate  */
412*7c478bd9Sstevel@tonic-gate void
413*7c478bd9Sstevel@tonic-gate usba_usba_initialization()
414*7c478bd9Sstevel@tonic-gate {
415*7c478bd9Sstevel@tonic-gate 	usba_log_handle = usb_alloc_log_hdl(NULL, "usba", &usba_errlevel,
416*7c478bd9Sstevel@tonic-gate 				&usba_errmask, NULL, 0);
417*7c478bd9Sstevel@tonic-gate 
418*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA,
419*7c478bd9Sstevel@tonic-gate 	    usba_log_handle, "usba_usba_initialization");
420*7c478bd9Sstevel@tonic-gate 
421*7c478bd9Sstevel@tonic-gate 	mutex_init(&usba_mutex, NULL, MUTEX_DRIVER, NULL);
422*7c478bd9Sstevel@tonic-gate 	usba_init_list(&usba_device_list, NULL, NULL);
423*7c478bd9Sstevel@tonic-gate }
424*7c478bd9Sstevel@tonic-gate 
425*7c478bd9Sstevel@tonic-gate 
426*7c478bd9Sstevel@tonic-gate void
427*7c478bd9Sstevel@tonic-gate usba_usba_destroy()
428*7c478bd9Sstevel@tonic-gate {
429*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle, "usba_usba_destroy");
430*7c478bd9Sstevel@tonic-gate 
431*7c478bd9Sstevel@tonic-gate 	mutex_destroy(&usba_mutex);
432*7c478bd9Sstevel@tonic-gate 	usba_destroy_list(&usba_device_list);
433*7c478bd9Sstevel@tonic-gate 
434*7c478bd9Sstevel@tonic-gate 	usb_free_log_hdl(usba_log_handle);
435*7c478bd9Sstevel@tonic-gate }
436*7c478bd9Sstevel@tonic-gate 
437*7c478bd9Sstevel@tonic-gate 
438*7c478bd9Sstevel@tonic-gate /*
439*7c478bd9Sstevel@tonic-gate  * usba_set_usb_address:
440*7c478bd9Sstevel@tonic-gate  *	set usb address in usba_device structure
441*7c478bd9Sstevel@tonic-gate  */
442*7c478bd9Sstevel@tonic-gate int
443*7c478bd9Sstevel@tonic-gate usba_set_usb_address(usba_device_t *usba_device)
444*7c478bd9Sstevel@tonic-gate {
445*7c478bd9Sstevel@tonic-gate 	usb_addr_t address;
446*7c478bd9Sstevel@tonic-gate 	uchar_t s = 8;
447*7c478bd9Sstevel@tonic-gate 	usba_hcdi_t *hcdi;
448*7c478bd9Sstevel@tonic-gate 	char *usb_address_in_use;
449*7c478bd9Sstevel@tonic-gate 
450*7c478bd9Sstevel@tonic-gate 	mutex_enter(&usba_device->usb_mutex);
451*7c478bd9Sstevel@tonic-gate 
452*7c478bd9Sstevel@tonic-gate 	hcdi = usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
453*7c478bd9Sstevel@tonic-gate 
454*7c478bd9Sstevel@tonic-gate 	mutex_enter(&hcdi->hcdi_mutex);
455*7c478bd9Sstevel@tonic-gate 	usb_address_in_use = hcdi->hcdi_usb_address_in_use;
456*7c478bd9Sstevel@tonic-gate 
457*7c478bd9Sstevel@tonic-gate 	for (address = ROOT_HUB_ADDR + 1;
458*7c478bd9Sstevel@tonic-gate 	    address <= USBA_MAX_ADDRESS; address++) {
459*7c478bd9Sstevel@tonic-gate 		if (usb_address_in_use[address/s] & (1 << (address % s))) {
460*7c478bd9Sstevel@tonic-gate 			continue;
461*7c478bd9Sstevel@tonic-gate 		}
462*7c478bd9Sstevel@tonic-gate 		usb_address_in_use[address/s] |= (1 << (address % s));
463*7c478bd9Sstevel@tonic-gate 		hcdi->hcdi_device_count++;
464*7c478bd9Sstevel@tonic-gate 		HCDI_HOTPLUG_STATS_DATA(hcdi)->hcdi_device_count.value.ui64++;
465*7c478bd9Sstevel@tonic-gate 		mutex_exit(&hcdi->hcdi_mutex);
466*7c478bd9Sstevel@tonic-gate 
467*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
468*7c478bd9Sstevel@tonic-gate 		    "usba_set_usb_address: %d", address);
469*7c478bd9Sstevel@tonic-gate 
470*7c478bd9Sstevel@tonic-gate 		usba_device->usb_addr = address;
471*7c478bd9Sstevel@tonic-gate 
472*7c478bd9Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
473*7c478bd9Sstevel@tonic-gate 
474*7c478bd9Sstevel@tonic-gate 		return (USB_SUCCESS);
475*7c478bd9Sstevel@tonic-gate 	}
476*7c478bd9Sstevel@tonic-gate 
477*7c478bd9Sstevel@tonic-gate 	usba_device->usb_addr = 0;
478*7c478bd9Sstevel@tonic-gate 
479*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L1(DPRINT_MASK_USBA, usba_log_handle,
480*7c478bd9Sstevel@tonic-gate 	    "no usb address available");
481*7c478bd9Sstevel@tonic-gate 
482*7c478bd9Sstevel@tonic-gate 	mutex_exit(&hcdi->hcdi_mutex);
483*7c478bd9Sstevel@tonic-gate 	mutex_exit(&usba_device->usb_mutex);
484*7c478bd9Sstevel@tonic-gate 
485*7c478bd9Sstevel@tonic-gate 	return (USB_FAILURE);
486*7c478bd9Sstevel@tonic-gate }
487*7c478bd9Sstevel@tonic-gate 
488*7c478bd9Sstevel@tonic-gate 
489*7c478bd9Sstevel@tonic-gate /*
490*7c478bd9Sstevel@tonic-gate  * usba_unset_usb_address:
491*7c478bd9Sstevel@tonic-gate  *	unset usb_address in usba_device structure
492*7c478bd9Sstevel@tonic-gate  */
493*7c478bd9Sstevel@tonic-gate void
494*7c478bd9Sstevel@tonic-gate usba_unset_usb_address(usba_device_t *usba_device)
495*7c478bd9Sstevel@tonic-gate {
496*7c478bd9Sstevel@tonic-gate 	usb_addr_t address;
497*7c478bd9Sstevel@tonic-gate 	usba_hcdi_t *hcdi;
498*7c478bd9Sstevel@tonic-gate 	uchar_t s = 8;
499*7c478bd9Sstevel@tonic-gate 	char *usb_address_in_use;
500*7c478bd9Sstevel@tonic-gate 
501*7c478bd9Sstevel@tonic-gate 	mutex_enter(&usba_device->usb_mutex);
502*7c478bd9Sstevel@tonic-gate 	address = usba_device->usb_addr;
503*7c478bd9Sstevel@tonic-gate 	hcdi = usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
504*7c478bd9Sstevel@tonic-gate 
505*7c478bd9Sstevel@tonic-gate 	if (address > ROOT_HUB_ADDR) {
506*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
507*7c478bd9Sstevel@tonic-gate 		    "usba_unset_usb_address: address=%d", address);
508*7c478bd9Sstevel@tonic-gate 
509*7c478bd9Sstevel@tonic-gate 		mutex_enter(&hcdi->hcdi_mutex);
510*7c478bd9Sstevel@tonic-gate 		usb_address_in_use = hcdi->hcdi_usb_address_in_use;
511*7c478bd9Sstevel@tonic-gate 
512*7c478bd9Sstevel@tonic-gate 		ASSERT(usb_address_in_use[address/s] & (1 << (address % s)));
513*7c478bd9Sstevel@tonic-gate 
514*7c478bd9Sstevel@tonic-gate 		usb_address_in_use[address/s] &= ~(1 << (address % s));
515*7c478bd9Sstevel@tonic-gate 
516*7c478bd9Sstevel@tonic-gate 		hcdi->hcdi_device_count--;
517*7c478bd9Sstevel@tonic-gate 		HCDI_HOTPLUG_STATS_DATA(hcdi)->hcdi_device_count.value.ui64--;
518*7c478bd9Sstevel@tonic-gate 
519*7c478bd9Sstevel@tonic-gate 		mutex_exit(&hcdi->hcdi_mutex);
520*7c478bd9Sstevel@tonic-gate 
521*7c478bd9Sstevel@tonic-gate 		usba_device->usb_addr = 0;
522*7c478bd9Sstevel@tonic-gate 	}
523*7c478bd9Sstevel@tonic-gate 	mutex_exit(&usba_device->usb_mutex);
524*7c478bd9Sstevel@tonic-gate }
525*7c478bd9Sstevel@tonic-gate 
526*7c478bd9Sstevel@tonic-gate 
527*7c478bd9Sstevel@tonic-gate struct usba_evdata *
528*7c478bd9Sstevel@tonic-gate usba_get_evdata(dev_info_t *dip)
529*7c478bd9Sstevel@tonic-gate {
530*7c478bd9Sstevel@tonic-gate 	usba_evdata_t *evdata;
531*7c478bd9Sstevel@tonic-gate 	usba_device_t *usba_device = usba_get_usba_device(dip);
532*7c478bd9Sstevel@tonic-gate 
533*7c478bd9Sstevel@tonic-gate 	/* called when dip attaches */
534*7c478bd9Sstevel@tonic-gate 	ASSERT(usba_device != NULL);
535*7c478bd9Sstevel@tonic-gate 
536*7c478bd9Sstevel@tonic-gate 	mutex_enter(&usba_device->usb_mutex);
537*7c478bd9Sstevel@tonic-gate 	evdata = usba_device->usb_evdata;
538*7c478bd9Sstevel@tonic-gate 	while (evdata) {
539*7c478bd9Sstevel@tonic-gate 		if (evdata->ev_dip == dip) {
540*7c478bd9Sstevel@tonic-gate 			mutex_exit(&usba_device->usb_mutex);
541*7c478bd9Sstevel@tonic-gate 
542*7c478bd9Sstevel@tonic-gate 			return (evdata);
543*7c478bd9Sstevel@tonic-gate 		}
544*7c478bd9Sstevel@tonic-gate 		evdata = evdata->ev_next;
545*7c478bd9Sstevel@tonic-gate 	}
546*7c478bd9Sstevel@tonic-gate 
547*7c478bd9Sstevel@tonic-gate 	evdata = kmem_zalloc(sizeof (usba_evdata_t), KM_SLEEP);
548*7c478bd9Sstevel@tonic-gate 	evdata->ev_dip = dip;
549*7c478bd9Sstevel@tonic-gate 	evdata->ev_next = usba_device->usb_evdata;
550*7c478bd9Sstevel@tonic-gate 	usba_device->usb_evdata = evdata;
551*7c478bd9Sstevel@tonic-gate 	mutex_exit(&usba_device->usb_mutex);
552*7c478bd9Sstevel@tonic-gate 
553*7c478bd9Sstevel@tonic-gate 	return (evdata);
554*7c478bd9Sstevel@tonic-gate }
555*7c478bd9Sstevel@tonic-gate 
556*7c478bd9Sstevel@tonic-gate 
557*7c478bd9Sstevel@tonic-gate /*
558*7c478bd9Sstevel@tonic-gate  * allocate a usb device structure and link it in the list
559*7c478bd9Sstevel@tonic-gate  */
560*7c478bd9Sstevel@tonic-gate usba_device_t *
561*7c478bd9Sstevel@tonic-gate usba_alloc_usba_device(dev_info_t *root_hub_dip)
562*7c478bd9Sstevel@tonic-gate {
563*7c478bd9Sstevel@tonic-gate 	usba_device_t	*usba_device;
564*7c478bd9Sstevel@tonic-gate 	int		ep_idx;
565*7c478bd9Sstevel@tonic-gate 	ddi_iblock_cookie_t iblock_cookie =
566*7c478bd9Sstevel@tonic-gate 	    usba_hcdi_get_hcdi(root_hub_dip)->hcdi_iblock_cookie;
567*7c478bd9Sstevel@tonic-gate 
568*7c478bd9Sstevel@tonic-gate 	/*
569*7c478bd9Sstevel@tonic-gate 	 * create a new usba_device structure
570*7c478bd9Sstevel@tonic-gate 	 */
571*7c478bd9Sstevel@tonic-gate 	usba_device = kmem_zalloc(sizeof (usba_device_t), KM_SLEEP);
572*7c478bd9Sstevel@tonic-gate 
573*7c478bd9Sstevel@tonic-gate 	/*
574*7c478bd9Sstevel@tonic-gate 	 * initialize usba_device
575*7c478bd9Sstevel@tonic-gate 	 */
576*7c478bd9Sstevel@tonic-gate 	mutex_init(&usba_device->usb_mutex, NULL, MUTEX_DRIVER,
577*7c478bd9Sstevel@tonic-gate 							iblock_cookie);
578*7c478bd9Sstevel@tonic-gate 
579*7c478bd9Sstevel@tonic-gate 	usba_init_list(&usba_device->usb_device_list, (usb_opaque_t)usba_device,
580*7c478bd9Sstevel@tonic-gate 							iblock_cookie);
581*7c478bd9Sstevel@tonic-gate 	usba_init_list(&usba_device->usb_allocated, (usb_opaque_t)usba_device,
582*7c478bd9Sstevel@tonic-gate 							iblock_cookie);
583*7c478bd9Sstevel@tonic-gate 	mutex_enter(&usba_device->usb_mutex);
584*7c478bd9Sstevel@tonic-gate 	usba_device->usb_root_hub_dip = root_hub_dip;
585*7c478bd9Sstevel@tonic-gate 
586*7c478bd9Sstevel@tonic-gate 	/*
587*7c478bd9Sstevel@tonic-gate 	 * add to list of usba_devices
588*7c478bd9Sstevel@tonic-gate 	 */
589*7c478bd9Sstevel@tonic-gate 	usba_add_to_list(&usba_device_list, &usba_device->usb_device_list);
590*7c478bd9Sstevel@tonic-gate 
591*7c478bd9Sstevel@tonic-gate 	/* init mutex in each usba_ph_impl structure */
592*7c478bd9Sstevel@tonic-gate 	for (ep_idx = 0; ep_idx < USBA_N_ENDPOINTS; ep_idx++) {
593*7c478bd9Sstevel@tonic-gate 		mutex_init(&usba_device->usb_ph_list[ep_idx].usba_ph_mutex,
594*7c478bd9Sstevel@tonic-gate 		    NULL, MUTEX_DRIVER, iblock_cookie);
595*7c478bd9Sstevel@tonic-gate 	}
596*7c478bd9Sstevel@tonic-gate 
597*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
598*7c478bd9Sstevel@tonic-gate 	    "allocated usba_device 0x%p", (void *)usba_device);
599*7c478bd9Sstevel@tonic-gate 
600*7c478bd9Sstevel@tonic-gate 	mutex_exit(&usba_device->usb_mutex);
601*7c478bd9Sstevel@tonic-gate 
602*7c478bd9Sstevel@tonic-gate 	return (usba_device);
603*7c478bd9Sstevel@tonic-gate }
604*7c478bd9Sstevel@tonic-gate 
605*7c478bd9Sstevel@tonic-gate 
606*7c478bd9Sstevel@tonic-gate /* free NDI event data associated with usba_device */
607*7c478bd9Sstevel@tonic-gate void
608*7c478bd9Sstevel@tonic-gate usba_free_evdata(usba_evdata_t *evdata)
609*7c478bd9Sstevel@tonic-gate {
610*7c478bd9Sstevel@tonic-gate 	usba_evdata_t *next;
611*7c478bd9Sstevel@tonic-gate 
612*7c478bd9Sstevel@tonic-gate 	while (evdata) {
613*7c478bd9Sstevel@tonic-gate 		next = evdata->ev_next;
614*7c478bd9Sstevel@tonic-gate 		kmem_free(evdata, sizeof (usba_evdata_t));
615*7c478bd9Sstevel@tonic-gate 		evdata = next;
616*7c478bd9Sstevel@tonic-gate 	}
617*7c478bd9Sstevel@tonic-gate }
618*7c478bd9Sstevel@tonic-gate 
619*7c478bd9Sstevel@tonic-gate 
620*7c478bd9Sstevel@tonic-gate /*
621*7c478bd9Sstevel@tonic-gate  * free usb device structure
622*7c478bd9Sstevel@tonic-gate  */
623*7c478bd9Sstevel@tonic-gate void
624*7c478bd9Sstevel@tonic-gate usba_free_usba_device(usba_device_t *usba_device)
625*7c478bd9Sstevel@tonic-gate {
626*7c478bd9Sstevel@tonic-gate 	int			i, ep_idx;
627*7c478bd9Sstevel@tonic-gate 	usb_pipe_handle_t	def_ph;
628*7c478bd9Sstevel@tonic-gate 
629*7c478bd9Sstevel@tonic-gate 	if (usba_device == NULL) {
630*7c478bd9Sstevel@tonic-gate 
631*7c478bd9Sstevel@tonic-gate 		return;
632*7c478bd9Sstevel@tonic-gate 	}
633*7c478bd9Sstevel@tonic-gate 
634*7c478bd9Sstevel@tonic-gate 	mutex_enter(&usba_device->usb_mutex);
635*7c478bd9Sstevel@tonic-gate 	if (usba_device->usb_ref_count) {
636*7c478bd9Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
637*7c478bd9Sstevel@tonic-gate 
638*7c478bd9Sstevel@tonic-gate 		return;
639*7c478bd9Sstevel@tonic-gate 	}
640*7c478bd9Sstevel@tonic-gate 
641*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
642*7c478bd9Sstevel@tonic-gate 	    "usba_free_usba_device 0x%p, address=0x%x, ref cnt=%d",
643*7c478bd9Sstevel@tonic-gate 	    (void *)usba_device, usba_device->usb_addr,
644*7c478bd9Sstevel@tonic-gate 	    usba_device->usb_ref_count);
645*7c478bd9Sstevel@tonic-gate 
646*7c478bd9Sstevel@tonic-gate 	usba_free_evdata(usba_device->usb_evdata);
647*7c478bd9Sstevel@tonic-gate 	mutex_exit(&usba_device->usb_mutex);
648*7c478bd9Sstevel@tonic-gate 
649*7c478bd9Sstevel@tonic-gate 	def_ph = usba_usbdev_to_dflt_pipe_handle(usba_device);
650*7c478bd9Sstevel@tonic-gate 	if (def_ph != NULL) {
651*7c478bd9Sstevel@tonic-gate 		usba_pipe_handle_data_t	*ph_data = usba_get_ph_data(def_ph);
652*7c478bd9Sstevel@tonic-gate 
653*7c478bd9Sstevel@tonic-gate 		if (ph_data) {
654*7c478bd9Sstevel@tonic-gate 			usb_pipe_close(ph_data->p_dip, def_ph,
655*7c478bd9Sstevel@tonic-gate 			    USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED,
656*7c478bd9Sstevel@tonic-gate 			    NULL, NULL);
657*7c478bd9Sstevel@tonic-gate 		}
658*7c478bd9Sstevel@tonic-gate 	}
659*7c478bd9Sstevel@tonic-gate 
660*7c478bd9Sstevel@tonic-gate 	mutex_enter(&usba_mutex);
661*7c478bd9Sstevel@tonic-gate 
662*7c478bd9Sstevel@tonic-gate 	/* destroy mutex in each usba_ph_impl structure */
663*7c478bd9Sstevel@tonic-gate 	for (ep_idx = 0; ep_idx < USBA_N_ENDPOINTS; ep_idx++) {
664*7c478bd9Sstevel@tonic-gate 		mutex_destroy(&usba_device->usb_ph_list[ep_idx].usba_ph_mutex);
665*7c478bd9Sstevel@tonic-gate 	}
666*7c478bd9Sstevel@tonic-gate 
667*7c478bd9Sstevel@tonic-gate 	(void) usba_rm_from_list(&usba_device_list,
668*7c478bd9Sstevel@tonic-gate 				&usba_device->usb_device_list);
669*7c478bd9Sstevel@tonic-gate 
670*7c478bd9Sstevel@tonic-gate 	mutex_exit(&usba_mutex);
671*7c478bd9Sstevel@tonic-gate 
672*7c478bd9Sstevel@tonic-gate 	usba_destroy_list(&usba_device->usb_device_list);
673*7c478bd9Sstevel@tonic-gate 	usba_destroy_list(&usba_device->usb_allocated);
674*7c478bd9Sstevel@tonic-gate 
675*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
676*7c478bd9Sstevel@tonic-gate 	    "deallocating usba_device = 0x%p, address = 0x%x",
677*7c478bd9Sstevel@tonic-gate 	    (void *)usba_device, usba_device->usb_addr);
678*7c478bd9Sstevel@tonic-gate 
679*7c478bd9Sstevel@tonic-gate 	/*
680*7c478bd9Sstevel@tonic-gate 	 * ohci allocates descriptors for root hub so we can't
681*7c478bd9Sstevel@tonic-gate 	 * deallocate these here
682*7c478bd9Sstevel@tonic-gate 	 */
683*7c478bd9Sstevel@tonic-gate 
684*7c478bd9Sstevel@tonic-gate 	if (usba_device->usb_addr != ROOT_HUB_ADDR) {
685*7c478bd9Sstevel@tonic-gate 		if (usba_device->usb_cfg_array) {
686*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
687*7c478bd9Sstevel@tonic-gate 			    "deallocating usb_config_array: 0x%p",
688*7c478bd9Sstevel@tonic-gate 			    usba_device->usb_cfg_array);
689*7c478bd9Sstevel@tonic-gate 			mutex_enter(&usba_device->usb_mutex);
690*7c478bd9Sstevel@tonic-gate 			for (i = 0;
691*7c478bd9Sstevel@tonic-gate 			    i < usba_device->usb_dev_descr->bNumConfigurations;
692*7c478bd9Sstevel@tonic-gate 			    i++) {
693*7c478bd9Sstevel@tonic-gate 				if (usba_device->usb_cfg_array[i]) {
694*7c478bd9Sstevel@tonic-gate 					kmem_free(
695*7c478bd9Sstevel@tonic-gate 					    usba_device->usb_cfg_array[i],
696*7c478bd9Sstevel@tonic-gate 					    usba_device->usb_cfg_array_len[i]);
697*7c478bd9Sstevel@tonic-gate 				}
698*7c478bd9Sstevel@tonic-gate 			}
699*7c478bd9Sstevel@tonic-gate 
700*7c478bd9Sstevel@tonic-gate 			/* free the array pointers */
701*7c478bd9Sstevel@tonic-gate 			kmem_free(usba_device->usb_cfg_array,
702*7c478bd9Sstevel@tonic-gate 			    usba_device->usb_cfg_array_length);
703*7c478bd9Sstevel@tonic-gate 			kmem_free(usba_device->usb_cfg_array_len,
704*7c478bd9Sstevel@tonic-gate 			    usba_device->usb_cfg_array_len_length);
705*7c478bd9Sstevel@tonic-gate 
706*7c478bd9Sstevel@tonic-gate 			mutex_exit(&usba_device->usb_mutex);
707*7c478bd9Sstevel@tonic-gate 		}
708*7c478bd9Sstevel@tonic-gate 
709*7c478bd9Sstevel@tonic-gate 		if (usba_device->usb_cfg_str_descr) {
710*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
711*7c478bd9Sstevel@tonic-gate 			    "deallocating usb_cfg_str_descr: 0x%p",
712*7c478bd9Sstevel@tonic-gate 			    usba_device->usb_cfg_str_descr);
713*7c478bd9Sstevel@tonic-gate 			for (i = 0;
714*7c478bd9Sstevel@tonic-gate 			    i < usba_device->usb_dev_descr->bNumConfigurations;
715*7c478bd9Sstevel@tonic-gate 			    i++) {
716*7c478bd9Sstevel@tonic-gate 				if (usba_device->usb_cfg_str_descr[i]) {
717*7c478bd9Sstevel@tonic-gate 					kmem_free(
718*7c478bd9Sstevel@tonic-gate 					    usba_device->usb_cfg_str_descr[i],
719*7c478bd9Sstevel@tonic-gate 					    strlen(usba_device->
720*7c478bd9Sstevel@tonic-gate 						usb_cfg_str_descr[i]) + 1);
721*7c478bd9Sstevel@tonic-gate 				}
722*7c478bd9Sstevel@tonic-gate 			}
723*7c478bd9Sstevel@tonic-gate 			/* free the array pointers */
724*7c478bd9Sstevel@tonic-gate 			kmem_free(usba_device->usb_cfg_str_descr,
725*7c478bd9Sstevel@tonic-gate 			    sizeof (uchar_t *) * usba_device->usb_n_cfgs);
726*7c478bd9Sstevel@tonic-gate 		}
727*7c478bd9Sstevel@tonic-gate 
728*7c478bd9Sstevel@tonic-gate 		if (usba_device->usb_dev_descr) {
729*7c478bd9Sstevel@tonic-gate 			kmem_free(usba_device->usb_dev_descr,
730*7c478bd9Sstevel@tonic-gate 				    sizeof (usb_dev_descr_t));
731*7c478bd9Sstevel@tonic-gate 		}
732*7c478bd9Sstevel@tonic-gate 
733*7c478bd9Sstevel@tonic-gate 		if (usba_device->usb_mfg_str) {
734*7c478bd9Sstevel@tonic-gate 			kmem_free(usba_device->usb_mfg_str,
735*7c478bd9Sstevel@tonic-gate 				strlen(usba_device->usb_mfg_str) + 1);
736*7c478bd9Sstevel@tonic-gate 		}
737*7c478bd9Sstevel@tonic-gate 
738*7c478bd9Sstevel@tonic-gate 		if (usba_device->usb_product_str) {
739*7c478bd9Sstevel@tonic-gate 			kmem_free(usba_device->usb_product_str,
740*7c478bd9Sstevel@tonic-gate 				strlen(usba_device->usb_product_str) + 1);
741*7c478bd9Sstevel@tonic-gate 		}
742*7c478bd9Sstevel@tonic-gate 
743*7c478bd9Sstevel@tonic-gate 		if (usba_device->usb_serialno_str) {
744*7c478bd9Sstevel@tonic-gate 			kmem_free(usba_device->usb_serialno_str,
745*7c478bd9Sstevel@tonic-gate 				strlen(usba_device->usb_serialno_str) + 1);
746*7c478bd9Sstevel@tonic-gate 		}
747*7c478bd9Sstevel@tonic-gate 
748*7c478bd9Sstevel@tonic-gate 		usba_unset_usb_address(usba_device);
749*7c478bd9Sstevel@tonic-gate 	}
750*7c478bd9Sstevel@tonic-gate 
751*7c478bd9Sstevel@tonic-gate #ifndef __lock_lint
752*7c478bd9Sstevel@tonic-gate 	ASSERT(usba_device->usb_client_dev_data_list.cddl_next == NULL);
753*7c478bd9Sstevel@tonic-gate #endif
754*7c478bd9Sstevel@tonic-gate 
755*7c478bd9Sstevel@tonic-gate 	if (usba_device->usb_client_flags) {
756*7c478bd9Sstevel@tonic-gate #ifndef __lock_lint
757*7c478bd9Sstevel@tonic-gate 		int i;
758*7c478bd9Sstevel@tonic-gate 
759*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < usba_device->usb_n_ifs; i++) {
760*7c478bd9Sstevel@tonic-gate 			ASSERT(usba_device->usb_client_flags[i] == 0);
761*7c478bd9Sstevel@tonic-gate 		}
762*7c478bd9Sstevel@tonic-gate #endif
763*7c478bd9Sstevel@tonic-gate 		kmem_free(usba_device->usb_client_flags,
764*7c478bd9Sstevel@tonic-gate 		    usba_device->usb_n_ifs * USBA_CLIENT_FLAG_SIZE);
765*7c478bd9Sstevel@tonic-gate 	}
766*7c478bd9Sstevel@tonic-gate 
767*7c478bd9Sstevel@tonic-gate 
768*7c478bd9Sstevel@tonic-gate 	if (usba_device->usb_client_attach_list) {
769*7c478bd9Sstevel@tonic-gate 		kmem_free(usba_device->usb_client_attach_list,
770*7c478bd9Sstevel@tonic-gate 		    usba_device->usb_n_ifs *
771*7c478bd9Sstevel@tonic-gate 		    sizeof (*usba_device->usb_client_attach_list));
772*7c478bd9Sstevel@tonic-gate 	}
773*7c478bd9Sstevel@tonic-gate 	if (usba_device->usb_client_ev_cb_list) {
774*7c478bd9Sstevel@tonic-gate 		kmem_free(usba_device->usb_client_ev_cb_list,
775*7c478bd9Sstevel@tonic-gate 		    usba_device->usb_n_ifs *
776*7c478bd9Sstevel@tonic-gate 		    sizeof (*usba_device->usb_client_ev_cb_list));
777*7c478bd9Sstevel@tonic-gate 	}
778*7c478bd9Sstevel@tonic-gate 
779*7c478bd9Sstevel@tonic-gate 	/*
780*7c478bd9Sstevel@tonic-gate 	 * finally ready to destroy the structure
781*7c478bd9Sstevel@tonic-gate 	 */
782*7c478bd9Sstevel@tonic-gate 	mutex_destroy(&usba_device->usb_mutex);
783*7c478bd9Sstevel@tonic-gate 
784*7c478bd9Sstevel@tonic-gate 	kmem_free((caddr_t)usba_device, sizeof (usba_device_t));
785*7c478bd9Sstevel@tonic-gate }
786*7c478bd9Sstevel@tonic-gate 
787*7c478bd9Sstevel@tonic-gate 
788*7c478bd9Sstevel@tonic-gate /* clear the data toggle for all endpoints on this device */
789*7c478bd9Sstevel@tonic-gate void
790*7c478bd9Sstevel@tonic-gate usba_clear_data_toggle(usba_device_t *usba_device)
791*7c478bd9Sstevel@tonic-gate {
792*7c478bd9Sstevel@tonic-gate 	int	i;
793*7c478bd9Sstevel@tonic-gate 
794*7c478bd9Sstevel@tonic-gate 	if (usba_device != NULL) {
795*7c478bd9Sstevel@tonic-gate 		mutex_enter(&usba_device->usb_mutex);
796*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < USBA_N_ENDPOINTS; i++) {
797*7c478bd9Sstevel@tonic-gate 			usba_device->usb_ph_list[i].usba_ph_flags &=
798*7c478bd9Sstevel@tonic-gate 			    ~USBA_PH_DATA_TOGGLE;
799*7c478bd9Sstevel@tonic-gate 		}
800*7c478bd9Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
801*7c478bd9Sstevel@tonic-gate 	}
802*7c478bd9Sstevel@tonic-gate }
803*7c478bd9Sstevel@tonic-gate 
804*7c478bd9Sstevel@tonic-gate 
805*7c478bd9Sstevel@tonic-gate /*
806*7c478bd9Sstevel@tonic-gate  * usba_create_child_devi():
807*7c478bd9Sstevel@tonic-gate  *	create a child devinfo node, usba_device, attach properties.
808*7c478bd9Sstevel@tonic-gate  *	the usba_device structure is shared between all interfaces
809*7c478bd9Sstevel@tonic-gate  */
810*7c478bd9Sstevel@tonic-gate int
811*7c478bd9Sstevel@tonic-gate usba_create_child_devi(dev_info_t	*dip,
812*7c478bd9Sstevel@tonic-gate 		char			*node_name,
813*7c478bd9Sstevel@tonic-gate 		usba_hcdi_ops_t		*usba_hcdi_ops,
814*7c478bd9Sstevel@tonic-gate 		dev_info_t		*usb_root_hub_dip,
815*7c478bd9Sstevel@tonic-gate 		usb_port_status_t	port_status,
816*7c478bd9Sstevel@tonic-gate 		usba_device_t		*usba_device,
817*7c478bd9Sstevel@tonic-gate 		dev_info_t		**child_dip)
818*7c478bd9Sstevel@tonic-gate {
819*7c478bd9Sstevel@tonic-gate 	int rval = USB_FAILURE;
820*7c478bd9Sstevel@tonic-gate 	int usba_device_allocated = 0;
821*7c478bd9Sstevel@tonic-gate 	usb_addr_t	address;
822*7c478bd9Sstevel@tonic-gate 
823*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
824*7c478bd9Sstevel@tonic-gate 	    "usba_create_child_devi: %s usba_device=0x%p "
825*7c478bd9Sstevel@tonic-gate 	    "port status=0x%x", node_name,
826*7c478bd9Sstevel@tonic-gate 	    (void *)usba_device, port_status);
827*7c478bd9Sstevel@tonic-gate 
828*7c478bd9Sstevel@tonic-gate 	ndi_devi_alloc_sleep(dip, node_name, (dnode_t)DEVI_SID_NODEID,
829*7c478bd9Sstevel@tonic-gate 				child_dip);
830*7c478bd9Sstevel@tonic-gate 
831*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
832*7c478bd9Sstevel@tonic-gate 	    "child dip=0x%p", *child_dip);
833*7c478bd9Sstevel@tonic-gate 
834*7c478bd9Sstevel@tonic-gate 	if (usba_device == NULL) {
835*7c478bd9Sstevel@tonic-gate 
836*7c478bd9Sstevel@tonic-gate 		usba_device = usba_alloc_usba_device(usb_root_hub_dip);
837*7c478bd9Sstevel@tonic-gate 
838*7c478bd9Sstevel@tonic-gate 		/* grab the mutex to keep warlock happy */
839*7c478bd9Sstevel@tonic-gate 		mutex_enter(&usba_device->usb_mutex);
840*7c478bd9Sstevel@tonic-gate 		usba_device->usb_hcdi_ops	= usba_hcdi_ops;
841*7c478bd9Sstevel@tonic-gate 		usba_device->usb_port_status	= port_status;
842*7c478bd9Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
843*7c478bd9Sstevel@tonic-gate 
844*7c478bd9Sstevel@tonic-gate 		usba_device_allocated++;
845*7c478bd9Sstevel@tonic-gate 	} else {
846*7c478bd9Sstevel@tonic-gate 		mutex_enter(&usba_device->usb_mutex);
847*7c478bd9Sstevel@tonic-gate 		if (usba_hcdi_ops) {
848*7c478bd9Sstevel@tonic-gate 			ASSERT(usba_device->usb_hcdi_ops == usba_hcdi_ops);
849*7c478bd9Sstevel@tonic-gate 		}
850*7c478bd9Sstevel@tonic-gate 		if (usb_root_hub_dip) {
851*7c478bd9Sstevel@tonic-gate 			ASSERT(usba_device->usb_root_hub_dip ==
852*7c478bd9Sstevel@tonic-gate 						usb_root_hub_dip);
853*7c478bd9Sstevel@tonic-gate 		}
854*7c478bd9Sstevel@tonic-gate 
855*7c478bd9Sstevel@tonic-gate 		usba_device->usb_port_status	= port_status;
856*7c478bd9Sstevel@tonic-gate 
857*7c478bd9Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
858*7c478bd9Sstevel@tonic-gate 	}
859*7c478bd9Sstevel@tonic-gate 
860*7c478bd9Sstevel@tonic-gate 	if (usba_device->usb_addr == 0) {
861*7c478bd9Sstevel@tonic-gate 		if (usba_set_usb_address(usba_device) == USB_FAILURE) {
862*7c478bd9Sstevel@tonic-gate 			address = 0;
863*7c478bd9Sstevel@tonic-gate 
864*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
865*7c478bd9Sstevel@tonic-gate 				"cannot set usb address for dip=0x%p",
866*7c478bd9Sstevel@tonic-gate 				*child_dip);
867*7c478bd9Sstevel@tonic-gate 
868*7c478bd9Sstevel@tonic-gate 			goto fail;
869*7c478bd9Sstevel@tonic-gate 		}
870*7c478bd9Sstevel@tonic-gate 	}
871*7c478bd9Sstevel@tonic-gate 	address = usba_device->usb_addr;
872*7c478bd9Sstevel@tonic-gate 
873*7c478bd9Sstevel@tonic-gate 	/* attach properties */
874*7c478bd9Sstevel@tonic-gate 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, *child_dip,
875*7c478bd9Sstevel@tonic-gate 		"assigned-address", address);
876*7c478bd9Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
877*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
878*7c478bd9Sstevel@tonic-gate 			"cannot set usb address property for dip=0x%p",
879*7c478bd9Sstevel@tonic-gate 			*child_dip);
880*7c478bd9Sstevel@tonic-gate 		rval = USB_FAILURE;
881*7c478bd9Sstevel@tonic-gate 
882*7c478bd9Sstevel@tonic-gate 		goto fail;
883*7c478bd9Sstevel@tonic-gate 	}
884*7c478bd9Sstevel@tonic-gate 
885*7c478bd9Sstevel@tonic-gate 	/*
886*7c478bd9Sstevel@tonic-gate 	 * store the usba_device point in the dip
887*7c478bd9Sstevel@tonic-gate 	 */
888*7c478bd9Sstevel@tonic-gate 	usba_set_usba_device(*child_dip, usba_device);
889*7c478bd9Sstevel@tonic-gate 
890*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
891*7c478bd9Sstevel@tonic-gate 	    "usba_create_child_devi: devi=0x%p (%s) ud=0x%p",
892*7c478bd9Sstevel@tonic-gate 		*child_dip, ddi_driver_name(*child_dip), usba_device);
893*7c478bd9Sstevel@tonic-gate 
894*7c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
895*7c478bd9Sstevel@tonic-gate 
896*7c478bd9Sstevel@tonic-gate fail:
897*7c478bd9Sstevel@tonic-gate 	if (*child_dip) {
898*7c478bd9Sstevel@tonic-gate 		int rval = usba_destroy_child_devi(*child_dip, NDI_DEVI_REMOVE);
899*7c478bd9Sstevel@tonic-gate 		ASSERT(rval == USB_SUCCESS);
900*7c478bd9Sstevel@tonic-gate 		*child_dip = NULL;
901*7c478bd9Sstevel@tonic-gate 	}
902*7c478bd9Sstevel@tonic-gate 
903*7c478bd9Sstevel@tonic-gate 	if (usba_device_allocated) {
904*7c478bd9Sstevel@tonic-gate 		usba_free_usba_device(usba_device);
905*7c478bd9Sstevel@tonic-gate 	} else if (address && usba_device) {
906*7c478bd9Sstevel@tonic-gate 		usba_unset_usb_address(usba_device);
907*7c478bd9Sstevel@tonic-gate 	}
908*7c478bd9Sstevel@tonic-gate 
909*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L1(DPRINT_MASK_USBA, usba_log_handle,
910*7c478bd9Sstevel@tonic-gate 	    "usba_create_child_devi failed: rval=%d", rval);
911*7c478bd9Sstevel@tonic-gate 
912*7c478bd9Sstevel@tonic-gate 	return (rval);
913*7c478bd9Sstevel@tonic-gate }
914*7c478bd9Sstevel@tonic-gate 
915*7c478bd9Sstevel@tonic-gate 
916*7c478bd9Sstevel@tonic-gate int
917*7c478bd9Sstevel@tonic-gate usba_destroy_child_devi(dev_info_t *dip, uint_t flag)
918*7c478bd9Sstevel@tonic-gate {
919*7c478bd9Sstevel@tonic-gate 	usba_device_t	*usba_device;
920*7c478bd9Sstevel@tonic-gate 	int		rval = NDI_SUCCESS;
921*7c478bd9Sstevel@tonic-gate 
922*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
923*7c478bd9Sstevel@tonic-gate 	    "usba_destroy_child_devi: %s%d (0x%p)",
924*7c478bd9Sstevel@tonic-gate 	    ddi_driver_name(dip), ddi_get_instance(dip), dip);
925*7c478bd9Sstevel@tonic-gate 
926*7c478bd9Sstevel@tonic-gate 	usba_device = usba_get_usba_device(dip);
927*7c478bd9Sstevel@tonic-gate 
928*7c478bd9Sstevel@tonic-gate 	/*
929*7c478bd9Sstevel@tonic-gate 	 * if the child hasn't been bound yet, we can just
930*7c478bd9Sstevel@tonic-gate 	 * free the dip
931*7c478bd9Sstevel@tonic-gate 	 */
932*7c478bd9Sstevel@tonic-gate 	if (i_ddi_node_state(dip) < DS_INITIALIZED) {
933*7c478bd9Sstevel@tonic-gate 		/*
934*7c478bd9Sstevel@tonic-gate 		 * do not call ndi_devi_free() since it might
935*7c478bd9Sstevel@tonic-gate 		 * deadlock
936*7c478bd9Sstevel@tonic-gate 		 */
937*7c478bd9Sstevel@tonic-gate 		rval = ddi_remove_child(dip, 0);
938*7c478bd9Sstevel@tonic-gate 
939*7c478bd9Sstevel@tonic-gate 	} else {
940*7c478bd9Sstevel@tonic-gate 		char *devnm = kmem_alloc(MAXNAMELEN + 1, KM_SLEEP);
941*7c478bd9Sstevel@tonic-gate 		dev_info_t *pdip = ddi_get_parent(dip);
942*7c478bd9Sstevel@tonic-gate 
943*7c478bd9Sstevel@tonic-gate 		(void) ddi_deviname(dip, devnm);
944*7c478bd9Sstevel@tonic-gate 
945*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
946*7c478bd9Sstevel@tonic-gate 		    "usba_destroy_child_devi:\n\t"
947*7c478bd9Sstevel@tonic-gate 		    "offlining dip 0x%p usba_device=0x%p (%s)", dip,
948*7c478bd9Sstevel@tonic-gate 		    (void *)usba_device, devnm);
949*7c478bd9Sstevel@tonic-gate 
950*7c478bd9Sstevel@tonic-gate 		(void) devfs_clean(pdip, NULL, DV_CLEAN_FORCE);
951*7c478bd9Sstevel@tonic-gate 		rval =	ndi_devi_unconfig_one(pdip, devnm + 1, NULL,
952*7c478bd9Sstevel@tonic-gate 		    flag | NDI_UNCONFIG | NDI_DEVI_OFFLINE);
953*7c478bd9Sstevel@tonic-gate 		if (rval != NDI_SUCCESS) {
954*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
955*7c478bd9Sstevel@tonic-gate 			    " ndi_devi_unconfig_one %s%d failed (%d)",
956*7c478bd9Sstevel@tonic-gate 			    ddi_driver_name(dip), ddi_get_instance(dip),
957*7c478bd9Sstevel@tonic-gate 			    rval);
958*7c478bd9Sstevel@tonic-gate 		}
959*7c478bd9Sstevel@tonic-gate 		kmem_free(devnm, MAXNAMELEN + 1);
960*7c478bd9Sstevel@tonic-gate 	}
961*7c478bd9Sstevel@tonic-gate 
962*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
963*7c478bd9Sstevel@tonic-gate 	    "usba_destroy_child_devi: rval=%d", rval);
964*7c478bd9Sstevel@tonic-gate 
965*7c478bd9Sstevel@tonic-gate 	return (rval == NDI_SUCCESS ? USB_SUCCESS : USB_FAILURE);
966*7c478bd9Sstevel@tonic-gate }
967*7c478bd9Sstevel@tonic-gate 
968*7c478bd9Sstevel@tonic-gate 
969*7c478bd9Sstevel@tonic-gate /*
970*7c478bd9Sstevel@tonic-gate  * list management
971*7c478bd9Sstevel@tonic-gate  */
972*7c478bd9Sstevel@tonic-gate void
973*7c478bd9Sstevel@tonic-gate usba_init_list(usba_list_entry_t *element, usb_opaque_t private,
974*7c478bd9Sstevel@tonic-gate 	ddi_iblock_cookie_t	iblock_cookie)
975*7c478bd9Sstevel@tonic-gate {
976*7c478bd9Sstevel@tonic-gate 	mutex_init(&element->list_mutex, NULL, MUTEX_DRIVER,
977*7c478bd9Sstevel@tonic-gate 						iblock_cookie);
978*7c478bd9Sstevel@tonic-gate 	mutex_enter(&element->list_mutex);
979*7c478bd9Sstevel@tonic-gate 	element->private = private;
980*7c478bd9Sstevel@tonic-gate 	mutex_exit(&element->list_mutex);
981*7c478bd9Sstevel@tonic-gate }
982*7c478bd9Sstevel@tonic-gate 
983*7c478bd9Sstevel@tonic-gate 
984*7c478bd9Sstevel@tonic-gate void
985*7c478bd9Sstevel@tonic-gate usba_destroy_list(usba_list_entry_t *head)
986*7c478bd9Sstevel@tonic-gate {
987*7c478bd9Sstevel@tonic-gate 	mutex_enter(&head->list_mutex);
988*7c478bd9Sstevel@tonic-gate 	ASSERT(head->next == NULL);
989*7c478bd9Sstevel@tonic-gate 	ASSERT(head->prev == NULL);
990*7c478bd9Sstevel@tonic-gate 	mutex_exit(&head->list_mutex);
991*7c478bd9Sstevel@tonic-gate 
992*7c478bd9Sstevel@tonic-gate 	mutex_destroy(&head->list_mutex);
993*7c478bd9Sstevel@tonic-gate }
994*7c478bd9Sstevel@tonic-gate 
995*7c478bd9Sstevel@tonic-gate 
996*7c478bd9Sstevel@tonic-gate void
997*7c478bd9Sstevel@tonic-gate usba_add_to_list(usba_list_entry_t *head, usba_list_entry_t *element)
998*7c478bd9Sstevel@tonic-gate {
999*7c478bd9Sstevel@tonic-gate 	usba_list_entry_t *next;
1000*7c478bd9Sstevel@tonic-gate 	int		remaining;
1001*7c478bd9Sstevel@tonic-gate 
1002*7c478bd9Sstevel@tonic-gate 	mutex_enter(&head->list_mutex);
1003*7c478bd9Sstevel@tonic-gate 	mutex_enter(&element->list_mutex);
1004*7c478bd9Sstevel@tonic-gate 
1005*7c478bd9Sstevel@tonic-gate 	remaining = head->count;
1006*7c478bd9Sstevel@tonic-gate 
1007*7c478bd9Sstevel@tonic-gate 	/* check if it is not in another list */
1008*7c478bd9Sstevel@tonic-gate 	ASSERT(element->next == NULL);
1009*7c478bd9Sstevel@tonic-gate 	ASSERT(element->prev == NULL);
1010*7c478bd9Sstevel@tonic-gate 
1011*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1012*7c478bd9Sstevel@tonic-gate 	/*
1013*7c478bd9Sstevel@tonic-gate 	 * only verify the list when not in interrupt context, we
1014*7c478bd9Sstevel@tonic-gate 	 * have to trust the HCD
1015*7c478bd9Sstevel@tonic-gate 	 */
1016*7c478bd9Sstevel@tonic-gate 	if (!servicing_interrupt()) {
1017*7c478bd9Sstevel@tonic-gate 
1018*7c478bd9Sstevel@tonic-gate 		/* check if not already in this list */
1019*7c478bd9Sstevel@tonic-gate 		for (next = head->next; (next != NULL);
1020*7c478bd9Sstevel@tonic-gate 		    next = next->next) {
1021*7c478bd9Sstevel@tonic-gate 			if (next == element) {
1022*7c478bd9Sstevel@tonic-gate 				USB_DPRINTF_L0(DPRINT_MASK_USBA,
1023*7c478bd9Sstevel@tonic-gate 				    usba_log_handle,
1024*7c478bd9Sstevel@tonic-gate 				    "Attempt to corrupt USB list at 0x%p",
1025*7c478bd9Sstevel@tonic-gate 				    (void *)head);
1026*7c478bd9Sstevel@tonic-gate 				ASSERT(next == element);
1027*7c478bd9Sstevel@tonic-gate 
1028*7c478bd9Sstevel@tonic-gate 				goto done;
1029*7c478bd9Sstevel@tonic-gate 			}
1030*7c478bd9Sstevel@tonic-gate 			remaining--;
1031*7c478bd9Sstevel@tonic-gate 
1032*7c478bd9Sstevel@tonic-gate 			/*
1033*7c478bd9Sstevel@tonic-gate 			 * Detect incorrect circ links or found
1034*7c478bd9Sstevel@tonic-gate 			 * unexpected elements.
1035*7c478bd9Sstevel@tonic-gate 			 */
1036*7c478bd9Sstevel@tonic-gate 			if ((next->next && (remaining == 0)) ||
1037*7c478bd9Sstevel@tonic-gate 			    ((next->next == NULL) && remaining)) {
1038*7c478bd9Sstevel@tonic-gate 				panic("Corrupted USB list at 0x%p",
1039*7c478bd9Sstevel@tonic-gate 				    (void *)head);
1040*7c478bd9Sstevel@tonic-gate 				/*NOTREACHED*/
1041*7c478bd9Sstevel@tonic-gate 			}
1042*7c478bd9Sstevel@tonic-gate 		}
1043*7c478bd9Sstevel@tonic-gate 	}
1044*7c478bd9Sstevel@tonic-gate #endif
1045*7c478bd9Sstevel@tonic-gate 
1046*7c478bd9Sstevel@tonic-gate 	if (head->next == NULL) {
1047*7c478bd9Sstevel@tonic-gate 		head->prev = head->next = element;
1048*7c478bd9Sstevel@tonic-gate 	} else {
1049*7c478bd9Sstevel@tonic-gate 		/* add to tail */
1050*7c478bd9Sstevel@tonic-gate 		head->prev->next = element;
1051*7c478bd9Sstevel@tonic-gate 		element->prev = head->prev;
1052*7c478bd9Sstevel@tonic-gate 		head->prev = element;
1053*7c478bd9Sstevel@tonic-gate 	}
1054*7c478bd9Sstevel@tonic-gate 
1055*7c478bd9Sstevel@tonic-gate 	head->count++;
1056*7c478bd9Sstevel@tonic-gate 
1057*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
1058*7c478bd9Sstevel@tonic-gate 	    "usba_add_to_list: head=0x%p element=0x%p count=%d",
1059*7c478bd9Sstevel@tonic-gate 	    head, element, head->count);
1060*7c478bd9Sstevel@tonic-gate 
1061*7c478bd9Sstevel@tonic-gate done:
1062*7c478bd9Sstevel@tonic-gate 	mutex_exit(&head->list_mutex);
1063*7c478bd9Sstevel@tonic-gate 	mutex_exit(&element->list_mutex);
1064*7c478bd9Sstevel@tonic-gate }
1065*7c478bd9Sstevel@tonic-gate 
1066*7c478bd9Sstevel@tonic-gate 
1067*7c478bd9Sstevel@tonic-gate int
1068*7c478bd9Sstevel@tonic-gate usba_rm_from_list(usba_list_entry_t *head, usba_list_entry_t *element)
1069*7c478bd9Sstevel@tonic-gate {
1070*7c478bd9Sstevel@tonic-gate 	usba_list_entry_t *e;
1071*7c478bd9Sstevel@tonic-gate 	int		found = 0;
1072*7c478bd9Sstevel@tonic-gate 	int		remaining;
1073*7c478bd9Sstevel@tonic-gate 
1074*7c478bd9Sstevel@tonic-gate 	/* find the element in the list first */
1075*7c478bd9Sstevel@tonic-gate 	mutex_enter(&head->list_mutex);
1076*7c478bd9Sstevel@tonic-gate 
1077*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
1078*7c478bd9Sstevel@tonic-gate 	    "usba_rm_from_list: head=0x%p element=0x%p count=%d",
1079*7c478bd9Sstevel@tonic-gate 	    head, element, head->count);
1080*7c478bd9Sstevel@tonic-gate 
1081*7c478bd9Sstevel@tonic-gate 	remaining = head->count;
1082*7c478bd9Sstevel@tonic-gate 	e = head->next;
1083*7c478bd9Sstevel@tonic-gate 
1084*7c478bd9Sstevel@tonic-gate 	while (e) {
1085*7c478bd9Sstevel@tonic-gate 		if (e == element) {
1086*7c478bd9Sstevel@tonic-gate 			found++;
1087*7c478bd9Sstevel@tonic-gate 			break;
1088*7c478bd9Sstevel@tonic-gate 		}
1089*7c478bd9Sstevel@tonic-gate 		e = e->next;
1090*7c478bd9Sstevel@tonic-gate 
1091*7c478bd9Sstevel@tonic-gate 		remaining--;
1092*7c478bd9Sstevel@tonic-gate 
1093*7c478bd9Sstevel@tonic-gate 		/* Detect incorrect circ links or found unexpected elements. */
1094*7c478bd9Sstevel@tonic-gate 		if ((e && (remaining == 0)) ||
1095*7c478bd9Sstevel@tonic-gate 		    ((e == NULL) && (remaining))) {
1096*7c478bd9Sstevel@tonic-gate 			panic("Corrupted USB list at 0x%p", (void *)head);
1097*7c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
1098*7c478bd9Sstevel@tonic-gate 		}
1099*7c478bd9Sstevel@tonic-gate 	}
1100*7c478bd9Sstevel@tonic-gate 
1101*7c478bd9Sstevel@tonic-gate 	if (!found) {
1102*7c478bd9Sstevel@tonic-gate 		mutex_exit(&head->list_mutex);
1103*7c478bd9Sstevel@tonic-gate 
1104*7c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
1105*7c478bd9Sstevel@tonic-gate 	}
1106*7c478bd9Sstevel@tonic-gate 
1107*7c478bd9Sstevel@tonic-gate 	/* now remove the element */
1108*7c478bd9Sstevel@tonic-gate 	mutex_enter(&element->list_mutex);
1109*7c478bd9Sstevel@tonic-gate 
1110*7c478bd9Sstevel@tonic-gate 	if (element->next) {
1111*7c478bd9Sstevel@tonic-gate 		element->next->prev = element->prev;
1112*7c478bd9Sstevel@tonic-gate 	}
1113*7c478bd9Sstevel@tonic-gate 	if (element->prev) {
1114*7c478bd9Sstevel@tonic-gate 		element->prev->next = element->next;
1115*7c478bd9Sstevel@tonic-gate 	}
1116*7c478bd9Sstevel@tonic-gate 	if (head->next == element) {
1117*7c478bd9Sstevel@tonic-gate 		head->next = element->next;
1118*7c478bd9Sstevel@tonic-gate 	}
1119*7c478bd9Sstevel@tonic-gate 	if (head->prev == element) {
1120*7c478bd9Sstevel@tonic-gate 		head->prev = element->prev;
1121*7c478bd9Sstevel@tonic-gate 	}
1122*7c478bd9Sstevel@tonic-gate 
1123*7c478bd9Sstevel@tonic-gate 	element->prev = element->next = NULL;
1124*7c478bd9Sstevel@tonic-gate 	if (head->next == NULL) {
1125*7c478bd9Sstevel@tonic-gate 		ASSERT(head->prev == NULL);
1126*7c478bd9Sstevel@tonic-gate 	} else {
1127*7c478bd9Sstevel@tonic-gate 		ASSERT(head->next->prev == NULL);
1128*7c478bd9Sstevel@tonic-gate 	}
1129*7c478bd9Sstevel@tonic-gate 	if (head->prev == NULL) {
1130*7c478bd9Sstevel@tonic-gate 		ASSERT(head->next == NULL);
1131*7c478bd9Sstevel@tonic-gate 	} else {
1132*7c478bd9Sstevel@tonic-gate 		ASSERT(head->prev->next == NULL);
1133*7c478bd9Sstevel@tonic-gate 	}
1134*7c478bd9Sstevel@tonic-gate 
1135*7c478bd9Sstevel@tonic-gate 	head->count--;
1136*7c478bd9Sstevel@tonic-gate 
1137*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
1138*7c478bd9Sstevel@tonic-gate 	    "usba_rm_from_list success: head=0x%p element=0x%p cnt=%d",
1139*7c478bd9Sstevel@tonic-gate 	    head, element, head->count);
1140*7c478bd9Sstevel@tonic-gate 
1141*7c478bd9Sstevel@tonic-gate 	mutex_exit(&element->list_mutex);
1142*7c478bd9Sstevel@tonic-gate 	mutex_exit(&head->list_mutex);
1143*7c478bd9Sstevel@tonic-gate 
1144*7c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
1145*7c478bd9Sstevel@tonic-gate }
1146*7c478bd9Sstevel@tonic-gate 
1147*7c478bd9Sstevel@tonic-gate 
1148*7c478bd9Sstevel@tonic-gate usba_list_entry_t *
1149*7c478bd9Sstevel@tonic-gate usba_rm_first_from_list(usba_list_entry_t *head)
1150*7c478bd9Sstevel@tonic-gate {
1151*7c478bd9Sstevel@tonic-gate 	usba_list_entry_t *element = NULL;
1152*7c478bd9Sstevel@tonic-gate 
1153*7c478bd9Sstevel@tonic-gate 	if (head) {
1154*7c478bd9Sstevel@tonic-gate 		mutex_enter(&head->list_mutex);
1155*7c478bd9Sstevel@tonic-gate 		element = head->next;
1156*7c478bd9Sstevel@tonic-gate 		if (element) {
1157*7c478bd9Sstevel@tonic-gate 			/* now remove the element */
1158*7c478bd9Sstevel@tonic-gate 			mutex_enter(&element->list_mutex);
1159*7c478bd9Sstevel@tonic-gate 			head->next = element->next;
1160*7c478bd9Sstevel@tonic-gate 			if (head->next) {
1161*7c478bd9Sstevel@tonic-gate 				head->next->prev = NULL;
1162*7c478bd9Sstevel@tonic-gate 			}
1163*7c478bd9Sstevel@tonic-gate 			if (head->prev == element) {
1164*7c478bd9Sstevel@tonic-gate 				head->prev = element->next;
1165*7c478bd9Sstevel@tonic-gate 			}
1166*7c478bd9Sstevel@tonic-gate 			element->prev = element->next = NULL;
1167*7c478bd9Sstevel@tonic-gate 			mutex_exit(&element->list_mutex);
1168*7c478bd9Sstevel@tonic-gate 			head->count--;
1169*7c478bd9Sstevel@tonic-gate 		}
1170*7c478bd9Sstevel@tonic-gate 		if (head->next == NULL) {
1171*7c478bd9Sstevel@tonic-gate 			ASSERT(head->prev == NULL);
1172*7c478bd9Sstevel@tonic-gate 		} else {
1173*7c478bd9Sstevel@tonic-gate 			ASSERT(head->next->prev == NULL);
1174*7c478bd9Sstevel@tonic-gate 		}
1175*7c478bd9Sstevel@tonic-gate 		if (head->prev == NULL) {
1176*7c478bd9Sstevel@tonic-gate 			ASSERT(head->next == NULL);
1177*7c478bd9Sstevel@tonic-gate 		} else {
1178*7c478bd9Sstevel@tonic-gate 			ASSERT(head->prev->next == NULL);
1179*7c478bd9Sstevel@tonic-gate 		}
1180*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
1181*7c478bd9Sstevel@tonic-gate 		    "usba_rm_first_from_list: head=0x%p el=0x%p cnt=%d",
1182*7c478bd9Sstevel@tonic-gate 		    head, element, head->count);
1183*7c478bd9Sstevel@tonic-gate 
1184*7c478bd9Sstevel@tonic-gate 		mutex_exit(&head->list_mutex);
1185*7c478bd9Sstevel@tonic-gate 	}
1186*7c478bd9Sstevel@tonic-gate 
1187*7c478bd9Sstevel@tonic-gate 	return (element);
1188*7c478bd9Sstevel@tonic-gate }
1189*7c478bd9Sstevel@tonic-gate 
1190*7c478bd9Sstevel@tonic-gate 
1191*7c478bd9Sstevel@tonic-gate usb_opaque_t
1192*7c478bd9Sstevel@tonic-gate usba_rm_first_pvt_from_list(usba_list_entry_t *head)
1193*7c478bd9Sstevel@tonic-gate {
1194*7c478bd9Sstevel@tonic-gate 	usba_list_entry_t *element = usba_rm_first_from_list(head);
1195*7c478bd9Sstevel@tonic-gate 	usb_opaque_t private = NULL;
1196*7c478bd9Sstevel@tonic-gate 
1197*7c478bd9Sstevel@tonic-gate 	if (element) {
1198*7c478bd9Sstevel@tonic-gate 		mutex_enter(&element->list_mutex);
1199*7c478bd9Sstevel@tonic-gate 		private = element->private;
1200*7c478bd9Sstevel@tonic-gate 		mutex_exit(&element->list_mutex);
1201*7c478bd9Sstevel@tonic-gate 	}
1202*7c478bd9Sstevel@tonic-gate 
1203*7c478bd9Sstevel@tonic-gate 	return (private);
1204*7c478bd9Sstevel@tonic-gate }
1205*7c478bd9Sstevel@tonic-gate 
1206*7c478bd9Sstevel@tonic-gate 
1207*7c478bd9Sstevel@tonic-gate /*
1208*7c478bd9Sstevel@tonic-gate  * move list to new list and zero original list
1209*7c478bd9Sstevel@tonic-gate  */
1210*7c478bd9Sstevel@tonic-gate void
1211*7c478bd9Sstevel@tonic-gate usba_move_list(usba_list_entry_t *head, usba_list_entry_t *new,
1212*7c478bd9Sstevel@tonic-gate 	ddi_iblock_cookie_t iblock_cookie)
1213*7c478bd9Sstevel@tonic-gate {
1214*7c478bd9Sstevel@tonic-gate 	usba_init_list(new, NULL, iblock_cookie);
1215*7c478bd9Sstevel@tonic-gate 	mutex_enter(&head->list_mutex);
1216*7c478bd9Sstevel@tonic-gate 	mutex_enter(&new->list_mutex);
1217*7c478bd9Sstevel@tonic-gate 
1218*7c478bd9Sstevel@tonic-gate 	new->next = head->next;
1219*7c478bd9Sstevel@tonic-gate 	new->prev = head->prev;
1220*7c478bd9Sstevel@tonic-gate 	new->count = head->count;
1221*7c478bd9Sstevel@tonic-gate 	new->private = head->private;
1222*7c478bd9Sstevel@tonic-gate 
1223*7c478bd9Sstevel@tonic-gate 	head->next = NULL;
1224*7c478bd9Sstevel@tonic-gate 	head->prev = NULL;
1225*7c478bd9Sstevel@tonic-gate 	head->count = 0;
1226*7c478bd9Sstevel@tonic-gate 	head->private = NULL;
1227*7c478bd9Sstevel@tonic-gate 	mutex_exit(&head->list_mutex);
1228*7c478bd9Sstevel@tonic-gate 	mutex_exit(&new->list_mutex);
1229*7c478bd9Sstevel@tonic-gate }
1230*7c478bd9Sstevel@tonic-gate 
1231*7c478bd9Sstevel@tonic-gate 
1232*7c478bd9Sstevel@tonic-gate int
1233*7c478bd9Sstevel@tonic-gate usba_check_in_list(usba_list_entry_t *head, usba_list_entry_t *element)
1234*7c478bd9Sstevel@tonic-gate {
1235*7c478bd9Sstevel@tonic-gate 	int		rval = USB_FAILURE;
1236*7c478bd9Sstevel@tonic-gate 	int		remaining;
1237*7c478bd9Sstevel@tonic-gate 	usba_list_entry_t *next;
1238*7c478bd9Sstevel@tonic-gate 
1239*7c478bd9Sstevel@tonic-gate 	mutex_enter(&head->list_mutex);
1240*7c478bd9Sstevel@tonic-gate 	remaining = head->count;
1241*7c478bd9Sstevel@tonic-gate 
1242*7c478bd9Sstevel@tonic-gate 	mutex_enter(&element->list_mutex);
1243*7c478bd9Sstevel@tonic-gate 	for (next = head->next; next != NULL; next = next->next) {
1244*7c478bd9Sstevel@tonic-gate 		if (next == element) {
1245*7c478bd9Sstevel@tonic-gate 			rval = USB_SUCCESS;
1246*7c478bd9Sstevel@tonic-gate 			break;
1247*7c478bd9Sstevel@tonic-gate 		}
1248*7c478bd9Sstevel@tonic-gate 		remaining--;
1249*7c478bd9Sstevel@tonic-gate 
1250*7c478bd9Sstevel@tonic-gate 		/* Detect incorrect circ links or found unexpected elements. */
1251*7c478bd9Sstevel@tonic-gate 		if ((next->next && (remaining == 0)) ||
1252*7c478bd9Sstevel@tonic-gate 		    ((next->next == NULL) && remaining)) {
1253*7c478bd9Sstevel@tonic-gate 			panic("Corrupted USB list at 0x%p", (void *)head);
1254*7c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
1255*7c478bd9Sstevel@tonic-gate 		}
1256*7c478bd9Sstevel@tonic-gate 	}
1257*7c478bd9Sstevel@tonic-gate 	mutex_exit(&element->list_mutex);
1258*7c478bd9Sstevel@tonic-gate 	mutex_exit(&head->list_mutex);
1259*7c478bd9Sstevel@tonic-gate 
1260*7c478bd9Sstevel@tonic-gate 	return (rval);
1261*7c478bd9Sstevel@tonic-gate }
1262*7c478bd9Sstevel@tonic-gate 
1263*7c478bd9Sstevel@tonic-gate 
1264*7c478bd9Sstevel@tonic-gate int
1265*7c478bd9Sstevel@tonic-gate usba_list_entry_leaks(usba_list_entry_t *head, char *what)
1266*7c478bd9Sstevel@tonic-gate {
1267*7c478bd9Sstevel@tonic-gate 	int		count = 0;
1268*7c478bd9Sstevel@tonic-gate 	int		remaining;
1269*7c478bd9Sstevel@tonic-gate 	usba_list_entry_t *next;
1270*7c478bd9Sstevel@tonic-gate 
1271*7c478bd9Sstevel@tonic-gate 	mutex_enter(&head->list_mutex);
1272*7c478bd9Sstevel@tonic-gate 	remaining = head->count;
1273*7c478bd9Sstevel@tonic-gate 	for (next = head->next; next != NULL; next = next->next) {
1274*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_HCDI, usba_log_handle,
1275*7c478bd9Sstevel@tonic-gate 		    "leaking %s 0x%p", what, next->private);
1276*7c478bd9Sstevel@tonic-gate 		count++;
1277*7c478bd9Sstevel@tonic-gate 
1278*7c478bd9Sstevel@tonic-gate 		remaining--;
1279*7c478bd9Sstevel@tonic-gate 
1280*7c478bd9Sstevel@tonic-gate 		/* Detect incorrect circ links or found unexpected elements. */
1281*7c478bd9Sstevel@tonic-gate 		if ((next->next && (remaining == 0)) ||
1282*7c478bd9Sstevel@tonic-gate 		    ((next->next == NULL) && remaining)) {
1283*7c478bd9Sstevel@tonic-gate 			panic("Corrupted USB list at 0x%p", (void *)head);
1284*7c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
1285*7c478bd9Sstevel@tonic-gate 		}
1286*7c478bd9Sstevel@tonic-gate 	}
1287*7c478bd9Sstevel@tonic-gate 	ASSERT(count == head->count);
1288*7c478bd9Sstevel@tonic-gate 	mutex_exit(&head->list_mutex);
1289*7c478bd9Sstevel@tonic-gate 
1290*7c478bd9Sstevel@tonic-gate 	if (count) {
1291*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_HCDI, usba_log_handle,
1292*7c478bd9Sstevel@tonic-gate 		    "usba_list_entry_count: leaking %d", count);
1293*7c478bd9Sstevel@tonic-gate 	}
1294*7c478bd9Sstevel@tonic-gate 
1295*7c478bd9Sstevel@tonic-gate 	return (count);
1296*7c478bd9Sstevel@tonic-gate }
1297*7c478bd9Sstevel@tonic-gate 
1298*7c478bd9Sstevel@tonic-gate 
1299*7c478bd9Sstevel@tonic-gate int
1300*7c478bd9Sstevel@tonic-gate usba_list_entry_count(usba_list_entry_t *head)
1301*7c478bd9Sstevel@tonic-gate {
1302*7c478bd9Sstevel@tonic-gate 	int count;
1303*7c478bd9Sstevel@tonic-gate 
1304*7c478bd9Sstevel@tonic-gate 	mutex_enter(&head->list_mutex);
1305*7c478bd9Sstevel@tonic-gate 	count = head->count;
1306*7c478bd9Sstevel@tonic-gate 	mutex_exit(&head->list_mutex);
1307*7c478bd9Sstevel@tonic-gate 
1308*7c478bd9Sstevel@tonic-gate 	return (count);
1309*7c478bd9Sstevel@tonic-gate }
1310*7c478bd9Sstevel@tonic-gate 
1311*7c478bd9Sstevel@tonic-gate 
1312*7c478bd9Sstevel@tonic-gate /*
1313*7c478bd9Sstevel@tonic-gate  * check whether this dip is the root hub. instead of doing a
1314*7c478bd9Sstevel@tonic-gate  * strcmp on the node name we could also check the address
1315*7c478bd9Sstevel@tonic-gate  */
1316*7c478bd9Sstevel@tonic-gate int
1317*7c478bd9Sstevel@tonic-gate usba_is_root_hub(dev_info_t *dip)
1318*7c478bd9Sstevel@tonic-gate {
1319*7c478bd9Sstevel@tonic-gate 	if (dip) {
1320*7c478bd9Sstevel@tonic-gate 		return (ddi_prop_exists(DDI_DEV_T_ANY, dip,
1321*7c478bd9Sstevel@tonic-gate 		    DDI_PROP_DONTPASS|DDI_PROP_NOTPROM, "root-hub"));
1322*7c478bd9Sstevel@tonic-gate 	}
1323*7c478bd9Sstevel@tonic-gate 	return (0);
1324*7c478bd9Sstevel@tonic-gate }
1325*7c478bd9Sstevel@tonic-gate 
1326*7c478bd9Sstevel@tonic-gate 
1327*7c478bd9Sstevel@tonic-gate /*
1328*7c478bd9Sstevel@tonic-gate  * get and store usba_device pointer in the devi
1329*7c478bd9Sstevel@tonic-gate  */
1330*7c478bd9Sstevel@tonic-gate usba_device_t *
1331*7c478bd9Sstevel@tonic-gate usba_get_usba_device(dev_info_t *dip)
1332*7c478bd9Sstevel@tonic-gate {
1333*7c478bd9Sstevel@tonic-gate 	/*
1334*7c478bd9Sstevel@tonic-gate 	 * we cannot use parent_data in the usb node because its
1335*7c478bd9Sstevel@tonic-gate 	 * bus parent (eg. PCI nexus driver) uses this data
1336*7c478bd9Sstevel@tonic-gate 	 *
1337*7c478bd9Sstevel@tonic-gate 	 * we cannot use driver data in the other usb nodes since
1338*7c478bd9Sstevel@tonic-gate 	 * usb drivers may need to use this
1339*7c478bd9Sstevel@tonic-gate 	 */
1340*7c478bd9Sstevel@tonic-gate 	if (usba_is_root_hub(dip)) {
1341*7c478bd9Sstevel@tonic-gate 		usba_hcdi_t *hcdi = usba_hcdi_get_hcdi(dip);
1342*7c478bd9Sstevel@tonic-gate 
1343*7c478bd9Sstevel@tonic-gate 		return (hcdi->hcdi_usba_device);
1344*7c478bd9Sstevel@tonic-gate 	} else {
1345*7c478bd9Sstevel@tonic-gate 
1346*7c478bd9Sstevel@tonic-gate 		return (ddi_get_parent_data(dip));
1347*7c478bd9Sstevel@tonic-gate 	}
1348*7c478bd9Sstevel@tonic-gate }
1349*7c478bd9Sstevel@tonic-gate 
1350*7c478bd9Sstevel@tonic-gate 
1351*7c478bd9Sstevel@tonic-gate /*
1352*7c478bd9Sstevel@tonic-gate  * Retrieve the usba_device pointer from the dev without checking for
1353*7c478bd9Sstevel@tonic-gate  * the root hub first.	This function is only used in polled mode.
1354*7c478bd9Sstevel@tonic-gate  */
1355*7c478bd9Sstevel@tonic-gate usba_device_t *
1356*7c478bd9Sstevel@tonic-gate usba_polled_get_usba_device(dev_info_t *dip)
1357*7c478bd9Sstevel@tonic-gate {
1358*7c478bd9Sstevel@tonic-gate 	/*
1359*7c478bd9Sstevel@tonic-gate 	 * Don't call usba_is_root_hub() to find out if this is
1360*7c478bd9Sstevel@tonic-gate 	 * the root hub  usba_is_root_hub() calls into the DDI
1361*7c478bd9Sstevel@tonic-gate 	 * where there are locking issues. The dip sent in during
1362*7c478bd9Sstevel@tonic-gate 	 * polled mode will never be the root hub, so just get
1363*7c478bd9Sstevel@tonic-gate 	 * the usba_device pointer from the dip.
1364*7c478bd9Sstevel@tonic-gate 	 */
1365*7c478bd9Sstevel@tonic-gate 	return (ddi_get_parent_data(dip));
1366*7c478bd9Sstevel@tonic-gate }
1367*7c478bd9Sstevel@tonic-gate 
1368*7c478bd9Sstevel@tonic-gate 
1369*7c478bd9Sstevel@tonic-gate void
1370*7c478bd9Sstevel@tonic-gate usba_set_usba_device(dev_info_t *dip, usba_device_t *usba_device)
1371*7c478bd9Sstevel@tonic-gate {
1372*7c478bd9Sstevel@tonic-gate 	if (usba_is_root_hub(dip)) {
1373*7c478bd9Sstevel@tonic-gate 		usba_hcdi_t *hcdi = usba_hcdi_get_hcdi(dip);
1374*7c478bd9Sstevel@tonic-gate 		/* no locking is needed here */
1375*7c478bd9Sstevel@tonic-gate 		_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(hcdi->hcdi_usba_device))
1376*7c478bd9Sstevel@tonic-gate 		hcdi->hcdi_usba_device = usba_device;
1377*7c478bd9Sstevel@tonic-gate 		_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(hcdi->hcdi_usba_device))
1378*7c478bd9Sstevel@tonic-gate 	} else {
1379*7c478bd9Sstevel@tonic-gate 		ddi_set_parent_data(dip, usba_device);
1380*7c478bd9Sstevel@tonic-gate 	}
1381*7c478bd9Sstevel@tonic-gate }
1382*7c478bd9Sstevel@tonic-gate 
1383*7c478bd9Sstevel@tonic-gate 
1384*7c478bd9Sstevel@tonic-gate /*
1385*7c478bd9Sstevel@tonic-gate  * usba_set_node_name() according to class, subclass, and protocol
1386*7c478bd9Sstevel@tonic-gate  * following the 1275 USB binding tables.
1387*7c478bd9Sstevel@tonic-gate  */
1388*7c478bd9Sstevel@tonic-gate 
1389*7c478bd9Sstevel@tonic-gate /* device node table, refer to section 3.2.2.1 of 1275 binding */
1390*7c478bd9Sstevel@tonic-gate static node_name_entry_t device_node_name_table[] = {
1391*7c478bd9Sstevel@tonic-gate { USB_CLASS_COMM,	DONTCARE,	DONTCARE,	"communications" },
1392*7c478bd9Sstevel@tonic-gate { USB_CLASS_HUB,	DONTCARE,	DONTCARE,	"hub" },
1393*7c478bd9Sstevel@tonic-gate { DONTCARE,		DONTCARE,	DONTCARE,	"device" }
1394*7c478bd9Sstevel@tonic-gate };
1395*7c478bd9Sstevel@tonic-gate 
1396*7c478bd9Sstevel@tonic-gate /* interface node table, refer to section 3.3.2.1 */
1397*7c478bd9Sstevel@tonic-gate static node_name_entry_t if_node_name_table[] = {
1398*7c478bd9Sstevel@tonic-gate { USB_CLASS_AUDIO, USB_SUBCLS_AUD_CONTROL, DONTCARE,	"sound-control" },
1399*7c478bd9Sstevel@tonic-gate { USB_CLASS_AUDIO, USB_SUBCLS_AUD_STREAMING, DONTCARE, "sound" },
1400*7c478bd9Sstevel@tonic-gate { USB_CLASS_AUDIO, USB_SUBCLS_AUD_MIDI_STREAMING, DONTCARE, "midi" },
1401*7c478bd9Sstevel@tonic-gate { USB_CLASS_AUDIO, DONTCARE,		DONTCARE,	"sound" },
1402*7c478bd9Sstevel@tonic-gate 
1403*7c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_DIRECT_LINE,	DONTCARE, "line" },
1404*7c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_ABSTRCT_CTRL,	DONTCARE, "modem" },
1405*7c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_PHONE_CTRL, DONTCARE, "telephone" },
1406*7c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_MULTCNL_ISDN, DONTCARE, "isdn" },
1407*7c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_ISDN,		DONTCARE, "isdn" },
1408*7c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_ETHERNET,	DONTCARE, "ethernet" },
1409*7c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_ATM_NETWORK, DONTCARE, "atm-network" },
1410*7c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, DONTCARE,		DONTCARE,	"control" },
1411*7c478bd9Sstevel@tonic-gate 
1412*7c478bd9Sstevel@tonic-gate { USB_CLASS_HID, USB_SUBCLS_HID_1, USB_PROTO_HID_KEYBOARD,	"keyboard" },
1413*7c478bd9Sstevel@tonic-gate { USB_CLASS_HID, USB_SUBCLS_HID_1, USB_PROTO_HID_MOUSE,	"mouse" },
1414*7c478bd9Sstevel@tonic-gate { USB_CLASS_HID,	DONTCARE,	DONTCARE,	"input" },
1415*7c478bd9Sstevel@tonic-gate 
1416*7c478bd9Sstevel@tonic-gate { USB_CLASS_HUB,	DONTCARE,	DONTCARE,	"hub" },
1417*7c478bd9Sstevel@tonic-gate 
1418*7c478bd9Sstevel@tonic-gate { USB_CLASS_PHYSICAL,	DONTCARE,	DONTCARE,	"physical" },
1419*7c478bd9Sstevel@tonic-gate 
1420*7c478bd9Sstevel@tonic-gate { USB_CLASS_PRINTER,	DONTCARE,	DONTCARE,	"printer" },
1421*7c478bd9Sstevel@tonic-gate 
1422*7c478bd9Sstevel@tonic-gate { USB_CLASS_MASS_STORAGE, DONTCARE,	DONTCARE,	"storage" },
1423*7c478bd9Sstevel@tonic-gate 
1424*7c478bd9Sstevel@tonic-gate { USB_CLASS_CDC_DATA,	DONTCARE,	DONTCARE,	"data" },
1425*7c478bd9Sstevel@tonic-gate 
1426*7c478bd9Sstevel@tonic-gate { USB_CLASS_SECURITY,	DONTCARE,	DONTCARE,	"security" },
1427*7c478bd9Sstevel@tonic-gate 
1428*7c478bd9Sstevel@tonic-gate { USB_CLASS_APP,	USB_SUBCLS_APP_FIRMWARE, DONTCARE, "firmware" },
1429*7c478bd9Sstevel@tonic-gate { USB_CLASS_APP,	USB_SUBCLS_APP_IRDA,	DONTCARE, "IrDa" },
1430*7c478bd9Sstevel@tonic-gate { USB_CLASS_APP,	USB_SUBCLS_APP_TEST,	DONTCARE, "test" },
1431*7c478bd9Sstevel@tonic-gate 
1432*7c478bd9Sstevel@tonic-gate { DONTCARE,		DONTCARE,	DONTCARE,	"interface" },
1433*7c478bd9Sstevel@tonic-gate 
1434*7c478bd9Sstevel@tonic-gate };
1435*7c478bd9Sstevel@tonic-gate 
1436*7c478bd9Sstevel@tonic-gate /* combined node table, refer to section 3.4.2.1 */
1437*7c478bd9Sstevel@tonic-gate static node_name_entry_t combined_node_name_table[] = {
1438*7c478bd9Sstevel@tonic-gate { USB_CLASS_AUDIO, USB_SUBCLS_AUD_CONTROL, DONTCARE,	"sound-control" },
1439*7c478bd9Sstevel@tonic-gate { USB_CLASS_AUDIO, USB_SUBCLS_AUD_STREAMING, DONTCARE, "sound" },
1440*7c478bd9Sstevel@tonic-gate { USB_CLASS_AUDIO, USB_SUBCLS_AUD_MIDI_STREAMING, DONTCARE, "midi" },
1441*7c478bd9Sstevel@tonic-gate { USB_CLASS_AUDIO, DONTCARE,		DONTCARE,	"sound" },
1442*7c478bd9Sstevel@tonic-gate 
1443*7c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_DIRECT_LINE,	DONTCARE, "line" },
1444*7c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_ABSTRCT_CTRL,	DONTCARE, "modem" },
1445*7c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_PHONE_CTRL, DONTCARE, "telephone" },
1446*7c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_MULTCNL_ISDN, DONTCARE, "isdn" },
1447*7c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_ISDN,		DONTCARE, "isdn" },
1448*7c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_ETHERNET,	DONTCARE, "ethernet" },
1449*7c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_ATM_NETWORK, DONTCARE, "atm-network" },
1450*7c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, DONTCARE,		DONTCARE,	"control" },
1451*7c478bd9Sstevel@tonic-gate 
1452*7c478bd9Sstevel@tonic-gate { USB_CLASS_HID, USB_SUBCLS_HID_1, USB_PROTO_HID_KEYBOARD, "keyboard" },
1453*7c478bd9Sstevel@tonic-gate { USB_CLASS_HID, USB_SUBCLS_HID_1, USB_PROTO_HID_MOUSE,	"mouse" },
1454*7c478bd9Sstevel@tonic-gate { USB_CLASS_HID,	DONTCARE,	DONTCARE,	"input" },
1455*7c478bd9Sstevel@tonic-gate 
1456*7c478bd9Sstevel@tonic-gate { USB_CLASS_PHYSICAL,	DONTCARE,	DONTCARE,	"physical" },
1457*7c478bd9Sstevel@tonic-gate 
1458*7c478bd9Sstevel@tonic-gate { USB_CLASS_PRINTER,	DONTCARE,	DONTCARE,	"printer" },
1459*7c478bd9Sstevel@tonic-gate 
1460*7c478bd9Sstevel@tonic-gate { USB_CLASS_MASS_STORAGE, DONTCARE,	DONTCARE,	"storage" },
1461*7c478bd9Sstevel@tonic-gate 
1462*7c478bd9Sstevel@tonic-gate { USB_CLASS_CDC_DATA,	DONTCARE,	DONTCARE,	"data" },
1463*7c478bd9Sstevel@tonic-gate 
1464*7c478bd9Sstevel@tonic-gate { USB_CLASS_SECURITY,	DONTCARE,	DONTCARE,	"security" },
1465*7c478bd9Sstevel@tonic-gate 
1466*7c478bd9Sstevel@tonic-gate { USB_CLASS_APP,	USB_SUBCLS_APP_FIRMWARE, DONTCARE, "firmware" },
1467*7c478bd9Sstevel@tonic-gate { USB_CLASS_APP,	USB_SUBCLS_APP_IRDA,	DONTCARE, "IrDa" },
1468*7c478bd9Sstevel@tonic-gate { USB_CLASS_APP,	USB_SUBCLS_APP_TEST,	DONTCARE, "test" },
1469*7c478bd9Sstevel@tonic-gate 
1470*7c478bd9Sstevel@tonic-gate { USB_CLASS_HUB,	DONTCARE,	DONTCARE,	"hub" },
1471*7c478bd9Sstevel@tonic-gate { USB_CLASS_COMM,	DONTCARE,	DONTCARE,	"communications" },
1472*7c478bd9Sstevel@tonic-gate { DONTCARE,		DONTCARE,	DONTCARE,	"device" },
1473*7c478bd9Sstevel@tonic-gate };
1474*7c478bd9Sstevel@tonic-gate 
1475*7c478bd9Sstevel@tonic-gate static size_t device_node_name_table_size =
1476*7c478bd9Sstevel@tonic-gate 	sizeof (device_node_name_table)/sizeof (struct node_name_entry);
1477*7c478bd9Sstevel@tonic-gate static size_t if_node_name_table_size =
1478*7c478bd9Sstevel@tonic-gate 	sizeof (if_node_name_table)/sizeof (struct node_name_entry);
1479*7c478bd9Sstevel@tonic-gate static size_t combined_node_name_table_size =
1480*7c478bd9Sstevel@tonic-gate 	sizeof (combined_node_name_table)/sizeof (struct node_name_entry);
1481*7c478bd9Sstevel@tonic-gate 
1482*7c478bd9Sstevel@tonic-gate 
1483*7c478bd9Sstevel@tonic-gate static void
1484*7c478bd9Sstevel@tonic-gate usba_set_node_name(dev_info_t *dip, uint8_t class, uint8_t subclass,
1485*7c478bd9Sstevel@tonic-gate     uint8_t protocol, uint_t flag)
1486*7c478bd9Sstevel@tonic-gate {
1487*7c478bd9Sstevel@tonic-gate 	int i;
1488*7c478bd9Sstevel@tonic-gate 	size_t size;
1489*7c478bd9Sstevel@tonic-gate 	node_name_entry_t *node_name_table;
1490*7c478bd9Sstevel@tonic-gate 
1491*7c478bd9Sstevel@tonic-gate 	switch (flag) {
1492*7c478bd9Sstevel@tonic-gate 	case FLAG_INTERFACE_NODE:
1493*7c478bd9Sstevel@tonic-gate 		node_name_table = if_node_name_table;
1494*7c478bd9Sstevel@tonic-gate 		size = if_node_name_table_size;
1495*7c478bd9Sstevel@tonic-gate 		break;
1496*7c478bd9Sstevel@tonic-gate 	case FLAG_DEVICE_NODE:
1497*7c478bd9Sstevel@tonic-gate 		node_name_table = device_node_name_table;
1498*7c478bd9Sstevel@tonic-gate 		size = device_node_name_table_size;
1499*7c478bd9Sstevel@tonic-gate 		break;
1500*7c478bd9Sstevel@tonic-gate 	case FLAG_COMBINED_NODE:
1501*7c478bd9Sstevel@tonic-gate 		node_name_table = combined_node_name_table;
1502*7c478bd9Sstevel@tonic-gate 		size = combined_node_name_table_size;
1503*7c478bd9Sstevel@tonic-gate 		break;
1504*7c478bd9Sstevel@tonic-gate 	default:
1505*7c478bd9Sstevel@tonic-gate 
1506*7c478bd9Sstevel@tonic-gate 		return;
1507*7c478bd9Sstevel@tonic-gate 	}
1508*7c478bd9Sstevel@tonic-gate 
1509*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < size; i++) {
1510*7c478bd9Sstevel@tonic-gate 		int16_t c = node_name_table[i].class;
1511*7c478bd9Sstevel@tonic-gate 		int16_t s = node_name_table[i].subclass;
1512*7c478bd9Sstevel@tonic-gate 		int16_t p = node_name_table[i].protocol;
1513*7c478bd9Sstevel@tonic-gate 
1514*7c478bd9Sstevel@tonic-gate 		if (((c == DONTCARE) || (c == class)) &&
1515*7c478bd9Sstevel@tonic-gate 		    ((s == DONTCARE) || (s == subclass)) &&
1516*7c478bd9Sstevel@tonic-gate 		    ((p == DONTCARE) || (p == protocol))) {
1517*7c478bd9Sstevel@tonic-gate 			char *name = node_name_table[i].name;
1518*7c478bd9Sstevel@tonic-gate 			(void) ndi_devi_set_nodename(dip, name, 0);
1519*7c478bd9Sstevel@tonic-gate 			break;
1520*7c478bd9Sstevel@tonic-gate 		}
1521*7c478bd9Sstevel@tonic-gate 	}
1522*7c478bd9Sstevel@tonic-gate }
1523*7c478bd9Sstevel@tonic-gate 
1524*7c478bd9Sstevel@tonic-gate 
1525*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1526*7c478bd9Sstevel@tonic-gate /*
1527*7c478bd9Sstevel@tonic-gate  * walk the children of the parent of this devi and compare the
1528*7c478bd9Sstevel@tonic-gate  * name and  reg property of each child. If there is a match
1529*7c478bd9Sstevel@tonic-gate  * return this node
1530*7c478bd9Sstevel@tonic-gate  */
1531*7c478bd9Sstevel@tonic-gate static dev_info_t *
1532*7c478bd9Sstevel@tonic-gate usba_find_existing_node(dev_info_t *odip)
1533*7c478bd9Sstevel@tonic-gate {
1534*7c478bd9Sstevel@tonic-gate 	dev_info_t *ndip, *child, *pdip;
1535*7c478bd9Sstevel@tonic-gate 	int	*odata, *ndata;
1536*7c478bd9Sstevel@tonic-gate 	uint_t	n_odata, n_ndata;
1537*7c478bd9Sstevel@tonic-gate 	int	circular;
1538*7c478bd9Sstevel@tonic-gate 
1539*7c478bd9Sstevel@tonic-gate 	pdip = ddi_get_parent(odip);
1540*7c478bd9Sstevel@tonic-gate 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY,
1541*7c478bd9Sstevel@tonic-gate 	    odip, DDI_PROP_DONTPASS, "reg",
1542*7c478bd9Sstevel@tonic-gate 	    &odata, &n_odata) != DDI_SUCCESS) {
1543*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_HCDI, usba_log_handle,
1544*7c478bd9Sstevel@tonic-gate 		    "usba_find_existing_node: "
1545*7c478bd9Sstevel@tonic-gate 		    "%s: DDI_NOT_WELL_FORMED", ddi_driver_name(odip));
1546*7c478bd9Sstevel@tonic-gate 
1547*7c478bd9Sstevel@tonic-gate 		return (NULL);
1548*7c478bd9Sstevel@tonic-gate 	}
1549*7c478bd9Sstevel@tonic-gate 
1550*7c478bd9Sstevel@tonic-gate 	ndi_devi_enter(pdip, &circular);
1551*7c478bd9Sstevel@tonic-gate 	ndip = (dev_info_t *)(DEVI(pdip)->devi_child);
1552*7c478bd9Sstevel@tonic-gate 	while ((child = ndip) != NULL) {
1553*7c478bd9Sstevel@tonic-gate 
1554*7c478bd9Sstevel@tonic-gate 		ndip = (dev_info_t *)(DEVI(child)->devi_sibling);
1555*7c478bd9Sstevel@tonic-gate 
1556*7c478bd9Sstevel@tonic-gate 		if (child == odip) {
1557*7c478bd9Sstevel@tonic-gate 			continue;
1558*7c478bd9Sstevel@tonic-gate 		}
1559*7c478bd9Sstevel@tonic-gate 
1560*7c478bd9Sstevel@tonic-gate 		if (strcmp(DEVI(child)->devi_node_name,
1561*7c478bd9Sstevel@tonic-gate 		    DEVI(odip)->devi_node_name)) {
1562*7c478bd9Sstevel@tonic-gate 			continue;
1563*7c478bd9Sstevel@tonic-gate 		}
1564*7c478bd9Sstevel@tonic-gate 
1565*7c478bd9Sstevel@tonic-gate 		if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY,
1566*7c478bd9Sstevel@tonic-gate 		    child, DDI_PROP_DONTPASS, "reg",
1567*7c478bd9Sstevel@tonic-gate 		    &ndata, &n_ndata) != DDI_SUCCESS) {
1568*7c478bd9Sstevel@tonic-gate 
1569*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_HCDI, usba_log_handle,
1570*7c478bd9Sstevel@tonic-gate 			    "usba_find_existing_node: "
1571*7c478bd9Sstevel@tonic-gate 			    "%s DDI_NOT_WELL_FORMED", ddi_driver_name(child));
1572*7c478bd9Sstevel@tonic-gate 
1573*7c478bd9Sstevel@tonic-gate 		} else if (n_ndata && n_odata && (bcmp(odata, ndata,
1574*7c478bd9Sstevel@tonic-gate 		    max(n_odata, n_ndata) * sizeof (int)) == 0)) {
1575*7c478bd9Sstevel@tonic-gate 
1576*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L3(DPRINT_MASK_HCDI, usba_log_handle,
1577*7c478bd9Sstevel@tonic-gate 			    "usba_find_existing_node: found %s%d (%p)",
1578*7c478bd9Sstevel@tonic-gate 			    ddi_driver_name(child),
1579*7c478bd9Sstevel@tonic-gate 			    ddi_get_instance(child), (void *)child);
1580*7c478bd9Sstevel@tonic-gate 
1581*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L3(DPRINT_MASK_HCDI, usba_log_handle,
1582*7c478bd9Sstevel@tonic-gate 			    "usba_find_existing_node: "
1583*7c478bd9Sstevel@tonic-gate 			    "reg: %x %x %x - %x %x %x",
1584*7c478bd9Sstevel@tonic-gate 			    n_odata, odata[0], odata[1],
1585*7c478bd9Sstevel@tonic-gate 			    n_ndata, ndata[0], ndata[1]);
1586*7c478bd9Sstevel@tonic-gate 
1587*7c478bd9Sstevel@tonic-gate 			ddi_prop_free(ndata);
1588*7c478bd9Sstevel@tonic-gate 			break;
1589*7c478bd9Sstevel@tonic-gate 
1590*7c478bd9Sstevel@tonic-gate 		} else {
1591*7c478bd9Sstevel@tonic-gate 			ddi_prop_free(ndata);
1592*7c478bd9Sstevel@tonic-gate 		}
1593*7c478bd9Sstevel@tonic-gate 	}
1594*7c478bd9Sstevel@tonic-gate 
1595*7c478bd9Sstevel@tonic-gate 	ndi_devi_exit(pdip, circular);
1596*7c478bd9Sstevel@tonic-gate 
1597*7c478bd9Sstevel@tonic-gate 	ddi_prop_free(odata);
1598*7c478bd9Sstevel@tonic-gate 
1599*7c478bd9Sstevel@tonic-gate 	return (child);
1600*7c478bd9Sstevel@tonic-gate }
1601*7c478bd9Sstevel@tonic-gate #endif
1602*7c478bd9Sstevel@tonic-gate 
1603*7c478bd9Sstevel@tonic-gate /* change all unprintable characters to spaces */
1604*7c478bd9Sstevel@tonic-gate static void
1605*7c478bd9Sstevel@tonic-gate usba_filter_string(char *instr, char *outstr)
1606*7c478bd9Sstevel@tonic-gate {
1607*7c478bd9Sstevel@tonic-gate 	while (*instr) {
1608*7c478bd9Sstevel@tonic-gate 		if ((*instr >= ' ') && (*instr <= '~')) {
1609*7c478bd9Sstevel@tonic-gate 			*outstr = *instr;
1610*7c478bd9Sstevel@tonic-gate 		} else {
1611*7c478bd9Sstevel@tonic-gate 			*outstr = ' ';
1612*7c478bd9Sstevel@tonic-gate 		}
1613*7c478bd9Sstevel@tonic-gate 		outstr++;
1614*7c478bd9Sstevel@tonic-gate 		instr++;
1615*7c478bd9Sstevel@tonic-gate 	}
1616*7c478bd9Sstevel@tonic-gate 	*outstr = '\0';
1617*7c478bd9Sstevel@tonic-gate }
1618*7c478bd9Sstevel@tonic-gate 
1619*7c478bd9Sstevel@tonic-gate 
1620*7c478bd9Sstevel@tonic-gate /*
1621*7c478bd9Sstevel@tonic-gate  * lookup ugen binding specified in property in
1622*7c478bd9Sstevel@tonic-gate  * hcd.conf files
1623*7c478bd9Sstevel@tonic-gate  */
1624*7c478bd9Sstevel@tonic-gate int
1625*7c478bd9Sstevel@tonic-gate usba_get_ugen_binding(dev_info_t *dip)
1626*7c478bd9Sstevel@tonic-gate {
1627*7c478bd9Sstevel@tonic-gate 	usba_device_t	*usba_device = usba_get_usba_device(dip);
1628*7c478bd9Sstevel@tonic-gate 	usba_hcdi_t	*hcdi =
1629*7c478bd9Sstevel@tonic-gate 			    usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
1630*7c478bd9Sstevel@tonic-gate 
1631*7c478bd9Sstevel@tonic-gate 	return (hcdi->hcdi_ugen_default_binding);
1632*7c478bd9Sstevel@tonic-gate }
1633*7c478bd9Sstevel@tonic-gate 
1634*7c478bd9Sstevel@tonic-gate 
1635*7c478bd9Sstevel@tonic-gate /*
1636*7c478bd9Sstevel@tonic-gate  * driver binding support at device level
1637*7c478bd9Sstevel@tonic-gate  */
1638*7c478bd9Sstevel@tonic-gate dev_info_t *
1639*7c478bd9Sstevel@tonic-gate usba_ready_device_node(dev_info_t *child_dip)
1640*7c478bd9Sstevel@tonic-gate {
1641*7c478bd9Sstevel@tonic-gate 	int		rval, i;
1642*7c478bd9Sstevel@tonic-gate 	int		n = 0;
1643*7c478bd9Sstevel@tonic-gate 	usba_device_t	*usba_device = usba_get_usba_device(child_dip);
1644*7c478bd9Sstevel@tonic-gate 	usb_dev_descr_t	*usb_dev_descr;
1645*7c478bd9Sstevel@tonic-gate 	uint_t		n_cfgs;	/* number of configs */
1646*7c478bd9Sstevel@tonic-gate 	uint_t		n_ifs;	/* number of interfaces */
1647*7c478bd9Sstevel@tonic-gate 	uint_t		port;
1648*7c478bd9Sstevel@tonic-gate 	size_t		usb_config_length;
1649*7c478bd9Sstevel@tonic-gate 	uchar_t 	*usb_config;
1650*7c478bd9Sstevel@tonic-gate 	int		reg[1];
1651*7c478bd9Sstevel@tonic-gate 	usb_addr_t	address = usb_get_addr(child_dip);
1652*7c478bd9Sstevel@tonic-gate 	usb_if_descr_t	if_descr;
1653*7c478bd9Sstevel@tonic-gate 	size_t		size;
1654*7c478bd9Sstevel@tonic-gate 	int		combined_node = 0;
1655*7c478bd9Sstevel@tonic-gate 	int		is_hub;
1656*7c478bd9Sstevel@tonic-gate 	char		*devprop_str;
1657*7c478bd9Sstevel@tonic-gate 	char		*force_bind = NULL;
1658*7c478bd9Sstevel@tonic-gate 
1659*7c478bd9Sstevel@tonic-gate 	usb_config = usb_get_raw_cfg_data(child_dip, &usb_config_length);
1660*7c478bd9Sstevel@tonic-gate 
1661*7c478bd9Sstevel@tonic-gate 	mutex_enter(&usba_device->usb_mutex);
1662*7c478bd9Sstevel@tonic-gate 	mutex_enter(&usba_mutex);
1663*7c478bd9Sstevel@tonic-gate 
1664*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
1665*7c478bd9Sstevel@tonic-gate 	    "usba_ready_device_node: child=0x%p", (void *)child_dip);
1666*7c478bd9Sstevel@tonic-gate 
1667*7c478bd9Sstevel@tonic-gate 	port = usba_device->usb_port;
1668*7c478bd9Sstevel@tonic-gate 	usb_dev_descr = usba_device->usb_dev_descr;
1669*7c478bd9Sstevel@tonic-gate 	n_cfgs = usba_device->usb_n_cfgs;
1670*7c478bd9Sstevel@tonic-gate 	n_ifs = usba_device->usb_n_ifs;
1671*7c478bd9Sstevel@tonic-gate 
1672*7c478bd9Sstevel@tonic-gate 
1673*7c478bd9Sstevel@tonic-gate 	if (address != ROOT_HUB_ADDR) {
1674*7c478bd9Sstevel@tonic-gate 		size = usb_parse_if_descr(
1675*7c478bd9Sstevel@tonic-gate 				usb_config,
1676*7c478bd9Sstevel@tonic-gate 				usb_config_length,
1677*7c478bd9Sstevel@tonic-gate 				0,		/* interface index */
1678*7c478bd9Sstevel@tonic-gate 				0,		/* alt interface index */
1679*7c478bd9Sstevel@tonic-gate 				&if_descr,
1680*7c478bd9Sstevel@tonic-gate 				USB_IF_DESCR_SIZE);
1681*7c478bd9Sstevel@tonic-gate 
1682*7c478bd9Sstevel@tonic-gate 		if (size != USB_IF_DESCR_SIZE) {
1683*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_USBA, usba_log_handle,
1684*7c478bd9Sstevel@tonic-gate 			    "parsing interface: "
1685*7c478bd9Sstevel@tonic-gate 			    "size (%lu) != USB_IF_DESCR_SIZE (%d)",
1686*7c478bd9Sstevel@tonic-gate 			    size, USB_IF_DESCR_SIZE);
1687*7c478bd9Sstevel@tonic-gate 
1688*7c478bd9Sstevel@tonic-gate 			mutex_exit(&usba_mutex);
1689*7c478bd9Sstevel@tonic-gate 			mutex_exit(&usba_device->usb_mutex);
1690*7c478bd9Sstevel@tonic-gate 
1691*7c478bd9Sstevel@tonic-gate 			return (child_dip);
1692*7c478bd9Sstevel@tonic-gate 		}
1693*7c478bd9Sstevel@tonic-gate 	} else {
1694*7c478bd9Sstevel@tonic-gate 		/* fake an interface descriptor for the root hub */
1695*7c478bd9Sstevel@tonic-gate 		bzero(&if_descr, sizeof (if_descr));
1696*7c478bd9Sstevel@tonic-gate 
1697*7c478bd9Sstevel@tonic-gate 		if_descr.bInterfaceClass = USB_CLASS_HUB;
1698*7c478bd9Sstevel@tonic-gate 	}
1699*7c478bd9Sstevel@tonic-gate 
1700*7c478bd9Sstevel@tonic-gate 	reg[0] = port;
1701*7c478bd9Sstevel@tonic-gate 
1702*7c478bd9Sstevel@tonic-gate 	mutex_exit(&usba_mutex);
1703*7c478bd9Sstevel@tonic-gate 	mutex_exit(&usba_device->usb_mutex);
1704*7c478bd9Sstevel@tonic-gate 
1705*7c478bd9Sstevel@tonic-gate 	rval = ndi_prop_update_int_array(
1706*7c478bd9Sstevel@tonic-gate 		DDI_DEV_T_NONE, child_dip, "reg", reg, 1);
1707*7c478bd9Sstevel@tonic-gate 
1708*7c478bd9Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
1709*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_USBA, usba_log_handle,
1710*7c478bd9Sstevel@tonic-gate 		    "usba_ready_device_node: property update failed");
1711*7c478bd9Sstevel@tonic-gate 
1712*7c478bd9Sstevel@tonic-gate 		return (child_dip);
1713*7c478bd9Sstevel@tonic-gate 	}
1714*7c478bd9Sstevel@tonic-gate 
1715*7c478bd9Sstevel@tonic-gate 	combined_node = ((n_cfgs == 1) && (n_ifs == 1) &&
1716*7c478bd9Sstevel@tonic-gate 	    ((usb_dev_descr->bDeviceClass == USB_CLASS_HUB) ||
1717*7c478bd9Sstevel@tonic-gate 	    (usb_dev_descr->bDeviceClass == 0)));
1718*7c478bd9Sstevel@tonic-gate 
1719*7c478bd9Sstevel@tonic-gate 	is_hub = (if_descr.bInterfaceClass == USB_CLASS_HUB) ||
1720*7c478bd9Sstevel@tonic-gate 		(usb_dev_descr->bDeviceClass == USB_CLASS_HUB);
1721*7c478bd9Sstevel@tonic-gate 
1722*7c478bd9Sstevel@tonic-gate 	/* set node name */
1723*7c478bd9Sstevel@tonic-gate 	if (combined_node) {
1724*7c478bd9Sstevel@tonic-gate 		usba_set_node_name(child_dip,
1725*7c478bd9Sstevel@tonic-gate 		    if_descr.bInterfaceClass,
1726*7c478bd9Sstevel@tonic-gate 		    if_descr.bInterfaceSubClass,
1727*7c478bd9Sstevel@tonic-gate 		    if_descr.bInterfaceProtocol,
1728*7c478bd9Sstevel@tonic-gate 		    FLAG_COMBINED_NODE);
1729*7c478bd9Sstevel@tonic-gate 	} else {
1730*7c478bd9Sstevel@tonic-gate 		usba_set_node_name(child_dip,
1731*7c478bd9Sstevel@tonic-gate 		    usb_dev_descr->bDeviceClass,
1732*7c478bd9Sstevel@tonic-gate 		    usb_dev_descr->bDeviceSubClass,
1733*7c478bd9Sstevel@tonic-gate 		    usb_dev_descr->bDeviceProtocol,
1734*7c478bd9Sstevel@tonic-gate 		    FLAG_DEVICE_NODE);
1735*7c478bd9Sstevel@tonic-gate 	}
1736*7c478bd9Sstevel@tonic-gate 
1737*7c478bd9Sstevel@tonic-gate 	/*
1738*7c478bd9Sstevel@tonic-gate 	 * check force binding rules
1739*7c478bd9Sstevel@tonic-gate 	 */
1740*7c478bd9Sstevel@tonic-gate 	if ((address != ROOT_HUB_ADDR) && usba_ddivs_usbc &&
1741*7c478bd9Sstevel@tonic-gate 	    (address != usba_ddivs_usbc_xaddress) &&
1742*7c478bd9Sstevel@tonic-gate 	    (!(usba_ddivs_usbc_xhubs && is_hub))) {
1743*7c478bd9Sstevel@tonic-gate 		force_bind = "ddivs_usbc";
1744*7c478bd9Sstevel@tonic-gate 		(void) ndi_devi_set_nodename(child_dip, "ddivs_usbc", 0);
1745*7c478bd9Sstevel@tonic-gate 
1746*7c478bd9Sstevel@tonic-gate 	} else if (usba_device->usb_preferred_driver) {
1747*7c478bd9Sstevel@tonic-gate 		force_bind = usba_device->usb_preferred_driver;
1748*7c478bd9Sstevel@tonic-gate 
1749*7c478bd9Sstevel@tonic-gate 	} else if ((address != ROOT_HUB_ADDR) &&
1750*7c478bd9Sstevel@tonic-gate 	    ((usba_ugen_force_binding == USBA_UGEN_DEVICE_BINDING) ||
1751*7c478bd9Sstevel@tonic-gate 	    ((usba_ugen_force_binding == USBA_UGEN_INTERFACE_BINDING) &&
1752*7c478bd9Sstevel@tonic-gate 	    combined_node)) && (!is_hub)) {
1753*7c478bd9Sstevel@tonic-gate 		force_bind = "ugen";
1754*7c478bd9Sstevel@tonic-gate 	}
1755*7c478bd9Sstevel@tonic-gate 
1756*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1757*7c478bd9Sstevel@tonic-gate 	/*
1758*7c478bd9Sstevel@tonic-gate 	 * check whether there is another dip with this name and address
1759*7c478bd9Sstevel@tonic-gate 	 * If the dip contains usba_device, it is held by the previous
1760*7c478bd9Sstevel@tonic-gate 	 * round of configuration.
1761*7c478bd9Sstevel@tonic-gate 	 */
1762*7c478bd9Sstevel@tonic-gate 	ASSERT(usba_find_existing_node(child_dip) == NULL);
1763*7c478bd9Sstevel@tonic-gate #endif
1764*7c478bd9Sstevel@tonic-gate 	mutex_enter(&usba_mutex);
1765*7c478bd9Sstevel@tonic-gate 
1766*7c478bd9Sstevel@tonic-gate 	if (force_bind) {
1767*7c478bd9Sstevel@tonic-gate 		(void) ndi_devi_set_nodename(child_dip, force_bind, 0);
1768*7c478bd9Sstevel@tonic-gate 		(void) strncpy(usba_name[n++], force_bind,
1769*7c478bd9Sstevel@tonic-gate 						USBA_MAX_COMPAT_NAME_LEN);
1770*7c478bd9Sstevel@tonic-gate 	}
1771*7c478bd9Sstevel@tonic-gate 
1772*7c478bd9Sstevel@tonic-gate 	/* create compatible names */
1773*7c478bd9Sstevel@tonic-gate 	if (combined_node) {
1774*7c478bd9Sstevel@tonic-gate 
1775*7c478bd9Sstevel@tonic-gate 		/* 1. usbVID,PID.REV */
1776*7c478bd9Sstevel@tonic-gate 		(void) sprintf(usba_name[n++],
1777*7c478bd9Sstevel@tonic-gate 			"usb%x,%x.%x",
1778*7c478bd9Sstevel@tonic-gate 			usb_dev_descr->idVendor,
1779*7c478bd9Sstevel@tonic-gate 			usb_dev_descr->idProduct,
1780*7c478bd9Sstevel@tonic-gate 			usb_dev_descr->bcdDevice);
1781*7c478bd9Sstevel@tonic-gate 
1782*7c478bd9Sstevel@tonic-gate 		/* 2. usbVID,PID */
1783*7c478bd9Sstevel@tonic-gate 		(void) sprintf(usba_name[n++],
1784*7c478bd9Sstevel@tonic-gate 			"usb%x,%x",
1785*7c478bd9Sstevel@tonic-gate 			usb_dev_descr->idVendor,
1786*7c478bd9Sstevel@tonic-gate 			usb_dev_descr->idProduct);
1787*7c478bd9Sstevel@tonic-gate 
1788*7c478bd9Sstevel@tonic-gate 		if (usb_dev_descr->bDeviceClass != 0) {
1789*7c478bd9Sstevel@tonic-gate 			/* 3. usbVID,classDC.DSC.DPROTO */
1790*7c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
1791*7c478bd9Sstevel@tonic-gate 				"usb%x,class%x.%x.%x",
1792*7c478bd9Sstevel@tonic-gate 				usb_dev_descr->idVendor,
1793*7c478bd9Sstevel@tonic-gate 				usb_dev_descr->bDeviceClass,
1794*7c478bd9Sstevel@tonic-gate 				usb_dev_descr->bDeviceSubClass,
1795*7c478bd9Sstevel@tonic-gate 				usb_dev_descr->bDeviceProtocol);
1796*7c478bd9Sstevel@tonic-gate 
1797*7c478bd9Sstevel@tonic-gate 			/* 4. usbVID,classDC.DSC */
1798*7c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
1799*7c478bd9Sstevel@tonic-gate 				"usb%x,class%x.%x",
1800*7c478bd9Sstevel@tonic-gate 				usb_dev_descr->idVendor,
1801*7c478bd9Sstevel@tonic-gate 				usb_dev_descr->bDeviceClass,
1802*7c478bd9Sstevel@tonic-gate 				usb_dev_descr->bDeviceSubClass);
1803*7c478bd9Sstevel@tonic-gate 
1804*7c478bd9Sstevel@tonic-gate 			/* 5. usbVID,classDC */
1805*7c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
1806*7c478bd9Sstevel@tonic-gate 				"usb%x,class%x",
1807*7c478bd9Sstevel@tonic-gate 				usb_dev_descr->idVendor,
1808*7c478bd9Sstevel@tonic-gate 				usb_dev_descr->bDeviceClass);
1809*7c478bd9Sstevel@tonic-gate 
1810*7c478bd9Sstevel@tonic-gate 			/* 6. usb,classDC.DSC.DPROTO */
1811*7c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
1812*7c478bd9Sstevel@tonic-gate 				"usb,class%x.%x.%x",
1813*7c478bd9Sstevel@tonic-gate 				usb_dev_descr->bDeviceClass,
1814*7c478bd9Sstevel@tonic-gate 				usb_dev_descr->bDeviceSubClass,
1815*7c478bd9Sstevel@tonic-gate 				usb_dev_descr->bDeviceProtocol);
1816*7c478bd9Sstevel@tonic-gate 
1817*7c478bd9Sstevel@tonic-gate 			/* 7. usb,classDC.DSC */
1818*7c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
1819*7c478bd9Sstevel@tonic-gate 				"usb,class%x.%x",
1820*7c478bd9Sstevel@tonic-gate 				usb_dev_descr->bDeviceClass,
1821*7c478bd9Sstevel@tonic-gate 				usb_dev_descr->bDeviceSubClass);
1822*7c478bd9Sstevel@tonic-gate 
1823*7c478bd9Sstevel@tonic-gate 			/* 8. usb,classDC */
1824*7c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
1825*7c478bd9Sstevel@tonic-gate 				"usb,class%x",
1826*7c478bd9Sstevel@tonic-gate 				usb_dev_descr->bDeviceClass);
1827*7c478bd9Sstevel@tonic-gate 		}
1828*7c478bd9Sstevel@tonic-gate 
1829*7c478bd9Sstevel@tonic-gate 		if (if_descr.bInterfaceClass != 0) {
1830*7c478bd9Sstevel@tonic-gate 			/* 9. usbifVID,classIC.ISC.IPROTO */
1831*7c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
1832*7c478bd9Sstevel@tonic-gate 				"usbif%x,class%x.%x.%x",
1833*7c478bd9Sstevel@tonic-gate 				usb_dev_descr->idVendor,
1834*7c478bd9Sstevel@tonic-gate 				if_descr.bInterfaceClass,
1835*7c478bd9Sstevel@tonic-gate 				if_descr.bInterfaceSubClass,
1836*7c478bd9Sstevel@tonic-gate 				if_descr.bInterfaceProtocol);
1837*7c478bd9Sstevel@tonic-gate 
1838*7c478bd9Sstevel@tonic-gate 			/* 10. usbifVID,classIC.ISC */
1839*7c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
1840*7c478bd9Sstevel@tonic-gate 				"usbif%x,class%x.%x",
1841*7c478bd9Sstevel@tonic-gate 				usb_dev_descr->idVendor,
1842*7c478bd9Sstevel@tonic-gate 				if_descr.bInterfaceClass,
1843*7c478bd9Sstevel@tonic-gate 				if_descr.bInterfaceSubClass);
1844*7c478bd9Sstevel@tonic-gate 
1845*7c478bd9Sstevel@tonic-gate 			/* 11. usbifVID,classIC */
1846*7c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
1847*7c478bd9Sstevel@tonic-gate 				"usbif%x,class%x",
1848*7c478bd9Sstevel@tonic-gate 				usb_dev_descr->idVendor,
1849*7c478bd9Sstevel@tonic-gate 				if_descr.bInterfaceClass);
1850*7c478bd9Sstevel@tonic-gate 
1851*7c478bd9Sstevel@tonic-gate 			/* 12. usbif,classIC.ISC.IPROTO */
1852*7c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
1853*7c478bd9Sstevel@tonic-gate 				"usbif,class%x.%x.%x",
1854*7c478bd9Sstevel@tonic-gate 				if_descr.bInterfaceClass,
1855*7c478bd9Sstevel@tonic-gate 				if_descr.bInterfaceSubClass,
1856*7c478bd9Sstevel@tonic-gate 				if_descr.bInterfaceProtocol);
1857*7c478bd9Sstevel@tonic-gate 
1858*7c478bd9Sstevel@tonic-gate 			/* 13. usbif,classIC.ISC */
1859*7c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
1860*7c478bd9Sstevel@tonic-gate 				"usbif,class%x.%x",
1861*7c478bd9Sstevel@tonic-gate 				if_descr.bInterfaceClass,
1862*7c478bd9Sstevel@tonic-gate 				if_descr.bInterfaceSubClass);
1863*7c478bd9Sstevel@tonic-gate 
1864*7c478bd9Sstevel@tonic-gate 			/* 14. usbif,classIC */
1865*7c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
1866*7c478bd9Sstevel@tonic-gate 				"usbif,class%x",
1867*7c478bd9Sstevel@tonic-gate 				if_descr.bInterfaceClass);
1868*7c478bd9Sstevel@tonic-gate 		}
1869*7c478bd9Sstevel@tonic-gate 
1870*7c478bd9Sstevel@tonic-gate 		/* 15. ugen or usb_mid */
1871*7c478bd9Sstevel@tonic-gate 		if (usba_get_ugen_binding(child_dip) ==
1872*7c478bd9Sstevel@tonic-gate 		    USBA_UGEN_DEVICE_BINDING) {
1873*7c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++], "ugen");
1874*7c478bd9Sstevel@tonic-gate 		} else {
1875*7c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++], "usb,device");
1876*7c478bd9Sstevel@tonic-gate 		}
1877*7c478bd9Sstevel@tonic-gate 
1878*7c478bd9Sstevel@tonic-gate 	} else {
1879*7c478bd9Sstevel@tonic-gate 		if (n_cfgs > 1) {
1880*7c478bd9Sstevel@tonic-gate 			/* 1. usbVID,PID.REV.configCN */
1881*7c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
1882*7c478bd9Sstevel@tonic-gate 				"usb%x,%x.%x.config%x",
1883*7c478bd9Sstevel@tonic-gate 				usb_dev_descr->idVendor,
1884*7c478bd9Sstevel@tonic-gate 				usb_dev_descr->idProduct,
1885*7c478bd9Sstevel@tonic-gate 				usb_dev_descr->bcdDevice,
1886*7c478bd9Sstevel@tonic-gate 				usba_device->usb_cfg_value);
1887*7c478bd9Sstevel@tonic-gate 		}
1888*7c478bd9Sstevel@tonic-gate 
1889*7c478bd9Sstevel@tonic-gate 		/* 2. usbVID,PID.REV */
1890*7c478bd9Sstevel@tonic-gate 		(void) sprintf(usba_name[n++],
1891*7c478bd9Sstevel@tonic-gate 			"usb%x,%x.%x",
1892*7c478bd9Sstevel@tonic-gate 			usb_dev_descr->idVendor,
1893*7c478bd9Sstevel@tonic-gate 			usb_dev_descr->idProduct,
1894*7c478bd9Sstevel@tonic-gate 			usb_dev_descr->bcdDevice);
1895*7c478bd9Sstevel@tonic-gate 
1896*7c478bd9Sstevel@tonic-gate 		/* 3. usbVID,PID.configCN */
1897*7c478bd9Sstevel@tonic-gate 		if (n_cfgs > 1) {
1898*7c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
1899*7c478bd9Sstevel@tonic-gate 				"usb%x,%x.%x",
1900*7c478bd9Sstevel@tonic-gate 				usb_dev_descr->idVendor,
1901*7c478bd9Sstevel@tonic-gate 				usb_dev_descr->idProduct,
1902*7c478bd9Sstevel@tonic-gate 				usba_device->usb_cfg_value);
1903*7c478bd9Sstevel@tonic-gate 		}
1904*7c478bd9Sstevel@tonic-gate 
1905*7c478bd9Sstevel@tonic-gate 		/* 4. usbVID,PID */
1906*7c478bd9Sstevel@tonic-gate 		(void) sprintf(usba_name[n++],
1907*7c478bd9Sstevel@tonic-gate 			"usb%x,%x",
1908*7c478bd9Sstevel@tonic-gate 			usb_dev_descr->idVendor,
1909*7c478bd9Sstevel@tonic-gate 			usb_dev_descr->idProduct);
1910*7c478bd9Sstevel@tonic-gate 
1911*7c478bd9Sstevel@tonic-gate 		if (usb_dev_descr->bDeviceClass != 0) {
1912*7c478bd9Sstevel@tonic-gate 			/* 5. usbVID,classDC.DSC.DPROTO */
1913*7c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
1914*7c478bd9Sstevel@tonic-gate 				"usb%x,class%x.%x.%x",
1915*7c478bd9Sstevel@tonic-gate 				usb_dev_descr->idVendor,
1916*7c478bd9Sstevel@tonic-gate 				usb_dev_descr->bDeviceClass,
1917*7c478bd9Sstevel@tonic-gate 				usb_dev_descr->bDeviceSubClass,
1918*7c478bd9Sstevel@tonic-gate 				usb_dev_descr->bDeviceProtocol);
1919*7c478bd9Sstevel@tonic-gate 
1920*7c478bd9Sstevel@tonic-gate 			/* 6. usbVID,classDC.DSC */
1921*7c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
1922*7c478bd9Sstevel@tonic-gate 				"usb%x.class%x.%x",
1923*7c478bd9Sstevel@tonic-gate 				usb_dev_descr->idVendor,
1924*7c478bd9Sstevel@tonic-gate 				usb_dev_descr->bDeviceClass,
1925*7c478bd9Sstevel@tonic-gate 				usb_dev_descr->bDeviceSubClass);
1926*7c478bd9Sstevel@tonic-gate 
1927*7c478bd9Sstevel@tonic-gate 			/* 7. usbVID,classDC */
1928*7c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
1929*7c478bd9Sstevel@tonic-gate 				"usb%x.class%x",
1930*7c478bd9Sstevel@tonic-gate 				usb_dev_descr->idVendor,
1931*7c478bd9Sstevel@tonic-gate 				usb_dev_descr->bDeviceClass);
1932*7c478bd9Sstevel@tonic-gate 
1933*7c478bd9Sstevel@tonic-gate 			/* 8. usb,classDC.DSC.DPROTO */
1934*7c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
1935*7c478bd9Sstevel@tonic-gate 				"usb,class%x.%x.%x",
1936*7c478bd9Sstevel@tonic-gate 				usb_dev_descr->bDeviceClass,
1937*7c478bd9Sstevel@tonic-gate 				usb_dev_descr->bDeviceSubClass,
1938*7c478bd9Sstevel@tonic-gate 				usb_dev_descr->bDeviceProtocol);
1939*7c478bd9Sstevel@tonic-gate 
1940*7c478bd9Sstevel@tonic-gate 			/* 9. usb,classDC.DSC */
1941*7c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
1942*7c478bd9Sstevel@tonic-gate 				"usb,class%x.%x",
1943*7c478bd9Sstevel@tonic-gate 				usb_dev_descr->bDeviceClass,
1944*7c478bd9Sstevel@tonic-gate 				usb_dev_descr->bDeviceSubClass);
1945*7c478bd9Sstevel@tonic-gate 
1946*7c478bd9Sstevel@tonic-gate 			/* 10. usb,classDC */
1947*7c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
1948*7c478bd9Sstevel@tonic-gate 				"usb,class%x",
1949*7c478bd9Sstevel@tonic-gate 				usb_dev_descr->bDeviceClass);
1950*7c478bd9Sstevel@tonic-gate 		}
1951*7c478bd9Sstevel@tonic-gate 
1952*7c478bd9Sstevel@tonic-gate 		if (usba_get_ugen_binding(child_dip) ==
1953*7c478bd9Sstevel@tonic-gate 		    USBA_UGEN_DEVICE_BINDING) {
1954*7c478bd9Sstevel@tonic-gate 			/* 11. ugen */
1955*7c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++], "ugen");
1956*7c478bd9Sstevel@tonic-gate 		} else {
1957*7c478bd9Sstevel@tonic-gate 			/* 11. usb,device */
1958*7c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++], "usb,device");
1959*7c478bd9Sstevel@tonic-gate 		}
1960*7c478bd9Sstevel@tonic-gate 	}
1961*7c478bd9Sstevel@tonic-gate 
1962*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < n; i += 2) {
1963*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
1964*7c478bd9Sstevel@tonic-gate 		    "compatible name:\t%s\t%s", usba_compatible[i],
1965*7c478bd9Sstevel@tonic-gate 		    (((i+1) < n)? usba_compatible[i+1] : ""));
1966*7c478bd9Sstevel@tonic-gate 	}
1967*7c478bd9Sstevel@tonic-gate 	mutex_exit(&usba_mutex);
1968*7c478bd9Sstevel@tonic-gate 
1969*7c478bd9Sstevel@tonic-gate 	if (n) {
1970*7c478bd9Sstevel@tonic-gate 		rval = ndi_prop_update_string_array(
1971*7c478bd9Sstevel@tonic-gate 		    DDI_DEV_T_NONE, child_dip,
1972*7c478bd9Sstevel@tonic-gate 		    "compatible", (char **)usba_compatible, n);
1973*7c478bd9Sstevel@tonic-gate 
1974*7c478bd9Sstevel@tonic-gate 		if (rval != DDI_PROP_SUCCESS) {
1975*7c478bd9Sstevel@tonic-gate 
1976*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_USBA, usba_log_handle,
1977*7c478bd9Sstevel@tonic-gate 			    "usba_ready_device_node: property update failed");
1978*7c478bd9Sstevel@tonic-gate 
1979*7c478bd9Sstevel@tonic-gate 			return (child_dip);
1980*7c478bd9Sstevel@tonic-gate 		}
1981*7c478bd9Sstevel@tonic-gate 	}
1982*7c478bd9Sstevel@tonic-gate 
1983*7c478bd9Sstevel@tonic-gate 	/* update the address property */
1984*7c478bd9Sstevel@tonic-gate 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
1985*7c478bd9Sstevel@tonic-gate 			"assigned-address", usba_device->usb_addr);
1986*7c478bd9Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
1987*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_USBA, usba_log_handle,
1988*7c478bd9Sstevel@tonic-gate 		    "usba_ready_device_node: address update failed");
1989*7c478bd9Sstevel@tonic-gate 	}
1990*7c478bd9Sstevel@tonic-gate 
1991*7c478bd9Sstevel@tonic-gate 	/* update the address property */
1992*7c478bd9Sstevel@tonic-gate 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
1993*7c478bd9Sstevel@tonic-gate 			"assigned-address", usba_device->usb_addr);
1994*7c478bd9Sstevel@tonic-gate 
1995*7c478bd9Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
1996*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_USBA, usba_log_handle,
1997*7c478bd9Sstevel@tonic-gate 		    "usba_ready_device_node: address update failed");
1998*7c478bd9Sstevel@tonic-gate 	}
1999*7c478bd9Sstevel@tonic-gate 
2000*7c478bd9Sstevel@tonic-gate 	/* update the usb device properties (PSARC/2000/454) */
2001*7c478bd9Sstevel@tonic-gate 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2002*7c478bd9Sstevel@tonic-gate 	    "usb-vendor-id", usb_dev_descr->idVendor);
2003*7c478bd9Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
2004*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_USBA, usba_log_handle,
2005*7c478bd9Sstevel@tonic-gate 		    "usba_ready_device_node: usb-vendor-id update failed");
2006*7c478bd9Sstevel@tonic-gate 	}
2007*7c478bd9Sstevel@tonic-gate 
2008*7c478bd9Sstevel@tonic-gate 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2009*7c478bd9Sstevel@tonic-gate 	    "usb-product-id", usb_dev_descr->idProduct);
2010*7c478bd9Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
2011*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_USBA, usba_log_handle,
2012*7c478bd9Sstevel@tonic-gate 		    "usba_ready_device_node: usb-product-id update failed");
2013*7c478bd9Sstevel@tonic-gate 	}
2014*7c478bd9Sstevel@tonic-gate 
2015*7c478bd9Sstevel@tonic-gate 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2016*7c478bd9Sstevel@tonic-gate 	    "usb-revision-id", usb_dev_descr->bcdDevice);
2017*7c478bd9Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
2018*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_USBA, usba_log_handle,
2019*7c478bd9Sstevel@tonic-gate 		    "usba_ready_device_node: usb-revision-id update failed");
2020*7c478bd9Sstevel@tonic-gate 	}
2021*7c478bd9Sstevel@tonic-gate 
2022*7c478bd9Sstevel@tonic-gate 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2023*7c478bd9Sstevel@tonic-gate 	    "usb-num-configs", usb_dev_descr->bNumConfigurations);
2024*7c478bd9Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
2025*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_USBA, usba_log_handle,
2026*7c478bd9Sstevel@tonic-gate 		    "usba_ready_device_node: usb-num-configs update failed");
2027*7c478bd9Sstevel@tonic-gate 	}
2028*7c478bd9Sstevel@tonic-gate 
2029*7c478bd9Sstevel@tonic-gate 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2030*7c478bd9Sstevel@tonic-gate 	    "usb-release", usb_dev_descr->bcdUSB);
2031*7c478bd9Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
2032*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_USBA, usba_log_handle,
2033*7c478bd9Sstevel@tonic-gate 		    "usba_ready_device_node: usb-release update failed");
2034*7c478bd9Sstevel@tonic-gate 	}
2035*7c478bd9Sstevel@tonic-gate 
2036*7c478bd9Sstevel@tonic-gate 	devprop_str = kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP);
2037*7c478bd9Sstevel@tonic-gate 
2038*7c478bd9Sstevel@tonic-gate 	if (usba_device->usb_serialno_str) {
2039*7c478bd9Sstevel@tonic-gate 		usba_filter_string(usba_device->usb_serialno_str, devprop_str);
2040*7c478bd9Sstevel@tonic-gate 		rval = ndi_prop_update_string(DDI_DEV_T_NONE, child_dip,
2041*7c478bd9Sstevel@tonic-gate 		    "usb-serialno", devprop_str);
2042*7c478bd9Sstevel@tonic-gate 		if (rval != DDI_PROP_SUCCESS) {
2043*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_USBA, usba_log_handle,
2044*7c478bd9Sstevel@tonic-gate 			    "usba_ready_device_node: "
2045*7c478bd9Sstevel@tonic-gate 			    "usb-serialno update failed");
2046*7c478bd9Sstevel@tonic-gate 		}
2047*7c478bd9Sstevel@tonic-gate 	}
2048*7c478bd9Sstevel@tonic-gate 
2049*7c478bd9Sstevel@tonic-gate 	if (usba_device->usb_mfg_str) {
2050*7c478bd9Sstevel@tonic-gate 		usba_filter_string(usba_device->usb_mfg_str, devprop_str);
2051*7c478bd9Sstevel@tonic-gate 		rval = ndi_prop_update_string(DDI_DEV_T_NONE, child_dip,
2052*7c478bd9Sstevel@tonic-gate 		    "usb-vendor-name", devprop_str);
2053*7c478bd9Sstevel@tonic-gate 		if (rval != DDI_PROP_SUCCESS) {
2054*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_USBA, usba_log_handle,
2055*7c478bd9Sstevel@tonic-gate 			    "usba_ready_device_node: "
2056*7c478bd9Sstevel@tonic-gate 			    "usb-vendor-name update failed");
2057*7c478bd9Sstevel@tonic-gate 		}
2058*7c478bd9Sstevel@tonic-gate 	}
2059*7c478bd9Sstevel@tonic-gate 
2060*7c478bd9Sstevel@tonic-gate 	if (usba_device->usb_product_str) {
2061*7c478bd9Sstevel@tonic-gate 		usba_filter_string(usba_device->usb_product_str, devprop_str);
2062*7c478bd9Sstevel@tonic-gate 		rval = ndi_prop_update_string(DDI_DEV_T_NONE, child_dip,
2063*7c478bd9Sstevel@tonic-gate 		    "usb-product-name", devprop_str);
2064*7c478bd9Sstevel@tonic-gate 		if (rval != DDI_PROP_SUCCESS) {
2065*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_USBA, usba_log_handle,
2066*7c478bd9Sstevel@tonic-gate 			    "usba_ready_device_node: "
2067*7c478bd9Sstevel@tonic-gate 			    "usb-product-name update failed");
2068*7c478bd9Sstevel@tonic-gate 		}
2069*7c478bd9Sstevel@tonic-gate 	}
2070*7c478bd9Sstevel@tonic-gate 
2071*7c478bd9Sstevel@tonic-gate 	kmem_free(devprop_str, USB_MAXSTRINGLEN);
2072*7c478bd9Sstevel@tonic-gate 
2073*7c478bd9Sstevel@tonic-gate 	if (!combined_node) {
2074*7c478bd9Sstevel@tonic-gate 		/* update the configuration property */
2075*7c478bd9Sstevel@tonic-gate 		rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2076*7c478bd9Sstevel@tonic-gate 			"configuration#", usba_device->usb_cfg_value);
2077*7c478bd9Sstevel@tonic-gate 		if (rval != DDI_PROP_SUCCESS) {
2078*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2079*7c478bd9Sstevel@tonic-gate 			    "usba_ready_device_node: "
2080*7c478bd9Sstevel@tonic-gate 			    "config prop update failed");
2081*7c478bd9Sstevel@tonic-gate 		}
2082*7c478bd9Sstevel@tonic-gate 	}
2083*7c478bd9Sstevel@tonic-gate 
2084*7c478bd9Sstevel@tonic-gate 	if (usba_device->usb_port_status == USBA_LOW_SPEED_DEV) {
2085*7c478bd9Sstevel@tonic-gate 		/* create boolean property */
2086*7c478bd9Sstevel@tonic-gate 		rval = ndi_prop_create_boolean(DDI_DEV_T_NONE, child_dip,
2087*7c478bd9Sstevel@tonic-gate 			"low-speed");
2088*7c478bd9Sstevel@tonic-gate 		if (rval != DDI_PROP_SUCCESS) {
2089*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_USBA, usba_log_handle,
2090*7c478bd9Sstevel@tonic-gate 			    "usba_ready_device_node: "
2091*7c478bd9Sstevel@tonic-gate 			    "low speed prop update failed");
2092*7c478bd9Sstevel@tonic-gate 		}
2093*7c478bd9Sstevel@tonic-gate 	}
2094*7c478bd9Sstevel@tonic-gate 
2095*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
2096*7c478bd9Sstevel@tonic-gate 	    "%s%d at port %d: %s, dip=0x%p",
2097*7c478bd9Sstevel@tonic-gate 	    ddi_node_name(ddi_get_parent(child_dip)),
2098*7c478bd9Sstevel@tonic-gate 	    ddi_get_instance(ddi_get_parent(child_dip)),
2099*7c478bd9Sstevel@tonic-gate 	    port, ddi_node_name(child_dip), child_dip);
2100*7c478bd9Sstevel@tonic-gate 
2101*7c478bd9Sstevel@tonic-gate 	usba_set_usba_device(child_dip, usba_device);
2102*7c478bd9Sstevel@tonic-gate 
2103*7c478bd9Sstevel@tonic-gate 	ASSERT(!mutex_owned(&(usba_get_usba_device(child_dip)->usb_mutex)));
2104*7c478bd9Sstevel@tonic-gate 
2105*7c478bd9Sstevel@tonic-gate 	return (child_dip);
2106*7c478bd9Sstevel@tonic-gate }
2107*7c478bd9Sstevel@tonic-gate 
2108*7c478bd9Sstevel@tonic-gate 
2109*7c478bd9Sstevel@tonic-gate /*
2110*7c478bd9Sstevel@tonic-gate  * driver binding at interface level, the first arg will be the
2111*7c478bd9Sstevel@tonic-gate  * the parent dip
2112*7c478bd9Sstevel@tonic-gate  */
2113*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2114*7c478bd9Sstevel@tonic-gate dev_info_t *
2115*7c478bd9Sstevel@tonic-gate usba_ready_interface_node(dev_info_t *dip, uint_t intf)
2116*7c478bd9Sstevel@tonic-gate {
2117*7c478bd9Sstevel@tonic-gate 	dev_info_t		*child_dip = NULL;
2118*7c478bd9Sstevel@tonic-gate 	usba_device_t		*child_ud = usba_get_usba_device(dip);
2119*7c478bd9Sstevel@tonic-gate 	usb_dev_descr_t	*usb_dev_descr;
2120*7c478bd9Sstevel@tonic-gate 	size_t			usb_cfg_length;
2121*7c478bd9Sstevel@tonic-gate 	uchar_t 		*usb_cfg;
2122*7c478bd9Sstevel@tonic-gate 	usb_if_descr_t	if_descr;
2123*7c478bd9Sstevel@tonic-gate 	int			i, n, rval;
2124*7c478bd9Sstevel@tonic-gate 	int			reg[2];
2125*7c478bd9Sstevel@tonic-gate 	size_t			size;
2126*7c478bd9Sstevel@tonic-gate 	usb_port_status_t	port_status;
2127*7c478bd9Sstevel@tonic-gate 	char			*force_bind = NULL;
2128*7c478bd9Sstevel@tonic-gate 
2129*7c478bd9Sstevel@tonic-gate 	usb_cfg = usb_get_raw_cfg_data(dip, &usb_cfg_length);
2130*7c478bd9Sstevel@tonic-gate 
2131*7c478bd9Sstevel@tonic-gate 	mutex_enter(&child_ud->usb_mutex);
2132*7c478bd9Sstevel@tonic-gate 
2133*7c478bd9Sstevel@tonic-gate 	usb_dev_descr = child_ud->usb_dev_descr;
2134*7c478bd9Sstevel@tonic-gate 
2135*7c478bd9Sstevel@tonic-gate 	/*
2136*7c478bd9Sstevel@tonic-gate 	 * for each interface, determine all compatible names
2137*7c478bd9Sstevel@tonic-gate 	 */
2138*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
2139*7c478bd9Sstevel@tonic-gate 	    "usba_ready_interface_node: "
2140*7c478bd9Sstevel@tonic-gate 	    "port %d, interface = %d port status = %x",
2141*7c478bd9Sstevel@tonic-gate 	    child_ud->usb_port, intf, child_ud->usb_port_status);
2142*7c478bd9Sstevel@tonic-gate 
2143*7c478bd9Sstevel@tonic-gate 	/* Parse the interface descriptor */
2144*7c478bd9Sstevel@tonic-gate 	size = usb_parse_if_descr(
2145*7c478bd9Sstevel@tonic-gate 			usb_cfg,
2146*7c478bd9Sstevel@tonic-gate 			usb_cfg_length,
2147*7c478bd9Sstevel@tonic-gate 			intf,		/* interface index */
2148*7c478bd9Sstevel@tonic-gate 			0,		/* alt interface index */
2149*7c478bd9Sstevel@tonic-gate 			&if_descr,
2150*7c478bd9Sstevel@tonic-gate 			USB_IF_DESCR_SIZE);
2151*7c478bd9Sstevel@tonic-gate 
2152*7c478bd9Sstevel@tonic-gate 	if (size != USB_IF_DESCR_SIZE) {
2153*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_USBA, usba_log_handle,
2154*7c478bd9Sstevel@tonic-gate 		    "parsing interface: size (%lu) != USB_IF_DESCR_SIZE (%d)",
2155*7c478bd9Sstevel@tonic-gate 		    size, USB_IF_DESCR_SIZE);
2156*7c478bd9Sstevel@tonic-gate 		mutex_exit(&child_ud->usb_mutex);
2157*7c478bd9Sstevel@tonic-gate 
2158*7c478bd9Sstevel@tonic-gate 		return (NULL);
2159*7c478bd9Sstevel@tonic-gate 	}
2160*7c478bd9Sstevel@tonic-gate 
2161*7c478bd9Sstevel@tonic-gate 	port_status = child_ud->usb_port_status;
2162*7c478bd9Sstevel@tonic-gate 
2163*7c478bd9Sstevel@tonic-gate 	/* create reg property */
2164*7c478bd9Sstevel@tonic-gate 	reg[0] = intf;
2165*7c478bd9Sstevel@tonic-gate 	reg[1] = child_ud->usb_cfg_value;
2166*7c478bd9Sstevel@tonic-gate 
2167*7c478bd9Sstevel@tonic-gate 	mutex_exit(&child_ud->usb_mutex);
2168*7c478bd9Sstevel@tonic-gate 
2169*7c478bd9Sstevel@tonic-gate 	/* clone this dip */
2170*7c478bd9Sstevel@tonic-gate 	rval =	usba_create_child_devi(dip,
2171*7c478bd9Sstevel@tonic-gate 			"interface",
2172*7c478bd9Sstevel@tonic-gate 			NULL,		/* usba_hcdi ops */
2173*7c478bd9Sstevel@tonic-gate 			NULL,		/* root hub dip */
2174*7c478bd9Sstevel@tonic-gate 			port_status,	/* port status */
2175*7c478bd9Sstevel@tonic-gate 			child_ud,	/* share this usba_device */
2176*7c478bd9Sstevel@tonic-gate 			&child_dip);
2177*7c478bd9Sstevel@tonic-gate 
2178*7c478bd9Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
2179*7c478bd9Sstevel@tonic-gate 
2180*7c478bd9Sstevel@tonic-gate 		goto fail;
2181*7c478bd9Sstevel@tonic-gate 	}
2182*7c478bd9Sstevel@tonic-gate 
2183*7c478bd9Sstevel@tonic-gate 	rval = ndi_prop_update_int_array(
2184*7c478bd9Sstevel@tonic-gate 		DDI_DEV_T_NONE, child_dip, "reg", reg, 2);
2185*7c478bd9Sstevel@tonic-gate 
2186*7c478bd9Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
2187*7c478bd9Sstevel@tonic-gate 
2188*7c478bd9Sstevel@tonic-gate 		goto fail;
2189*7c478bd9Sstevel@tonic-gate 	}
2190*7c478bd9Sstevel@tonic-gate 
2191*7c478bd9Sstevel@tonic-gate 	usba_set_node_name(child_dip, if_descr.bInterfaceClass,
2192*7c478bd9Sstevel@tonic-gate 	    if_descr.bInterfaceSubClass, if_descr.bInterfaceProtocol,
2193*7c478bd9Sstevel@tonic-gate 	    FLAG_INTERFACE_NODE);
2194*7c478bd9Sstevel@tonic-gate 
2195*7c478bd9Sstevel@tonic-gate 	/* check force binding */
2196*7c478bd9Sstevel@tonic-gate 	if (usba_ugen_force_binding == USBA_UGEN_INTERFACE_BINDING) {
2197*7c478bd9Sstevel@tonic-gate 		force_bind = "ugen";
2198*7c478bd9Sstevel@tonic-gate 	}
2199*7c478bd9Sstevel@tonic-gate 
2200*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
2201*7c478bd9Sstevel@tonic-gate 	/*
2202*7c478bd9Sstevel@tonic-gate 	 * check whether there is another dip with this name and address
2203*7c478bd9Sstevel@tonic-gate 	 */
2204*7c478bd9Sstevel@tonic-gate 	ASSERT(usba_find_existing_node(child_dip) == NULL);
2205*7c478bd9Sstevel@tonic-gate #endif
2206*7c478bd9Sstevel@tonic-gate 
2207*7c478bd9Sstevel@tonic-gate 	mutex_enter(&usba_mutex);
2208*7c478bd9Sstevel@tonic-gate 	n = 0;
2209*7c478bd9Sstevel@tonic-gate 
2210*7c478bd9Sstevel@tonic-gate 	if (force_bind) {
2211*7c478bd9Sstevel@tonic-gate 		(void) ndi_devi_set_nodename(child_dip, force_bind, 0);
2212*7c478bd9Sstevel@tonic-gate 		(void) strncpy(usba_name[n++], force_bind,
2213*7c478bd9Sstevel@tonic-gate 						USBA_MAX_COMPAT_NAME_LEN);
2214*7c478bd9Sstevel@tonic-gate 	}
2215*7c478bd9Sstevel@tonic-gate 
2216*7c478bd9Sstevel@tonic-gate 	/* 1) usbifVID,PID.REV.configCN.IN */
2217*7c478bd9Sstevel@tonic-gate 	(void) sprintf(usba_name[n++],
2218*7c478bd9Sstevel@tonic-gate 			"usbif%x,%x.%x.config%x.%x",
2219*7c478bd9Sstevel@tonic-gate 			usb_dev_descr->idVendor,
2220*7c478bd9Sstevel@tonic-gate 			usb_dev_descr->idProduct,
2221*7c478bd9Sstevel@tonic-gate 			usb_dev_descr->bcdDevice,
2222*7c478bd9Sstevel@tonic-gate 			child_ud->usb_cfg_value,
2223*7c478bd9Sstevel@tonic-gate 			intf);
2224*7c478bd9Sstevel@tonic-gate 
2225*7c478bd9Sstevel@tonic-gate 	/* 2) usbifVID,PID.configCN.IN */
2226*7c478bd9Sstevel@tonic-gate 	(void) sprintf(usba_name[n++],
2227*7c478bd9Sstevel@tonic-gate 			"usbif%x,%x.config%x.%x",
2228*7c478bd9Sstevel@tonic-gate 			usb_dev_descr->idVendor,
2229*7c478bd9Sstevel@tonic-gate 			usb_dev_descr->idProduct,
2230*7c478bd9Sstevel@tonic-gate 			child_ud->usb_cfg_value,
2231*7c478bd9Sstevel@tonic-gate 			intf);
2232*7c478bd9Sstevel@tonic-gate 
2233*7c478bd9Sstevel@tonic-gate 
2234*7c478bd9Sstevel@tonic-gate 	if (if_descr.bInterfaceClass) {
2235*7c478bd9Sstevel@tonic-gate 		/* 3) usbifVID,classIC.ISC.IPROTO */
2236*7c478bd9Sstevel@tonic-gate 		(void) sprintf(usba_name[n++],
2237*7c478bd9Sstevel@tonic-gate 			"usbif%x,class%x.%x.%x",
2238*7c478bd9Sstevel@tonic-gate 			usb_dev_descr->idVendor,
2239*7c478bd9Sstevel@tonic-gate 			if_descr.bInterfaceClass,
2240*7c478bd9Sstevel@tonic-gate 			if_descr.bInterfaceSubClass,
2241*7c478bd9Sstevel@tonic-gate 			if_descr.bInterfaceProtocol);
2242*7c478bd9Sstevel@tonic-gate 
2243*7c478bd9Sstevel@tonic-gate 		/* 4) usbifVID,classIC.ISC */
2244*7c478bd9Sstevel@tonic-gate 		(void) sprintf(usba_name[n++],
2245*7c478bd9Sstevel@tonic-gate 			"usbif%x,class%x.%x",
2246*7c478bd9Sstevel@tonic-gate 			usb_dev_descr->idVendor,
2247*7c478bd9Sstevel@tonic-gate 			if_descr.bInterfaceClass,
2248*7c478bd9Sstevel@tonic-gate 			if_descr.bInterfaceSubClass);
2249*7c478bd9Sstevel@tonic-gate 
2250*7c478bd9Sstevel@tonic-gate 		/* 5) usbifVID,classIC */
2251*7c478bd9Sstevel@tonic-gate 		(void) sprintf(usba_name[n++],
2252*7c478bd9Sstevel@tonic-gate 			"usbif%x,class%x",
2253*7c478bd9Sstevel@tonic-gate 			usb_dev_descr->idVendor,
2254*7c478bd9Sstevel@tonic-gate 			if_descr.bInterfaceClass);
2255*7c478bd9Sstevel@tonic-gate 
2256*7c478bd9Sstevel@tonic-gate 		/* 6) usbif,classIC.ISC.IPROTO */
2257*7c478bd9Sstevel@tonic-gate 		(void) sprintf(usba_name[n++],
2258*7c478bd9Sstevel@tonic-gate 			"usbif,class%x.%x.%x",
2259*7c478bd9Sstevel@tonic-gate 			if_descr.bInterfaceClass,
2260*7c478bd9Sstevel@tonic-gate 			if_descr.bInterfaceSubClass,
2261*7c478bd9Sstevel@tonic-gate 			if_descr.bInterfaceProtocol);
2262*7c478bd9Sstevel@tonic-gate 
2263*7c478bd9Sstevel@tonic-gate 		/* 7) usbif,classIC.ISC */
2264*7c478bd9Sstevel@tonic-gate 		(void) sprintf(usba_name[n++],
2265*7c478bd9Sstevel@tonic-gate 			"usbif,class%x.%x",
2266*7c478bd9Sstevel@tonic-gate 			if_descr.bInterfaceClass,
2267*7c478bd9Sstevel@tonic-gate 			if_descr.bInterfaceSubClass);
2268*7c478bd9Sstevel@tonic-gate 
2269*7c478bd9Sstevel@tonic-gate 		/* 8) usbif,classIC */
2270*7c478bd9Sstevel@tonic-gate 		(void) sprintf(usba_name[n++],
2271*7c478bd9Sstevel@tonic-gate 			"usbif,class%x",
2272*7c478bd9Sstevel@tonic-gate 			if_descr.bInterfaceClass);
2273*7c478bd9Sstevel@tonic-gate 	}
2274*7c478bd9Sstevel@tonic-gate 
2275*7c478bd9Sstevel@tonic-gate 	if (usba_get_ugen_binding(child_dip) ==
2276*7c478bd9Sstevel@tonic-gate 	    USBA_UGEN_INTERFACE_BINDING) {
2277*7c478bd9Sstevel@tonic-gate 		/* 9) ugen */
2278*7c478bd9Sstevel@tonic-gate 		(void) sprintf(usba_name[n++], "ugen");
2279*7c478bd9Sstevel@tonic-gate 	}
2280*7c478bd9Sstevel@tonic-gate 
2281*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < n; i += 2) {
2282*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
2283*7c478bd9Sstevel@tonic-gate 		    "compatible name:\t%s\t%s", usba_compatible[i],
2284*7c478bd9Sstevel@tonic-gate 		    (((i+1) < n)? usba_compatible[i+1] : ""));
2285*7c478bd9Sstevel@tonic-gate 	}
2286*7c478bd9Sstevel@tonic-gate 	mutex_exit(&usba_mutex);
2287*7c478bd9Sstevel@tonic-gate 
2288*7c478bd9Sstevel@tonic-gate 	/* create compatible property */
2289*7c478bd9Sstevel@tonic-gate 	if (n) {
2290*7c478bd9Sstevel@tonic-gate 		rval = ndi_prop_update_string_array(
2291*7c478bd9Sstevel@tonic-gate 		    DDI_DEV_T_NONE, child_dip,
2292*7c478bd9Sstevel@tonic-gate 		    "compatible", (char **)usba_compatible,
2293*7c478bd9Sstevel@tonic-gate 		    n);
2294*7c478bd9Sstevel@tonic-gate 
2295*7c478bd9Sstevel@tonic-gate 		if (rval != DDI_PROP_SUCCESS) {
2296*7c478bd9Sstevel@tonic-gate 
2297*7c478bd9Sstevel@tonic-gate 			goto fail;
2298*7c478bd9Sstevel@tonic-gate 		}
2299*7c478bd9Sstevel@tonic-gate 	}
2300*7c478bd9Sstevel@tonic-gate 
2301*7c478bd9Sstevel@tonic-gate 	/* update the address property */
2302*7c478bd9Sstevel@tonic-gate 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2303*7c478bd9Sstevel@tonic-gate 			"assigned-address", child_ud->usb_addr);
2304*7c478bd9Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
2305*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_USBA, usba_log_handle,
2306*7c478bd9Sstevel@tonic-gate 		    "usba_ready_interface_node: address update failed");
2307*7c478bd9Sstevel@tonic-gate 	}
2308*7c478bd9Sstevel@tonic-gate 
2309*7c478bd9Sstevel@tonic-gate 	/* create property with if number */
2310*7c478bd9Sstevel@tonic-gate 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2311*7c478bd9Sstevel@tonic-gate 		"interface", intf);
2312*7c478bd9Sstevel@tonic-gate 
2313*7c478bd9Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
2314*7c478bd9Sstevel@tonic-gate 
2315*7c478bd9Sstevel@tonic-gate 		goto fail;
2316*7c478bd9Sstevel@tonic-gate 	}
2317*7c478bd9Sstevel@tonic-gate 
2318*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2319*7c478bd9Sstevel@tonic-gate 	    "%s%d port %d: %s, dip = 0x%p",
2320*7c478bd9Sstevel@tonic-gate 	    ddi_node_name(ddi_get_parent(dip)),
2321*7c478bd9Sstevel@tonic-gate 	    ddi_get_instance(ddi_get_parent(dip)),
2322*7c478bd9Sstevel@tonic-gate 	    child_ud->usb_port, ddi_node_name(child_dip), child_dip);
2323*7c478bd9Sstevel@tonic-gate 
2324*7c478bd9Sstevel@tonic-gate 	usba_set_usba_device(child_dip, child_ud);
2325*7c478bd9Sstevel@tonic-gate 	ASSERT(!mutex_owned(&(usba_get_usba_device(child_dip)->usb_mutex)));
2326*7c478bd9Sstevel@tonic-gate 
2327*7c478bd9Sstevel@tonic-gate 	return (child_dip);
2328*7c478bd9Sstevel@tonic-gate 
2329*7c478bd9Sstevel@tonic-gate fail:
2330*7c478bd9Sstevel@tonic-gate 	(void) usba_destroy_child_devi(child_dip, NDI_DEVI_REMOVE);
2331*7c478bd9Sstevel@tonic-gate 
2332*7c478bd9Sstevel@tonic-gate 	return (NULL);
2333*7c478bd9Sstevel@tonic-gate }
2334*7c478bd9Sstevel@tonic-gate 
2335*7c478bd9Sstevel@tonic-gate 
2336*7c478bd9Sstevel@tonic-gate /*
2337*7c478bd9Sstevel@tonic-gate  * retrieve string descriptors for manufacturer, vendor and serial
2338*7c478bd9Sstevel@tonic-gate  * number
2339*7c478bd9Sstevel@tonic-gate  */
2340*7c478bd9Sstevel@tonic-gate void
2341*7c478bd9Sstevel@tonic-gate usba_get_dev_string_descrs(dev_info_t *dip, usba_device_t *ud)
2342*7c478bd9Sstevel@tonic-gate {
2343*7c478bd9Sstevel@tonic-gate 	char	*tmpbuf, *str;
2344*7c478bd9Sstevel@tonic-gate 	int	l;
2345*7c478bd9Sstevel@tonic-gate 	usb_dev_descr_t *usb_dev_descr = ud->usb_dev_descr;
2346*7c478bd9Sstevel@tonic-gate 
2347*7c478bd9Sstevel@tonic-gate 
2348*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
2349*7c478bd9Sstevel@tonic-gate 	    "usba_get_usb_string_descr: m=%d, p=%d, s=%d",
2350*7c478bd9Sstevel@tonic-gate 	    usb_dev_descr->iManufacturer,
2351*7c478bd9Sstevel@tonic-gate 	    usb_dev_descr->iProduct,
2352*7c478bd9Sstevel@tonic-gate 	    usb_dev_descr->iSerialNumber);
2353*7c478bd9Sstevel@tonic-gate 
2354*7c478bd9Sstevel@tonic-gate 	tmpbuf = kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP);
2355*7c478bd9Sstevel@tonic-gate 
2356*7c478bd9Sstevel@tonic-gate 	/* fetch manufacturer string */
2357*7c478bd9Sstevel@tonic-gate 	if ((ud->usb_mfg_str == NULL) && usb_dev_descr->iManufacturer &&
2358*7c478bd9Sstevel@tonic-gate 	    (usb_get_string_descr(dip, USB_LANG_ID,
2359*7c478bd9Sstevel@tonic-gate 		usb_dev_descr->iManufacturer, tmpbuf, USB_MAXSTRINGLEN) ==
2360*7c478bd9Sstevel@tonic-gate 		USB_SUCCESS)) {
2361*7c478bd9Sstevel@tonic-gate 
2362*7c478bd9Sstevel@tonic-gate 		l = strlen(tmpbuf);
2363*7c478bd9Sstevel@tonic-gate 		if (l > 0) {
2364*7c478bd9Sstevel@tonic-gate 			str = kmem_zalloc(l + 1, KM_SLEEP);
2365*7c478bd9Sstevel@tonic-gate 			mutex_enter(&ud->usb_mutex);
2366*7c478bd9Sstevel@tonic-gate 			ud->usb_mfg_str = str;
2367*7c478bd9Sstevel@tonic-gate 			(void) strcpy(ud->usb_mfg_str, tmpbuf);
2368*7c478bd9Sstevel@tonic-gate 			mutex_exit(&ud->usb_mutex);
2369*7c478bd9Sstevel@tonic-gate 		}
2370*7c478bd9Sstevel@tonic-gate 	}
2371*7c478bd9Sstevel@tonic-gate 
2372*7c478bd9Sstevel@tonic-gate 	/* fetch product string */
2373*7c478bd9Sstevel@tonic-gate 	if ((ud->usb_product_str == NULL) && usb_dev_descr->iProduct &&
2374*7c478bd9Sstevel@tonic-gate 	    (usb_get_string_descr(dip, USB_LANG_ID, usb_dev_descr->iProduct,
2375*7c478bd9Sstevel@tonic-gate 	    tmpbuf, USB_MAXSTRINGLEN) ==
2376*7c478bd9Sstevel@tonic-gate 		USB_SUCCESS)) {
2377*7c478bd9Sstevel@tonic-gate 
2378*7c478bd9Sstevel@tonic-gate 		l = strlen(tmpbuf);
2379*7c478bd9Sstevel@tonic-gate 		if (l > 0) {
2380*7c478bd9Sstevel@tonic-gate 			str = kmem_zalloc(l + 1, KM_SLEEP);
2381*7c478bd9Sstevel@tonic-gate 			mutex_enter(&ud->usb_mutex);
2382*7c478bd9Sstevel@tonic-gate 			ud->usb_product_str = str;
2383*7c478bd9Sstevel@tonic-gate 			(void) strcpy(ud->usb_product_str, tmpbuf);
2384*7c478bd9Sstevel@tonic-gate 			mutex_exit(&ud->usb_mutex);
2385*7c478bd9Sstevel@tonic-gate 		}
2386*7c478bd9Sstevel@tonic-gate 	}
2387*7c478bd9Sstevel@tonic-gate 
2388*7c478bd9Sstevel@tonic-gate 	/* fetch device serial number string */
2389*7c478bd9Sstevel@tonic-gate 	if ((ud->usb_serialno_str == NULL) && usb_dev_descr->iSerialNumber &&
2390*7c478bd9Sstevel@tonic-gate 	    (usb_get_string_descr(dip, USB_LANG_ID,
2391*7c478bd9Sstevel@tonic-gate 		usb_dev_descr->iSerialNumber, tmpbuf, USB_MAXSTRINGLEN) ==
2392*7c478bd9Sstevel@tonic-gate 		USB_SUCCESS)) {
2393*7c478bd9Sstevel@tonic-gate 
2394*7c478bd9Sstevel@tonic-gate 		l = strlen(tmpbuf);
2395*7c478bd9Sstevel@tonic-gate 		if (l > 0) {
2396*7c478bd9Sstevel@tonic-gate 			str = kmem_zalloc(l + 1, KM_SLEEP);
2397*7c478bd9Sstevel@tonic-gate 			mutex_enter(&ud->usb_mutex);
2398*7c478bd9Sstevel@tonic-gate 			ud->usb_serialno_str = str;
2399*7c478bd9Sstevel@tonic-gate 			(void) strcpy(ud->usb_serialno_str, tmpbuf);
2400*7c478bd9Sstevel@tonic-gate 			mutex_exit(&ud->usb_mutex);
2401*7c478bd9Sstevel@tonic-gate 		}
2402*7c478bd9Sstevel@tonic-gate 	}
2403*7c478bd9Sstevel@tonic-gate 
2404*7c478bd9Sstevel@tonic-gate 	kmem_free(tmpbuf, USB_MAXSTRINGLEN);
2405*7c478bd9Sstevel@tonic-gate }
2406*7c478bd9Sstevel@tonic-gate 
2407*7c478bd9Sstevel@tonic-gate 
2408*7c478bd9Sstevel@tonic-gate /*
2409*7c478bd9Sstevel@tonic-gate  * usba_str_startcmp:
2410*7c478bd9Sstevel@tonic-gate  *	Return the number of characters duplicated from the beginning of the
2411*7c478bd9Sstevel@tonic-gate  *	string.  Return -1 if a complete duplicate.
2412*7c478bd9Sstevel@tonic-gate  *
2413*7c478bd9Sstevel@tonic-gate  * Arguments:
2414*7c478bd9Sstevel@tonic-gate  *	Two strings to compare.
2415*7c478bd9Sstevel@tonic-gate  */
2416*7c478bd9Sstevel@tonic-gate static int usba_str_startcmp(char *first, char *second)
2417*7c478bd9Sstevel@tonic-gate {
2418*7c478bd9Sstevel@tonic-gate 	int num_same_chars = 0;
2419*7c478bd9Sstevel@tonic-gate 	while (*first == *second++) {
2420*7c478bd9Sstevel@tonic-gate 		if (*first++ == '\0') {
2421*7c478bd9Sstevel@tonic-gate 			return (-1);
2422*7c478bd9Sstevel@tonic-gate 		}
2423*7c478bd9Sstevel@tonic-gate 		num_same_chars++;
2424*7c478bd9Sstevel@tonic-gate 	}
2425*7c478bd9Sstevel@tonic-gate 
2426*7c478bd9Sstevel@tonic-gate 	return (num_same_chars);
2427*7c478bd9Sstevel@tonic-gate }
2428*7c478bd9Sstevel@tonic-gate 
2429*7c478bd9Sstevel@tonic-gate 
2430*7c478bd9Sstevel@tonic-gate /*
2431*7c478bd9Sstevel@tonic-gate  * usba_get_mfg_prod_sn_str:
2432*7c478bd9Sstevel@tonic-gate  *	Return a string containing mfg, product, serial number strings.
2433*7c478bd9Sstevel@tonic-gate  *	Remove duplicates if some strings are the same.
2434*7c478bd9Sstevel@tonic-gate  *
2435*7c478bd9Sstevel@tonic-gate  * Arguments:
2436*7c478bd9Sstevel@tonic-gate  *	dip	- pointer to dev info
2437*7c478bd9Sstevel@tonic-gate  *	buffer	- Where string is returned
2438*7c478bd9Sstevel@tonic-gate  *	buflen	- Length of buffer
2439*7c478bd9Sstevel@tonic-gate  *
2440*7c478bd9Sstevel@tonic-gate  * Returns:
2441*7c478bd9Sstevel@tonic-gate  *	Same as second arg.
2442*7c478bd9Sstevel@tonic-gate  */
2443*7c478bd9Sstevel@tonic-gate char *
2444*7c478bd9Sstevel@tonic-gate usba_get_mfg_prod_sn_str(
2445*7c478bd9Sstevel@tonic-gate     dev_info_t	*dip,
2446*7c478bd9Sstevel@tonic-gate     char	*buffer,
2447*7c478bd9Sstevel@tonic-gate     int		buflen)
2448*7c478bd9Sstevel@tonic-gate {
2449*7c478bd9Sstevel@tonic-gate 	usba_device_t *usba_device = usba_get_usba_device(dip);
2450*7c478bd9Sstevel@tonic-gate 	int return_len = 0;
2451*7c478bd9Sstevel@tonic-gate 	int len = 0;
2452*7c478bd9Sstevel@tonic-gate 	int duplen;
2453*7c478bd9Sstevel@tonic-gate 
2454*7c478bd9Sstevel@tonic-gate 	buffer[0] = '\0';
2455*7c478bd9Sstevel@tonic-gate 	buffer[buflen-1] = '\0';
2456*7c478bd9Sstevel@tonic-gate 
2457*7c478bd9Sstevel@tonic-gate 	if ((usba_device->usb_mfg_str) &&
2458*7c478bd9Sstevel@tonic-gate 	    ((len = strlen(usba_device->usb_mfg_str)) != 0)) {
2459*7c478bd9Sstevel@tonic-gate 		(void) strncpy(buffer, usba_device->usb_mfg_str, buflen - 1);
2460*7c478bd9Sstevel@tonic-gate 		return_len = min(buflen - 1, len);
2461*7c478bd9Sstevel@tonic-gate 	}
2462*7c478bd9Sstevel@tonic-gate 
2463*7c478bd9Sstevel@tonic-gate 	/* Product string exists to append. */
2464*7c478bd9Sstevel@tonic-gate 	if ((usba_device->usb_product_str) &&
2465*7c478bd9Sstevel@tonic-gate 	    ((len = strlen(usba_device->usb_product_str)) != 0)) {
2466*7c478bd9Sstevel@tonic-gate 
2467*7c478bd9Sstevel@tonic-gate 		/* Append only parts of string that don't match mfg string. */
2468*7c478bd9Sstevel@tonic-gate 		duplen = usba_str_startcmp(buffer,
2469*7c478bd9Sstevel@tonic-gate 					usba_device->usb_product_str);
2470*7c478bd9Sstevel@tonic-gate 
2471*7c478bd9Sstevel@tonic-gate 		if (duplen != -1) {		/* Not a complete match. */
2472*7c478bd9Sstevel@tonic-gate 			if (return_len > 0) {
2473*7c478bd9Sstevel@tonic-gate 				buffer[return_len++] = ' ';
2474*7c478bd9Sstevel@tonic-gate 			}
2475*7c478bd9Sstevel@tonic-gate 
2476*7c478bd9Sstevel@tonic-gate 			/* Skip over the dup part of the concat'ed string. */
2477*7c478bd9Sstevel@tonic-gate 			len -= duplen;
2478*7c478bd9Sstevel@tonic-gate 			(void) strncpy(&buffer[return_len],
2479*7c478bd9Sstevel@tonic-gate 			    &usba_device->usb_product_str[duplen],
2480*7c478bd9Sstevel@tonic-gate 			    buflen - return_len - 1);
2481*7c478bd9Sstevel@tonic-gate 			return_len = min(buflen - 1, return_len + len);
2482*7c478bd9Sstevel@tonic-gate 		}
2483*7c478bd9Sstevel@tonic-gate 	}
2484*7c478bd9Sstevel@tonic-gate 
2485*7c478bd9Sstevel@tonic-gate 	if ((usba_device->usb_serialno_str) &&
2486*7c478bd9Sstevel@tonic-gate 	    ((len = strlen(usba_device->usb_serialno_str)) != 0)) {
2487*7c478bd9Sstevel@tonic-gate 		if (return_len > 0) {
2488*7c478bd9Sstevel@tonic-gate 			buffer[return_len++] = ' ';
2489*7c478bd9Sstevel@tonic-gate 		}
2490*7c478bd9Sstevel@tonic-gate 		(void) strncpy(&buffer[return_len],
2491*7c478bd9Sstevel@tonic-gate 				usba_device->usb_serialno_str,
2492*7c478bd9Sstevel@tonic-gate 				buflen - return_len - 1);
2493*7c478bd9Sstevel@tonic-gate 	}
2494*7c478bd9Sstevel@tonic-gate 
2495*7c478bd9Sstevel@tonic-gate 	return (buffer);
2496*7c478bd9Sstevel@tonic-gate }
2497*7c478bd9Sstevel@tonic-gate 
2498*7c478bd9Sstevel@tonic-gate 
2499*7c478bd9Sstevel@tonic-gate /*
2500*7c478bd9Sstevel@tonic-gate  * USB enumeration statistic functions
2501*7c478bd9Sstevel@tonic-gate  */
2502*7c478bd9Sstevel@tonic-gate 
2503*7c478bd9Sstevel@tonic-gate /*
2504*7c478bd9Sstevel@tonic-gate  * Increments the hotplug statistics based on flags.
2505*7c478bd9Sstevel@tonic-gate  */
2506*7c478bd9Sstevel@tonic-gate void
2507*7c478bd9Sstevel@tonic-gate usba_update_hotplug_stats(dev_info_t *dip, usb_flags_t flags)
2508*7c478bd9Sstevel@tonic-gate {
2509*7c478bd9Sstevel@tonic-gate 	usba_device_t	*usba_device = usba_get_usba_device(dip);
2510*7c478bd9Sstevel@tonic-gate 	usba_hcdi_t	*hcdi =
2511*7c478bd9Sstevel@tonic-gate 			    usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
2512*7c478bd9Sstevel@tonic-gate 
2513*7c478bd9Sstevel@tonic-gate 	mutex_enter(&hcdi->hcdi_mutex);
2514*7c478bd9Sstevel@tonic-gate 	if (flags & USBA_TOTAL_HOTPLUG_SUCCESS) {
2515*7c478bd9Sstevel@tonic-gate 		hcdi->hcdi_total_hotplug_success++;
2516*7c478bd9Sstevel@tonic-gate 		HCDI_HOTPLUG_STATS_DATA(hcdi)->
2517*7c478bd9Sstevel@tonic-gate 		    hcdi_hotplug_total_success.value.ui64++;
2518*7c478bd9Sstevel@tonic-gate 	}
2519*7c478bd9Sstevel@tonic-gate 	if (flags & USBA_HOTPLUG_SUCCESS) {
2520*7c478bd9Sstevel@tonic-gate 		hcdi->hcdi_hotplug_success++;
2521*7c478bd9Sstevel@tonic-gate 		HCDI_HOTPLUG_STATS_DATA(hcdi)->
2522*7c478bd9Sstevel@tonic-gate 		    hcdi_hotplug_success.value.ui64++;
2523*7c478bd9Sstevel@tonic-gate 	}
2524*7c478bd9Sstevel@tonic-gate 	if (flags & USBA_TOTAL_HOTPLUG_FAILURE) {
2525*7c478bd9Sstevel@tonic-gate 		hcdi->hcdi_total_hotplug_failure++;
2526*7c478bd9Sstevel@tonic-gate 		HCDI_HOTPLUG_STATS_DATA(hcdi)->
2527*7c478bd9Sstevel@tonic-gate 		    hcdi_hotplug_total_failure.value.ui64++;
2528*7c478bd9Sstevel@tonic-gate 	}
2529*7c478bd9Sstevel@tonic-gate 	if (flags & USBA_HOTPLUG_FAILURE) {
2530*7c478bd9Sstevel@tonic-gate 		hcdi->hcdi_hotplug_failure++;
2531*7c478bd9Sstevel@tonic-gate 		HCDI_HOTPLUG_STATS_DATA(hcdi)->
2532*7c478bd9Sstevel@tonic-gate 		    hcdi_hotplug_failure.value.ui64++;
2533*7c478bd9Sstevel@tonic-gate 	}
2534*7c478bd9Sstevel@tonic-gate 	mutex_exit(&hcdi->hcdi_mutex);
2535*7c478bd9Sstevel@tonic-gate }
2536*7c478bd9Sstevel@tonic-gate 
2537*7c478bd9Sstevel@tonic-gate 
2538*7c478bd9Sstevel@tonic-gate /*
2539*7c478bd9Sstevel@tonic-gate  * Retrieve the current enumeration statistics
2540*7c478bd9Sstevel@tonic-gate  */
2541*7c478bd9Sstevel@tonic-gate void
2542*7c478bd9Sstevel@tonic-gate usba_get_hotplug_stats(dev_info_t *dip, ulong_t *total_success,
2543*7c478bd9Sstevel@tonic-gate     ulong_t *success, ulong_t *total_failure, ulong_t *failure,
2544*7c478bd9Sstevel@tonic-gate     uchar_t *device_count)
2545*7c478bd9Sstevel@tonic-gate {
2546*7c478bd9Sstevel@tonic-gate 	usba_device_t	*usba_device = usba_get_usba_device(dip);
2547*7c478bd9Sstevel@tonic-gate 	usba_hcdi_t	*hcdi =
2548*7c478bd9Sstevel@tonic-gate 			    usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
2549*7c478bd9Sstevel@tonic-gate 
2550*7c478bd9Sstevel@tonic-gate 	mutex_enter(&hcdi->hcdi_mutex);
2551*7c478bd9Sstevel@tonic-gate 	*total_success = hcdi->hcdi_total_hotplug_success;
2552*7c478bd9Sstevel@tonic-gate 	*success = hcdi->hcdi_hotplug_success;
2553*7c478bd9Sstevel@tonic-gate 	*total_failure = hcdi->hcdi_total_hotplug_failure;
2554*7c478bd9Sstevel@tonic-gate 	*failure = hcdi->hcdi_hotplug_failure;
2555*7c478bd9Sstevel@tonic-gate 	*device_count = hcdi->hcdi_device_count;
2556*7c478bd9Sstevel@tonic-gate 	mutex_exit(&hcdi->hcdi_mutex);
2557*7c478bd9Sstevel@tonic-gate }
2558*7c478bd9Sstevel@tonic-gate 
2559*7c478bd9Sstevel@tonic-gate 
2560*7c478bd9Sstevel@tonic-gate /*
2561*7c478bd9Sstevel@tonic-gate  * Reset the resetable hotplug stats
2562*7c478bd9Sstevel@tonic-gate  */
2563*7c478bd9Sstevel@tonic-gate void
2564*7c478bd9Sstevel@tonic-gate usba_reset_hotplug_stats(dev_info_t *dip)
2565*7c478bd9Sstevel@tonic-gate {
2566*7c478bd9Sstevel@tonic-gate 	usba_device_t	*usba_device = usba_get_usba_device(dip);
2567*7c478bd9Sstevel@tonic-gate 	usba_hcdi_t	*hcdi =
2568*7c478bd9Sstevel@tonic-gate 			    usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
2569*7c478bd9Sstevel@tonic-gate 	hcdi_hotplug_stats_t *hsp;
2570*7c478bd9Sstevel@tonic-gate 
2571*7c478bd9Sstevel@tonic-gate 	mutex_enter(&hcdi->hcdi_mutex);
2572*7c478bd9Sstevel@tonic-gate 	hcdi->hcdi_hotplug_success = 0;
2573*7c478bd9Sstevel@tonic-gate 	hcdi->hcdi_hotplug_failure = 0;
2574*7c478bd9Sstevel@tonic-gate 
2575*7c478bd9Sstevel@tonic-gate 	hsp = HCDI_HOTPLUG_STATS_DATA(hcdi);
2576*7c478bd9Sstevel@tonic-gate 	hsp->hcdi_hotplug_success.value.ui64 = 0;
2577*7c478bd9Sstevel@tonic-gate 	hsp->hcdi_hotplug_failure.value.ui64 = 0;
2578*7c478bd9Sstevel@tonic-gate 	mutex_exit(&hcdi->hcdi_mutex);
2579*7c478bd9Sstevel@tonic-gate }
2580*7c478bd9Sstevel@tonic-gate 
2581*7c478bd9Sstevel@tonic-gate 
2582*7c478bd9Sstevel@tonic-gate /*
2583*7c478bd9Sstevel@tonic-gate  * usba_bind_driver():
2584*7c478bd9Sstevel@tonic-gate  *	This function calls ndi_devi_bind_driver() which tries to
2585*7c478bd9Sstevel@tonic-gate  *	bind a driver to the device.  If the driver binding fails
2586*7c478bd9Sstevel@tonic-gate  *	we get an rval of NDI_UNBOUD and report an error to the
2587*7c478bd9Sstevel@tonic-gate  *	syslog that the driver failed binding.
2588*7c478bd9Sstevel@tonic-gate  *	If rval is something other than NDI_UNBOUND we report an
2589*7c478bd9Sstevel@tonic-gate  *	error to the console.
2590*7c478bd9Sstevel@tonic-gate  *
2591*7c478bd9Sstevel@tonic-gate  *	This function returns USB_SUCCESS if no errors were
2592*7c478bd9Sstevel@tonic-gate  *	encountered while binding.
2593*7c478bd9Sstevel@tonic-gate  */
2594*7c478bd9Sstevel@tonic-gate int
2595*7c478bd9Sstevel@tonic-gate usba_bind_driver(dev_info_t *dip)
2596*7c478bd9Sstevel@tonic-gate {
2597*7c478bd9Sstevel@tonic-gate 	int	rval;
2598*7c478bd9Sstevel@tonic-gate 	char	*name;
2599*7c478bd9Sstevel@tonic-gate 	uint8_t if_num = usba_get_ifno(dip);
2600*7c478bd9Sstevel@tonic-gate 
2601*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
2602*7c478bd9Sstevel@tonic-gate 	    "usba_bind_driver: dip = 0x%p, if_num = 0x%x", dip, if_num);
2603*7c478bd9Sstevel@tonic-gate 
2604*7c478bd9Sstevel@tonic-gate 	name = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
2605*7c478bd9Sstevel@tonic-gate 
2606*7c478bd9Sstevel@tonic-gate 	/* bind device to the driver */
2607*7c478bd9Sstevel@tonic-gate 	if ((rval = ndi_devi_bind_driver(dip, 0)) != NDI_SUCCESS) {
2608*7c478bd9Sstevel@tonic-gate 		/* if we fail to bind report an error */
2609*7c478bd9Sstevel@tonic-gate 		(void) usba_get_mfg_prod_sn_str(dip, name, MAXNAMELEN);
2610*7c478bd9Sstevel@tonic-gate 		if (name[0] != '\0') {
2611*7c478bd9Sstevel@tonic-gate 			if (!usb_owns_device(dip)) {
2612*7c478bd9Sstevel@tonic-gate 				USB_DPRINTF_L1(DPRINT_MASK_USBA,
2613*7c478bd9Sstevel@tonic-gate 				    usba_log_handle,
2614*7c478bd9Sstevel@tonic-gate 				    "no driver found for "
2615*7c478bd9Sstevel@tonic-gate 				    "interface %d (nodename: '%s') of %s",
2616*7c478bd9Sstevel@tonic-gate 				    if_num, ddi_node_name(dip), name);
2617*7c478bd9Sstevel@tonic-gate 			} else {
2618*7c478bd9Sstevel@tonic-gate 				USB_DPRINTF_L1(DPRINT_MASK_USBA,
2619*7c478bd9Sstevel@tonic-gate 				    usba_log_handle,
2620*7c478bd9Sstevel@tonic-gate 				    "no driver found for device %s", name);
2621*7c478bd9Sstevel@tonic-gate 			}
2622*7c478bd9Sstevel@tonic-gate 		} else {
2623*7c478bd9Sstevel@tonic-gate 			(void) ddi_pathname(dip, name);
2624*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_USBA,
2625*7c478bd9Sstevel@tonic-gate 			    usba_log_handle,
2626*7c478bd9Sstevel@tonic-gate 			    "no driver found for device %s", name);
2627*7c478bd9Sstevel@tonic-gate 		}
2628*7c478bd9Sstevel@tonic-gate 
2629*7c478bd9Sstevel@tonic-gate 		kmem_free(name, MAXNAMELEN);
2630*7c478bd9Sstevel@tonic-gate 
2631*7c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
2632*7c478bd9Sstevel@tonic-gate 	}
2633*7c478bd9Sstevel@tonic-gate 	kmem_free(name, MAXNAMELEN);
2634*7c478bd9Sstevel@tonic-gate 
2635*7c478bd9Sstevel@tonic-gate 	return ((rval == NDI_SUCCESS) ? USB_SUCCESS : USB_FAILURE);
2636*7c478bd9Sstevel@tonic-gate }
2637*7c478bd9Sstevel@tonic-gate 
2638*7c478bd9Sstevel@tonic-gate 
2639*7c478bd9Sstevel@tonic-gate /*
2640*7c478bd9Sstevel@tonic-gate  * usba_get_hc_dma_attr:
2641*7c478bd9Sstevel@tonic-gate  *	function returning dma attributes of the HCD
2642*7c478bd9Sstevel@tonic-gate  *
2643*7c478bd9Sstevel@tonic-gate  * Arguments:
2644*7c478bd9Sstevel@tonic-gate  *	dip	- pointer to devinfo of the client
2645*7c478bd9Sstevel@tonic-gate  *
2646*7c478bd9Sstevel@tonic-gate  * Return Values:
2647*7c478bd9Sstevel@tonic-gate  *	hcdi_dma_attr
2648*7c478bd9Sstevel@tonic-gate  */
2649*7c478bd9Sstevel@tonic-gate ddi_dma_attr_t *
2650*7c478bd9Sstevel@tonic-gate usba_get_hc_dma_attr(dev_info_t *dip)
2651*7c478bd9Sstevel@tonic-gate {
2652*7c478bd9Sstevel@tonic-gate 	usba_device_t *usba_device = usba_get_usba_device(dip);
2653*7c478bd9Sstevel@tonic-gate 	usba_hcdi_t *hcdi = usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
2654*7c478bd9Sstevel@tonic-gate 
2655*7c478bd9Sstevel@tonic-gate 	return (hcdi->hcdi_dma_attr);
2656*7c478bd9Sstevel@tonic-gate }
2657*7c478bd9Sstevel@tonic-gate 
2658*7c478bd9Sstevel@tonic-gate 
2659*7c478bd9Sstevel@tonic-gate /*
2660*7c478bd9Sstevel@tonic-gate  * usba_check_for_leaks:
2661*7c478bd9Sstevel@tonic-gate  *	check usba_device structure for leaks
2662*7c478bd9Sstevel@tonic-gate  *
2663*7c478bd9Sstevel@tonic-gate  * Arguments:
2664*7c478bd9Sstevel@tonic-gate  *	usba_device	- usba_device structure pointer
2665*7c478bd9Sstevel@tonic-gate  */
2666*7c478bd9Sstevel@tonic-gate void
2667*7c478bd9Sstevel@tonic-gate usba_check_for_leaks(usba_device_t *usba_device)
2668*7c478bd9Sstevel@tonic-gate {
2669*7c478bd9Sstevel@tonic-gate 	int i, ph_open_cnt, req_wrp_leaks, iface;
2670*7c478bd9Sstevel@tonic-gate 	int leaks = 0;
2671*7c478bd9Sstevel@tonic-gate 
2672*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
2673*7c478bd9Sstevel@tonic-gate 	    "usba_check_for_leaks: %s%d usba_device=0x%p",
2674*7c478bd9Sstevel@tonic-gate 	    ddi_driver_name(usba_device->usb_dip),
2675*7c478bd9Sstevel@tonic-gate 	    ddi_get_instance(usba_device->usb_dip), usba_device);
2676*7c478bd9Sstevel@tonic-gate 
2677*7c478bd9Sstevel@tonic-gate 	/*
2678*7c478bd9Sstevel@tonic-gate 	 * default pipe is still open
2679*7c478bd9Sstevel@tonic-gate 	 * all other pipes should be closed
2680*7c478bd9Sstevel@tonic-gate 	 */
2681*7c478bd9Sstevel@tonic-gate 	for (ph_open_cnt = 0, i = 1; i < USBA_N_ENDPOINTS; i++) {
2682*7c478bd9Sstevel@tonic-gate 		usba_ph_impl_t *ph_impl =
2683*7c478bd9Sstevel@tonic-gate 		    &usba_device->usb_ph_list[i];
2684*7c478bd9Sstevel@tonic-gate 		if (ph_impl->usba_ph_data) {
2685*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_USBA,
2686*7c478bd9Sstevel@tonic-gate 			    usba_log_handle,
2687*7c478bd9Sstevel@tonic-gate 			    "%s%d: leaking pipehandle=0x%p (0x%p) ep_addr=0x%x",
2688*7c478bd9Sstevel@tonic-gate 			    ddi_driver_name(ph_impl->usba_ph_data->p_dip),
2689*7c478bd9Sstevel@tonic-gate 			    ddi_get_instance(ph_impl->usba_ph_data->p_dip),
2690*7c478bd9Sstevel@tonic-gate 			    ph_impl,
2691*7c478bd9Sstevel@tonic-gate 			    ph_impl->usba_ph_data,
2692*7c478bd9Sstevel@tonic-gate 			    ph_impl->usba_ph_ep.bEndpointAddress);
2693*7c478bd9Sstevel@tonic-gate 			ph_open_cnt++;
2694*7c478bd9Sstevel@tonic-gate 			leaks++;
2695*7c478bd9Sstevel@tonic-gate #ifndef DEBUG
2696*7c478bd9Sstevel@tonic-gate 			usb_pipe_close(ph_impl->usba_ph_data->p_dip,
2697*7c478bd9Sstevel@tonic-gate 			    (usb_pipe_handle_t)ph_impl, USB_FLAGS_SLEEP,
2698*7c478bd9Sstevel@tonic-gate 			    NULL, NULL);
2699*7c478bd9Sstevel@tonic-gate #endif
2700*7c478bd9Sstevel@tonic-gate 		}
2701*7c478bd9Sstevel@tonic-gate 	}
2702*7c478bd9Sstevel@tonic-gate 	req_wrp_leaks =  usba_list_entry_leaks(&usba_device->
2703*7c478bd9Sstevel@tonic-gate 	    usb_allocated, "request wrappers");
2704*7c478bd9Sstevel@tonic-gate 
2705*7c478bd9Sstevel@tonic-gate 	ASSERT(ph_open_cnt == 0);
2706*7c478bd9Sstevel@tonic-gate 	ASSERT(req_wrp_leaks == 0);
2707*7c478bd9Sstevel@tonic-gate 
2708*7c478bd9Sstevel@tonic-gate 	if (req_wrp_leaks) {
2709*7c478bd9Sstevel@tonic-gate 		usba_list_entry_t *entry;
2710*7c478bd9Sstevel@tonic-gate 
2711*7c478bd9Sstevel@tonic-gate 		while ((entry = usba_rm_first_from_list(
2712*7c478bd9Sstevel@tonic-gate 		    &usba_device->usb_allocated)) != NULL) {
2713*7c478bd9Sstevel@tonic-gate 			usba_req_wrapper_t *wrp;
2714*7c478bd9Sstevel@tonic-gate 
2715*7c478bd9Sstevel@tonic-gate 			mutex_enter(&entry->list_mutex);
2716*7c478bd9Sstevel@tonic-gate 			wrp = (usba_req_wrapper_t *)entry->private;
2717*7c478bd9Sstevel@tonic-gate 			mutex_exit(&entry->list_mutex);
2718*7c478bd9Sstevel@tonic-gate 			leaks++;
2719*7c478bd9Sstevel@tonic-gate 
2720*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_USBA,
2721*7c478bd9Sstevel@tonic-gate 			    usba_log_handle,
2722*7c478bd9Sstevel@tonic-gate 			    "%s%d: leaking request 0x%p",
2723*7c478bd9Sstevel@tonic-gate 			    ddi_driver_name(wrp->wr_dip),
2724*7c478bd9Sstevel@tonic-gate 			    ddi_get_instance(wrp->wr_dip),
2725*7c478bd9Sstevel@tonic-gate 			    wrp->wr_req);
2726*7c478bd9Sstevel@tonic-gate 
2727*7c478bd9Sstevel@tonic-gate 			/*
2728*7c478bd9Sstevel@tonic-gate 			 * put it back, usba_req_wrapper_free
2729*7c478bd9Sstevel@tonic-gate 			 * expects it on the list
2730*7c478bd9Sstevel@tonic-gate 			 */
2731*7c478bd9Sstevel@tonic-gate 			usba_add_to_list(&usba_device->usb_allocated,
2732*7c478bd9Sstevel@tonic-gate 			    &wrp->wr_allocated_list);
2733*7c478bd9Sstevel@tonic-gate 
2734*7c478bd9Sstevel@tonic-gate 			usba_req_wrapper_free(wrp);
2735*7c478bd9Sstevel@tonic-gate 		}
2736*7c478bd9Sstevel@tonic-gate 	}
2737*7c478bd9Sstevel@tonic-gate 
2738*7c478bd9Sstevel@tonic-gate 	mutex_enter(&usba_device->usb_mutex);
2739*7c478bd9Sstevel@tonic-gate 	for (iface = 0; iface < usba_device->usb_n_ifs; iface++) {
2740*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
2741*7c478bd9Sstevel@tonic-gate 		    "usba_check_for_leaks: if=%d client_flags=0x%x",
2742*7c478bd9Sstevel@tonic-gate 		    iface, usba_device->usb_client_flags[iface]);
2743*7c478bd9Sstevel@tonic-gate 
2744*7c478bd9Sstevel@tonic-gate 		if (usba_device->usb_client_flags[iface] &
2745*7c478bd9Sstevel@tonic-gate 		    USBA_CLIENT_FLAG_DEV_DATA) {
2746*7c478bd9Sstevel@tonic-gate 			usb_client_dev_data_list_t *entry =
2747*7c478bd9Sstevel@tonic-gate 			    usba_device->usb_client_dev_data_list.cddl_next;
2748*7c478bd9Sstevel@tonic-gate 			usb_client_dev_data_list_t *next;
2749*7c478bd9Sstevel@tonic-gate 			usb_client_dev_data_t *dev_data;
2750*7c478bd9Sstevel@tonic-gate 
2751*7c478bd9Sstevel@tonic-gate 			while (entry) {
2752*7c478bd9Sstevel@tonic-gate 				dev_info_t *dip = entry->cddl_dip;
2753*7c478bd9Sstevel@tonic-gate 				next = entry->cddl_next;
2754*7c478bd9Sstevel@tonic-gate 				dev_data = entry->cddl_dev_data;
2755*7c478bd9Sstevel@tonic-gate 
2756*7c478bd9Sstevel@tonic-gate 
2757*7c478bd9Sstevel@tonic-gate 				if (i_ddi_node_state(dip) < DS_ATTACHED) {
2758*7c478bd9Sstevel@tonic-gate 					USB_DPRINTF_L1(DPRINT_MASK_USBA,
2759*7c478bd9Sstevel@tonic-gate 					    usba_log_handle,
2760*7c478bd9Sstevel@tonic-gate 					    "%s%d: leaking dev_data 0x%p",
2761*7c478bd9Sstevel@tonic-gate 					    ddi_driver_name(dip),
2762*7c478bd9Sstevel@tonic-gate 					    ddi_get_instance(dip),
2763*7c478bd9Sstevel@tonic-gate 					    (void *)dev_data);
2764*7c478bd9Sstevel@tonic-gate 
2765*7c478bd9Sstevel@tonic-gate 					leaks++;
2766*7c478bd9Sstevel@tonic-gate 
2767*7c478bd9Sstevel@tonic-gate 					mutex_exit(&usba_device->usb_mutex);
2768*7c478bd9Sstevel@tonic-gate 					usb_free_dev_data(dip, dev_data);
2769*7c478bd9Sstevel@tonic-gate 					mutex_enter(&usba_device->usb_mutex);
2770*7c478bd9Sstevel@tonic-gate 				}
2771*7c478bd9Sstevel@tonic-gate 
2772*7c478bd9Sstevel@tonic-gate 				entry = next;
2773*7c478bd9Sstevel@tonic-gate 			}
2774*7c478bd9Sstevel@tonic-gate 		}
2775*7c478bd9Sstevel@tonic-gate 		if (usba_device->usb_client_flags[iface] &
2776*7c478bd9Sstevel@tonic-gate 		    USBA_CLIENT_FLAG_ATTACH) {
2777*7c478bd9Sstevel@tonic-gate 			dev_info_t *dip = usba_device->
2778*7c478bd9Sstevel@tonic-gate 				usb_client_attach_list[iface].dip;
2779*7c478bd9Sstevel@tonic-gate 
2780*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_USBA,
2781*7c478bd9Sstevel@tonic-gate 			    usba_log_handle,
2782*7c478bd9Sstevel@tonic-gate 			    "%s%d: did no usb_client_detach",
2783*7c478bd9Sstevel@tonic-gate 			    ddi_driver_name(dip), ddi_get_instance(dip));
2784*7c478bd9Sstevel@tonic-gate 			leaks++;
2785*7c478bd9Sstevel@tonic-gate 
2786*7c478bd9Sstevel@tonic-gate 			mutex_exit(&usba_device->usb_mutex);
2787*7c478bd9Sstevel@tonic-gate 			usb_client_detach(dip, NULL);
2788*7c478bd9Sstevel@tonic-gate 			mutex_enter(&usba_device->usb_mutex);
2789*7c478bd9Sstevel@tonic-gate 
2790*7c478bd9Sstevel@tonic-gate 			usba_device->
2791*7c478bd9Sstevel@tonic-gate 			    usb_client_attach_list[iface].dip = NULL;
2792*7c478bd9Sstevel@tonic-gate 
2793*7c478bd9Sstevel@tonic-gate 			usba_device->usb_client_flags[iface] &=
2794*7c478bd9Sstevel@tonic-gate 			    ~USBA_CLIENT_FLAG_ATTACH;
2795*7c478bd9Sstevel@tonic-gate 
2796*7c478bd9Sstevel@tonic-gate 		}
2797*7c478bd9Sstevel@tonic-gate 		if (usba_device->usb_client_flags[iface] &
2798*7c478bd9Sstevel@tonic-gate 		    USBA_CLIENT_FLAG_EV_CBS) {
2799*7c478bd9Sstevel@tonic-gate 			dev_info_t *dip =
2800*7c478bd9Sstevel@tonic-gate 			    usba_device->usb_client_ev_cb_list[iface].
2801*7c478bd9Sstevel@tonic-gate 							dip;
2802*7c478bd9Sstevel@tonic-gate 			usb_event_t *ev_data =
2803*7c478bd9Sstevel@tonic-gate 			    usba_device->usb_client_ev_cb_list[iface].
2804*7c478bd9Sstevel@tonic-gate 							ev_data;
2805*7c478bd9Sstevel@tonic-gate 
2806*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_USBA,
2807*7c478bd9Sstevel@tonic-gate 			    usba_log_handle,
2808*7c478bd9Sstevel@tonic-gate 			    "%s%d: did no usb_unregister_event_cbs",
2809*7c478bd9Sstevel@tonic-gate 			    ddi_driver_name(dip), ddi_get_instance(dip));
2810*7c478bd9Sstevel@tonic-gate 			leaks++;
2811*7c478bd9Sstevel@tonic-gate 
2812*7c478bd9Sstevel@tonic-gate 			mutex_exit(&usba_device->usb_mutex);
2813*7c478bd9Sstevel@tonic-gate 			usb_unregister_event_cbs(dip, ev_data);
2814*7c478bd9Sstevel@tonic-gate 			mutex_enter(&usba_device->usb_mutex);
2815*7c478bd9Sstevel@tonic-gate 
2816*7c478bd9Sstevel@tonic-gate 			usba_device->usb_client_ev_cb_list[iface].
2817*7c478bd9Sstevel@tonic-gate 					dip = NULL;
2818*7c478bd9Sstevel@tonic-gate 			usba_device->usb_client_ev_cb_list[iface].
2819*7c478bd9Sstevel@tonic-gate 					ev_data = NULL;
2820*7c478bd9Sstevel@tonic-gate 			usba_device->usb_client_flags[iface] &=
2821*7c478bd9Sstevel@tonic-gate 			    ~USBA_CLIENT_FLAG_EV_CBS;
2822*7c478bd9Sstevel@tonic-gate 		}
2823*7c478bd9Sstevel@tonic-gate 	}
2824*7c478bd9Sstevel@tonic-gate 	mutex_exit(&usba_device->usb_mutex);
2825*7c478bd9Sstevel@tonic-gate 
2826*7c478bd9Sstevel@tonic-gate 	if (leaks) {
2827*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_USBA, usba_log_handle,
2828*7c478bd9Sstevel@tonic-gate 		    "all %d leaks fixed", leaks);
2829*7c478bd9Sstevel@tonic-gate 	}
2830*7c478bd9Sstevel@tonic-gate }
2831