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