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