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