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