xref: /titanic_50/usr/src/uts/common/io/usb/usba/usba.c (revision e2c88f0c2610f16de7b639746b40dea5f3e2256e)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5cbab2b26Slg150142  * Common Development and Distribution License (the "License").
6cbab2b26Slg150142  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22de6f998eSrui wang - Sun Microsystems - Beijing China  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
24*e2c88f0cSGarrett D'Amore  *
25*e2c88f0cSGarrett D'Amore  * Copyright 2014 Garrett D'Amore <garrett@damore.org>
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate  * USBA: Solaris USB Architecture support
317c478bd9Sstevel@tonic-gate  */
327c478bd9Sstevel@tonic-gate #define	USBA_FRAMEWORK
337c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usba_impl.h>
347c478bd9Sstevel@tonic-gate #include <sys/usb/usba/hcdi_impl.h>
357c478bd9Sstevel@tonic-gate #include <sys/usb/hubd/hub.h>
367c478bd9Sstevel@tonic-gate #include <sys/fs/dv_node.h>
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate static int usba_str_startcmp(char *, char *);
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate /*
417c478bd9Sstevel@tonic-gate  * USBA private variables and tunables
427c478bd9Sstevel@tonic-gate  */
437c478bd9Sstevel@tonic-gate static kmutex_t	usba_mutex;
447c478bd9Sstevel@tonic-gate 
45de6f998eSrui wang - Sun Microsystems - Beijing China /* mutex to protect usba_root_hubs */
46de6f998eSrui wang - Sun Microsystems - Beijing China static kmutex_t usba_hub_mutex;
47de6f998eSrui wang - Sun Microsystems - Beijing China 
48de6f998eSrui wang - Sun Microsystems - Beijing China typedef struct usba_root_hub_ent {
49de6f998eSrui wang - Sun Microsystems - Beijing China 	dev_info_t *dip;
50de6f998eSrui wang - Sun Microsystems - Beijing China 	struct usba_root_hub_ent *next;
51de6f998eSrui wang - Sun Microsystems - Beijing China }usba_root_hub_ent_t;
52de6f998eSrui wang - Sun Microsystems - Beijing China 
53de6f998eSrui wang - Sun Microsystems - Beijing China static usba_root_hub_ent_t *usba_root_hubs = NULL;
54de6f998eSrui wang - Sun Microsystems - Beijing China 
557c478bd9Sstevel@tonic-gate /*
567c478bd9Sstevel@tonic-gate  * ddivs forced binding:
577c478bd9Sstevel@tonic-gate  *
587c478bd9Sstevel@tonic-gate  *    usbc usbc_xhubs usbc_xaddress  node name
597c478bd9Sstevel@tonic-gate  *
607c478bd9Sstevel@tonic-gate  *	0	x	x	class name or "device"
617c478bd9Sstevel@tonic-gate  *
627c478bd9Sstevel@tonic-gate  *	1	0	0	ddivs_usbc
637c478bd9Sstevel@tonic-gate  *	1	0	>1	ddivs_usbc except device
647c478bd9Sstevel@tonic-gate  *				at usbc_xaddress
657c478bd9Sstevel@tonic-gate  *	1	1	0	ddivs_usbc except hubs
667c478bd9Sstevel@tonic-gate  *	1	1	>1	ddivs_usbc except hubs and
677c478bd9Sstevel@tonic-gate  *				device at usbc_xaddress
687c478bd9Sstevel@tonic-gate  */
697c478bd9Sstevel@tonic-gate uint_t usba_ddivs_usbc;
707c478bd9Sstevel@tonic-gate uint_t usba_ddivs_usbc_xhubs;
717c478bd9Sstevel@tonic-gate uint_t usba_ddivs_usbc_xaddress;
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate uint_t usba_ugen_force_binding;
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate /*
767c478bd9Sstevel@tonic-gate  * compatible name handling
777c478bd9Sstevel@tonic-gate  */
78a7df97baSStrony Zhang - Solaris China Team /*
79a7df97baSStrony Zhang - Solaris China Team  * allowing for 15 compat names, plus one force bind name and
80a7df97baSStrony Zhang - Solaris China Team  * one possible specified client driver name
81a7df97baSStrony Zhang - Solaris China Team  */
82a7df97baSStrony Zhang - Solaris China Team #define	USBA_MAX_COMPAT_NAMES		17
837c478bd9Sstevel@tonic-gate #define	USBA_MAX_COMPAT_NAME_LEN	64
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate /* double linked list for usba_devices */
867c478bd9Sstevel@tonic-gate usba_list_entry_t	usba_device_list;
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate _NOTE(MUTEX_PROTECTS_DATA(usba_mutex, usba_device_list))
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate /*
917c478bd9Sstevel@tonic-gate  * modload support
927c478bd9Sstevel@tonic-gate  */
937c478bd9Sstevel@tonic-gate 
94e8ed0869SJohn Beck static struct modlmisc modlmisc	= {
957c478bd9Sstevel@tonic-gate 	&mod_miscops,	/* Type	of module */
96d73ae94eSgc161489 	"USBA: USB Architecture 2.0 1.66"
977c478bd9Sstevel@tonic-gate };
987c478bd9Sstevel@tonic-gate 
99e8ed0869SJohn Beck static struct modlinkage modlinkage = {
1007c478bd9Sstevel@tonic-gate 	MODREV_1, (void	*)&modlmisc, NULL
1017c478bd9Sstevel@tonic-gate };
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate static usb_log_handle_t	usba_log_handle;
1054610e4a0Sfrits uint_t		usba_errlevel = USB_LOG_L4;
1064610e4a0Sfrits uint_t		usba_errmask = (uint_t)-1;
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate extern usb_log_handle_t	hubdi_log_handle;
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate int
_init(void)1117c478bd9Sstevel@tonic-gate _init(void)
1127c478bd9Sstevel@tonic-gate {
1133c91d182Slg150142 	int rval;
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate 	/*
1167c478bd9Sstevel@tonic-gate 	 * usbai providing log support needs to be init'ed first
1177c478bd9Sstevel@tonic-gate 	 * and destroyed last
1187c478bd9Sstevel@tonic-gate 	 */
1197c478bd9Sstevel@tonic-gate 	usba_usbai_initialization();
1207c478bd9Sstevel@tonic-gate 	usba_usba_initialization();
1217c478bd9Sstevel@tonic-gate 	usba_usbai_register_initialization();
1227c478bd9Sstevel@tonic-gate 	usba_hcdi_initialization();
1237c478bd9Sstevel@tonic-gate 	usba_hubdi_initialization();
1247c478bd9Sstevel@tonic-gate 	usba_devdb_initialization();
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate 	if ((rval = mod_install(&modlinkage)) != 0) {
1277c478bd9Sstevel@tonic-gate 		usba_devdb_destroy();
1287c478bd9Sstevel@tonic-gate 		usba_hubdi_destroy();
1297c478bd9Sstevel@tonic-gate 		usba_hcdi_destroy();
1307c478bd9Sstevel@tonic-gate 		usba_usbai_register_destroy();
1317c478bd9Sstevel@tonic-gate 		usba_usba_destroy();
1327c478bd9Sstevel@tonic-gate 		usba_usbai_destroy();
1337c478bd9Sstevel@tonic-gate 	}
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate 	return (rval);
1367c478bd9Sstevel@tonic-gate }
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate int
_fini()1397c478bd9Sstevel@tonic-gate _fini()
1407c478bd9Sstevel@tonic-gate {
1417c478bd9Sstevel@tonic-gate 	int rval;
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate 	if ((rval = mod_remove(&modlinkage)) == 0) {
1447c478bd9Sstevel@tonic-gate 		usba_devdb_destroy();
1457c478bd9Sstevel@tonic-gate 		usba_hubdi_destroy();
1467c478bd9Sstevel@tonic-gate 		usba_hcdi_destroy();
1477c478bd9Sstevel@tonic-gate 		usba_usbai_register_destroy();
1487c478bd9Sstevel@tonic-gate 		usba_usba_destroy();
1497c478bd9Sstevel@tonic-gate 		usba_usbai_destroy();
1507c478bd9Sstevel@tonic-gate 	}
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate 	return (rval);
1537c478bd9Sstevel@tonic-gate }
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)1567c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
1577c478bd9Sstevel@tonic-gate {
1587c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
1597c478bd9Sstevel@tonic-gate }
1607c478bd9Sstevel@tonic-gate 
161d73ae94eSgc161489 boolean_t
usba_owns_ia(dev_info_t * dip)162d73ae94eSgc161489 usba_owns_ia(dev_info_t *dip)
163d73ae94eSgc161489 {
164d73ae94eSgc161489 	int if_count = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
165d73ae94eSgc161489 	    "interface-count", 0);
166d73ae94eSgc161489 
167d73ae94eSgc161489 	return ((if_count) ? B_TRUE : B_FALSE);
168d73ae94eSgc161489 }
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate /*
1717c478bd9Sstevel@tonic-gate  * common bus ctl for hcd, usb_mid, and hubd
1727c478bd9Sstevel@tonic-gate  */
1737c478bd9Sstevel@tonic-gate int
usba_bus_ctl(dev_info_t * dip,dev_info_t * rdip,ddi_ctl_enum_t op,void * arg,void * result)1747c478bd9Sstevel@tonic-gate usba_bus_ctl(dev_info_t	*dip,
1757c478bd9Sstevel@tonic-gate 	dev_info_t		*rdip,
1767c478bd9Sstevel@tonic-gate 	ddi_ctl_enum_t		op,
1777c478bd9Sstevel@tonic-gate 	void			*arg,
1787c478bd9Sstevel@tonic-gate 	void			*result)
1797c478bd9Sstevel@tonic-gate {
1807c478bd9Sstevel@tonic-gate 	dev_info_t		*child_dip = (dev_info_t *)arg;
1817c478bd9Sstevel@tonic-gate 	usba_device_t		*usba_device;
1827c478bd9Sstevel@tonic-gate 	usba_hcdi_t		*usba_hcdi;
1837c478bd9Sstevel@tonic-gate 	usba_hcdi_ops_t		*usba_hcdi_ops;
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, hubdi_log_handle,
1867c478bd9Sstevel@tonic-gate 	    "usba_bus_ctl: %s%d %s%d op=%d", ddi_node_name(rdip),
1877c478bd9Sstevel@tonic-gate 	    ddi_get_instance(rdip), ddi_node_name(dip),
1887c478bd9Sstevel@tonic-gate 	    ddi_get_instance(dip), op);
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate 	switch (op) {
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_REPORTDEV:
1937c478bd9Sstevel@tonic-gate 	{
1947c478bd9Sstevel@tonic-gate 		char *name, compat_name[64], *speed;
1957c478bd9Sstevel@tonic-gate 		usba_device_t	*hub_usba_device;
1967c478bd9Sstevel@tonic-gate 		dev_info_t	*hubdip;
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate 		usba_device = usba_get_usba_device(rdip);
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate 		/* find the parent hub */
2017c478bd9Sstevel@tonic-gate 		hubdip = ddi_get_parent(rdip);
2027c478bd9Sstevel@tonic-gate 		while ((strcmp(ddi_driver_name(hubdip), "hubd") != 0) &&
2037c478bd9Sstevel@tonic-gate 		    !(usba_is_root_hub(hubdip))) {
2047c478bd9Sstevel@tonic-gate 			hubdip = ddi_get_parent(hubdip);
2057c478bd9Sstevel@tonic-gate 		}
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 		hub_usba_device = usba_get_usba_device(hubdip);
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 		if (usba_device) {
2107c478bd9Sstevel@tonic-gate 			if (usb_owns_device(rdip)) {
2117c478bd9Sstevel@tonic-gate 				(void) snprintf(compat_name,
2127c478bd9Sstevel@tonic-gate 				    sizeof (compat_name),
2137c478bd9Sstevel@tonic-gate 				    "usb%x,%x",
2147c478bd9Sstevel@tonic-gate 				    usba_device->usb_dev_descr->idVendor,
2157c478bd9Sstevel@tonic-gate 				    usba_device->usb_dev_descr->idProduct);
216d73ae94eSgc161489 			} else if (usba_owns_ia(rdip)) {
217d73ae94eSgc161489 				(void) snprintf(compat_name,
218d73ae94eSgc161489 				    sizeof (compat_name),
219d73ae94eSgc161489 				    "usbia%x,%x.config%x.%x",
220d73ae94eSgc161489 				    usba_device->usb_dev_descr->idVendor,
221d73ae94eSgc161489 				    usba_device->usb_dev_descr->idProduct,
222d73ae94eSgc161489 				    usba_device->usb_cfg_value,
223d73ae94eSgc161489 				    usb_get_if_number(rdip));
2247c478bd9Sstevel@tonic-gate 			} else {
2257c478bd9Sstevel@tonic-gate 				(void) snprintf(compat_name,
2267c478bd9Sstevel@tonic-gate 				    sizeof (compat_name),
2277c478bd9Sstevel@tonic-gate 				    "usbif%x,%x.config%x.%x",
2287c478bd9Sstevel@tonic-gate 				    usba_device->usb_dev_descr->idVendor,
2297c478bd9Sstevel@tonic-gate 				    usba_device->usb_dev_descr->idProduct,
2307c478bd9Sstevel@tonic-gate 				    usba_device->usb_cfg_value,
2317c478bd9Sstevel@tonic-gate 				    usb_get_if_number(rdip));
2327c478bd9Sstevel@tonic-gate 			}
2337c478bd9Sstevel@tonic-gate 			switch (usba_device->usb_port_status) {
2347c478bd9Sstevel@tonic-gate 			case USBA_HIGH_SPEED_DEV:
2357c478bd9Sstevel@tonic-gate 				speed = "hi speed (USB 2.x)";
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate 				break;
2387c478bd9Sstevel@tonic-gate 			case USBA_LOW_SPEED_DEV:
2397c478bd9Sstevel@tonic-gate 				speed = "low speed (USB 1.x)";
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate 				break;
2427c478bd9Sstevel@tonic-gate 			case USBA_FULL_SPEED_DEV:
2437c478bd9Sstevel@tonic-gate 			default:
2447c478bd9Sstevel@tonic-gate 				speed = "full speed (USB 1.x)";
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate 				break;
2477c478bd9Sstevel@tonic-gate 			}
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT,
2507c478bd9Sstevel@tonic-gate 			    "?USB %x.%x %s (%s) operating at %s on "
2517c478bd9Sstevel@tonic-gate 			    "USB %x.%x %s hub: "
2527c478bd9Sstevel@tonic-gate 			    "%s@%s, %s%d at bus address %d\n",
2537c478bd9Sstevel@tonic-gate 			    (usba_device->usb_dev_descr->bcdUSB & 0xff00) >> 8,
2547c478bd9Sstevel@tonic-gate 			    usba_device->usb_dev_descr->bcdUSB & 0xff,
255d73ae94eSgc161489 			    (usb_owns_device(rdip) ? "device" :
256d73ae94eSgc161489 			    ((usba_owns_ia(rdip) ? "interface-association" :
257d73ae94eSgc161489 			    "interface"))),
2587c478bd9Sstevel@tonic-gate 			    compat_name, speed,
2597c478bd9Sstevel@tonic-gate 			    (hub_usba_device->usb_dev_descr->bcdUSB &
2607c478bd9Sstevel@tonic-gate 			    0xff00) >> 8,
2617c478bd9Sstevel@tonic-gate 			    hub_usba_device->usb_dev_descr->bcdUSB & 0xff,
2627c478bd9Sstevel@tonic-gate 			    usba_is_root_hub(hubdip) ? "root" : "external",
2637c478bd9Sstevel@tonic-gate 			    ddi_node_name(rdip), ddi_get_name_addr(rdip),
2647c478bd9Sstevel@tonic-gate 			    ddi_driver_name(rdip),
2657c478bd9Sstevel@tonic-gate 			    ddi_get_instance(rdip), usba_device->usb_addr);
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate 			name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
2687c478bd9Sstevel@tonic-gate 			(void) usba_get_mfg_prod_sn_str(rdip, name, MAXNAMELEN);
2697c478bd9Sstevel@tonic-gate 			if (name[0] != '\0') {
2707c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "?\t%s\n", name);
2717c478bd9Sstevel@tonic-gate 			}
2727c478bd9Sstevel@tonic-gate 			kmem_free(name, MAXNAMELEN);
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 		} else { /* harden USBA against this case; if it happens */
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT,
2777c478bd9Sstevel@tonic-gate 			    "?USB-device: %s@%s, %s%d\n",
2787c478bd9Sstevel@tonic-gate 			    ddi_node_name(rdip), ddi_get_name_addr(rdip),
2797c478bd9Sstevel@tonic-gate 			    ddi_driver_name(rdip), ddi_get_instance(rdip));
2807c478bd9Sstevel@tonic-gate 		}
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
2837c478bd9Sstevel@tonic-gate 	}
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_INITCHILD:
2867c478bd9Sstevel@tonic-gate 	{
2877c478bd9Sstevel@tonic-gate 		int			usb_addr;
2887c478bd9Sstevel@tonic-gate 		uint_t			n;
2897c478bd9Sstevel@tonic-gate 		char			name[32];
2907c478bd9Sstevel@tonic-gate 		int			*data;
2917c478bd9Sstevel@tonic-gate 		int			rval;
2927c478bd9Sstevel@tonic-gate 		int			len = sizeof (usb_addr);
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 		usba_hcdi	= usba_hcdi_get_hcdi(dip);
2957c478bd9Sstevel@tonic-gate 		usba_hcdi_ops	= usba_hcdi->hcdi_ops;
2967c478bd9Sstevel@tonic-gate 		ASSERT(usba_hcdi_ops != NULL);
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 		/*
2997c478bd9Sstevel@tonic-gate 		 * as long as the dip exists, it should have
3007c478bd9Sstevel@tonic-gate 		 * usba_device structure associated with it
3017c478bd9Sstevel@tonic-gate 		 */
3027c478bd9Sstevel@tonic-gate 		usba_device = usba_get_usba_device(child_dip);
3037c478bd9Sstevel@tonic-gate 		if (usba_device == NULL) {
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_USBA, hubdi_log_handle,
3067c478bd9Sstevel@tonic-gate 			    "usba_bus_ctl: DDI_NOT_WELL_FORMED (%s (0x%p))",
3077c478bd9Sstevel@tonic-gate 			    ddi_node_name(child_dip), (void *)child_dip);
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 			return (DDI_NOT_WELL_FORMED);
3107c478bd9Sstevel@tonic-gate 		}
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 		/* the dip should have an address and reg property */
3137c478bd9Sstevel@tonic-gate 		if (ddi_prop_op(DDI_DEV_T_NONE, child_dip, PROP_LEN_AND_VAL_BUF,
3147c478bd9Sstevel@tonic-gate 		    DDI_PROP_DONTPASS |	DDI_PROP_CANSLEEP, "assigned-address",
3157c478bd9Sstevel@tonic-gate 		    (caddr_t)&usb_addr,	&len) != DDI_SUCCESS) {
3167c478bd9Sstevel@tonic-gate 
317d291d9f2Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_USBA, hubdi_log_handle,
3187c478bd9Sstevel@tonic-gate 			    "usba_bus_ctl:\n\t"
3197c478bd9Sstevel@tonic-gate 			    "%s%d %s%d op=%d rdip = 0x%p dip = 0x%p",
3207c478bd9Sstevel@tonic-gate 			    ddi_node_name(rdip), ddi_get_instance(rdip),
3217c478bd9Sstevel@tonic-gate 			    ddi_node_name(dip), ddi_get_instance(dip), op,
322112116d8Sfb209375 			    (void *)rdip, (void *)dip);
3237c478bd9Sstevel@tonic-gate 
324d291d9f2Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_USBA, hubdi_log_handle,
3257c478bd9Sstevel@tonic-gate 			    "usba_bus_ctl: DDI_NOT_WELL_FORMED (%s (0x%p))",
3267c478bd9Sstevel@tonic-gate 			    ddi_node_name(child_dip), (void *)child_dip);
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 			return (DDI_NOT_WELL_FORMED);
3297c478bd9Sstevel@tonic-gate 		}
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 		if ((rval = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child_dip,
3327c478bd9Sstevel@tonic-gate 		    DDI_PROP_DONTPASS, "reg",
3337c478bd9Sstevel@tonic-gate 		    &data, &n)) != DDI_SUCCESS) {
3347c478bd9Sstevel@tonic-gate 
335d291d9f2Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_USBA, hubdi_log_handle,
3367c478bd9Sstevel@tonic-gate 			    "usba_bus_ctl: %d, DDI_NOT_WELL_FORMED", rval);
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 			return (DDI_NOT_WELL_FORMED);
3397c478bd9Sstevel@tonic-gate 		}
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 		/*
3437c478bd9Sstevel@tonic-gate 		 * if the configuration is 1, the unit address is
3447c478bd9Sstevel@tonic-gate 		 * just the interface number
3457c478bd9Sstevel@tonic-gate 		 */
3467c478bd9Sstevel@tonic-gate 		if ((n == 1) || ((n > 1) && (data[1] == 1))) {
3477c478bd9Sstevel@tonic-gate 			(void) sprintf(name, "%x", data[0]);
3487c478bd9Sstevel@tonic-gate 		} else {
3497c478bd9Sstevel@tonic-gate 			(void) sprintf(name, "%x,%x", data[0], data[1]);
3507c478bd9Sstevel@tonic-gate 		}
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(DPRINT_MASK_USBA,
3537c478bd9Sstevel@tonic-gate 		    hubdi_log_handle, "usba_bus_ctl: name = %s", name);
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate 		ddi_prop_free(data);
3567c478bd9Sstevel@tonic-gate 		ddi_set_name_addr(child_dip, name);
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 		/*
3597c478bd9Sstevel@tonic-gate 		 * increment the reference count for each child using this
3607c478bd9Sstevel@tonic-gate 		 * usba_device structure
3617c478bd9Sstevel@tonic-gate 		 */
3627c478bd9Sstevel@tonic-gate 		mutex_enter(&usba_device->usb_mutex);
3637c478bd9Sstevel@tonic-gate 		usba_device->usb_ref_count++;
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(DPRINT_MASK_USBA, hubdi_log_handle,
3667c478bd9Sstevel@tonic-gate 		    "usba_bus_ctl: init usba_device = 0x%p ref_count = %d",
3677c478bd9Sstevel@tonic-gate 		    (void *)usba_device, usba_device->usb_ref_count);
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
3727c478bd9Sstevel@tonic-gate 	}
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_UNINITCHILD:
3757c478bd9Sstevel@tonic-gate 	{
3767c478bd9Sstevel@tonic-gate 		usba_device = usba_get_usba_device(child_dip);
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate 		if (usba_device != NULL) {
3797c478bd9Sstevel@tonic-gate 			/*
3807c478bd9Sstevel@tonic-gate 			 * decrement the reference count for each child
3817c478bd9Sstevel@tonic-gate 			 * using this  usba_device structure
3827c478bd9Sstevel@tonic-gate 			 */
3837c478bd9Sstevel@tonic-gate 			mutex_enter(&usba_device->usb_mutex);
3847c478bd9Sstevel@tonic-gate 			usba_device->usb_ref_count--;
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L3(DPRINT_MASK_USBA, hubdi_log_handle,
3877c478bd9Sstevel@tonic-gate 			    "usba_hcdi_bus_ctl: uninit usba_device=0x%p "
3887c478bd9Sstevel@tonic-gate 			    "ref_count=%d",
389112116d8Sfb209375 			    (void *)usba_device, usba_device->usb_ref_count);
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 			mutex_exit(&usba_device->usb_mutex);
3927c478bd9Sstevel@tonic-gate 		}
3937c478bd9Sstevel@tonic-gate 		ddi_set_name_addr(child_dip, NULL);
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
3967c478bd9Sstevel@tonic-gate 	}
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_IOMIN:
3997c478bd9Sstevel@tonic-gate 		/* Do nothing */
4007c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 	/*
4037c478bd9Sstevel@tonic-gate 	 * These ops correspond	to functions that "shouldn't" be called
4047c478bd9Sstevel@tonic-gate 	 * by a	USB client driver.  So	we whine when we're called.
4057c478bd9Sstevel@tonic-gate 	 */
4067c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_DMAPMAPC:
4077c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_REPORTINT:
4087c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_REGSIZE:
4097c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_NREGS:
4107c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_SIDDEV:
4117c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_SLAVEONLY:
4127c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_AFFINITY:
4137c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_POKE:
4147c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_PEEK:
4157c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "%s%d:	invalid	op (%d)	from %s%d",
4167c478bd9Sstevel@tonic-gate 		    ddi_node_name(dip), ddi_get_instance(dip),
4177c478bd9Sstevel@tonic-gate 		    op, ddi_node_name(rdip), ddi_get_instance(rdip));
4187c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate 	/*
4217c478bd9Sstevel@tonic-gate 	 * Everything else (e.g. PTOB/BTOP/BTOPR requests) we pass up
4227c478bd9Sstevel@tonic-gate 	 */
4237c478bd9Sstevel@tonic-gate 	default:
4247c478bd9Sstevel@tonic-gate 		return (ddi_ctlops(dip,	rdip, op, arg, result));
4257c478bd9Sstevel@tonic-gate 	}
4267c478bd9Sstevel@tonic-gate }
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate /*
4307c478bd9Sstevel@tonic-gate  * initialize and destroy USBA module
4317c478bd9Sstevel@tonic-gate  */
4327c478bd9Sstevel@tonic-gate void
usba_usba_initialization()4337c478bd9Sstevel@tonic-gate usba_usba_initialization()
4347c478bd9Sstevel@tonic-gate {
4357c478bd9Sstevel@tonic-gate 	usba_log_handle = usb_alloc_log_hdl(NULL, "usba", &usba_errlevel,
4367c478bd9Sstevel@tonic-gate 	    &usba_errmask, NULL, 0);
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA,
4397c478bd9Sstevel@tonic-gate 	    usba_log_handle, "usba_usba_initialization");
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 	mutex_init(&usba_mutex, NULL, MUTEX_DRIVER, NULL);
442de6f998eSrui wang - Sun Microsystems - Beijing China 	mutex_init(&usba_hub_mutex, NULL, MUTEX_DRIVER, NULL);
4437c478bd9Sstevel@tonic-gate 	usba_init_list(&usba_device_list, NULL, NULL);
4447c478bd9Sstevel@tonic-gate }
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate void
usba_usba_destroy()4487c478bd9Sstevel@tonic-gate usba_usba_destroy()
4497c478bd9Sstevel@tonic-gate {
4507c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle, "usba_usba_destroy");
4517c478bd9Sstevel@tonic-gate 
452de6f998eSrui wang - Sun Microsystems - Beijing China 	mutex_destroy(&usba_hub_mutex);
4537c478bd9Sstevel@tonic-gate 	mutex_destroy(&usba_mutex);
4547c478bd9Sstevel@tonic-gate 	usba_destroy_list(&usba_device_list);
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate 	usb_free_log_hdl(usba_log_handle);
4577c478bd9Sstevel@tonic-gate }
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate /*
4617c478bd9Sstevel@tonic-gate  * usba_set_usb_address:
4627c478bd9Sstevel@tonic-gate  *	set usb address in usba_device structure
4637c478bd9Sstevel@tonic-gate  */
4647c478bd9Sstevel@tonic-gate int
usba_set_usb_address(usba_device_t * usba_device)4657c478bd9Sstevel@tonic-gate usba_set_usb_address(usba_device_t *usba_device)
4667c478bd9Sstevel@tonic-gate {
4677c478bd9Sstevel@tonic-gate 	usb_addr_t address;
4687c478bd9Sstevel@tonic-gate 	uchar_t s = 8;
4697c478bd9Sstevel@tonic-gate 	usba_hcdi_t *hcdi;
4707c478bd9Sstevel@tonic-gate 	char *usb_address_in_use;
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 	mutex_enter(&usba_device->usb_mutex);
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate 	hcdi = usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate 	mutex_enter(&hcdi->hcdi_mutex);
4777c478bd9Sstevel@tonic-gate 	usb_address_in_use = hcdi->hcdi_usb_address_in_use;
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate 	for (address = ROOT_HUB_ADDR + 1;
4807c478bd9Sstevel@tonic-gate 	    address <= USBA_MAX_ADDRESS; address++) {
4817c478bd9Sstevel@tonic-gate 		if (usb_address_in_use[address/s] & (1 << (address % s))) {
4827c478bd9Sstevel@tonic-gate 			continue;
4837c478bd9Sstevel@tonic-gate 		}
4847c478bd9Sstevel@tonic-gate 		usb_address_in_use[address/s] |= (1 << (address % s));
4857c478bd9Sstevel@tonic-gate 		hcdi->hcdi_device_count++;
4867c478bd9Sstevel@tonic-gate 		HCDI_HOTPLUG_STATS_DATA(hcdi)->hcdi_device_count.value.ui64++;
4877c478bd9Sstevel@tonic-gate 		mutex_exit(&hcdi->hcdi_mutex);
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
4907c478bd9Sstevel@tonic-gate 		    "usba_set_usb_address: %d", address);
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate 		usba_device->usb_addr = address;
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate 		return (USB_SUCCESS);
4977c478bd9Sstevel@tonic-gate 	}
4987c478bd9Sstevel@tonic-gate 
4997c478bd9Sstevel@tonic-gate 	usba_device->usb_addr = 0;
5007c478bd9Sstevel@tonic-gate 
501d291d9f2Sfrits 	USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
5027c478bd9Sstevel@tonic-gate 	    "no usb address available");
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate 	mutex_exit(&hcdi->hcdi_mutex);
5057c478bd9Sstevel@tonic-gate 	mutex_exit(&usba_device->usb_mutex);
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 	return (USB_FAILURE);
5087c478bd9Sstevel@tonic-gate }
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate /*
5127c478bd9Sstevel@tonic-gate  * usba_unset_usb_address:
5137c478bd9Sstevel@tonic-gate  *	unset usb_address in usba_device structure
5147c478bd9Sstevel@tonic-gate  */
5157c478bd9Sstevel@tonic-gate void
usba_unset_usb_address(usba_device_t * usba_device)5167c478bd9Sstevel@tonic-gate usba_unset_usb_address(usba_device_t *usba_device)
5177c478bd9Sstevel@tonic-gate {
5187c478bd9Sstevel@tonic-gate 	usb_addr_t address;
5197c478bd9Sstevel@tonic-gate 	usba_hcdi_t *hcdi;
5207c478bd9Sstevel@tonic-gate 	uchar_t s = 8;
5217c478bd9Sstevel@tonic-gate 	char *usb_address_in_use;
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate 	mutex_enter(&usba_device->usb_mutex);
5247c478bd9Sstevel@tonic-gate 	address = usba_device->usb_addr;
5257c478bd9Sstevel@tonic-gate 	hcdi = usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate 	if (address > ROOT_HUB_ADDR) {
5287c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
5297c478bd9Sstevel@tonic-gate 		    "usba_unset_usb_address: address=%d", address);
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate 		mutex_enter(&hcdi->hcdi_mutex);
5327c478bd9Sstevel@tonic-gate 		usb_address_in_use = hcdi->hcdi_usb_address_in_use;
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate 		ASSERT(usb_address_in_use[address/s] & (1 << (address % s)));
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate 		usb_address_in_use[address/s] &= ~(1 << (address % s));
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate 		hcdi->hcdi_device_count--;
5397c478bd9Sstevel@tonic-gate 		HCDI_HOTPLUG_STATS_DATA(hcdi)->hcdi_device_count.value.ui64--;
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate 		mutex_exit(&hcdi->hcdi_mutex);
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate 		usba_device->usb_addr = 0;
5447c478bd9Sstevel@tonic-gate 	}
5457c478bd9Sstevel@tonic-gate 	mutex_exit(&usba_device->usb_mutex);
5467c478bd9Sstevel@tonic-gate }
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate struct usba_evdata *
usba_get_evdata(dev_info_t * dip)5507c478bd9Sstevel@tonic-gate usba_get_evdata(dev_info_t *dip)
5517c478bd9Sstevel@tonic-gate {
5527c478bd9Sstevel@tonic-gate 	usba_evdata_t *evdata;
5537c478bd9Sstevel@tonic-gate 	usba_device_t *usba_device = usba_get_usba_device(dip);
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate 	/* called when dip attaches */
5567c478bd9Sstevel@tonic-gate 	ASSERT(usba_device != NULL);
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate 	mutex_enter(&usba_device->usb_mutex);
5597c478bd9Sstevel@tonic-gate 	evdata = usba_device->usb_evdata;
5607c478bd9Sstevel@tonic-gate 	while (evdata) {
5617c478bd9Sstevel@tonic-gate 		if (evdata->ev_dip == dip) {
5627c478bd9Sstevel@tonic-gate 			mutex_exit(&usba_device->usb_mutex);
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate 			return (evdata);
5657c478bd9Sstevel@tonic-gate 		}
5667c478bd9Sstevel@tonic-gate 		evdata = evdata->ev_next;
5677c478bd9Sstevel@tonic-gate 	}
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate 	evdata = kmem_zalloc(sizeof (usba_evdata_t), KM_SLEEP);
5707c478bd9Sstevel@tonic-gate 	evdata->ev_dip = dip;
5717c478bd9Sstevel@tonic-gate 	evdata->ev_next = usba_device->usb_evdata;
5727c478bd9Sstevel@tonic-gate 	usba_device->usb_evdata = evdata;
5737c478bd9Sstevel@tonic-gate 	mutex_exit(&usba_device->usb_mutex);
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate 	return (evdata);
5767c478bd9Sstevel@tonic-gate }
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate /*
5807c478bd9Sstevel@tonic-gate  * allocate a usb device structure and link it in the list
5817c478bd9Sstevel@tonic-gate  */
5827c478bd9Sstevel@tonic-gate usba_device_t *
usba_alloc_usba_device(dev_info_t * root_hub_dip)5837c478bd9Sstevel@tonic-gate usba_alloc_usba_device(dev_info_t *root_hub_dip)
5847c478bd9Sstevel@tonic-gate {
5857c478bd9Sstevel@tonic-gate 	usba_device_t	*usba_device;
5867c478bd9Sstevel@tonic-gate 	int		ep_idx;
5877c478bd9Sstevel@tonic-gate 	ddi_iblock_cookie_t iblock_cookie =
5887c478bd9Sstevel@tonic-gate 	    usba_hcdi_get_hcdi(root_hub_dip)->hcdi_iblock_cookie;
5897c478bd9Sstevel@tonic-gate 
5907c478bd9Sstevel@tonic-gate 	/*
5917c478bd9Sstevel@tonic-gate 	 * create a new usba_device structure
5927c478bd9Sstevel@tonic-gate 	 */
5937c478bd9Sstevel@tonic-gate 	usba_device = kmem_zalloc(sizeof (usba_device_t), KM_SLEEP);
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate 	/*
5967c478bd9Sstevel@tonic-gate 	 * initialize usba_device
5977c478bd9Sstevel@tonic-gate 	 */
5987c478bd9Sstevel@tonic-gate 	mutex_init(&usba_device->usb_mutex, NULL, MUTEX_DRIVER,
5997c478bd9Sstevel@tonic-gate 	    iblock_cookie);
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate 	usba_init_list(&usba_device->usb_device_list, (usb_opaque_t)usba_device,
6027c478bd9Sstevel@tonic-gate 	    iblock_cookie);
6037c478bd9Sstevel@tonic-gate 	usba_init_list(&usba_device->usb_allocated, (usb_opaque_t)usba_device,
6047c478bd9Sstevel@tonic-gate 	    iblock_cookie);
6057c478bd9Sstevel@tonic-gate 	mutex_enter(&usba_device->usb_mutex);
6067c478bd9Sstevel@tonic-gate 	usba_device->usb_root_hub_dip = root_hub_dip;
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate 	/*
6097c478bd9Sstevel@tonic-gate 	 * add to list of usba_devices
6107c478bd9Sstevel@tonic-gate 	 */
6117c478bd9Sstevel@tonic-gate 	usba_add_to_list(&usba_device_list, &usba_device->usb_device_list);
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate 	/* init mutex in each usba_ph_impl structure */
6147c478bd9Sstevel@tonic-gate 	for (ep_idx = 0; ep_idx < USBA_N_ENDPOINTS; ep_idx++) {
6157c478bd9Sstevel@tonic-gate 		mutex_init(&usba_device->usb_ph_list[ep_idx].usba_ph_mutex,
6167c478bd9Sstevel@tonic-gate 		    NULL, MUTEX_DRIVER, iblock_cookie);
6177c478bd9Sstevel@tonic-gate 	}
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
6207c478bd9Sstevel@tonic-gate 	    "allocated usba_device 0x%p", (void *)usba_device);
6217c478bd9Sstevel@tonic-gate 
6227c478bd9Sstevel@tonic-gate 	mutex_exit(&usba_device->usb_mutex);
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 	return (usba_device);
6257c478bd9Sstevel@tonic-gate }
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate 
6287c478bd9Sstevel@tonic-gate /* free NDI event data associated with usba_device */
6297c478bd9Sstevel@tonic-gate void
usba_free_evdata(usba_evdata_t * evdata)6307c478bd9Sstevel@tonic-gate usba_free_evdata(usba_evdata_t *evdata)
6317c478bd9Sstevel@tonic-gate {
6327c478bd9Sstevel@tonic-gate 	usba_evdata_t *next;
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate 	while (evdata) {
6357c478bd9Sstevel@tonic-gate 		next = evdata->ev_next;
6367c478bd9Sstevel@tonic-gate 		kmem_free(evdata, sizeof (usba_evdata_t));
6377c478bd9Sstevel@tonic-gate 		evdata = next;
6387c478bd9Sstevel@tonic-gate 	}
6397c478bd9Sstevel@tonic-gate }
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate /*
6437c478bd9Sstevel@tonic-gate  * free usb device structure
6447c478bd9Sstevel@tonic-gate  */
6457c478bd9Sstevel@tonic-gate void
usba_free_usba_device(usba_device_t * usba_device)6467c478bd9Sstevel@tonic-gate usba_free_usba_device(usba_device_t *usba_device)
6477c478bd9Sstevel@tonic-gate {
6487c478bd9Sstevel@tonic-gate 	int			i, ep_idx;
6497c478bd9Sstevel@tonic-gate 	usb_pipe_handle_t	def_ph;
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate 	if (usba_device == NULL) {
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate 		return;
6547c478bd9Sstevel@tonic-gate 	}
6557c478bd9Sstevel@tonic-gate 
6567c478bd9Sstevel@tonic-gate 	mutex_enter(&usba_device->usb_mutex);
6577c478bd9Sstevel@tonic-gate 	if (usba_device->usb_ref_count) {
6587c478bd9Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate 		return;
6617c478bd9Sstevel@tonic-gate 	}
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
6647c478bd9Sstevel@tonic-gate 	    "usba_free_usba_device 0x%p, address=0x%x, ref cnt=%d",
6657c478bd9Sstevel@tonic-gate 	    (void *)usba_device, usba_device->usb_addr,
6667c478bd9Sstevel@tonic-gate 	    usba_device->usb_ref_count);
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate 	usba_free_evdata(usba_device->usb_evdata);
6697c478bd9Sstevel@tonic-gate 	mutex_exit(&usba_device->usb_mutex);
6707c478bd9Sstevel@tonic-gate 
6717c478bd9Sstevel@tonic-gate 	def_ph = usba_usbdev_to_dflt_pipe_handle(usba_device);
6727c478bd9Sstevel@tonic-gate 	if (def_ph != NULL) {
6737c478bd9Sstevel@tonic-gate 		usba_pipe_handle_data_t	*ph_data = usba_get_ph_data(def_ph);
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 		if (ph_data) {
6767c478bd9Sstevel@tonic-gate 			usb_pipe_close(ph_data->p_dip, def_ph,
6777c478bd9Sstevel@tonic-gate 			    USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED,
6787c478bd9Sstevel@tonic-gate 			    NULL, NULL);
6797c478bd9Sstevel@tonic-gate 		}
6807c478bd9Sstevel@tonic-gate 	}
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate 	mutex_enter(&usba_mutex);
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate 	/* destroy mutex in each usba_ph_impl structure */
6857c478bd9Sstevel@tonic-gate 	for (ep_idx = 0; ep_idx < USBA_N_ENDPOINTS; ep_idx++) {
6867c478bd9Sstevel@tonic-gate 		mutex_destroy(&usba_device->usb_ph_list[ep_idx].usba_ph_mutex);
6877c478bd9Sstevel@tonic-gate 	}
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate 	(void) usba_rm_from_list(&usba_device_list,
6907c478bd9Sstevel@tonic-gate 	    &usba_device->usb_device_list);
6917c478bd9Sstevel@tonic-gate 
6927c478bd9Sstevel@tonic-gate 	mutex_exit(&usba_mutex);
6937c478bd9Sstevel@tonic-gate 
6947c478bd9Sstevel@tonic-gate 	usba_destroy_list(&usba_device->usb_device_list);
6957c478bd9Sstevel@tonic-gate 	usba_destroy_list(&usba_device->usb_allocated);
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
6987c478bd9Sstevel@tonic-gate 	    "deallocating usba_device = 0x%p, address = 0x%x",
6997c478bd9Sstevel@tonic-gate 	    (void *)usba_device, usba_device->usb_addr);
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate 	/*
7027c478bd9Sstevel@tonic-gate 	 * ohci allocates descriptors for root hub so we can't
7037c478bd9Sstevel@tonic-gate 	 * deallocate these here
7047c478bd9Sstevel@tonic-gate 	 */
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate 	if (usba_device->usb_addr != ROOT_HUB_ADDR) {
7077c478bd9Sstevel@tonic-gate 		if (usba_device->usb_cfg_array) {
7087c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
7097c478bd9Sstevel@tonic-gate 			    "deallocating usb_config_array: 0x%p",
710112116d8Sfb209375 			    (void *)usba_device->usb_cfg_array);
7117c478bd9Sstevel@tonic-gate 			mutex_enter(&usba_device->usb_mutex);
7127c478bd9Sstevel@tonic-gate 			for (i = 0;
7137c478bd9Sstevel@tonic-gate 			    i < usba_device->usb_dev_descr->bNumConfigurations;
7147c478bd9Sstevel@tonic-gate 			    i++) {
7157c478bd9Sstevel@tonic-gate 				if (usba_device->usb_cfg_array[i]) {
7167c478bd9Sstevel@tonic-gate 					kmem_free(
7177c478bd9Sstevel@tonic-gate 					    usba_device->usb_cfg_array[i],
7187c478bd9Sstevel@tonic-gate 					    usba_device->usb_cfg_array_len[i]);
7197c478bd9Sstevel@tonic-gate 				}
7207c478bd9Sstevel@tonic-gate 			}
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate 			/* free the array pointers */
7237c478bd9Sstevel@tonic-gate 			kmem_free(usba_device->usb_cfg_array,
7247c478bd9Sstevel@tonic-gate 			    usba_device->usb_cfg_array_length);
7257c478bd9Sstevel@tonic-gate 			kmem_free(usba_device->usb_cfg_array_len,
7267c478bd9Sstevel@tonic-gate 			    usba_device->usb_cfg_array_len_length);
7277c478bd9Sstevel@tonic-gate 
7287c478bd9Sstevel@tonic-gate 			mutex_exit(&usba_device->usb_mutex);
7297c478bd9Sstevel@tonic-gate 		}
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate 		if (usba_device->usb_cfg_str_descr) {
7327c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
7337c478bd9Sstevel@tonic-gate 			    "deallocating usb_cfg_str_descr: 0x%p",
734112116d8Sfb209375 			    (void *)usba_device->usb_cfg_str_descr);
7357c478bd9Sstevel@tonic-gate 			for (i = 0;
7367c478bd9Sstevel@tonic-gate 			    i < usba_device->usb_dev_descr->bNumConfigurations;
7377c478bd9Sstevel@tonic-gate 			    i++) {
7387c478bd9Sstevel@tonic-gate 				if (usba_device->usb_cfg_str_descr[i]) {
7397c478bd9Sstevel@tonic-gate 					kmem_free(
7407c478bd9Sstevel@tonic-gate 					    usba_device->usb_cfg_str_descr[i],
7417c478bd9Sstevel@tonic-gate 					    strlen(usba_device->
7427c478bd9Sstevel@tonic-gate 					    usb_cfg_str_descr[i]) + 1);
7437c478bd9Sstevel@tonic-gate 				}
7447c478bd9Sstevel@tonic-gate 			}
7457c478bd9Sstevel@tonic-gate 			/* free the array pointers */
7467c478bd9Sstevel@tonic-gate 			kmem_free(usba_device->usb_cfg_str_descr,
7477c478bd9Sstevel@tonic-gate 			    sizeof (uchar_t *) * usba_device->usb_n_cfgs);
7487c478bd9Sstevel@tonic-gate 		}
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate 		if (usba_device->usb_dev_descr) {
7517c478bd9Sstevel@tonic-gate 			kmem_free(usba_device->usb_dev_descr,
7527c478bd9Sstevel@tonic-gate 			    sizeof (usb_dev_descr_t));
7537c478bd9Sstevel@tonic-gate 		}
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate 		if (usba_device->usb_mfg_str) {
7567c478bd9Sstevel@tonic-gate 			kmem_free(usba_device->usb_mfg_str,
7577c478bd9Sstevel@tonic-gate 			    strlen(usba_device->usb_mfg_str) + 1);
7587c478bd9Sstevel@tonic-gate 		}
7597c478bd9Sstevel@tonic-gate 
7607c478bd9Sstevel@tonic-gate 		if (usba_device->usb_product_str) {
7617c478bd9Sstevel@tonic-gate 			kmem_free(usba_device->usb_product_str,
7627c478bd9Sstevel@tonic-gate 			    strlen(usba_device->usb_product_str) + 1);
7637c478bd9Sstevel@tonic-gate 		}
7647c478bd9Sstevel@tonic-gate 
7657c478bd9Sstevel@tonic-gate 		if (usba_device->usb_serialno_str) {
7667c478bd9Sstevel@tonic-gate 			kmem_free(usba_device->usb_serialno_str,
7677c478bd9Sstevel@tonic-gate 			    strlen(usba_device->usb_serialno_str) + 1);
7687c478bd9Sstevel@tonic-gate 		}
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate 		usba_unset_usb_address(usba_device);
7717c478bd9Sstevel@tonic-gate 	}
7727c478bd9Sstevel@tonic-gate 
7737c478bd9Sstevel@tonic-gate #ifndef __lock_lint
7747c478bd9Sstevel@tonic-gate 	ASSERT(usba_device->usb_client_dev_data_list.cddl_next == NULL);
7757c478bd9Sstevel@tonic-gate #endif
7767c478bd9Sstevel@tonic-gate 
7777c478bd9Sstevel@tonic-gate 	if (usba_device->usb_client_flags) {
7787c478bd9Sstevel@tonic-gate #ifndef __lock_lint
7797c478bd9Sstevel@tonic-gate 		int i;
7807c478bd9Sstevel@tonic-gate 
7817c478bd9Sstevel@tonic-gate 		for (i = 0; i < usba_device->usb_n_ifs; i++) {
7827c478bd9Sstevel@tonic-gate 			ASSERT(usba_device->usb_client_flags[i] == 0);
7837c478bd9Sstevel@tonic-gate 		}
7847c478bd9Sstevel@tonic-gate #endif
7857c478bd9Sstevel@tonic-gate 		kmem_free(usba_device->usb_client_flags,
7867c478bd9Sstevel@tonic-gate 		    usba_device->usb_n_ifs * USBA_CLIENT_FLAG_SIZE);
7877c478bd9Sstevel@tonic-gate 	}
7887c478bd9Sstevel@tonic-gate 
7897c478bd9Sstevel@tonic-gate 
7907c478bd9Sstevel@tonic-gate 	if (usba_device->usb_client_attach_list) {
7917c478bd9Sstevel@tonic-gate 		kmem_free(usba_device->usb_client_attach_list,
7927c478bd9Sstevel@tonic-gate 		    usba_device->usb_n_ifs *
7937c478bd9Sstevel@tonic-gate 		    sizeof (*usba_device->usb_client_attach_list));
7947c478bd9Sstevel@tonic-gate 	}
7957c478bd9Sstevel@tonic-gate 	if (usba_device->usb_client_ev_cb_list) {
7967c478bd9Sstevel@tonic-gate 		kmem_free(usba_device->usb_client_ev_cb_list,
7977c478bd9Sstevel@tonic-gate 		    usba_device->usb_n_ifs *
7987c478bd9Sstevel@tonic-gate 		    sizeof (*usba_device->usb_client_ev_cb_list));
7997c478bd9Sstevel@tonic-gate 	}
8007c478bd9Sstevel@tonic-gate 
8017c478bd9Sstevel@tonic-gate 	/*
8027c478bd9Sstevel@tonic-gate 	 * finally ready to destroy the structure
8037c478bd9Sstevel@tonic-gate 	 */
8047c478bd9Sstevel@tonic-gate 	mutex_destroy(&usba_device->usb_mutex);
8057c478bd9Sstevel@tonic-gate 
8067c478bd9Sstevel@tonic-gate 	kmem_free((caddr_t)usba_device, sizeof (usba_device_t));
8077c478bd9Sstevel@tonic-gate }
8087c478bd9Sstevel@tonic-gate 
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate /* clear the data toggle for all endpoints on this device */
8117c478bd9Sstevel@tonic-gate void
usba_clear_data_toggle(usba_device_t * usba_device)8127c478bd9Sstevel@tonic-gate usba_clear_data_toggle(usba_device_t *usba_device)
8137c478bd9Sstevel@tonic-gate {
8147c478bd9Sstevel@tonic-gate 	int	i;
8157c478bd9Sstevel@tonic-gate 
8167c478bd9Sstevel@tonic-gate 	if (usba_device != NULL) {
8177c478bd9Sstevel@tonic-gate 		mutex_enter(&usba_device->usb_mutex);
8187c478bd9Sstevel@tonic-gate 		for (i = 0; i < USBA_N_ENDPOINTS; i++) {
8197c478bd9Sstevel@tonic-gate 			usba_device->usb_ph_list[i].usba_ph_flags &=
8207c478bd9Sstevel@tonic-gate 			    ~USBA_PH_DATA_TOGGLE;
8217c478bd9Sstevel@tonic-gate 		}
8227c478bd9Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
8237c478bd9Sstevel@tonic-gate 	}
8247c478bd9Sstevel@tonic-gate }
8257c478bd9Sstevel@tonic-gate 
8267c478bd9Sstevel@tonic-gate 
8277c478bd9Sstevel@tonic-gate /*
8287c478bd9Sstevel@tonic-gate  * usba_create_child_devi():
8297c478bd9Sstevel@tonic-gate  *	create a child devinfo node, usba_device, attach properties.
8307c478bd9Sstevel@tonic-gate  *	the usba_device structure is shared between all interfaces
8317c478bd9Sstevel@tonic-gate  */
8327c478bd9Sstevel@tonic-gate int
usba_create_child_devi(dev_info_t * dip,char * node_name,usba_hcdi_ops_t * usba_hcdi_ops,dev_info_t * usb_root_hub_dip,usb_port_status_t port_status,usba_device_t * usba_device,dev_info_t ** child_dip)8337c478bd9Sstevel@tonic-gate usba_create_child_devi(dev_info_t	*dip,
8347c478bd9Sstevel@tonic-gate 		char			*node_name,
8357c478bd9Sstevel@tonic-gate 		usba_hcdi_ops_t		*usba_hcdi_ops,
8367c478bd9Sstevel@tonic-gate 		dev_info_t		*usb_root_hub_dip,
8377c478bd9Sstevel@tonic-gate 		usb_port_status_t	port_status,
8387c478bd9Sstevel@tonic-gate 		usba_device_t		*usba_device,
8397c478bd9Sstevel@tonic-gate 		dev_info_t		**child_dip)
8407c478bd9Sstevel@tonic-gate {
8417c478bd9Sstevel@tonic-gate 	int rval = USB_FAILURE;
8427c478bd9Sstevel@tonic-gate 	int usba_device_allocated = 0;
8437c478bd9Sstevel@tonic-gate 	usb_addr_t	address;
8447c478bd9Sstevel@tonic-gate 
8457c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
8467c478bd9Sstevel@tonic-gate 	    "usba_create_child_devi: %s usba_device=0x%p "
8477c478bd9Sstevel@tonic-gate 	    "port status=0x%x", node_name,
8487c478bd9Sstevel@tonic-gate 	    (void *)usba_device, port_status);
8497c478bd9Sstevel@tonic-gate 
850fa9e4066Sahrens 	ndi_devi_alloc_sleep(dip, node_name, (pnode_t)DEVI_SID_NODEID,
8517c478bd9Sstevel@tonic-gate 	    child_dip);
8527c478bd9Sstevel@tonic-gate 
8537c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
854112116d8Sfb209375 	    "child dip=0x%p", (void *)*child_dip);
8557c478bd9Sstevel@tonic-gate 
8567c478bd9Sstevel@tonic-gate 	if (usba_device == NULL) {
8577c478bd9Sstevel@tonic-gate 
8587c478bd9Sstevel@tonic-gate 		usba_device = usba_alloc_usba_device(usb_root_hub_dip);
8597c478bd9Sstevel@tonic-gate 
8607c478bd9Sstevel@tonic-gate 		/* grab the mutex to keep warlock happy */
8617c478bd9Sstevel@tonic-gate 		mutex_enter(&usba_device->usb_mutex);
8627c478bd9Sstevel@tonic-gate 		usba_device->usb_hcdi_ops	= usba_hcdi_ops;
8637c478bd9Sstevel@tonic-gate 		usba_device->usb_port_status	= port_status;
8647c478bd9Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
8657c478bd9Sstevel@tonic-gate 
8667c478bd9Sstevel@tonic-gate 		usba_device_allocated++;
8677c478bd9Sstevel@tonic-gate 	} else {
8687c478bd9Sstevel@tonic-gate 		mutex_enter(&usba_device->usb_mutex);
8697c478bd9Sstevel@tonic-gate 		if (usba_hcdi_ops) {
8707c478bd9Sstevel@tonic-gate 			ASSERT(usba_device->usb_hcdi_ops == usba_hcdi_ops);
8717c478bd9Sstevel@tonic-gate 		}
8727c478bd9Sstevel@tonic-gate 		if (usb_root_hub_dip) {
8737c478bd9Sstevel@tonic-gate 			ASSERT(usba_device->usb_root_hub_dip ==
8747c478bd9Sstevel@tonic-gate 			    usb_root_hub_dip);
8757c478bd9Sstevel@tonic-gate 		}
8767c478bd9Sstevel@tonic-gate 
8777c478bd9Sstevel@tonic-gate 		usba_device->usb_port_status	= port_status;
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
8807c478bd9Sstevel@tonic-gate 	}
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate 	if (usba_device->usb_addr == 0) {
8837c478bd9Sstevel@tonic-gate 		if (usba_set_usb_address(usba_device) == USB_FAILURE) {
8847c478bd9Sstevel@tonic-gate 			address = 0;
8857c478bd9Sstevel@tonic-gate 
8867c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
8877c478bd9Sstevel@tonic-gate 			    "cannot set usb address for dip=0x%p",
888112116d8Sfb209375 			    (void *)*child_dip);
8897c478bd9Sstevel@tonic-gate 
8907c478bd9Sstevel@tonic-gate 			goto fail;
8917c478bd9Sstevel@tonic-gate 		}
8927c478bd9Sstevel@tonic-gate 	}
8937c478bd9Sstevel@tonic-gate 	address = usba_device->usb_addr;
8947c478bd9Sstevel@tonic-gate 
8957c478bd9Sstevel@tonic-gate 	/* attach properties */
8967c478bd9Sstevel@tonic-gate 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, *child_dip,
8977c478bd9Sstevel@tonic-gate 	    "assigned-address", address);
8987c478bd9Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
8997c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
9007c478bd9Sstevel@tonic-gate 		    "cannot set usb address property for dip=0x%p",
901112116d8Sfb209375 		    (void *)*child_dip);
9027c478bd9Sstevel@tonic-gate 		rval = USB_FAILURE;
9037c478bd9Sstevel@tonic-gate 
9047c478bd9Sstevel@tonic-gate 		goto fail;
9057c478bd9Sstevel@tonic-gate 	}
9067c478bd9Sstevel@tonic-gate 
9077c478bd9Sstevel@tonic-gate 	/*
9087c478bd9Sstevel@tonic-gate 	 * store the usba_device point in the dip
9097c478bd9Sstevel@tonic-gate 	 */
9107c478bd9Sstevel@tonic-gate 	usba_set_usba_device(*child_dip, usba_device);
9117c478bd9Sstevel@tonic-gate 
9127c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
9137c478bd9Sstevel@tonic-gate 	    "usba_create_child_devi: devi=0x%p (%s) ud=0x%p",
914112116d8Sfb209375 	    (void *)*child_dip, ddi_driver_name(*child_dip),
915112116d8Sfb209375 	    (void *)usba_device);
9167c478bd9Sstevel@tonic-gate 
9177c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
9187c478bd9Sstevel@tonic-gate 
9197c478bd9Sstevel@tonic-gate fail:
9207c478bd9Sstevel@tonic-gate 	if (*child_dip) {
9217c478bd9Sstevel@tonic-gate 		int rval = usba_destroy_child_devi(*child_dip, NDI_DEVI_REMOVE);
9227c478bd9Sstevel@tonic-gate 		ASSERT(rval == USB_SUCCESS);
9237c478bd9Sstevel@tonic-gate 		*child_dip = NULL;
9247c478bd9Sstevel@tonic-gate 	}
9257c478bd9Sstevel@tonic-gate 
9267c478bd9Sstevel@tonic-gate 	if (usba_device_allocated) {
9277c478bd9Sstevel@tonic-gate 		usba_free_usba_device(usba_device);
9287c478bd9Sstevel@tonic-gate 	} else if (address && usba_device) {
9297c478bd9Sstevel@tonic-gate 		usba_unset_usb_address(usba_device);
9307c478bd9Sstevel@tonic-gate 	}
9317c478bd9Sstevel@tonic-gate 
932d291d9f2Sfrits 	USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
9337c478bd9Sstevel@tonic-gate 	    "usba_create_child_devi failed: rval=%d", rval);
9347c478bd9Sstevel@tonic-gate 
9357c478bd9Sstevel@tonic-gate 	return (rval);
9367c478bd9Sstevel@tonic-gate }
9377c478bd9Sstevel@tonic-gate 
9387c478bd9Sstevel@tonic-gate 
9397c478bd9Sstevel@tonic-gate int
usba_destroy_child_devi(dev_info_t * dip,uint_t flag)9407c478bd9Sstevel@tonic-gate usba_destroy_child_devi(dev_info_t *dip, uint_t flag)
9417c478bd9Sstevel@tonic-gate {
9427c478bd9Sstevel@tonic-gate 	usba_device_t	*usba_device;
9437c478bd9Sstevel@tonic-gate 	int		rval = NDI_SUCCESS;
9447c478bd9Sstevel@tonic-gate 
9457c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
9467c478bd9Sstevel@tonic-gate 	    "usba_destroy_child_devi: %s%d (0x%p)",
947112116d8Sfb209375 	    ddi_driver_name(dip), ddi_get_instance(dip), (void *)dip);
9487c478bd9Sstevel@tonic-gate 
9497c478bd9Sstevel@tonic-gate 	usba_device = usba_get_usba_device(dip);
9507c478bd9Sstevel@tonic-gate 
9517c478bd9Sstevel@tonic-gate 	/*
9527c478bd9Sstevel@tonic-gate 	 * if the child hasn't been bound yet, we can just
9537c478bd9Sstevel@tonic-gate 	 * free the dip
9547c478bd9Sstevel@tonic-gate 	 */
9557c478bd9Sstevel@tonic-gate 	if (i_ddi_node_state(dip) < DS_INITIALIZED) {
9567c478bd9Sstevel@tonic-gate 		/*
9577c478bd9Sstevel@tonic-gate 		 * do not call ndi_devi_free() since it might
9587c478bd9Sstevel@tonic-gate 		 * deadlock
9597c478bd9Sstevel@tonic-gate 		 */
9607c478bd9Sstevel@tonic-gate 		rval = ddi_remove_child(dip, 0);
9617c478bd9Sstevel@tonic-gate 
9627c478bd9Sstevel@tonic-gate 	} else {
9637c478bd9Sstevel@tonic-gate 		char *devnm = kmem_alloc(MAXNAMELEN + 1, KM_SLEEP);
9647c478bd9Sstevel@tonic-gate 		dev_info_t *pdip = ddi_get_parent(dip);
9657c478bd9Sstevel@tonic-gate 
9667c478bd9Sstevel@tonic-gate 		(void) ddi_deviname(dip, devnm);
9677c478bd9Sstevel@tonic-gate 
9687c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
9697c478bd9Sstevel@tonic-gate 		    "usba_destroy_child_devi:\n\t"
970112116d8Sfb209375 		    "offlining dip 0x%p usba_device=0x%p (%s)", (void *)dip,
9717c478bd9Sstevel@tonic-gate 		    (void *)usba_device, devnm);
9727c478bd9Sstevel@tonic-gate 
9737c478bd9Sstevel@tonic-gate 		(void) devfs_clean(pdip, NULL, DV_CLEAN_FORCE);
9747c478bd9Sstevel@tonic-gate 		rval =	ndi_devi_unconfig_one(pdip, devnm + 1, NULL,
9757c478bd9Sstevel@tonic-gate 		    flag | NDI_UNCONFIG | NDI_DEVI_OFFLINE);
9767c478bd9Sstevel@tonic-gate 		if (rval != NDI_SUCCESS) {
9777c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
9787c478bd9Sstevel@tonic-gate 			    " ndi_devi_unconfig_one %s%d failed (%d)",
9797c478bd9Sstevel@tonic-gate 			    ddi_driver_name(dip), ddi_get_instance(dip),
9807c478bd9Sstevel@tonic-gate 			    rval);
9817c478bd9Sstevel@tonic-gate 		}
9827c478bd9Sstevel@tonic-gate 		kmem_free(devnm, MAXNAMELEN + 1);
9837c478bd9Sstevel@tonic-gate 	}
9847c478bd9Sstevel@tonic-gate 
9857c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
9867c478bd9Sstevel@tonic-gate 	    "usba_destroy_child_devi: rval=%d", rval);
9877c478bd9Sstevel@tonic-gate 
9887c478bd9Sstevel@tonic-gate 	return (rval == NDI_SUCCESS ? USB_SUCCESS : USB_FAILURE);
9897c478bd9Sstevel@tonic-gate }
9907c478bd9Sstevel@tonic-gate 
9917c478bd9Sstevel@tonic-gate 
9927c478bd9Sstevel@tonic-gate /*
9937c478bd9Sstevel@tonic-gate  * list management
9947c478bd9Sstevel@tonic-gate  */
9957c478bd9Sstevel@tonic-gate void
usba_init_list(usba_list_entry_t * element,usb_opaque_t private,ddi_iblock_cookie_t iblock_cookie)9967c478bd9Sstevel@tonic-gate usba_init_list(usba_list_entry_t *element, usb_opaque_t private,
9977c478bd9Sstevel@tonic-gate 	ddi_iblock_cookie_t	iblock_cookie)
9987c478bd9Sstevel@tonic-gate {
9997c478bd9Sstevel@tonic-gate 	mutex_init(&element->list_mutex, NULL, MUTEX_DRIVER,
10007c478bd9Sstevel@tonic-gate 	    iblock_cookie);
10017c478bd9Sstevel@tonic-gate 	mutex_enter(&element->list_mutex);
10027c478bd9Sstevel@tonic-gate 	element->private = private;
10037c478bd9Sstevel@tonic-gate 	mutex_exit(&element->list_mutex);
10047c478bd9Sstevel@tonic-gate }
10057c478bd9Sstevel@tonic-gate 
10067c478bd9Sstevel@tonic-gate 
10077c478bd9Sstevel@tonic-gate void
usba_destroy_list(usba_list_entry_t * head)10087c478bd9Sstevel@tonic-gate usba_destroy_list(usba_list_entry_t *head)
10097c478bd9Sstevel@tonic-gate {
10107c478bd9Sstevel@tonic-gate 	mutex_enter(&head->list_mutex);
10117c478bd9Sstevel@tonic-gate 	ASSERT(head->next == NULL);
10127c478bd9Sstevel@tonic-gate 	ASSERT(head->prev == NULL);
10137c478bd9Sstevel@tonic-gate 	mutex_exit(&head->list_mutex);
10147c478bd9Sstevel@tonic-gate 
10157c478bd9Sstevel@tonic-gate 	mutex_destroy(&head->list_mutex);
10167c478bd9Sstevel@tonic-gate }
10177c478bd9Sstevel@tonic-gate 
10187c478bd9Sstevel@tonic-gate 
10197c478bd9Sstevel@tonic-gate void
usba_add_to_list(usba_list_entry_t * head,usba_list_entry_t * element)10207c478bd9Sstevel@tonic-gate usba_add_to_list(usba_list_entry_t *head, usba_list_entry_t *element)
10217c478bd9Sstevel@tonic-gate {
10227c478bd9Sstevel@tonic-gate 	usba_list_entry_t *next;
10237c478bd9Sstevel@tonic-gate 	int		remaining;
10247c478bd9Sstevel@tonic-gate 
10257c478bd9Sstevel@tonic-gate 	mutex_enter(&head->list_mutex);
10267c478bd9Sstevel@tonic-gate 	mutex_enter(&element->list_mutex);
10277c478bd9Sstevel@tonic-gate 
10287c478bd9Sstevel@tonic-gate 	remaining = head->count;
10297c478bd9Sstevel@tonic-gate 
10307c478bd9Sstevel@tonic-gate 	/* check if it is not in another list */
10317c478bd9Sstevel@tonic-gate 	ASSERT(element->next == NULL);
10327c478bd9Sstevel@tonic-gate 	ASSERT(element->prev == NULL);
10337c478bd9Sstevel@tonic-gate 
10347c478bd9Sstevel@tonic-gate #ifdef DEBUG
10357c478bd9Sstevel@tonic-gate 	/*
10367c478bd9Sstevel@tonic-gate 	 * only verify the list when not in interrupt context, we
10377c478bd9Sstevel@tonic-gate 	 * have to trust the HCD
10387c478bd9Sstevel@tonic-gate 	 */
10397c478bd9Sstevel@tonic-gate 	if (!servicing_interrupt()) {
10407c478bd9Sstevel@tonic-gate 
10417c478bd9Sstevel@tonic-gate 		/* check if not already in this list */
10427c478bd9Sstevel@tonic-gate 		for (next = head->next; (next != NULL);
10437c478bd9Sstevel@tonic-gate 		    next = next->next) {
10447c478bd9Sstevel@tonic-gate 			if (next == element) {
10457c478bd9Sstevel@tonic-gate 				USB_DPRINTF_L0(DPRINT_MASK_USBA,
10467c478bd9Sstevel@tonic-gate 				    usba_log_handle,
10477c478bd9Sstevel@tonic-gate 				    "Attempt to corrupt USB list at 0x%p",
10487c478bd9Sstevel@tonic-gate 				    (void *)head);
10497c478bd9Sstevel@tonic-gate 				ASSERT(next == element);
10507c478bd9Sstevel@tonic-gate 
10517c478bd9Sstevel@tonic-gate 				goto done;
10527c478bd9Sstevel@tonic-gate 			}
10537c478bd9Sstevel@tonic-gate 			remaining--;
10547c478bd9Sstevel@tonic-gate 
10557c478bd9Sstevel@tonic-gate 			/*
10567c478bd9Sstevel@tonic-gate 			 * Detect incorrect circ links or found
10577c478bd9Sstevel@tonic-gate 			 * unexpected elements.
10587c478bd9Sstevel@tonic-gate 			 */
10597c478bd9Sstevel@tonic-gate 			if ((next->next && (remaining == 0)) ||
10607c478bd9Sstevel@tonic-gate 			    ((next->next == NULL) && remaining)) {
10617c478bd9Sstevel@tonic-gate 				panic("Corrupted USB list at 0x%p",
10627c478bd9Sstevel@tonic-gate 				    (void *)head);
10637c478bd9Sstevel@tonic-gate 				/*NOTREACHED*/
10647c478bd9Sstevel@tonic-gate 			}
10657c478bd9Sstevel@tonic-gate 		}
10667c478bd9Sstevel@tonic-gate 	}
10677c478bd9Sstevel@tonic-gate #endif
10687c478bd9Sstevel@tonic-gate 
10697c478bd9Sstevel@tonic-gate 	if (head->next == NULL) {
10707c478bd9Sstevel@tonic-gate 		head->prev = head->next = element;
10717c478bd9Sstevel@tonic-gate 	} else {
10727c478bd9Sstevel@tonic-gate 		/* add to tail */
10737c478bd9Sstevel@tonic-gate 		head->prev->next = element;
10747c478bd9Sstevel@tonic-gate 		element->prev = head->prev;
10757c478bd9Sstevel@tonic-gate 		head->prev = element;
10767c478bd9Sstevel@tonic-gate 	}
10777c478bd9Sstevel@tonic-gate 
10787c478bd9Sstevel@tonic-gate 	head->count++;
10797c478bd9Sstevel@tonic-gate 
10807c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
10817c478bd9Sstevel@tonic-gate 	    "usba_add_to_list: head=0x%p element=0x%p count=%d",
1082112116d8Sfb209375 	    (void *)head, (void *)element, head->count);
10837c478bd9Sstevel@tonic-gate 
10847c478bd9Sstevel@tonic-gate done:
10857c478bd9Sstevel@tonic-gate 	mutex_exit(&head->list_mutex);
10867c478bd9Sstevel@tonic-gate 	mutex_exit(&element->list_mutex);
10877c478bd9Sstevel@tonic-gate }
10887c478bd9Sstevel@tonic-gate 
10897c478bd9Sstevel@tonic-gate 
10907c478bd9Sstevel@tonic-gate int
usba_rm_from_list(usba_list_entry_t * head,usba_list_entry_t * element)10917c478bd9Sstevel@tonic-gate usba_rm_from_list(usba_list_entry_t *head, usba_list_entry_t *element)
10927c478bd9Sstevel@tonic-gate {
10937c478bd9Sstevel@tonic-gate 	usba_list_entry_t *e;
10947c478bd9Sstevel@tonic-gate 	int		found = 0;
10957c478bd9Sstevel@tonic-gate 	int		remaining;
10967c478bd9Sstevel@tonic-gate 
10977c478bd9Sstevel@tonic-gate 	/* find the element in the list first */
10987c478bd9Sstevel@tonic-gate 	mutex_enter(&head->list_mutex);
10997c478bd9Sstevel@tonic-gate 
11007c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
11017c478bd9Sstevel@tonic-gate 	    "usba_rm_from_list: head=0x%p element=0x%p count=%d",
1102112116d8Sfb209375 	    (void *)head, (void *)element, head->count);
11037c478bd9Sstevel@tonic-gate 
11047c478bd9Sstevel@tonic-gate 	remaining = head->count;
11057c478bd9Sstevel@tonic-gate 	e = head->next;
11067c478bd9Sstevel@tonic-gate 
11077c478bd9Sstevel@tonic-gate 	while (e) {
11087c478bd9Sstevel@tonic-gate 		if (e == element) {
11097c478bd9Sstevel@tonic-gate 			found++;
11107c478bd9Sstevel@tonic-gate 			break;
11117c478bd9Sstevel@tonic-gate 		}
11127c478bd9Sstevel@tonic-gate 		e = e->next;
11137c478bd9Sstevel@tonic-gate 
11147c478bd9Sstevel@tonic-gate 		remaining--;
11157c478bd9Sstevel@tonic-gate 
11167c478bd9Sstevel@tonic-gate 		/* Detect incorrect circ links or found unexpected elements. */
11177c478bd9Sstevel@tonic-gate 		if ((e && (remaining == 0)) ||
11187c478bd9Sstevel@tonic-gate 		    ((e == NULL) && (remaining))) {
11197c478bd9Sstevel@tonic-gate 			panic("Corrupted USB list at 0x%p", (void *)head);
11207c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
11217c478bd9Sstevel@tonic-gate 		}
11227c478bd9Sstevel@tonic-gate 	}
11237c478bd9Sstevel@tonic-gate 
11247c478bd9Sstevel@tonic-gate 	if (!found) {
11257c478bd9Sstevel@tonic-gate 		mutex_exit(&head->list_mutex);
11267c478bd9Sstevel@tonic-gate 
11277c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
11287c478bd9Sstevel@tonic-gate 	}
11297c478bd9Sstevel@tonic-gate 
11307c478bd9Sstevel@tonic-gate 	/* now remove the element */
11317c478bd9Sstevel@tonic-gate 	mutex_enter(&element->list_mutex);
11327c478bd9Sstevel@tonic-gate 
11337c478bd9Sstevel@tonic-gate 	if (element->next) {
11347c478bd9Sstevel@tonic-gate 		element->next->prev = element->prev;
11357c478bd9Sstevel@tonic-gate 	}
11367c478bd9Sstevel@tonic-gate 	if (element->prev) {
11377c478bd9Sstevel@tonic-gate 		element->prev->next = element->next;
11387c478bd9Sstevel@tonic-gate 	}
11397c478bd9Sstevel@tonic-gate 	if (head->next == element) {
11407c478bd9Sstevel@tonic-gate 		head->next = element->next;
11417c478bd9Sstevel@tonic-gate 	}
11427c478bd9Sstevel@tonic-gate 	if (head->prev == element) {
11437c478bd9Sstevel@tonic-gate 		head->prev = element->prev;
11447c478bd9Sstevel@tonic-gate 	}
11457c478bd9Sstevel@tonic-gate 
11467c478bd9Sstevel@tonic-gate 	element->prev = element->next = NULL;
11477c478bd9Sstevel@tonic-gate 	if (head->next == NULL) {
11487c478bd9Sstevel@tonic-gate 		ASSERT(head->prev == NULL);
11497c478bd9Sstevel@tonic-gate 	} else {
11507c478bd9Sstevel@tonic-gate 		ASSERT(head->next->prev == NULL);
11517c478bd9Sstevel@tonic-gate 	}
11527c478bd9Sstevel@tonic-gate 	if (head->prev == NULL) {
11537c478bd9Sstevel@tonic-gate 		ASSERT(head->next == NULL);
11547c478bd9Sstevel@tonic-gate 	} else {
11557c478bd9Sstevel@tonic-gate 		ASSERT(head->prev->next == NULL);
11567c478bd9Sstevel@tonic-gate 	}
11577c478bd9Sstevel@tonic-gate 
11587c478bd9Sstevel@tonic-gate 	head->count--;
11597c478bd9Sstevel@tonic-gate 
11607c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
11617c478bd9Sstevel@tonic-gate 	    "usba_rm_from_list success: head=0x%p element=0x%p cnt=%d",
1162112116d8Sfb209375 	    (void *)head, (void *)element, head->count);
11637c478bd9Sstevel@tonic-gate 
11647c478bd9Sstevel@tonic-gate 	mutex_exit(&element->list_mutex);
11657c478bd9Sstevel@tonic-gate 	mutex_exit(&head->list_mutex);
11667c478bd9Sstevel@tonic-gate 
11677c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
11687c478bd9Sstevel@tonic-gate }
11697c478bd9Sstevel@tonic-gate 
11707c478bd9Sstevel@tonic-gate 
11717c478bd9Sstevel@tonic-gate usba_list_entry_t *
usba_rm_first_from_list(usba_list_entry_t * head)11727c478bd9Sstevel@tonic-gate usba_rm_first_from_list(usba_list_entry_t *head)
11737c478bd9Sstevel@tonic-gate {
11747c478bd9Sstevel@tonic-gate 	usba_list_entry_t *element = NULL;
11757c478bd9Sstevel@tonic-gate 
11767c478bd9Sstevel@tonic-gate 	if (head) {
11777c478bd9Sstevel@tonic-gate 		mutex_enter(&head->list_mutex);
11787c478bd9Sstevel@tonic-gate 		element = head->next;
11797c478bd9Sstevel@tonic-gate 		if (element) {
11807c478bd9Sstevel@tonic-gate 			/* now remove the element */
11817c478bd9Sstevel@tonic-gate 			mutex_enter(&element->list_mutex);
11827c478bd9Sstevel@tonic-gate 			head->next = element->next;
11837c478bd9Sstevel@tonic-gate 			if (head->next) {
11847c478bd9Sstevel@tonic-gate 				head->next->prev = NULL;
11857c478bd9Sstevel@tonic-gate 			}
11867c478bd9Sstevel@tonic-gate 			if (head->prev == element) {
11877c478bd9Sstevel@tonic-gate 				head->prev = element->next;
11887c478bd9Sstevel@tonic-gate 			}
11897c478bd9Sstevel@tonic-gate 			element->prev = element->next = NULL;
11907c478bd9Sstevel@tonic-gate 			mutex_exit(&element->list_mutex);
11917c478bd9Sstevel@tonic-gate 			head->count--;
11927c478bd9Sstevel@tonic-gate 		}
11937c478bd9Sstevel@tonic-gate 		if (head->next == NULL) {
11947c478bd9Sstevel@tonic-gate 			ASSERT(head->prev == NULL);
11957c478bd9Sstevel@tonic-gate 		} else {
11967c478bd9Sstevel@tonic-gate 			ASSERT(head->next->prev == NULL);
11977c478bd9Sstevel@tonic-gate 		}
11987c478bd9Sstevel@tonic-gate 		if (head->prev == NULL) {
11997c478bd9Sstevel@tonic-gate 			ASSERT(head->next == NULL);
12007c478bd9Sstevel@tonic-gate 		} else {
12017c478bd9Sstevel@tonic-gate 			ASSERT(head->prev->next == NULL);
12027c478bd9Sstevel@tonic-gate 		}
12037c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
12047c478bd9Sstevel@tonic-gate 		    "usba_rm_first_from_list: head=0x%p el=0x%p cnt=%d",
1205112116d8Sfb209375 		    (void *)head, (void *)element, head->count);
12067c478bd9Sstevel@tonic-gate 
12077c478bd9Sstevel@tonic-gate 		mutex_exit(&head->list_mutex);
12087c478bd9Sstevel@tonic-gate 	}
12097c478bd9Sstevel@tonic-gate 
12107c478bd9Sstevel@tonic-gate 	return (element);
12117c478bd9Sstevel@tonic-gate }
12127c478bd9Sstevel@tonic-gate 
12137c478bd9Sstevel@tonic-gate 
12147c478bd9Sstevel@tonic-gate usb_opaque_t
usba_rm_first_pvt_from_list(usba_list_entry_t * head)12157c478bd9Sstevel@tonic-gate usba_rm_first_pvt_from_list(usba_list_entry_t *head)
12167c478bd9Sstevel@tonic-gate {
12177c478bd9Sstevel@tonic-gate 	usba_list_entry_t *element = usba_rm_first_from_list(head);
12187c478bd9Sstevel@tonic-gate 	usb_opaque_t private = NULL;
12197c478bd9Sstevel@tonic-gate 
12207c478bd9Sstevel@tonic-gate 	if (element) {
12217c478bd9Sstevel@tonic-gate 		mutex_enter(&element->list_mutex);
12227c478bd9Sstevel@tonic-gate 		private = element->private;
12237c478bd9Sstevel@tonic-gate 		mutex_exit(&element->list_mutex);
12247c478bd9Sstevel@tonic-gate 	}
12257c478bd9Sstevel@tonic-gate 
12267c478bd9Sstevel@tonic-gate 	return (private);
12277c478bd9Sstevel@tonic-gate }
12287c478bd9Sstevel@tonic-gate 
12297c478bd9Sstevel@tonic-gate 
12307c478bd9Sstevel@tonic-gate /*
12317c478bd9Sstevel@tonic-gate  * move list to new list and zero original list
12327c478bd9Sstevel@tonic-gate  */
12337c478bd9Sstevel@tonic-gate void
usba_move_list(usba_list_entry_t * head,usba_list_entry_t * new,ddi_iblock_cookie_t iblock_cookie)12347c478bd9Sstevel@tonic-gate usba_move_list(usba_list_entry_t *head, usba_list_entry_t *new,
12357c478bd9Sstevel@tonic-gate 	ddi_iblock_cookie_t iblock_cookie)
12367c478bd9Sstevel@tonic-gate {
12377c478bd9Sstevel@tonic-gate 	usba_init_list(new, NULL, iblock_cookie);
12387c478bd9Sstevel@tonic-gate 	mutex_enter(&head->list_mutex);
12397c478bd9Sstevel@tonic-gate 	mutex_enter(&new->list_mutex);
12407c478bd9Sstevel@tonic-gate 
12417c478bd9Sstevel@tonic-gate 	new->next = head->next;
12427c478bd9Sstevel@tonic-gate 	new->prev = head->prev;
12437c478bd9Sstevel@tonic-gate 	new->count = head->count;
12447c478bd9Sstevel@tonic-gate 	new->private = head->private;
12457c478bd9Sstevel@tonic-gate 
12467c478bd9Sstevel@tonic-gate 	head->next = NULL;
12477c478bd9Sstevel@tonic-gate 	head->prev = NULL;
12487c478bd9Sstevel@tonic-gate 	head->count = 0;
12497c478bd9Sstevel@tonic-gate 	head->private = NULL;
12507c478bd9Sstevel@tonic-gate 	mutex_exit(&head->list_mutex);
12517c478bd9Sstevel@tonic-gate 	mutex_exit(&new->list_mutex);
12527c478bd9Sstevel@tonic-gate }
12537c478bd9Sstevel@tonic-gate 
12547c478bd9Sstevel@tonic-gate 
12557c478bd9Sstevel@tonic-gate int
usba_check_in_list(usba_list_entry_t * head,usba_list_entry_t * element)12567c478bd9Sstevel@tonic-gate usba_check_in_list(usba_list_entry_t *head, usba_list_entry_t *element)
12577c478bd9Sstevel@tonic-gate {
12587c478bd9Sstevel@tonic-gate 	int		rval = USB_FAILURE;
12597c478bd9Sstevel@tonic-gate 	int		remaining;
12607c478bd9Sstevel@tonic-gate 	usba_list_entry_t *next;
12617c478bd9Sstevel@tonic-gate 
12627c478bd9Sstevel@tonic-gate 	mutex_enter(&head->list_mutex);
12637c478bd9Sstevel@tonic-gate 	remaining = head->count;
12647c478bd9Sstevel@tonic-gate 
12657c478bd9Sstevel@tonic-gate 	mutex_enter(&element->list_mutex);
12667c478bd9Sstevel@tonic-gate 	for (next = head->next; next != NULL; next = next->next) {
12677c478bd9Sstevel@tonic-gate 		if (next == element) {
12687c478bd9Sstevel@tonic-gate 			rval = USB_SUCCESS;
12697c478bd9Sstevel@tonic-gate 			break;
12707c478bd9Sstevel@tonic-gate 		}
12717c478bd9Sstevel@tonic-gate 		remaining--;
12727c478bd9Sstevel@tonic-gate 
12737c478bd9Sstevel@tonic-gate 		/* Detect incorrect circ links or found unexpected elements. */
12747c478bd9Sstevel@tonic-gate 		if ((next->next && (remaining == 0)) ||
12757c478bd9Sstevel@tonic-gate 		    ((next->next == NULL) && remaining)) {
12767c478bd9Sstevel@tonic-gate 			panic("Corrupted USB list at 0x%p", (void *)head);
12777c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
12787c478bd9Sstevel@tonic-gate 		}
12797c478bd9Sstevel@tonic-gate 	}
12807c478bd9Sstevel@tonic-gate 	mutex_exit(&element->list_mutex);
12817c478bd9Sstevel@tonic-gate 	mutex_exit(&head->list_mutex);
12827c478bd9Sstevel@tonic-gate 
12837c478bd9Sstevel@tonic-gate 	return (rval);
12847c478bd9Sstevel@tonic-gate }
12857c478bd9Sstevel@tonic-gate 
12867c478bd9Sstevel@tonic-gate 
12877c478bd9Sstevel@tonic-gate int
usba_list_entry_leaks(usba_list_entry_t * head,char * what)12887c478bd9Sstevel@tonic-gate usba_list_entry_leaks(usba_list_entry_t *head, char *what)
12897c478bd9Sstevel@tonic-gate {
12907c478bd9Sstevel@tonic-gate 	int		count = 0;
12917c478bd9Sstevel@tonic-gate 	int		remaining;
12927c478bd9Sstevel@tonic-gate 	usba_list_entry_t *next;
12937c478bd9Sstevel@tonic-gate 
12947c478bd9Sstevel@tonic-gate 	mutex_enter(&head->list_mutex);
12957c478bd9Sstevel@tonic-gate 	remaining = head->count;
12967c478bd9Sstevel@tonic-gate 	for (next = head->next; next != NULL; next = next->next) {
12977c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_HCDI, usba_log_handle,
1298112116d8Sfb209375 		    "leaking %s 0x%p", what, (void *)next->private);
12997c478bd9Sstevel@tonic-gate 		count++;
13007c478bd9Sstevel@tonic-gate 
13017c478bd9Sstevel@tonic-gate 		remaining--;
13027c478bd9Sstevel@tonic-gate 
13037c478bd9Sstevel@tonic-gate 		/* Detect incorrect circ links or found unexpected elements. */
13047c478bd9Sstevel@tonic-gate 		if ((next->next && (remaining == 0)) ||
13057c478bd9Sstevel@tonic-gate 		    ((next->next == NULL) && remaining)) {
13067c478bd9Sstevel@tonic-gate 			panic("Corrupted USB list at 0x%p", (void *)head);
13077c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
13087c478bd9Sstevel@tonic-gate 		}
13097c478bd9Sstevel@tonic-gate 	}
13107c478bd9Sstevel@tonic-gate 	ASSERT(count == head->count);
13117c478bd9Sstevel@tonic-gate 	mutex_exit(&head->list_mutex);
13127c478bd9Sstevel@tonic-gate 
13137c478bd9Sstevel@tonic-gate 	if (count) {
13147c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_HCDI, usba_log_handle,
13157c478bd9Sstevel@tonic-gate 		    "usba_list_entry_count: leaking %d", count);
13167c478bd9Sstevel@tonic-gate 	}
13177c478bd9Sstevel@tonic-gate 
13187c478bd9Sstevel@tonic-gate 	return (count);
13197c478bd9Sstevel@tonic-gate }
13207c478bd9Sstevel@tonic-gate 
13217c478bd9Sstevel@tonic-gate 
13227c478bd9Sstevel@tonic-gate int
usba_list_entry_count(usba_list_entry_t * head)13237c478bd9Sstevel@tonic-gate usba_list_entry_count(usba_list_entry_t *head)
13247c478bd9Sstevel@tonic-gate {
13257c478bd9Sstevel@tonic-gate 	int count;
13267c478bd9Sstevel@tonic-gate 
13277c478bd9Sstevel@tonic-gate 	mutex_enter(&head->list_mutex);
13287c478bd9Sstevel@tonic-gate 	count = head->count;
13297c478bd9Sstevel@tonic-gate 	mutex_exit(&head->list_mutex);
13307c478bd9Sstevel@tonic-gate 
13317c478bd9Sstevel@tonic-gate 	return (count);
13327c478bd9Sstevel@tonic-gate }
13337c478bd9Sstevel@tonic-gate 
1334de6f998eSrui wang - Sun Microsystems - Beijing China /* add a new root hub to the usba_root_hubs list */
1335de6f998eSrui wang - Sun Microsystems - Beijing China 
1336de6f998eSrui wang - Sun Microsystems - Beijing China void
usba_add_root_hub(dev_info_t * dip)1337de6f998eSrui wang - Sun Microsystems - Beijing China usba_add_root_hub(dev_info_t *dip)
1338de6f998eSrui wang - Sun Microsystems - Beijing China {
1339de6f998eSrui wang - Sun Microsystems - Beijing China 	usba_root_hub_ent_t *hub;
1340de6f998eSrui wang - Sun Microsystems - Beijing China 
1341de6f998eSrui wang - Sun Microsystems - Beijing China 	hub = (usba_root_hub_ent_t *)
1342de6f998eSrui wang - Sun Microsystems - Beijing China 	    kmem_zalloc(sizeof (usba_root_hub_ent_t), KM_SLEEP);
1343de6f998eSrui wang - Sun Microsystems - Beijing China 
1344de6f998eSrui wang - Sun Microsystems - Beijing China 	mutex_enter(&usba_hub_mutex);
1345de6f998eSrui wang - Sun Microsystems - Beijing China 	hub->dip = dip;
1346de6f998eSrui wang - Sun Microsystems - Beijing China 	hub->next = usba_root_hubs;
1347de6f998eSrui wang - Sun Microsystems - Beijing China 	usba_root_hubs = hub;
1348de6f998eSrui wang - Sun Microsystems - Beijing China 	mutex_exit(&usba_hub_mutex);
1349de6f998eSrui wang - Sun Microsystems - Beijing China }
1350de6f998eSrui wang - Sun Microsystems - Beijing China 
1351de6f998eSrui wang - Sun Microsystems - Beijing China /* remove a root hub from the usba_root_hubs list */
1352de6f998eSrui wang - Sun Microsystems - Beijing China 
1353de6f998eSrui wang - Sun Microsystems - Beijing China void
usba_rem_root_hub(dev_info_t * dip)1354de6f998eSrui wang - Sun Microsystems - Beijing China usba_rem_root_hub(dev_info_t *dip)
1355de6f998eSrui wang - Sun Microsystems - Beijing China {
1356de6f998eSrui wang - Sun Microsystems - Beijing China 	usba_root_hub_ent_t **hubp, *hub;
1357de6f998eSrui wang - Sun Microsystems - Beijing China 
1358de6f998eSrui wang - Sun Microsystems - Beijing China 	mutex_enter(&usba_hub_mutex);
1359de6f998eSrui wang - Sun Microsystems - Beijing China 	hubp = &usba_root_hubs;
1360de6f998eSrui wang - Sun Microsystems - Beijing China 	while (*hubp) {
1361de6f998eSrui wang - Sun Microsystems - Beijing China 		if ((*hubp)->dip == dip) {
1362de6f998eSrui wang - Sun Microsystems - Beijing China 			hub = *hubp;
1363de6f998eSrui wang - Sun Microsystems - Beijing China 			*hubp = hub->next;
1364de6f998eSrui wang - Sun Microsystems - Beijing China 			kmem_free(hub, sizeof (struct usba_root_hub_ent));
1365de6f998eSrui wang - Sun Microsystems - Beijing China 			mutex_exit(&usba_hub_mutex);
1366de6f998eSrui wang - Sun Microsystems - Beijing China 
1367de6f998eSrui wang - Sun Microsystems - Beijing China 			return;
1368de6f998eSrui wang - Sun Microsystems - Beijing China 		}
1369de6f998eSrui wang - Sun Microsystems - Beijing China 		hubp = &(*hubp)->next;
1370de6f998eSrui wang - Sun Microsystems - Beijing China 	}
1371de6f998eSrui wang - Sun Microsystems - Beijing China 	mutex_exit(&usba_hub_mutex);
1372de6f998eSrui wang - Sun Microsystems - Beijing China }
13737c478bd9Sstevel@tonic-gate 
13747c478bd9Sstevel@tonic-gate /*
1375de6f998eSrui wang - Sun Microsystems - Beijing China  * check whether this dip is the root hub. Any root hub known by
1376de6f998eSrui wang - Sun Microsystems - Beijing China  * usba is recorded in the linked list pointed to by usba_root_hubs
13777c478bd9Sstevel@tonic-gate  */
13787c478bd9Sstevel@tonic-gate int
usba_is_root_hub(dev_info_t * dip)13797c478bd9Sstevel@tonic-gate usba_is_root_hub(dev_info_t *dip)
13807c478bd9Sstevel@tonic-gate {
1381de6f998eSrui wang - Sun Microsystems - Beijing China 	usba_root_hub_ent_t *hub;
1382de6f998eSrui wang - Sun Microsystems - Beijing China 
1383de6f998eSrui wang - Sun Microsystems - Beijing China 	mutex_enter(&usba_hub_mutex);
1384de6f998eSrui wang - Sun Microsystems - Beijing China 	hub = usba_root_hubs;
1385de6f998eSrui wang - Sun Microsystems - Beijing China 	while (hub) {
1386de6f998eSrui wang - Sun Microsystems - Beijing China 		if (hub->dip == dip) {
1387de6f998eSrui wang - Sun Microsystems - Beijing China 			mutex_exit(&usba_hub_mutex);
1388de6f998eSrui wang - Sun Microsystems - Beijing China 
1389de6f998eSrui wang - Sun Microsystems - Beijing China 			return (1);
13907c478bd9Sstevel@tonic-gate 		}
1391de6f998eSrui wang - Sun Microsystems - Beijing China 		hub = hub->next;
1392de6f998eSrui wang - Sun Microsystems - Beijing China 	}
1393de6f998eSrui wang - Sun Microsystems - Beijing China 	mutex_exit(&usba_hub_mutex);
1394de6f998eSrui wang - Sun Microsystems - Beijing China 
13957c478bd9Sstevel@tonic-gate 	return (0);
13967c478bd9Sstevel@tonic-gate }
13977c478bd9Sstevel@tonic-gate 
1398ff0e937bSRaymond Chen /*
13997c478bd9Sstevel@tonic-gate  * get and store usba_device pointer in the devi
14007c478bd9Sstevel@tonic-gate  */
14017c478bd9Sstevel@tonic-gate usba_device_t *
usba_get_usba_device(dev_info_t * dip)14027c478bd9Sstevel@tonic-gate usba_get_usba_device(dev_info_t *dip)
14037c478bd9Sstevel@tonic-gate {
14047c478bd9Sstevel@tonic-gate 	/*
14057c478bd9Sstevel@tonic-gate 	 * we cannot use parent_data in the usb node because its
14067c478bd9Sstevel@tonic-gate 	 * bus parent (eg. PCI nexus driver) uses this data
14077c478bd9Sstevel@tonic-gate 	 *
14087c478bd9Sstevel@tonic-gate 	 * we cannot use driver data in the other usb nodes since
14097c478bd9Sstevel@tonic-gate 	 * usb drivers may need to use this
14107c478bd9Sstevel@tonic-gate 	 */
14117c478bd9Sstevel@tonic-gate 	if (usba_is_root_hub(dip)) {
14127c478bd9Sstevel@tonic-gate 		usba_hcdi_t *hcdi = usba_hcdi_get_hcdi(dip);
14137c478bd9Sstevel@tonic-gate 
14147c478bd9Sstevel@tonic-gate 		return (hcdi->hcdi_usba_device);
14157c478bd9Sstevel@tonic-gate 	} else {
14167c478bd9Sstevel@tonic-gate 
14177c478bd9Sstevel@tonic-gate 		return (ddi_get_parent_data(dip));
14187c478bd9Sstevel@tonic-gate 	}
14197c478bd9Sstevel@tonic-gate }
14207c478bd9Sstevel@tonic-gate 
14217c478bd9Sstevel@tonic-gate 
14227c478bd9Sstevel@tonic-gate /*
14237c478bd9Sstevel@tonic-gate  * Retrieve the usba_device pointer from the dev without checking for
14247c478bd9Sstevel@tonic-gate  * the root hub first.	This function is only used in polled mode.
14257c478bd9Sstevel@tonic-gate  */
14267c478bd9Sstevel@tonic-gate usba_device_t *
usba_polled_get_usba_device(dev_info_t * dip)14277c478bd9Sstevel@tonic-gate usba_polled_get_usba_device(dev_info_t *dip)
14287c478bd9Sstevel@tonic-gate {
14297c478bd9Sstevel@tonic-gate 	/*
14307c478bd9Sstevel@tonic-gate 	 * Don't call usba_is_root_hub() to find out if this is
14317c478bd9Sstevel@tonic-gate 	 * the root hub  usba_is_root_hub() calls into the DDI
14327c478bd9Sstevel@tonic-gate 	 * where there are locking issues. The dip sent in during
14337c478bd9Sstevel@tonic-gate 	 * polled mode will never be the root hub, so just get
14347c478bd9Sstevel@tonic-gate 	 * the usba_device pointer from the dip.
14357c478bd9Sstevel@tonic-gate 	 */
14367c478bd9Sstevel@tonic-gate 	return (ddi_get_parent_data(dip));
14377c478bd9Sstevel@tonic-gate }
14387c478bd9Sstevel@tonic-gate 
14397c478bd9Sstevel@tonic-gate 
14407c478bd9Sstevel@tonic-gate void
usba_set_usba_device(dev_info_t * dip,usba_device_t * usba_device)14417c478bd9Sstevel@tonic-gate usba_set_usba_device(dev_info_t *dip, usba_device_t *usba_device)
14427c478bd9Sstevel@tonic-gate {
14437c478bd9Sstevel@tonic-gate 	if (usba_is_root_hub(dip)) {
14447c478bd9Sstevel@tonic-gate 		usba_hcdi_t *hcdi = usba_hcdi_get_hcdi(dip);
14457c478bd9Sstevel@tonic-gate 		/* no locking is needed here */
14467c478bd9Sstevel@tonic-gate 		_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(hcdi->hcdi_usba_device))
14477c478bd9Sstevel@tonic-gate 		hcdi->hcdi_usba_device = usba_device;
14487c478bd9Sstevel@tonic-gate 		_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(hcdi->hcdi_usba_device))
14497c478bd9Sstevel@tonic-gate 	} else {
14507c478bd9Sstevel@tonic-gate 		ddi_set_parent_data(dip, usba_device);
14517c478bd9Sstevel@tonic-gate 	}
14527c478bd9Sstevel@tonic-gate }
14537c478bd9Sstevel@tonic-gate 
14547c478bd9Sstevel@tonic-gate 
14557c478bd9Sstevel@tonic-gate /*
14567c478bd9Sstevel@tonic-gate  * usba_set_node_name() according to class, subclass, and protocol
14577c478bd9Sstevel@tonic-gate  * following the 1275 USB binding tables.
14587c478bd9Sstevel@tonic-gate  */
14597c478bd9Sstevel@tonic-gate 
14607c478bd9Sstevel@tonic-gate /* device node table, refer to section 3.2.2.1 of 1275 binding */
14617c478bd9Sstevel@tonic-gate static node_name_entry_t device_node_name_table[] = {
14627c478bd9Sstevel@tonic-gate { USB_CLASS_COMM,	DONTCARE,	DONTCARE,	"communications" },
14637c478bd9Sstevel@tonic-gate { USB_CLASS_HUB,	DONTCARE,	DONTCARE,	"hub" },
1464d73ae94eSgc161489 { USB_CLASS_DIAG,	DONTCARE,	DONTCARE,	"diagnostics" },
1465d73ae94eSgc161489 { USB_CLASS_MISC,	DONTCARE,	DONTCARE,	"miscellaneous" },
14667c478bd9Sstevel@tonic-gate { DONTCARE,		DONTCARE,	DONTCARE,	"device" }
14677c478bd9Sstevel@tonic-gate };
14687c478bd9Sstevel@tonic-gate 
1469d73ae94eSgc161489 /* interface-association node table */
1470d73ae94eSgc161489 static node_name_entry_t ia_node_name_table[] = {
1471d73ae94eSgc161489 { USB_CLASS_AUDIO,	DONTCARE,	DONTCARE, "audio" },
1472d73ae94eSgc161489 { USB_CLASS_VIDEO,	DONTCARE,	DONTCARE, "video" },
1473d73ae94eSgc161489 { USB_CLASS_WIRELESS,	USB_SUBCLS_WUSB_2, USB_PROTO_WUSB_DWA,
1474d73ae94eSgc161489 						"device-wire-adaptor" },
1475d73ae94eSgc161489 { USB_CLASS_WIRELESS,	DONTCARE,	DONTCARE, "wireless-controller" },
1476d73ae94eSgc161489 { DONTCARE,		DONTCARE,	DONTCARE, "interface-association" }
1477d73ae94eSgc161489 };
1478d73ae94eSgc161489 
14797c478bd9Sstevel@tonic-gate /* interface node table, refer to section 3.3.2.1 */
14807c478bd9Sstevel@tonic-gate static node_name_entry_t if_node_name_table[] = {
14817c478bd9Sstevel@tonic-gate { USB_CLASS_AUDIO, USB_SUBCLS_AUD_CONTROL, DONTCARE,	"sound-control" },
14827c478bd9Sstevel@tonic-gate { USB_CLASS_AUDIO, USB_SUBCLS_AUD_STREAMING, DONTCARE, "sound" },
14837c478bd9Sstevel@tonic-gate { USB_CLASS_AUDIO, USB_SUBCLS_AUD_MIDI_STREAMING, DONTCARE, "midi" },
14847c478bd9Sstevel@tonic-gate { USB_CLASS_AUDIO, DONTCARE,		DONTCARE,	"sound" },
14857c478bd9Sstevel@tonic-gate 
14867c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_DIRECT_LINE,	DONTCARE, "line" },
14877c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_ABSTRCT_CTRL,	DONTCARE, "modem" },
14887c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_PHONE_CTRL, DONTCARE, "telephone" },
14897c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_MULTCNL_ISDN, DONTCARE, "isdn" },
14907c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_ISDN,		DONTCARE, "isdn" },
14917c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_ETHERNET,	DONTCARE, "ethernet" },
14927c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_ATM_NETWORK, DONTCARE, "atm-network" },
1493d73ae94eSgc161489 { USB_CLASS_COMM, DONTCARE,		DONTCARE,	"communications" },
14947c478bd9Sstevel@tonic-gate 
14957c478bd9Sstevel@tonic-gate { USB_CLASS_HID, USB_SUBCLS_HID_1, USB_PROTO_HID_KEYBOARD,	"keyboard" },
14967c478bd9Sstevel@tonic-gate { USB_CLASS_HID, USB_SUBCLS_HID_1, USB_PROTO_HID_MOUSE,	"mouse" },
14977c478bd9Sstevel@tonic-gate { USB_CLASS_HID,	DONTCARE,	DONTCARE,	"input" },
14987c478bd9Sstevel@tonic-gate 
14997c478bd9Sstevel@tonic-gate { USB_CLASS_HUB,	DONTCARE,	DONTCARE,	"hub" },
15007c478bd9Sstevel@tonic-gate 
15017c478bd9Sstevel@tonic-gate { USB_CLASS_PHYSICAL,	DONTCARE,	DONTCARE,	"physical" },
15027c478bd9Sstevel@tonic-gate 
1503d73ae94eSgc161489 { USB_CLASS_IMAGE,	DONTCARE,	DONTCARE,	"image" },
1504d73ae94eSgc161489 
15057c478bd9Sstevel@tonic-gate { USB_CLASS_PRINTER,	DONTCARE,	DONTCARE,	"printer" },
15067c478bd9Sstevel@tonic-gate 
15077c478bd9Sstevel@tonic-gate { USB_CLASS_MASS_STORAGE, DONTCARE,	DONTCARE,	"storage" },
15087c478bd9Sstevel@tonic-gate 
15097c478bd9Sstevel@tonic-gate { USB_CLASS_CDC_DATA,	DONTCARE,	DONTCARE,	"data" },
15107c478bd9Sstevel@tonic-gate 
15117c478bd9Sstevel@tonic-gate { USB_CLASS_SECURITY,	DONTCARE,	DONTCARE,	"security" },
15127c478bd9Sstevel@tonic-gate 
1513d73ae94eSgc161489 { USB_CLASS_VIDEO, USB_SUBCLS_VIDEO_CONTROL, DONTCARE,	"video-control" },
1514d73ae94eSgc161489 { USB_CLASS_VIDEO, USB_SUBCLS_VIDEO_STREAM,  DONTCARE,	"video-stream" },
1515d73ae94eSgc161489 { USB_CLASS_VIDEO,	DONTCARE,	DONTCARE,	"video" },
1516d73ae94eSgc161489 
15177c478bd9Sstevel@tonic-gate { USB_CLASS_APP,	USB_SUBCLS_APP_FIRMWARE, DONTCARE, "firmware" },
15187c478bd9Sstevel@tonic-gate { USB_CLASS_APP,	USB_SUBCLS_APP_IRDA,	DONTCARE, "IrDa" },
15197c478bd9Sstevel@tonic-gate { USB_CLASS_APP,	USB_SUBCLS_APP_TEST,	DONTCARE, "test" },
15207c478bd9Sstevel@tonic-gate 
1521ff0e937bSRaymond Chen { USB_CLASS_MISC,	USB_SUBCLS_CBAF, USB_PROTO_CBAF,  "wusb_ca"},
1522ff0e937bSRaymond Chen { USB_CLASS_WIRELESS, USB_SUBCLS_WUSB_1, USB_PROTO_WUSB_RC, "hwa-radio" },
1523ff0e937bSRaymond Chen { USB_CLASS_WIRELESS, USB_SUBCLS_WUSB_2, USB_PROTO_WUSB_HWA, "hwa-host" },
1524ff0e937bSRaymond Chen { USB_CLASS_WIRELESS, USB_SUBCLS_WUSB_2, USB_PROTO_WUSB_DWA, "dwa-control" },
1525ff0e937bSRaymond Chen { USB_CLASS_WIRELESS, USB_SUBCLS_WUSB_2, USB_PROTO_WUSB_DWA_ISO, "dwa-isoc" },
1526ff0e937bSRaymond Chen { USB_CLASS_WIRELESS, DONTCARE, DONTCARE, "wireless" },
1527ff0e937bSRaymond Chen 
15287c478bd9Sstevel@tonic-gate { DONTCARE,		DONTCARE,	DONTCARE,	"interface" },
15297c478bd9Sstevel@tonic-gate 
15307c478bd9Sstevel@tonic-gate };
15317c478bd9Sstevel@tonic-gate 
15327c478bd9Sstevel@tonic-gate /* combined node table, refer to section 3.4.2.1 */
15337c478bd9Sstevel@tonic-gate static node_name_entry_t combined_node_name_table[] = {
15347c478bd9Sstevel@tonic-gate { USB_CLASS_AUDIO, USB_SUBCLS_AUD_CONTROL, DONTCARE,	"sound-control" },
15357c478bd9Sstevel@tonic-gate { USB_CLASS_AUDIO, USB_SUBCLS_AUD_STREAMING, DONTCARE, "sound" },
15367c478bd9Sstevel@tonic-gate { USB_CLASS_AUDIO, USB_SUBCLS_AUD_MIDI_STREAMING, DONTCARE, "midi" },
15377c478bd9Sstevel@tonic-gate { USB_CLASS_AUDIO, DONTCARE,		DONTCARE,	"sound" },
15387c478bd9Sstevel@tonic-gate 
15397c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_DIRECT_LINE,	DONTCARE, "line" },
15407c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_ABSTRCT_CTRL,	DONTCARE, "modem" },
15417c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_PHONE_CTRL, DONTCARE, "telephone" },
15427c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_MULTCNL_ISDN, DONTCARE, "isdn" },
15437c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_ISDN,		DONTCARE, "isdn" },
15447c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_ETHERNET,	DONTCARE, "ethernet" },
15457c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_ATM_NETWORK, DONTCARE, "atm-network" },
1546d73ae94eSgc161489 { USB_CLASS_COMM, DONTCARE,		DONTCARE,	"communications" },
15477c478bd9Sstevel@tonic-gate 
15487c478bd9Sstevel@tonic-gate { USB_CLASS_HID, USB_SUBCLS_HID_1, USB_PROTO_HID_KEYBOARD, "keyboard" },
15497c478bd9Sstevel@tonic-gate { USB_CLASS_HID, USB_SUBCLS_HID_1, USB_PROTO_HID_MOUSE,	"mouse" },
15507c478bd9Sstevel@tonic-gate { USB_CLASS_HID,	DONTCARE,	DONTCARE,	"input" },
15517c478bd9Sstevel@tonic-gate 
15527c478bd9Sstevel@tonic-gate { USB_CLASS_PHYSICAL,	DONTCARE,	DONTCARE,	"physical" },
15537c478bd9Sstevel@tonic-gate 
1554d73ae94eSgc161489 { USB_CLASS_IMAGE,	DONTCARE,	DONTCARE,	"image" },
1555d73ae94eSgc161489 
15567c478bd9Sstevel@tonic-gate { USB_CLASS_PRINTER,	DONTCARE,	DONTCARE,	"printer" },
15577c478bd9Sstevel@tonic-gate 
1558d73ae94eSgc161489 { USB_CLASS_MASS_STORAGE, USB_SUBCLS_MS_RBC_T10,	DONTCARE, "storage" },
1559d73ae94eSgc161489 { USB_CLASS_MASS_STORAGE, USB_SUBCLS_MS_SFF8020I,	DONTCARE, "cdrom" },
1560d73ae94eSgc161489 { USB_CLASS_MASS_STORAGE, USB_SUBCLS_MS_QIC_157,	DONTCARE, "tape" },
1561d73ae94eSgc161489 { USB_CLASS_MASS_STORAGE, USB_SUBCLS_MS_UFI,		DONTCARE, "floppy" },
1562d73ae94eSgc161489 { USB_CLASS_MASS_STORAGE, USB_SUBCLS_MS_SFF8070I,	DONTCARE, "storage" },
1563d73ae94eSgc161489 { USB_CLASS_MASS_STORAGE, USB_SUBCLS_MS_SCSI,		DONTCARE, "storage" },
15647c478bd9Sstevel@tonic-gate { USB_CLASS_MASS_STORAGE, DONTCARE,	DONTCARE,	"storage" },
15657c478bd9Sstevel@tonic-gate 
15667c478bd9Sstevel@tonic-gate { USB_CLASS_CDC_DATA,	DONTCARE,	DONTCARE,	"data" },
15677c478bd9Sstevel@tonic-gate 
15687c478bd9Sstevel@tonic-gate { USB_CLASS_SECURITY,	DONTCARE,	DONTCARE,	"security" },
15697c478bd9Sstevel@tonic-gate 
1570d73ae94eSgc161489 { USB_CLASS_VIDEO, USB_SUBCLS_VIDEO_CONTROL, DONTCARE,	"video-control" },
1571d73ae94eSgc161489 { USB_CLASS_VIDEO, USB_SUBCLS_VIDEO_STREAM,  DONTCARE,	"video-stream" },
1572d73ae94eSgc161489 { USB_CLASS_VIDEO,	DONTCARE,	DONTCARE,	"video" },
1573d73ae94eSgc161489 
15747c478bd9Sstevel@tonic-gate { USB_CLASS_APP,	USB_SUBCLS_APP_FIRMWARE, DONTCARE, "firmware" },
15757c478bd9Sstevel@tonic-gate { USB_CLASS_APP,	USB_SUBCLS_APP_IRDA,	DONTCARE, "IrDa" },
15767c478bd9Sstevel@tonic-gate { USB_CLASS_APP,	USB_SUBCLS_APP_TEST,	DONTCARE, "test" },
15777c478bd9Sstevel@tonic-gate 
15787c478bd9Sstevel@tonic-gate { USB_CLASS_COMM,	DONTCARE,	DONTCARE,	"communications" },
1579d73ae94eSgc161489 { USB_CLASS_HUB,	DONTCARE,	DONTCARE,	"hub" },
1580d73ae94eSgc161489 { USB_CLASS_DIAG,	DONTCARE,	DONTCARE,	"diagnostics" },
1581d73ae94eSgc161489 { USB_CLASS_MISC,	DONTCARE,	DONTCARE,	"miscellaneous" },
1582d73ae94eSgc161489 { DONTCARE,		DONTCARE,	DONTCARE,	"device" }
15837c478bd9Sstevel@tonic-gate };
15847c478bd9Sstevel@tonic-gate 
15857c478bd9Sstevel@tonic-gate static size_t device_node_name_table_size =
15867c478bd9Sstevel@tonic-gate 	sizeof (device_node_name_table)/sizeof (struct node_name_entry);
1587d73ae94eSgc161489 static size_t ia_node_name_table_size =
1588d73ae94eSgc161489 	sizeof (ia_node_name_table)/sizeof (struct node_name_entry);
15897c478bd9Sstevel@tonic-gate static size_t if_node_name_table_size =
15907c478bd9Sstevel@tonic-gate 	sizeof (if_node_name_table)/sizeof (struct node_name_entry);
15917c478bd9Sstevel@tonic-gate static size_t combined_node_name_table_size =
15927c478bd9Sstevel@tonic-gate 	sizeof (combined_node_name_table)/sizeof (struct node_name_entry);
15937c478bd9Sstevel@tonic-gate 
15947c478bd9Sstevel@tonic-gate 
15957c478bd9Sstevel@tonic-gate static void
usba_set_node_name(dev_info_t * dip,uint8_t class,uint8_t subclass,uint8_t protocol,uint_t flag)15967c478bd9Sstevel@tonic-gate usba_set_node_name(dev_info_t *dip, uint8_t class, uint8_t subclass,
15977c478bd9Sstevel@tonic-gate     uint8_t protocol, uint_t flag)
15987c478bd9Sstevel@tonic-gate {
15997c478bd9Sstevel@tonic-gate 	int i;
16007c478bd9Sstevel@tonic-gate 	size_t size;
16017c478bd9Sstevel@tonic-gate 	node_name_entry_t *node_name_table;
16027c478bd9Sstevel@tonic-gate 
16037c478bd9Sstevel@tonic-gate 	switch (flag) {
1604d73ae94eSgc161489 	/* interface share node names with interface-association */
1605d73ae94eSgc161489 	case FLAG_INTERFACE_ASSOCIATION_NODE:
1606d73ae94eSgc161489 		node_name_table = ia_node_name_table;
1607d73ae94eSgc161489 		size = ia_node_name_table_size;
1608d73ae94eSgc161489 		break;
16097c478bd9Sstevel@tonic-gate 	case FLAG_INTERFACE_NODE:
16107c478bd9Sstevel@tonic-gate 		node_name_table = if_node_name_table;
16117c478bd9Sstevel@tonic-gate 		size = if_node_name_table_size;
16127c478bd9Sstevel@tonic-gate 		break;
16137c478bd9Sstevel@tonic-gate 	case FLAG_DEVICE_NODE:
16147c478bd9Sstevel@tonic-gate 		node_name_table = device_node_name_table;
16157c478bd9Sstevel@tonic-gate 		size = device_node_name_table_size;
16167c478bd9Sstevel@tonic-gate 		break;
16177c478bd9Sstevel@tonic-gate 	case FLAG_COMBINED_NODE:
16187c478bd9Sstevel@tonic-gate 		node_name_table = combined_node_name_table;
16197c478bd9Sstevel@tonic-gate 		size = combined_node_name_table_size;
16207c478bd9Sstevel@tonic-gate 		break;
16217c478bd9Sstevel@tonic-gate 	default:
16227c478bd9Sstevel@tonic-gate 
16237c478bd9Sstevel@tonic-gate 		return;
16247c478bd9Sstevel@tonic-gate 	}
16257c478bd9Sstevel@tonic-gate 
16267c478bd9Sstevel@tonic-gate 	for (i = 0; i < size; i++) {
16277c478bd9Sstevel@tonic-gate 		int16_t c = node_name_table[i].class;
16287c478bd9Sstevel@tonic-gate 		int16_t s = node_name_table[i].subclass;
16297c478bd9Sstevel@tonic-gate 		int16_t p = node_name_table[i].protocol;
16307c478bd9Sstevel@tonic-gate 
16317c478bd9Sstevel@tonic-gate 		if (((c == DONTCARE) || (c == class)) &&
16327c478bd9Sstevel@tonic-gate 		    ((s == DONTCARE) || (s == subclass)) &&
16337c478bd9Sstevel@tonic-gate 		    ((p == DONTCARE) || (p == protocol))) {
16347c478bd9Sstevel@tonic-gate 			char *name = node_name_table[i].name;
1635d73ae94eSgc161489 
16367c478bd9Sstevel@tonic-gate 			(void) ndi_devi_set_nodename(dip, name, 0);
16377c478bd9Sstevel@tonic-gate 			break;
16387c478bd9Sstevel@tonic-gate 		}
16397c478bd9Sstevel@tonic-gate 	}
16407c478bd9Sstevel@tonic-gate }
16417c478bd9Sstevel@tonic-gate 
16427c478bd9Sstevel@tonic-gate 
16437c478bd9Sstevel@tonic-gate #ifdef DEBUG
16447c478bd9Sstevel@tonic-gate /*
16457c478bd9Sstevel@tonic-gate  * walk the children of the parent of this devi and compare the
16467c478bd9Sstevel@tonic-gate  * name and  reg property of each child. If there is a match
16477c478bd9Sstevel@tonic-gate  * return this node
16487c478bd9Sstevel@tonic-gate  */
16497c478bd9Sstevel@tonic-gate static dev_info_t *
usba_find_existing_node(dev_info_t * odip)16507c478bd9Sstevel@tonic-gate usba_find_existing_node(dev_info_t *odip)
16517c478bd9Sstevel@tonic-gate {
16527c478bd9Sstevel@tonic-gate 	dev_info_t *ndip, *child, *pdip;
16537c478bd9Sstevel@tonic-gate 	int	*odata, *ndata;
16547c478bd9Sstevel@tonic-gate 	uint_t	n_odata, n_ndata;
16557c478bd9Sstevel@tonic-gate 	int	circular;
16567c478bd9Sstevel@tonic-gate 
16577c478bd9Sstevel@tonic-gate 	pdip = ddi_get_parent(odip);
16587c478bd9Sstevel@tonic-gate 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY,
16597c478bd9Sstevel@tonic-gate 	    odip, DDI_PROP_DONTPASS, "reg",
16607c478bd9Sstevel@tonic-gate 	    &odata, &n_odata) != DDI_SUCCESS) {
1661d291d9f2Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_HCDI, usba_log_handle,
16627c478bd9Sstevel@tonic-gate 		    "usba_find_existing_node: "
16637c478bd9Sstevel@tonic-gate 		    "%s: DDI_NOT_WELL_FORMED", ddi_driver_name(odip));
16647c478bd9Sstevel@tonic-gate 
16657c478bd9Sstevel@tonic-gate 		return (NULL);
16667c478bd9Sstevel@tonic-gate 	}
16677c478bd9Sstevel@tonic-gate 
16687c478bd9Sstevel@tonic-gate 	ndi_devi_enter(pdip, &circular);
16697c478bd9Sstevel@tonic-gate 	ndip = (dev_info_t *)(DEVI(pdip)->devi_child);
16707c478bd9Sstevel@tonic-gate 	while ((child = ndip) != NULL) {
16717c478bd9Sstevel@tonic-gate 
16727c478bd9Sstevel@tonic-gate 		ndip = (dev_info_t *)(DEVI(child)->devi_sibling);
16737c478bd9Sstevel@tonic-gate 
16747c478bd9Sstevel@tonic-gate 		if (child == odip) {
16757c478bd9Sstevel@tonic-gate 			continue;
16767c478bd9Sstevel@tonic-gate 		}
16777c478bd9Sstevel@tonic-gate 
16787c478bd9Sstevel@tonic-gate 		if (strcmp(DEVI(child)->devi_node_name,
16797c478bd9Sstevel@tonic-gate 		    DEVI(odip)->devi_node_name)) {
16807c478bd9Sstevel@tonic-gate 			continue;
16817c478bd9Sstevel@tonic-gate 		}
16827c478bd9Sstevel@tonic-gate 
16837c478bd9Sstevel@tonic-gate 		if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY,
16847c478bd9Sstevel@tonic-gate 		    child, DDI_PROP_DONTPASS, "reg",
16857c478bd9Sstevel@tonic-gate 		    &ndata, &n_ndata) != DDI_SUCCESS) {
16867c478bd9Sstevel@tonic-gate 
1687d291d9f2Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_HCDI, usba_log_handle,
16887c478bd9Sstevel@tonic-gate 			    "usba_find_existing_node: "
16897c478bd9Sstevel@tonic-gate 			    "%s DDI_NOT_WELL_FORMED", ddi_driver_name(child));
16907c478bd9Sstevel@tonic-gate 
16917c478bd9Sstevel@tonic-gate 		} else if (n_ndata && n_odata && (bcmp(odata, ndata,
16927c478bd9Sstevel@tonic-gate 		    max(n_odata, n_ndata) * sizeof (int)) == 0)) {
16937c478bd9Sstevel@tonic-gate 
16947c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L3(DPRINT_MASK_HCDI, usba_log_handle,
16957c478bd9Sstevel@tonic-gate 			    "usba_find_existing_node: found %s%d (%p)",
16967c478bd9Sstevel@tonic-gate 			    ddi_driver_name(child),
16977c478bd9Sstevel@tonic-gate 			    ddi_get_instance(child), (void *)child);
16987c478bd9Sstevel@tonic-gate 
16997c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L3(DPRINT_MASK_HCDI, usba_log_handle,
17007c478bd9Sstevel@tonic-gate 			    "usba_find_existing_node: "
17017c478bd9Sstevel@tonic-gate 			    "reg: %x %x %x - %x %x %x",
17027c478bd9Sstevel@tonic-gate 			    n_odata, odata[0], odata[1],
17037c478bd9Sstevel@tonic-gate 			    n_ndata, ndata[0], ndata[1]);
17047c478bd9Sstevel@tonic-gate 
17057c478bd9Sstevel@tonic-gate 			ddi_prop_free(ndata);
17067c478bd9Sstevel@tonic-gate 			break;
17077c478bd9Sstevel@tonic-gate 
17087c478bd9Sstevel@tonic-gate 		} else {
17097c478bd9Sstevel@tonic-gate 			ddi_prop_free(ndata);
17107c478bd9Sstevel@tonic-gate 		}
17117c478bd9Sstevel@tonic-gate 	}
17127c478bd9Sstevel@tonic-gate 
17137c478bd9Sstevel@tonic-gate 	ndi_devi_exit(pdip, circular);
17147c478bd9Sstevel@tonic-gate 
17157c478bd9Sstevel@tonic-gate 	ddi_prop_free(odata);
17167c478bd9Sstevel@tonic-gate 
17177c478bd9Sstevel@tonic-gate 	return (child);
17187c478bd9Sstevel@tonic-gate }
17197c478bd9Sstevel@tonic-gate #endif
17207c478bd9Sstevel@tonic-gate 
17217c478bd9Sstevel@tonic-gate /* change all unprintable characters to spaces */
17227c478bd9Sstevel@tonic-gate static void
usba_filter_string(char * instr,char * outstr)17237c478bd9Sstevel@tonic-gate usba_filter_string(char *instr, char *outstr)
17247c478bd9Sstevel@tonic-gate {
17257c478bd9Sstevel@tonic-gate 	while (*instr) {
17267c478bd9Sstevel@tonic-gate 		if ((*instr >= ' ') && (*instr <= '~')) {
17277c478bd9Sstevel@tonic-gate 			*outstr = *instr;
17287c478bd9Sstevel@tonic-gate 		} else {
17297c478bd9Sstevel@tonic-gate 			*outstr = ' ';
17307c478bd9Sstevel@tonic-gate 		}
17317c478bd9Sstevel@tonic-gate 		outstr++;
17327c478bd9Sstevel@tonic-gate 		instr++;
17337c478bd9Sstevel@tonic-gate 	}
17347c478bd9Sstevel@tonic-gate 	*outstr = '\0';
17357c478bd9Sstevel@tonic-gate }
17367c478bd9Sstevel@tonic-gate 
17377c478bd9Sstevel@tonic-gate 
17387c478bd9Sstevel@tonic-gate /*
17397c478bd9Sstevel@tonic-gate  * lookup ugen binding specified in property in
17407c478bd9Sstevel@tonic-gate  * hcd.conf files
17417c478bd9Sstevel@tonic-gate  */
17427c478bd9Sstevel@tonic-gate int
usba_get_ugen_binding(dev_info_t * dip)17437c478bd9Sstevel@tonic-gate usba_get_ugen_binding(dev_info_t *dip)
17447c478bd9Sstevel@tonic-gate {
17457c478bd9Sstevel@tonic-gate 	usba_device_t	*usba_device = usba_get_usba_device(dip);
17467c478bd9Sstevel@tonic-gate 	usba_hcdi_t	*hcdi =
17477c478bd9Sstevel@tonic-gate 	    usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
17487c478bd9Sstevel@tonic-gate 
17497c478bd9Sstevel@tonic-gate 	return (hcdi->hcdi_ugen_default_binding);
17507c478bd9Sstevel@tonic-gate }
17517c478bd9Sstevel@tonic-gate 
17527c478bd9Sstevel@tonic-gate 
17537c478bd9Sstevel@tonic-gate /*
17547c478bd9Sstevel@tonic-gate  * driver binding support at device level
17557c478bd9Sstevel@tonic-gate  */
17567c478bd9Sstevel@tonic-gate dev_info_t *
usba_ready_device_node(dev_info_t * child_dip)17577c478bd9Sstevel@tonic-gate usba_ready_device_node(dev_info_t *child_dip)
17587c478bd9Sstevel@tonic-gate {
17597c478bd9Sstevel@tonic-gate 	int		rval, i;
17607c478bd9Sstevel@tonic-gate 	int		n = 0;
17617c478bd9Sstevel@tonic-gate 	usba_device_t	*usba_device = usba_get_usba_device(child_dip);
17627c478bd9Sstevel@tonic-gate 	usb_dev_descr_t	*usb_dev_descr;
17637c478bd9Sstevel@tonic-gate 	uint_t		n_cfgs;	/* number of configs */
17647c478bd9Sstevel@tonic-gate 	uint_t		n_ifs;	/* number of interfaces */
1765a7df97baSStrony Zhang - Solaris China Team 	uint_t		port, bus_num;
17667c478bd9Sstevel@tonic-gate 	size_t		usb_config_length;
17677c478bd9Sstevel@tonic-gate 	uchar_t 	*usb_config;
17687c478bd9Sstevel@tonic-gate 	int		reg[1];
17697c478bd9Sstevel@tonic-gate 	usb_addr_t	address = usb_get_addr(child_dip);
17707c478bd9Sstevel@tonic-gate 	usb_if_descr_t	if_descr;
17717c478bd9Sstevel@tonic-gate 	size_t		size;
17727c478bd9Sstevel@tonic-gate 	int		combined_node = 0;
17737c478bd9Sstevel@tonic-gate 	int		is_hub;
17747c478bd9Sstevel@tonic-gate 	char		*devprop_str;
17757c478bd9Sstevel@tonic-gate 	char		*force_bind = NULL;
17763c91d182Slg150142 	char		*usba_name_buf = NULL;
17773c91d182Slg150142 	char		*usba_name[USBA_MAX_COMPAT_NAMES];
17787c478bd9Sstevel@tonic-gate 
17797c478bd9Sstevel@tonic-gate 	usb_config = usb_get_raw_cfg_data(child_dip, &usb_config_length);
17807c478bd9Sstevel@tonic-gate 
17817c478bd9Sstevel@tonic-gate 	mutex_enter(&usba_device->usb_mutex);
17827c478bd9Sstevel@tonic-gate 	mutex_enter(&usba_mutex);
17837c478bd9Sstevel@tonic-gate 
17847c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
17857c478bd9Sstevel@tonic-gate 	    "usba_ready_device_node: child=0x%p", (void *)child_dip);
17867c478bd9Sstevel@tonic-gate 
17877c478bd9Sstevel@tonic-gate 	port = usba_device->usb_port;
17887c478bd9Sstevel@tonic-gate 	usb_dev_descr = usba_device->usb_dev_descr;
17897c478bd9Sstevel@tonic-gate 	n_cfgs = usba_device->usb_n_cfgs;
17907c478bd9Sstevel@tonic-gate 	n_ifs = usba_device->usb_n_ifs;
1791a7df97baSStrony Zhang - Solaris China Team 	bus_num = usba_device->usb_addr;
17927c478bd9Sstevel@tonic-gate 
17937c478bd9Sstevel@tonic-gate 	if (address != ROOT_HUB_ADDR) {
17947c478bd9Sstevel@tonic-gate 		size = usb_parse_if_descr(
17957c478bd9Sstevel@tonic-gate 		    usb_config,
17967c478bd9Sstevel@tonic-gate 		    usb_config_length,
17977c478bd9Sstevel@tonic-gate 		    0,		/* interface index */
17987c478bd9Sstevel@tonic-gate 		    0,		/* alt interface index */
17997c478bd9Sstevel@tonic-gate 		    &if_descr,
18007c478bd9Sstevel@tonic-gate 		    USB_IF_DESCR_SIZE);
18017c478bd9Sstevel@tonic-gate 
18027c478bd9Sstevel@tonic-gate 		if (size != USB_IF_DESCR_SIZE) {
1803d291d9f2Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
18047c478bd9Sstevel@tonic-gate 			    "parsing interface: "
18057c478bd9Sstevel@tonic-gate 			    "size (%lu) != USB_IF_DESCR_SIZE (%d)",
18067c478bd9Sstevel@tonic-gate 			    size, USB_IF_DESCR_SIZE);
18077c478bd9Sstevel@tonic-gate 
18087c478bd9Sstevel@tonic-gate 			mutex_exit(&usba_mutex);
18097c478bd9Sstevel@tonic-gate 			mutex_exit(&usba_device->usb_mutex);
18107c478bd9Sstevel@tonic-gate 
18117c478bd9Sstevel@tonic-gate 			return (child_dip);
18127c478bd9Sstevel@tonic-gate 		}
18137c478bd9Sstevel@tonic-gate 	} else {
18147c478bd9Sstevel@tonic-gate 		/* fake an interface descriptor for the root hub */
18157c478bd9Sstevel@tonic-gate 		bzero(&if_descr, sizeof (if_descr));
18167c478bd9Sstevel@tonic-gate 
18177c478bd9Sstevel@tonic-gate 		if_descr.bInterfaceClass = USB_CLASS_HUB;
18187c478bd9Sstevel@tonic-gate 	}
18197c478bd9Sstevel@tonic-gate 
18207c478bd9Sstevel@tonic-gate 	reg[0] = port;
18217c478bd9Sstevel@tonic-gate 
18227c478bd9Sstevel@tonic-gate 	mutex_exit(&usba_mutex);
18237c478bd9Sstevel@tonic-gate 	mutex_exit(&usba_device->usb_mutex);
18247c478bd9Sstevel@tonic-gate 
18257c478bd9Sstevel@tonic-gate 	rval = ndi_prop_update_int_array(
18267c478bd9Sstevel@tonic-gate 	    DDI_DEV_T_NONE, child_dip, "reg", reg, 1);
18277c478bd9Sstevel@tonic-gate 
18287c478bd9Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
1829d291d9f2Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
18307c478bd9Sstevel@tonic-gate 		    "usba_ready_device_node: property update failed");
18317c478bd9Sstevel@tonic-gate 
18327c478bd9Sstevel@tonic-gate 		return (child_dip);
18337c478bd9Sstevel@tonic-gate 	}
18347c478bd9Sstevel@tonic-gate 
18357c478bd9Sstevel@tonic-gate 	combined_node = ((n_cfgs == 1) && (n_ifs == 1) &&
18367c478bd9Sstevel@tonic-gate 	    ((usb_dev_descr->bDeviceClass == USB_CLASS_HUB) ||
18377c478bd9Sstevel@tonic-gate 	    (usb_dev_descr->bDeviceClass == 0)));
18387c478bd9Sstevel@tonic-gate 
18397c478bd9Sstevel@tonic-gate 	is_hub = (if_descr.bInterfaceClass == USB_CLASS_HUB) ||
18407c478bd9Sstevel@tonic-gate 	    (usb_dev_descr->bDeviceClass == USB_CLASS_HUB);
18417c478bd9Sstevel@tonic-gate 
18427c478bd9Sstevel@tonic-gate 	/* set node name */
18437c478bd9Sstevel@tonic-gate 	if (combined_node) {
18447c478bd9Sstevel@tonic-gate 		usba_set_node_name(child_dip,
18457c478bd9Sstevel@tonic-gate 		    if_descr.bInterfaceClass,
18467c478bd9Sstevel@tonic-gate 		    if_descr.bInterfaceSubClass,
18477c478bd9Sstevel@tonic-gate 		    if_descr.bInterfaceProtocol,
18487c478bd9Sstevel@tonic-gate 		    FLAG_COMBINED_NODE);
18497c478bd9Sstevel@tonic-gate 	} else {
18507c478bd9Sstevel@tonic-gate 		usba_set_node_name(child_dip,
18517c478bd9Sstevel@tonic-gate 		    usb_dev_descr->bDeviceClass,
18527c478bd9Sstevel@tonic-gate 		    usb_dev_descr->bDeviceSubClass,
18537c478bd9Sstevel@tonic-gate 		    usb_dev_descr->bDeviceProtocol,
18547c478bd9Sstevel@tonic-gate 		    FLAG_DEVICE_NODE);
18557c478bd9Sstevel@tonic-gate 	}
18567c478bd9Sstevel@tonic-gate 
18577c478bd9Sstevel@tonic-gate 	/*
18587c478bd9Sstevel@tonic-gate 	 * check force binding rules
18597c478bd9Sstevel@tonic-gate 	 */
18607c478bd9Sstevel@tonic-gate 	if ((address != ROOT_HUB_ADDR) && usba_ddivs_usbc &&
18617c478bd9Sstevel@tonic-gate 	    (address != usba_ddivs_usbc_xaddress) &&
18627c478bd9Sstevel@tonic-gate 	    (!(usba_ddivs_usbc_xhubs && is_hub))) {
18637c478bd9Sstevel@tonic-gate 		force_bind = "ddivs_usbc";
18647c478bd9Sstevel@tonic-gate 		(void) ndi_devi_set_nodename(child_dip, "ddivs_usbc", 0);
18657c478bd9Sstevel@tonic-gate 
18667c478bd9Sstevel@tonic-gate 	} else if (usba_device->usb_preferred_driver) {
18677c478bd9Sstevel@tonic-gate 		force_bind = usba_device->usb_preferred_driver;
18687c478bd9Sstevel@tonic-gate 
18697c478bd9Sstevel@tonic-gate 	} else if ((address != ROOT_HUB_ADDR) &&
18707c478bd9Sstevel@tonic-gate 	    ((usba_ugen_force_binding == USBA_UGEN_DEVICE_BINDING) ||
18717c478bd9Sstevel@tonic-gate 	    ((usba_ugen_force_binding == USBA_UGEN_INTERFACE_BINDING) &&
18727c478bd9Sstevel@tonic-gate 	    combined_node)) && (!is_hub)) {
18737c478bd9Sstevel@tonic-gate 		force_bind = "ugen";
18747c478bd9Sstevel@tonic-gate 	}
18757c478bd9Sstevel@tonic-gate 
18767c478bd9Sstevel@tonic-gate #ifdef DEBUG
18777c478bd9Sstevel@tonic-gate 	/*
18787c478bd9Sstevel@tonic-gate 	 * check whether there is another dip with this name and address
18797c478bd9Sstevel@tonic-gate 	 * If the dip contains usba_device, it is held by the previous
18807c478bd9Sstevel@tonic-gate 	 * round of configuration.
18817c478bd9Sstevel@tonic-gate 	 */
18827c478bd9Sstevel@tonic-gate 	ASSERT(usba_find_existing_node(child_dip) == NULL);
18837c478bd9Sstevel@tonic-gate #endif
18843c91d182Slg150142 
18853c91d182Slg150142 	usba_name_buf = kmem_zalloc(USBA_MAX_COMPAT_NAMES *
18863c91d182Slg150142 	    USBA_MAX_COMPAT_NAME_LEN, KM_SLEEP);
18873c91d182Slg150142 
18883c91d182Slg150142 	for (i = 0; i < USBA_MAX_COMPAT_NAMES; i++) {
18893c91d182Slg150142 		usba_name[i] = usba_name_buf + (i * USBA_MAX_COMPAT_NAME_LEN);
18903c91d182Slg150142 	}
18917c478bd9Sstevel@tonic-gate 
18927c478bd9Sstevel@tonic-gate 	if (force_bind) {
18937c478bd9Sstevel@tonic-gate 		(void) ndi_devi_set_nodename(child_dip, force_bind, 0);
18947c478bd9Sstevel@tonic-gate 		(void) strncpy(usba_name[n++], force_bind,
18957c478bd9Sstevel@tonic-gate 		    USBA_MAX_COMPAT_NAME_LEN);
18967c478bd9Sstevel@tonic-gate 	}
18977c478bd9Sstevel@tonic-gate 
1898a7df97baSStrony Zhang - Solaris China Team 	/*
1899a7df97baSStrony Zhang - Solaris China Team 	 * If the callback function of specified driver is registered,
1900a7df97baSStrony Zhang - Solaris China Team 	 * it will be called here to check whether to take over the device.
1901a7df97baSStrony Zhang - Solaris China Team 	 */
1902a7df97baSStrony Zhang - Solaris China Team 	if (usb_cap.usba_dev_driver_cb != NULL) {
1903a7df97baSStrony Zhang - Solaris China Team 		char		*dev_drv = NULL;
1904a7df97baSStrony Zhang - Solaris China Team 		usb_dev_str_t	dev_str;
1905a7df97baSStrony Zhang - Solaris China Team 		char		*pathname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1906a7df97baSStrony Zhang - Solaris China Team 
1907a7df97baSStrony Zhang - Solaris China Team 		dev_str.usb_mfg = usba_device->usb_mfg_str;
1908a7df97baSStrony Zhang - Solaris China Team 		dev_str.usb_product = usba_device->usb_product_str;
1909a7df97baSStrony Zhang - Solaris China Team 		dev_str.usb_serialno = usba_device->usb_serialno_str;
1910a7df97baSStrony Zhang - Solaris China Team 
1911a7df97baSStrony Zhang - Solaris China Team 		(void) ddi_pathname(child_dip, pathname);
1912a7df97baSStrony Zhang - Solaris China Team 
1913a7df97baSStrony Zhang - Solaris China Team 		if ((usb_cap.usba_dev_driver_cb(usb_dev_descr, &dev_str,
1914a7df97baSStrony Zhang - Solaris China Team 		    pathname, bus_num, port, &dev_drv, NULL) == USB_SUCCESS) &&
1915a7df97baSStrony Zhang - Solaris China Team 		    (dev_drv != NULL)) {
1916a7df97baSStrony Zhang - Solaris China Team 			USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
1917a7df97baSStrony Zhang - Solaris China Team 			    "usba_ready_device_node: dev_driver=%s, port =%d,"
1918a7df97baSStrony Zhang - Solaris China Team 			    "bus =%d, path=%s\n\t",
1919a7df97baSStrony Zhang - Solaris China Team 			    dev_drv, port, bus_num, pathname);
1920a7df97baSStrony Zhang - Solaris China Team 
1921a7df97baSStrony Zhang - Solaris China Team 			(void) strncpy(usba_name[n++], dev_drv,
1922a7df97baSStrony Zhang - Solaris China Team 			    USBA_MAX_COMPAT_NAME_LEN);
1923a7df97baSStrony Zhang - Solaris China Team 		}
1924a7df97baSStrony Zhang - Solaris China Team 		kmem_free(pathname, MAXPATHLEN);
1925a7df97baSStrony Zhang - Solaris China Team 	}
1926a7df97baSStrony Zhang - Solaris China Team 
19277c478bd9Sstevel@tonic-gate 	/* create compatible names */
19287c478bd9Sstevel@tonic-gate 	if (combined_node) {
19297c478bd9Sstevel@tonic-gate 
19307c478bd9Sstevel@tonic-gate 		/* 1. usbVID,PID.REV */
19317c478bd9Sstevel@tonic-gate 		(void) sprintf(usba_name[n++],
19327c478bd9Sstevel@tonic-gate 		    "usb%x,%x.%x",
19337c478bd9Sstevel@tonic-gate 		    usb_dev_descr->idVendor,
19347c478bd9Sstevel@tonic-gate 		    usb_dev_descr->idProduct,
19357c478bd9Sstevel@tonic-gate 		    usb_dev_descr->bcdDevice);
19367c478bd9Sstevel@tonic-gate 
19377c478bd9Sstevel@tonic-gate 		/* 2. usbVID,PID */
19387c478bd9Sstevel@tonic-gate 		(void) sprintf(usba_name[n++],
19397c478bd9Sstevel@tonic-gate 		    "usb%x,%x",
19407c478bd9Sstevel@tonic-gate 		    usb_dev_descr->idVendor,
19417c478bd9Sstevel@tonic-gate 		    usb_dev_descr->idProduct);
19427c478bd9Sstevel@tonic-gate 
19437c478bd9Sstevel@tonic-gate 		if (usb_dev_descr->bDeviceClass != 0) {
19447c478bd9Sstevel@tonic-gate 			/* 3. usbVID,classDC.DSC.DPROTO */
19457c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
19467c478bd9Sstevel@tonic-gate 			    "usb%x,class%x.%x.%x",
19477c478bd9Sstevel@tonic-gate 			    usb_dev_descr->idVendor,
19487c478bd9Sstevel@tonic-gate 			    usb_dev_descr->bDeviceClass,
19497c478bd9Sstevel@tonic-gate 			    usb_dev_descr->bDeviceSubClass,
19507c478bd9Sstevel@tonic-gate 			    usb_dev_descr->bDeviceProtocol);
19517c478bd9Sstevel@tonic-gate 
19527c478bd9Sstevel@tonic-gate 			/* 4. usbVID,classDC.DSC */
19537c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
19547c478bd9Sstevel@tonic-gate 			    "usb%x,class%x.%x",
19557c478bd9Sstevel@tonic-gate 			    usb_dev_descr->idVendor,
19567c478bd9Sstevel@tonic-gate 			    usb_dev_descr->bDeviceClass,
19577c478bd9Sstevel@tonic-gate 			    usb_dev_descr->bDeviceSubClass);
19587c478bd9Sstevel@tonic-gate 
19597c478bd9Sstevel@tonic-gate 			/* 5. usbVID,classDC */
19607c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
19617c478bd9Sstevel@tonic-gate 			    "usb%x,class%x",
19627c478bd9Sstevel@tonic-gate 			    usb_dev_descr->idVendor,
19637c478bd9Sstevel@tonic-gate 			    usb_dev_descr->bDeviceClass);
19647c478bd9Sstevel@tonic-gate 
19657c478bd9Sstevel@tonic-gate 			/* 6. usb,classDC.DSC.DPROTO */
19667c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
19677c478bd9Sstevel@tonic-gate 			    "usb,class%x.%x.%x",
19687c478bd9Sstevel@tonic-gate 			    usb_dev_descr->bDeviceClass,
19697c478bd9Sstevel@tonic-gate 			    usb_dev_descr->bDeviceSubClass,
19707c478bd9Sstevel@tonic-gate 			    usb_dev_descr->bDeviceProtocol);
19717c478bd9Sstevel@tonic-gate 
19727c478bd9Sstevel@tonic-gate 			/* 7. usb,classDC.DSC */
19737c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
19747c478bd9Sstevel@tonic-gate 			    "usb,class%x.%x",
19757c478bd9Sstevel@tonic-gate 			    usb_dev_descr->bDeviceClass,
19767c478bd9Sstevel@tonic-gate 			    usb_dev_descr->bDeviceSubClass);
19777c478bd9Sstevel@tonic-gate 
19787c478bd9Sstevel@tonic-gate 			/* 8. usb,classDC */
19797c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
19807c478bd9Sstevel@tonic-gate 			    "usb,class%x",
19817c478bd9Sstevel@tonic-gate 			    usb_dev_descr->bDeviceClass);
19827c478bd9Sstevel@tonic-gate 		}
19837c478bd9Sstevel@tonic-gate 
19847c478bd9Sstevel@tonic-gate 		if (if_descr.bInterfaceClass != 0) {
19857c478bd9Sstevel@tonic-gate 			/* 9. usbifVID,classIC.ISC.IPROTO */
19867c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
19877c478bd9Sstevel@tonic-gate 			    "usbif%x,class%x.%x.%x",
19887c478bd9Sstevel@tonic-gate 			    usb_dev_descr->idVendor,
19897c478bd9Sstevel@tonic-gate 			    if_descr.bInterfaceClass,
19907c478bd9Sstevel@tonic-gate 			    if_descr.bInterfaceSubClass,
19917c478bd9Sstevel@tonic-gate 			    if_descr.bInterfaceProtocol);
19927c478bd9Sstevel@tonic-gate 
19937c478bd9Sstevel@tonic-gate 			/* 10. usbifVID,classIC.ISC */
19947c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
19957c478bd9Sstevel@tonic-gate 			    "usbif%x,class%x.%x",
19967c478bd9Sstevel@tonic-gate 			    usb_dev_descr->idVendor,
19977c478bd9Sstevel@tonic-gate 			    if_descr.bInterfaceClass,
19987c478bd9Sstevel@tonic-gate 			    if_descr.bInterfaceSubClass);
19997c478bd9Sstevel@tonic-gate 
20007c478bd9Sstevel@tonic-gate 			/* 11. usbifVID,classIC */
20017c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
20027c478bd9Sstevel@tonic-gate 			    "usbif%x,class%x",
20037c478bd9Sstevel@tonic-gate 			    usb_dev_descr->idVendor,
20047c478bd9Sstevel@tonic-gate 			    if_descr.bInterfaceClass);
20057c478bd9Sstevel@tonic-gate 
20067c478bd9Sstevel@tonic-gate 			/* 12. usbif,classIC.ISC.IPROTO */
20077c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
20087c478bd9Sstevel@tonic-gate 			    "usbif,class%x.%x.%x",
20097c478bd9Sstevel@tonic-gate 			    if_descr.bInterfaceClass,
20107c478bd9Sstevel@tonic-gate 			    if_descr.bInterfaceSubClass,
20117c478bd9Sstevel@tonic-gate 			    if_descr.bInterfaceProtocol);
20127c478bd9Sstevel@tonic-gate 
20137c478bd9Sstevel@tonic-gate 			/* 13. usbif,classIC.ISC */
20147c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
20157c478bd9Sstevel@tonic-gate 			    "usbif,class%x.%x",
20167c478bd9Sstevel@tonic-gate 			    if_descr.bInterfaceClass,
20177c478bd9Sstevel@tonic-gate 			    if_descr.bInterfaceSubClass);
20187c478bd9Sstevel@tonic-gate 
20197c478bd9Sstevel@tonic-gate 			/* 14. usbif,classIC */
20207c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
20217c478bd9Sstevel@tonic-gate 			    "usbif,class%x",
20227c478bd9Sstevel@tonic-gate 			    if_descr.bInterfaceClass);
20237c478bd9Sstevel@tonic-gate 		}
20247c478bd9Sstevel@tonic-gate 
20257c478bd9Sstevel@tonic-gate 		/* 15. ugen or usb_mid */
20267c478bd9Sstevel@tonic-gate 		if (usba_get_ugen_binding(child_dip) ==
20277c478bd9Sstevel@tonic-gate 		    USBA_UGEN_DEVICE_BINDING) {
20287c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++], "ugen");
20297c478bd9Sstevel@tonic-gate 		} else {
20307c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++], "usb,device");
20317c478bd9Sstevel@tonic-gate 		}
20327c478bd9Sstevel@tonic-gate 
20337c478bd9Sstevel@tonic-gate 	} else {
20347c478bd9Sstevel@tonic-gate 		if (n_cfgs > 1) {
20357c478bd9Sstevel@tonic-gate 			/* 1. usbVID,PID.REV.configCN */
20367c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
20377c478bd9Sstevel@tonic-gate 			    "usb%x,%x.%x.config%x",
20387c478bd9Sstevel@tonic-gate 			    usb_dev_descr->idVendor,
20397c478bd9Sstevel@tonic-gate 			    usb_dev_descr->idProduct,
20407c478bd9Sstevel@tonic-gate 			    usb_dev_descr->bcdDevice,
20417c478bd9Sstevel@tonic-gate 			    usba_device->usb_cfg_value);
20427c478bd9Sstevel@tonic-gate 		}
20437c478bd9Sstevel@tonic-gate 
20447c478bd9Sstevel@tonic-gate 		/* 2. usbVID,PID.REV */
20457c478bd9Sstevel@tonic-gate 		(void) sprintf(usba_name[n++],
20467c478bd9Sstevel@tonic-gate 		    "usb%x,%x.%x",
20477c478bd9Sstevel@tonic-gate 		    usb_dev_descr->idVendor,
20487c478bd9Sstevel@tonic-gate 		    usb_dev_descr->idProduct,
20497c478bd9Sstevel@tonic-gate 		    usb_dev_descr->bcdDevice);
20507c478bd9Sstevel@tonic-gate 
20517c478bd9Sstevel@tonic-gate 		/* 3. usbVID,PID.configCN */
20527c478bd9Sstevel@tonic-gate 		if (n_cfgs > 1) {
20537c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
20547c478bd9Sstevel@tonic-gate 			    "usb%x,%x.%x",
20557c478bd9Sstevel@tonic-gate 			    usb_dev_descr->idVendor,
20567c478bd9Sstevel@tonic-gate 			    usb_dev_descr->idProduct,
20577c478bd9Sstevel@tonic-gate 			    usba_device->usb_cfg_value);
20587c478bd9Sstevel@tonic-gate 		}
20597c478bd9Sstevel@tonic-gate 
20607c478bd9Sstevel@tonic-gate 		/* 4. usbVID,PID */
20617c478bd9Sstevel@tonic-gate 		(void) sprintf(usba_name[n++],
20627c478bd9Sstevel@tonic-gate 		    "usb%x,%x",
20637c478bd9Sstevel@tonic-gate 		    usb_dev_descr->idVendor,
20647c478bd9Sstevel@tonic-gate 		    usb_dev_descr->idProduct);
20657c478bd9Sstevel@tonic-gate 
20667c478bd9Sstevel@tonic-gate 		if (usb_dev_descr->bDeviceClass != 0) {
20677c478bd9Sstevel@tonic-gate 			/* 5. usbVID,classDC.DSC.DPROTO */
20687c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
20697c478bd9Sstevel@tonic-gate 			    "usb%x,class%x.%x.%x",
20707c478bd9Sstevel@tonic-gate 			    usb_dev_descr->idVendor,
20717c478bd9Sstevel@tonic-gate 			    usb_dev_descr->bDeviceClass,
20727c478bd9Sstevel@tonic-gate 			    usb_dev_descr->bDeviceSubClass,
20737c478bd9Sstevel@tonic-gate 			    usb_dev_descr->bDeviceProtocol);
20747c478bd9Sstevel@tonic-gate 
20757c478bd9Sstevel@tonic-gate 			/* 6. usbVID,classDC.DSC */
20767c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
20777c478bd9Sstevel@tonic-gate 			    "usb%x.class%x.%x",
20787c478bd9Sstevel@tonic-gate 			    usb_dev_descr->idVendor,
20797c478bd9Sstevel@tonic-gate 			    usb_dev_descr->bDeviceClass,
20807c478bd9Sstevel@tonic-gate 			    usb_dev_descr->bDeviceSubClass);
20817c478bd9Sstevel@tonic-gate 
20827c478bd9Sstevel@tonic-gate 			/* 7. usbVID,classDC */
20837c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
20847c478bd9Sstevel@tonic-gate 			    "usb%x.class%x",
20857c478bd9Sstevel@tonic-gate 			    usb_dev_descr->idVendor,
20867c478bd9Sstevel@tonic-gate 			    usb_dev_descr->bDeviceClass);
20877c478bd9Sstevel@tonic-gate 
20887c478bd9Sstevel@tonic-gate 			/* 8. usb,classDC.DSC.DPROTO */
20897c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
20907c478bd9Sstevel@tonic-gate 			    "usb,class%x.%x.%x",
20917c478bd9Sstevel@tonic-gate 			    usb_dev_descr->bDeviceClass,
20927c478bd9Sstevel@tonic-gate 			    usb_dev_descr->bDeviceSubClass,
20937c478bd9Sstevel@tonic-gate 			    usb_dev_descr->bDeviceProtocol);
20947c478bd9Sstevel@tonic-gate 
20957c478bd9Sstevel@tonic-gate 			/* 9. usb,classDC.DSC */
20967c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
20977c478bd9Sstevel@tonic-gate 			    "usb,class%x.%x",
20987c478bd9Sstevel@tonic-gate 			    usb_dev_descr->bDeviceClass,
20997c478bd9Sstevel@tonic-gate 			    usb_dev_descr->bDeviceSubClass);
21007c478bd9Sstevel@tonic-gate 
21017c478bd9Sstevel@tonic-gate 			/* 10. usb,classDC */
21027c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
21037c478bd9Sstevel@tonic-gate 			    "usb,class%x",
21047c478bd9Sstevel@tonic-gate 			    usb_dev_descr->bDeviceClass);
21057c478bd9Sstevel@tonic-gate 		}
21067c478bd9Sstevel@tonic-gate 
21077c478bd9Sstevel@tonic-gate 		if (usba_get_ugen_binding(child_dip) ==
21087c478bd9Sstevel@tonic-gate 		    USBA_UGEN_DEVICE_BINDING) {
21097c478bd9Sstevel@tonic-gate 			/* 11. ugen */
21107c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++], "ugen");
21117c478bd9Sstevel@tonic-gate 		} else {
21127c478bd9Sstevel@tonic-gate 			/* 11. usb,device */
21137c478bd9Sstevel@tonic-gate 			(void) sprintf(usba_name[n++], "usb,device");
21147c478bd9Sstevel@tonic-gate 		}
21157c478bd9Sstevel@tonic-gate 	}
21167c478bd9Sstevel@tonic-gate 
21177c478bd9Sstevel@tonic-gate 	for (i = 0; i < n; i += 2) {
21187c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
21193c91d182Slg150142 		    "compatible name:\t%s\t%s", usba_name[i],
21203c91d182Slg150142 		    (((i+1) < n)? usba_name[i+1] : ""));
21217c478bd9Sstevel@tonic-gate 	}
21227c478bd9Sstevel@tonic-gate 
21233c91d182Slg150142 	rval = ndi_prop_update_string_array(DDI_DEV_T_NONE, child_dip,
21243c91d182Slg150142 	    "compatible", (char **)usba_name, n);
21253c91d182Slg150142 
21263c91d182Slg150142 	kmem_free(usba_name_buf, USBA_MAX_COMPAT_NAMES *
21273c91d182Slg150142 	    USBA_MAX_COMPAT_NAME_LEN);
21287c478bd9Sstevel@tonic-gate 
21297c478bd9Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
21307c478bd9Sstevel@tonic-gate 
2131d291d9f2Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
21327c478bd9Sstevel@tonic-gate 		    "usba_ready_device_node: property update failed");
21337c478bd9Sstevel@tonic-gate 
21347c478bd9Sstevel@tonic-gate 		return (child_dip);
21357c478bd9Sstevel@tonic-gate 	}
21367c478bd9Sstevel@tonic-gate 
21377c478bd9Sstevel@tonic-gate 	/* update the address property */
21387c478bd9Sstevel@tonic-gate 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
21397c478bd9Sstevel@tonic-gate 	    "assigned-address", usba_device->usb_addr);
21407c478bd9Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
2141d291d9f2Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
21427c478bd9Sstevel@tonic-gate 		    "usba_ready_device_node: address update failed");
21437c478bd9Sstevel@tonic-gate 	}
21447c478bd9Sstevel@tonic-gate 
21457c478bd9Sstevel@tonic-gate 	/* update the usb device properties (PSARC/2000/454) */
21467c478bd9Sstevel@tonic-gate 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
21477c478bd9Sstevel@tonic-gate 	    "usb-vendor-id", usb_dev_descr->idVendor);
21487c478bd9Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
2149d291d9f2Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
21507c478bd9Sstevel@tonic-gate 		    "usba_ready_device_node: usb-vendor-id update failed");
21517c478bd9Sstevel@tonic-gate 	}
21527c478bd9Sstevel@tonic-gate 
21537c478bd9Sstevel@tonic-gate 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
21547c478bd9Sstevel@tonic-gate 	    "usb-product-id", usb_dev_descr->idProduct);
21557c478bd9Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
2156d291d9f2Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
21577c478bd9Sstevel@tonic-gate 		    "usba_ready_device_node: usb-product-id update failed");
21587c478bd9Sstevel@tonic-gate 	}
21597c478bd9Sstevel@tonic-gate 
21607c478bd9Sstevel@tonic-gate 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
21617c478bd9Sstevel@tonic-gate 	    "usb-revision-id", usb_dev_descr->bcdDevice);
21627c478bd9Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
2163d291d9f2Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
21647c478bd9Sstevel@tonic-gate 		    "usba_ready_device_node: usb-revision-id update failed");
21657c478bd9Sstevel@tonic-gate 	}
21667c478bd9Sstevel@tonic-gate 
21677c478bd9Sstevel@tonic-gate 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
21687c478bd9Sstevel@tonic-gate 	    "usb-num-configs", usb_dev_descr->bNumConfigurations);
21697c478bd9Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
2170d291d9f2Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
21717c478bd9Sstevel@tonic-gate 		    "usba_ready_device_node: usb-num-configs update failed");
21727c478bd9Sstevel@tonic-gate 	}
21737c478bd9Sstevel@tonic-gate 
21747c478bd9Sstevel@tonic-gate 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
21757c478bd9Sstevel@tonic-gate 	    "usb-release", usb_dev_descr->bcdUSB);
21767c478bd9Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
2177d291d9f2Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
21787c478bd9Sstevel@tonic-gate 		    "usba_ready_device_node: usb-release update failed");
21797c478bd9Sstevel@tonic-gate 	}
21807c478bd9Sstevel@tonic-gate 
2181112cd14aSqz150045 	rval = ndi_prop_update_byte_array(DDI_DEV_T_NONE, child_dip,
2182112cd14aSqz150045 	    "usb-dev-descriptor", (uchar_t *)usb_dev_descr,
2183112cd14aSqz150045 	    sizeof (usb_dev_descr_t));
2184112cd14aSqz150045 	if (rval != DDI_PROP_SUCCESS) {
2185112cd14aSqz150045 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2186112cd14aSqz150045 		    "usba_ready_device_node: usb-descriptor update failed");
2187112cd14aSqz150045 	}
2188112cd14aSqz150045 
2189112cd14aSqz150045 	rval = ndi_prop_update_byte_array(DDI_DEV_T_NONE, child_dip,
2190112cd14aSqz150045 	    "usb-raw-cfg-descriptors", usb_config, usb_config_length);
2191112cd14aSqz150045 	if (rval != DDI_PROP_SUCCESS) {
2192112cd14aSqz150045 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2193112cd14aSqz150045 		    "usba_ready_device_node: usb-raw-cfg-descriptors update "
2194112cd14aSqz150045 		    "failed");
2195112cd14aSqz150045 	}
2196112cd14aSqz150045 
21977c478bd9Sstevel@tonic-gate 	devprop_str = kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP);
21987c478bd9Sstevel@tonic-gate 
21997c478bd9Sstevel@tonic-gate 	if (usba_device->usb_serialno_str) {
22007c478bd9Sstevel@tonic-gate 		usba_filter_string(usba_device->usb_serialno_str, devprop_str);
22017c478bd9Sstevel@tonic-gate 		rval = ndi_prop_update_string(DDI_DEV_T_NONE, child_dip,
22027c478bd9Sstevel@tonic-gate 		    "usb-serialno", devprop_str);
22037c478bd9Sstevel@tonic-gate 		if (rval != DDI_PROP_SUCCESS) {
2204d291d9f2Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
22057c478bd9Sstevel@tonic-gate 			    "usba_ready_device_node: "
22067c478bd9Sstevel@tonic-gate 			    "usb-serialno update failed");
22077c478bd9Sstevel@tonic-gate 		}
22087c478bd9Sstevel@tonic-gate 	}
22097c478bd9Sstevel@tonic-gate 
22107c478bd9Sstevel@tonic-gate 	if (usba_device->usb_mfg_str) {
22117c478bd9Sstevel@tonic-gate 		usba_filter_string(usba_device->usb_mfg_str, devprop_str);
22127c478bd9Sstevel@tonic-gate 		rval = ndi_prop_update_string(DDI_DEV_T_NONE, child_dip,
22137c478bd9Sstevel@tonic-gate 		    "usb-vendor-name", devprop_str);
22147c478bd9Sstevel@tonic-gate 		if (rval != DDI_PROP_SUCCESS) {
2215d291d9f2Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
22167c478bd9Sstevel@tonic-gate 			    "usba_ready_device_node: "
22177c478bd9Sstevel@tonic-gate 			    "usb-vendor-name update failed");
22187c478bd9Sstevel@tonic-gate 		}
22197c478bd9Sstevel@tonic-gate 	}
22207c478bd9Sstevel@tonic-gate 
22217c478bd9Sstevel@tonic-gate 	if (usba_device->usb_product_str) {
22227c478bd9Sstevel@tonic-gate 		usba_filter_string(usba_device->usb_product_str, devprop_str);
22237c478bd9Sstevel@tonic-gate 		rval = ndi_prop_update_string(DDI_DEV_T_NONE, child_dip,
22247c478bd9Sstevel@tonic-gate 		    "usb-product-name", devprop_str);
22257c478bd9Sstevel@tonic-gate 		if (rval != DDI_PROP_SUCCESS) {
2226d291d9f2Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
22277c478bd9Sstevel@tonic-gate 			    "usba_ready_device_node: "
22287c478bd9Sstevel@tonic-gate 			    "usb-product-name update failed");
22297c478bd9Sstevel@tonic-gate 		}
22307c478bd9Sstevel@tonic-gate 	}
22317c478bd9Sstevel@tonic-gate 
22327c478bd9Sstevel@tonic-gate 	kmem_free(devprop_str, USB_MAXSTRINGLEN);
22337c478bd9Sstevel@tonic-gate 
22347c478bd9Sstevel@tonic-gate 	if (!combined_node) {
22357c478bd9Sstevel@tonic-gate 		/* update the configuration property */
22367c478bd9Sstevel@tonic-gate 		rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
22377c478bd9Sstevel@tonic-gate 		    "configuration#", usba_device->usb_cfg_value);
22387c478bd9Sstevel@tonic-gate 		if (rval != DDI_PROP_SUCCESS) {
22397c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
22407c478bd9Sstevel@tonic-gate 			    "usba_ready_device_node: "
22417c478bd9Sstevel@tonic-gate 			    "config prop update failed");
22427c478bd9Sstevel@tonic-gate 		}
22437c478bd9Sstevel@tonic-gate 	}
22447c478bd9Sstevel@tonic-gate 
22457c478bd9Sstevel@tonic-gate 	if (usba_device->usb_port_status == USBA_LOW_SPEED_DEV) {
22467c478bd9Sstevel@tonic-gate 		/* create boolean property */
22477c478bd9Sstevel@tonic-gate 		rval = ndi_prop_create_boolean(DDI_DEV_T_NONE, child_dip,
22487c478bd9Sstevel@tonic-gate 		    "low-speed");
22497c478bd9Sstevel@tonic-gate 		if (rval != DDI_PROP_SUCCESS) {
2250d291d9f2Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
22517c478bd9Sstevel@tonic-gate 			    "usba_ready_device_node: "
22527c478bd9Sstevel@tonic-gate 			    "low speed prop update failed");
22537c478bd9Sstevel@tonic-gate 		}
22547c478bd9Sstevel@tonic-gate 	}
22557c478bd9Sstevel@tonic-gate 
2256112cd14aSqz150045 	if (usba_device->usb_port_status == USBA_HIGH_SPEED_DEV) {
2257112cd14aSqz150045 		/* create boolean property */
2258112cd14aSqz150045 		rval = ndi_prop_create_boolean(DDI_DEV_T_NONE, child_dip,
2259112cd14aSqz150045 		    "high-speed");
2260112cd14aSqz150045 		if (rval != DDI_PROP_SUCCESS) {
2261112cd14aSqz150045 			USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2262112cd14aSqz150045 			    "usba_ready_device_node: "
2263112cd14aSqz150045 			    "high speed prop update failed");
2264112cd14aSqz150045 		}
2265112cd14aSqz150045 	}
2266112cd14aSqz150045 
22677c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
22687c478bd9Sstevel@tonic-gate 	    "%s%d at port %d: %s, dip=0x%p",
22697c478bd9Sstevel@tonic-gate 	    ddi_node_name(ddi_get_parent(child_dip)),
22707c478bd9Sstevel@tonic-gate 	    ddi_get_instance(ddi_get_parent(child_dip)),
2271112116d8Sfb209375 	    port, ddi_node_name(child_dip), (void *)child_dip);
22727c478bd9Sstevel@tonic-gate 
22737c478bd9Sstevel@tonic-gate 	usba_set_usba_device(child_dip, usba_device);
22747c478bd9Sstevel@tonic-gate 
22757c478bd9Sstevel@tonic-gate 	ASSERT(!mutex_owned(&(usba_get_usba_device(child_dip)->usb_mutex)));
22767c478bd9Sstevel@tonic-gate 
22777c478bd9Sstevel@tonic-gate 	return (child_dip);
22787c478bd9Sstevel@tonic-gate }
22797c478bd9Sstevel@tonic-gate 
22807c478bd9Sstevel@tonic-gate 
22817c478bd9Sstevel@tonic-gate /*
2282d73ae94eSgc161489  * driver binding at interface association level. the first arg is the parent
2283d73ae94eSgc161489  * dip. if_count returns amount of interfaces which are associated within
2284d73ae94eSgc161489  * this interface-association that starts from first_if.
2285d73ae94eSgc161489  */
2286d73ae94eSgc161489 /*ARGSUSED*/
2287d73ae94eSgc161489 dev_info_t *
usba_ready_interface_association_node(dev_info_t * dip,uint_t first_if,uint_t * if_count)2288d73ae94eSgc161489 usba_ready_interface_association_node(dev_info_t	*dip,
2289d73ae94eSgc161489 					uint_t		first_if,
2290d73ae94eSgc161489 					uint_t		*if_count)
2291d73ae94eSgc161489 {
2292d73ae94eSgc161489 	dev_info_t		*child_dip = NULL;
2293d73ae94eSgc161489 	usba_device_t		*child_ud = usba_get_usba_device(dip);
2294d73ae94eSgc161489 	usb_dev_descr_t		*usb_dev_descr;
2295d73ae94eSgc161489 	size_t			usb_cfg_length;
2296d73ae94eSgc161489 	uchar_t			*usb_cfg;
2297d73ae94eSgc161489 	usb_ia_descr_t		ia_descr;
2298d73ae94eSgc161489 	int			i, n, rval;
2299d73ae94eSgc161489 	int			reg[2];
2300d73ae94eSgc161489 	size_t			size;
2301d73ae94eSgc161489 	usb_port_status_t	port_status;
2302d73ae94eSgc161489 	char			*force_bind = NULL;
23033c91d182Slg150142 	char			*usba_name_buf = NULL;
23043c91d182Slg150142 	char			*usba_name[USBA_MAX_COMPAT_NAMES];
2305d73ae94eSgc161489 
2306d73ae94eSgc161489 	usb_cfg = usb_get_raw_cfg_data(dip, &usb_cfg_length);
2307d73ae94eSgc161489 
2308d73ae94eSgc161489 	mutex_enter(&child_ud->usb_mutex);
2309d73ae94eSgc161489 
2310d73ae94eSgc161489 	usb_dev_descr = child_ud->usb_dev_descr;
2311d73ae94eSgc161489 
2312d73ae94eSgc161489 	/*
2313d73ae94eSgc161489 	 * for each interface association, determine all compatible names
2314d73ae94eSgc161489 	 */
2315d73ae94eSgc161489 	USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
2316d73ae94eSgc161489 	    "usba_ready_ia_node: "
2317d73ae94eSgc161489 	    "port %d, interface = %d, port_status = %x",
2318d73ae94eSgc161489 	    child_ud->usb_port, first_if, child_ud->usb_port_status);
2319d73ae94eSgc161489 
2320d73ae94eSgc161489 	/* Parse the interface descriptor */
2321d73ae94eSgc161489 	size = usb_parse_ia_descr(
2322d73ae94eSgc161489 	    usb_cfg,
2323d73ae94eSgc161489 	    usb_cfg_length,
2324d73ae94eSgc161489 	    first_if,	/* interface index */
2325d73ae94eSgc161489 	    &ia_descr,
2326d73ae94eSgc161489 	    USB_IA_DESCR_SIZE);
2327d73ae94eSgc161489 
2328d73ae94eSgc161489 	*if_count = 1;
2329d73ae94eSgc161489 	if (size != USB_IA_DESCR_SIZE) {
2330d73ae94eSgc161489 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2331d73ae94eSgc161489 		    "parsing ia: size (%lu) != USB_IA_DESCR_SIZE (%d)",
2332d73ae94eSgc161489 		    size, USB_IA_DESCR_SIZE);
2333d73ae94eSgc161489 		mutex_exit(&child_ud->usb_mutex);
2334d73ae94eSgc161489 
2335d73ae94eSgc161489 		return (NULL);
2336d73ae94eSgc161489 	}
2337d73ae94eSgc161489 
2338d73ae94eSgc161489 	port_status = child_ud->usb_port_status;
2339d73ae94eSgc161489 
2340d73ae94eSgc161489 	/* create reg property */
2341d73ae94eSgc161489 	reg[0] = first_if;
2342d73ae94eSgc161489 	reg[1] = child_ud->usb_cfg_value;
2343d73ae94eSgc161489 
2344d73ae94eSgc161489 	mutex_exit(&child_ud->usb_mutex);
2345d73ae94eSgc161489 
2346d73ae94eSgc161489 	/* clone this dip */
2347d73ae94eSgc161489 	rval =	usba_create_child_devi(dip,
2348d73ae94eSgc161489 	    "interface-association",
2349d73ae94eSgc161489 	    NULL,		/* usba_hcdi ops */
2350d73ae94eSgc161489 	    NULL,		/* root hub dip */
2351d73ae94eSgc161489 	    port_status,	/* port status */
2352d73ae94eSgc161489 	    child_ud,	/* share this usba_device */
2353d73ae94eSgc161489 	    &child_dip);
2354d73ae94eSgc161489 
2355d73ae94eSgc161489 	if (rval != USB_SUCCESS) {
2356d73ae94eSgc161489 
2357d73ae94eSgc161489 		goto fail;
2358d73ae94eSgc161489 	}
2359d73ae94eSgc161489 
2360d73ae94eSgc161489 	rval = ndi_prop_update_int_array(
2361d73ae94eSgc161489 	    DDI_DEV_T_NONE, child_dip, "reg", reg, 2);
2362d73ae94eSgc161489 
2363d73ae94eSgc161489 	if (rval != DDI_PROP_SUCCESS) {
2364d73ae94eSgc161489 
2365d73ae94eSgc161489 		goto fail;
2366d73ae94eSgc161489 	}
2367d73ae94eSgc161489 
2368d73ae94eSgc161489 	usba_set_node_name(child_dip, ia_descr.bFunctionClass,
2369d73ae94eSgc161489 	    ia_descr.bFunctionSubClass, ia_descr.bFunctionProtocol,
2370d73ae94eSgc161489 	    FLAG_INTERFACE_ASSOCIATION_NODE);
2371d73ae94eSgc161489 
2372d73ae94eSgc161489 	/* check force binding */
2373d73ae94eSgc161489 	if (usba_ugen_force_binding ==
2374d73ae94eSgc161489 	    USBA_UGEN_INTERFACE_ASSOCIATION_BINDING) {
2375d73ae94eSgc161489 		force_bind = "ugen";
2376d73ae94eSgc161489 	}
2377d73ae94eSgc161489 
2378d73ae94eSgc161489 	/*
2379d73ae94eSgc161489 	 * check whether there is another dip with this name and address
2380d73ae94eSgc161489 	 */
2381d73ae94eSgc161489 	ASSERT(usba_find_existing_node(child_dip) == NULL);
2382d73ae94eSgc161489 
23833c91d182Slg150142 	usba_name_buf = kmem_zalloc(USBA_MAX_COMPAT_NAMES *
23843c91d182Slg150142 	    USBA_MAX_COMPAT_NAME_LEN, KM_SLEEP);
23853c91d182Slg150142 
23863c91d182Slg150142 	for (i = 0; i < USBA_MAX_COMPAT_NAMES; i++) {
23873c91d182Slg150142 		usba_name[i] = usba_name_buf + (i * USBA_MAX_COMPAT_NAME_LEN);
23883c91d182Slg150142 	}
23893c91d182Slg150142 
2390d73ae94eSgc161489 	n = 0;
2391d73ae94eSgc161489 
2392d73ae94eSgc161489 	if (force_bind) {
2393d73ae94eSgc161489 		(void) ndi_devi_set_nodename(child_dip, force_bind, 0);
2394d73ae94eSgc161489 		(void) strncpy(usba_name[n++], force_bind,
2395d73ae94eSgc161489 		    USBA_MAX_COMPAT_NAME_LEN);
2396d73ae94eSgc161489 	}
2397d73ae94eSgc161489 
2398d73ae94eSgc161489 	/* 1) usbiaVID,PID.REV.configCN.FN */
2399d73ae94eSgc161489 	(void) sprintf(usba_name[n++],
2400d73ae94eSgc161489 	    "usbia%x,%x.%x.config%x.%x",
2401d73ae94eSgc161489 	    usb_dev_descr->idVendor,
2402d73ae94eSgc161489 	    usb_dev_descr->idProduct,
2403d73ae94eSgc161489 	    usb_dev_descr->bcdDevice,
2404d73ae94eSgc161489 	    child_ud->usb_cfg_value,
2405d73ae94eSgc161489 	    first_if);
2406d73ae94eSgc161489 
2407d73ae94eSgc161489 	/* 2) usbiaVID,PID.configCN.FN */
2408d73ae94eSgc161489 	(void) sprintf(usba_name[n++],
2409d73ae94eSgc161489 	    "usbia%x,%x.config%x.%x",
2410d73ae94eSgc161489 	    usb_dev_descr->idVendor,
2411d73ae94eSgc161489 	    usb_dev_descr->idProduct,
2412d73ae94eSgc161489 	    child_ud->usb_cfg_value,
2413d73ae94eSgc161489 	    first_if);
2414d73ae94eSgc161489 
2415d73ae94eSgc161489 
2416d73ae94eSgc161489 	if (ia_descr.bFunctionClass) {
2417d73ae94eSgc161489 		/* 3) usbiaVID,classFC.FSC.FPROTO */
2418d73ae94eSgc161489 		(void) sprintf(usba_name[n++],
2419d73ae94eSgc161489 		    "usbia%x,class%x.%x.%x",
2420d73ae94eSgc161489 		    usb_dev_descr->idVendor,
2421d73ae94eSgc161489 		    ia_descr.bFunctionClass,
2422d73ae94eSgc161489 		    ia_descr.bFunctionSubClass,
2423d73ae94eSgc161489 		    ia_descr.bFunctionProtocol);
2424d73ae94eSgc161489 
2425d73ae94eSgc161489 		/* 4) usbiaVID,classFC.FSC */
2426d73ae94eSgc161489 		(void) sprintf(usba_name[n++],
2427d73ae94eSgc161489 		    "usbia%x,class%x.%x",
2428d73ae94eSgc161489 		    usb_dev_descr->idVendor,
2429d73ae94eSgc161489 		    ia_descr.bFunctionClass,
2430d73ae94eSgc161489 		    ia_descr.bFunctionSubClass);
2431d73ae94eSgc161489 
2432d73ae94eSgc161489 		/* 5) usbiaVID,classFC */
2433d73ae94eSgc161489 		(void) sprintf(usba_name[n++],
2434d73ae94eSgc161489 		    "usbia%x,class%x",
2435d73ae94eSgc161489 		    usb_dev_descr->idVendor,
2436d73ae94eSgc161489 		    ia_descr.bFunctionClass);
2437d73ae94eSgc161489 
2438d73ae94eSgc161489 		/* 6) usbia,classFC.FSC.FPROTO */
2439d73ae94eSgc161489 		(void) sprintf(usba_name[n++],
2440d73ae94eSgc161489 		    "usbia,class%x.%x.%x",
2441d73ae94eSgc161489 		    ia_descr.bFunctionClass,
2442d73ae94eSgc161489 		    ia_descr.bFunctionSubClass,
2443d73ae94eSgc161489 		    ia_descr.bFunctionProtocol);
2444d73ae94eSgc161489 
2445d73ae94eSgc161489 		/* 7) usbia,classFC.FSC */
2446d73ae94eSgc161489 		(void) sprintf(usba_name[n++],
2447d73ae94eSgc161489 		    "usbia,class%x.%x",
2448d73ae94eSgc161489 		    ia_descr.bFunctionClass,
2449d73ae94eSgc161489 		    ia_descr.bFunctionSubClass);
2450d73ae94eSgc161489 
2451d73ae94eSgc161489 		/* 8) usbia,classFC */
2452d73ae94eSgc161489 		(void) sprintf(usba_name[n++],
2453d73ae94eSgc161489 		    "usbia,class%x",
2454d73ae94eSgc161489 		    ia_descr.bFunctionClass);
2455d73ae94eSgc161489 	}
2456d73ae94eSgc161489 
2457d73ae94eSgc161489 	if (usba_get_ugen_binding(child_dip) ==
2458d73ae94eSgc161489 	    USBA_UGEN_INTERFACE_ASSOCIATION_BINDING) {
2459d73ae94eSgc161489 		/* 9) ugen */
2460d73ae94eSgc161489 		(void) sprintf(usba_name[n++], "ugen");
2461d73ae94eSgc161489 	} else {
2462d73ae94eSgc161489 
2463d73ae94eSgc161489 		(void) sprintf(usba_name[n++], "usb,ia");
2464d73ae94eSgc161489 	}
2465d73ae94eSgc161489 
2466d73ae94eSgc161489 	for (i = 0; i < n; i += 2) {
2467d73ae94eSgc161489 		USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
24683c91d182Slg150142 		    "compatible name:\t%s\t%s", usba_name[i],
24693c91d182Slg150142 		    (((i+1) < n)? usba_name[i+1] : ""));
2470d73ae94eSgc161489 	}
2471d73ae94eSgc161489 
2472d73ae94eSgc161489 	/* create compatible property */
24733c91d182Slg150142 	rval = ndi_prop_update_string_array(DDI_DEV_T_NONE, child_dip,
24743c91d182Slg150142 	    "compatible", (char **)usba_name, n);
24753c91d182Slg150142 
24763c91d182Slg150142 	kmem_free(usba_name_buf, USBA_MAX_COMPAT_NAMES *
24773c91d182Slg150142 	    USBA_MAX_COMPAT_NAME_LEN);
2478d73ae94eSgc161489 
2479d73ae94eSgc161489 	if (rval != DDI_PROP_SUCCESS) {
2480d73ae94eSgc161489 
2481d73ae94eSgc161489 		goto fail;
2482d73ae94eSgc161489 	}
2483d73ae94eSgc161489 
2484d73ae94eSgc161489 	/* update the address property */
2485d73ae94eSgc161489 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2486d73ae94eSgc161489 	    "assigned-address", child_ud->usb_addr);
2487d73ae94eSgc161489 	if (rval != DDI_PROP_SUCCESS) {
2488d73ae94eSgc161489 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2489d73ae94eSgc161489 		    "usba_ready_interface_node: address update failed");
2490d73ae94eSgc161489 	}
2491d73ae94eSgc161489 
2492d73ae94eSgc161489 	/* create property with first interface number */
2493d73ae94eSgc161489 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2494d73ae94eSgc161489 	    "interface", ia_descr.bFirstInterface);
2495d73ae94eSgc161489 
2496d73ae94eSgc161489 	if (rval != DDI_PROP_SUCCESS) {
2497d73ae94eSgc161489 
2498d73ae94eSgc161489 		goto fail;
2499d73ae94eSgc161489 	}
2500d73ae94eSgc161489 
2501d73ae94eSgc161489 	/* create property with the count of interfaces in this ia */
2502d73ae94eSgc161489 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2503d73ae94eSgc161489 	    "interface-count", ia_descr.bInterfaceCount);
2504d73ae94eSgc161489 
2505d73ae94eSgc161489 	if (rval != DDI_PROP_SUCCESS) {
2506d73ae94eSgc161489 
2507d73ae94eSgc161489 		goto fail;
2508d73ae94eSgc161489 	}
2509d73ae94eSgc161489 
2510d73ae94eSgc161489 	USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2511d73ae94eSgc161489 	    "%s%d port %d: %s, dip = 0x%p",
2512d73ae94eSgc161489 	    ddi_node_name(ddi_get_parent(dip)),
2513d73ae94eSgc161489 	    ddi_get_instance(ddi_get_parent(dip)),
2514112116d8Sfb209375 	    child_ud->usb_port, ddi_node_name(child_dip), (void *)child_dip);
2515d73ae94eSgc161489 
2516d73ae94eSgc161489 	*if_count = ia_descr.bInterfaceCount;
2517d73ae94eSgc161489 	usba_set_usba_device(child_dip, child_ud);
2518d73ae94eSgc161489 	ASSERT(!mutex_owned(&(usba_get_usba_device(child_dip)->usb_mutex)));
2519d73ae94eSgc161489 
2520d73ae94eSgc161489 	return (child_dip);
2521d73ae94eSgc161489 
2522d73ae94eSgc161489 fail:
2523d73ae94eSgc161489 	(void) usba_destroy_child_devi(child_dip, NDI_DEVI_REMOVE);
2524d73ae94eSgc161489 
2525d73ae94eSgc161489 	return (NULL);
2526d73ae94eSgc161489 }
2527d73ae94eSgc161489 
2528d73ae94eSgc161489 
2529d73ae94eSgc161489 /*
25307c478bd9Sstevel@tonic-gate  * driver binding at interface level, the first arg will be the
25317c478bd9Sstevel@tonic-gate  * the parent dip
25327c478bd9Sstevel@tonic-gate  */
25337c478bd9Sstevel@tonic-gate /*ARGSUSED*/
25347c478bd9Sstevel@tonic-gate dev_info_t *
usba_ready_interface_node(dev_info_t * dip,uint_t intf)25357c478bd9Sstevel@tonic-gate usba_ready_interface_node(dev_info_t *dip, uint_t intf)
25367c478bd9Sstevel@tonic-gate {
25377c478bd9Sstevel@tonic-gate 	dev_info_t		*child_dip = NULL;
25387c478bd9Sstevel@tonic-gate 	usba_device_t		*child_ud = usba_get_usba_device(dip);
25397c478bd9Sstevel@tonic-gate 	usb_dev_descr_t	*usb_dev_descr;
25407c478bd9Sstevel@tonic-gate 	size_t			usb_cfg_length;
25417c478bd9Sstevel@tonic-gate 	uchar_t 		*usb_cfg;
25427c478bd9Sstevel@tonic-gate 	usb_if_descr_t	if_descr;
25437c478bd9Sstevel@tonic-gate 	int			i, n, rval;
25447c478bd9Sstevel@tonic-gate 	int			reg[2];
25457c478bd9Sstevel@tonic-gate 	size_t			size;
25467c478bd9Sstevel@tonic-gate 	usb_port_status_t	port_status;
25477c478bd9Sstevel@tonic-gate 	char			*force_bind = NULL;
25483c91d182Slg150142 	char			*usba_name_buf = NULL;
25493c91d182Slg150142 	char			*usba_name[USBA_MAX_COMPAT_NAMES];
25507c478bd9Sstevel@tonic-gate 
25517c478bd9Sstevel@tonic-gate 	usb_cfg = usb_get_raw_cfg_data(dip, &usb_cfg_length);
25527c478bd9Sstevel@tonic-gate 
25537c478bd9Sstevel@tonic-gate 	mutex_enter(&child_ud->usb_mutex);
25547c478bd9Sstevel@tonic-gate 
25557c478bd9Sstevel@tonic-gate 	usb_dev_descr = child_ud->usb_dev_descr;
25567c478bd9Sstevel@tonic-gate 
25577c478bd9Sstevel@tonic-gate 	/*
25587c478bd9Sstevel@tonic-gate 	 * for each interface, determine all compatible names
25597c478bd9Sstevel@tonic-gate 	 */
25607c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
25617c478bd9Sstevel@tonic-gate 	    "usba_ready_interface_node: "
25627c478bd9Sstevel@tonic-gate 	    "port %d, interface = %d port status = %x",
25637c478bd9Sstevel@tonic-gate 	    child_ud->usb_port, intf, child_ud->usb_port_status);
25647c478bd9Sstevel@tonic-gate 
25657c478bd9Sstevel@tonic-gate 	/* Parse the interface descriptor */
25667c478bd9Sstevel@tonic-gate 	size = usb_parse_if_descr(
25677c478bd9Sstevel@tonic-gate 	    usb_cfg,
25687c478bd9Sstevel@tonic-gate 	    usb_cfg_length,
25697c478bd9Sstevel@tonic-gate 	    intf,		/* interface index */
25707c478bd9Sstevel@tonic-gate 	    0,		/* alt interface index */
25717c478bd9Sstevel@tonic-gate 	    &if_descr,
25727c478bd9Sstevel@tonic-gate 	    USB_IF_DESCR_SIZE);
25737c478bd9Sstevel@tonic-gate 
25747c478bd9Sstevel@tonic-gate 	if (size != USB_IF_DESCR_SIZE) {
2575d291d9f2Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
25767c478bd9Sstevel@tonic-gate 		    "parsing interface: size (%lu) != USB_IF_DESCR_SIZE (%d)",
25777c478bd9Sstevel@tonic-gate 		    size, USB_IF_DESCR_SIZE);
25787c478bd9Sstevel@tonic-gate 		mutex_exit(&child_ud->usb_mutex);
25797c478bd9Sstevel@tonic-gate 
25807c478bd9Sstevel@tonic-gate 		return (NULL);
25817c478bd9Sstevel@tonic-gate 	}
25827c478bd9Sstevel@tonic-gate 
25837c478bd9Sstevel@tonic-gate 	port_status = child_ud->usb_port_status;
25847c478bd9Sstevel@tonic-gate 
25857c478bd9Sstevel@tonic-gate 	/* create reg property */
25867c478bd9Sstevel@tonic-gate 	reg[0] = intf;
25877c478bd9Sstevel@tonic-gate 	reg[1] = child_ud->usb_cfg_value;
25887c478bd9Sstevel@tonic-gate 
25897c478bd9Sstevel@tonic-gate 	mutex_exit(&child_ud->usb_mutex);
25907c478bd9Sstevel@tonic-gate 
25917c478bd9Sstevel@tonic-gate 	/* clone this dip */
25927c478bd9Sstevel@tonic-gate 	rval =	usba_create_child_devi(dip,
25937c478bd9Sstevel@tonic-gate 	    "interface",
25947c478bd9Sstevel@tonic-gate 	    NULL,		/* usba_hcdi ops */
25957c478bd9Sstevel@tonic-gate 	    NULL,		/* root hub dip */
25967c478bd9Sstevel@tonic-gate 	    port_status,	/* port status */
25977c478bd9Sstevel@tonic-gate 	    child_ud,	/* share this usba_device */
25987c478bd9Sstevel@tonic-gate 	    &child_dip);
25997c478bd9Sstevel@tonic-gate 
26007c478bd9Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
26017c478bd9Sstevel@tonic-gate 
26027c478bd9Sstevel@tonic-gate 		goto fail;
26037c478bd9Sstevel@tonic-gate 	}
26047c478bd9Sstevel@tonic-gate 
26057c478bd9Sstevel@tonic-gate 	rval = ndi_prop_update_int_array(
26067c478bd9Sstevel@tonic-gate 	    DDI_DEV_T_NONE, child_dip, "reg", reg, 2);
26077c478bd9Sstevel@tonic-gate 
26087c478bd9Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
26097c478bd9Sstevel@tonic-gate 
26107c478bd9Sstevel@tonic-gate 		goto fail;
26117c478bd9Sstevel@tonic-gate 	}
26127c478bd9Sstevel@tonic-gate 
26137c478bd9Sstevel@tonic-gate 	usba_set_node_name(child_dip, if_descr.bInterfaceClass,
26147c478bd9Sstevel@tonic-gate 	    if_descr.bInterfaceSubClass, if_descr.bInterfaceProtocol,
26157c478bd9Sstevel@tonic-gate 	    FLAG_INTERFACE_NODE);
26167c478bd9Sstevel@tonic-gate 
26177c478bd9Sstevel@tonic-gate 	/* check force binding */
26187c478bd9Sstevel@tonic-gate 	if (usba_ugen_force_binding == USBA_UGEN_INTERFACE_BINDING) {
26197c478bd9Sstevel@tonic-gate 		force_bind = "ugen";
26207c478bd9Sstevel@tonic-gate 	}
26217c478bd9Sstevel@tonic-gate 
26227c478bd9Sstevel@tonic-gate 	/*
26237c478bd9Sstevel@tonic-gate 	 * check whether there is another dip with this name and address
26247c478bd9Sstevel@tonic-gate 	 */
26257c478bd9Sstevel@tonic-gate 	ASSERT(usba_find_existing_node(child_dip) == NULL);
26267c478bd9Sstevel@tonic-gate 
26273c91d182Slg150142 	usba_name_buf = kmem_zalloc(USBA_MAX_COMPAT_NAMES *
26283c91d182Slg150142 	    USBA_MAX_COMPAT_NAME_LEN, KM_SLEEP);
26293c91d182Slg150142 
26303c91d182Slg150142 	for (i = 0; i < USBA_MAX_COMPAT_NAMES; i++) {
26313c91d182Slg150142 		usba_name[i] = usba_name_buf + (i * USBA_MAX_COMPAT_NAME_LEN);
26323c91d182Slg150142 	}
26333c91d182Slg150142 
26347c478bd9Sstevel@tonic-gate 	n = 0;
26357c478bd9Sstevel@tonic-gate 
26367c478bd9Sstevel@tonic-gate 	if (force_bind) {
26377c478bd9Sstevel@tonic-gate 		(void) ndi_devi_set_nodename(child_dip, force_bind, 0);
26387c478bd9Sstevel@tonic-gate 		(void) strncpy(usba_name[n++], force_bind,
26397c478bd9Sstevel@tonic-gate 		    USBA_MAX_COMPAT_NAME_LEN);
26407c478bd9Sstevel@tonic-gate 	}
26417c478bd9Sstevel@tonic-gate 
26427c478bd9Sstevel@tonic-gate 	/* 1) usbifVID,PID.REV.configCN.IN */
26437c478bd9Sstevel@tonic-gate 	(void) sprintf(usba_name[n++],
26447c478bd9Sstevel@tonic-gate 	    "usbif%x,%x.%x.config%x.%x",
26457c478bd9Sstevel@tonic-gate 	    usb_dev_descr->idVendor,
26467c478bd9Sstevel@tonic-gate 	    usb_dev_descr->idProduct,
26477c478bd9Sstevel@tonic-gate 	    usb_dev_descr->bcdDevice,
26487c478bd9Sstevel@tonic-gate 	    child_ud->usb_cfg_value,
26497c478bd9Sstevel@tonic-gate 	    intf);
26507c478bd9Sstevel@tonic-gate 
26517c478bd9Sstevel@tonic-gate 	/* 2) usbifVID,PID.configCN.IN */
26527c478bd9Sstevel@tonic-gate 	(void) sprintf(usba_name[n++],
26537c478bd9Sstevel@tonic-gate 	    "usbif%x,%x.config%x.%x",
26547c478bd9Sstevel@tonic-gate 	    usb_dev_descr->idVendor,
26557c478bd9Sstevel@tonic-gate 	    usb_dev_descr->idProduct,
26567c478bd9Sstevel@tonic-gate 	    child_ud->usb_cfg_value,
26577c478bd9Sstevel@tonic-gate 	    intf);
26587c478bd9Sstevel@tonic-gate 
26597c478bd9Sstevel@tonic-gate 
26607c478bd9Sstevel@tonic-gate 	if (if_descr.bInterfaceClass) {
26617c478bd9Sstevel@tonic-gate 		/* 3) usbifVID,classIC.ISC.IPROTO */
26627c478bd9Sstevel@tonic-gate 		(void) sprintf(usba_name[n++],
26637c478bd9Sstevel@tonic-gate 		    "usbif%x,class%x.%x.%x",
26647c478bd9Sstevel@tonic-gate 		    usb_dev_descr->idVendor,
26657c478bd9Sstevel@tonic-gate 		    if_descr.bInterfaceClass,
26667c478bd9Sstevel@tonic-gate 		    if_descr.bInterfaceSubClass,
26677c478bd9Sstevel@tonic-gate 		    if_descr.bInterfaceProtocol);
26687c478bd9Sstevel@tonic-gate 
26697c478bd9Sstevel@tonic-gate 		/* 4) usbifVID,classIC.ISC */
26707c478bd9Sstevel@tonic-gate 		(void) sprintf(usba_name[n++],
26717c478bd9Sstevel@tonic-gate 		    "usbif%x,class%x.%x",
26727c478bd9Sstevel@tonic-gate 		    usb_dev_descr->idVendor,
26737c478bd9Sstevel@tonic-gate 		    if_descr.bInterfaceClass,
26747c478bd9Sstevel@tonic-gate 		    if_descr.bInterfaceSubClass);
26757c478bd9Sstevel@tonic-gate 
26767c478bd9Sstevel@tonic-gate 		/* 5) usbifVID,classIC */
26777c478bd9Sstevel@tonic-gate 		(void) sprintf(usba_name[n++],
26787c478bd9Sstevel@tonic-gate 		    "usbif%x,class%x",
26797c478bd9Sstevel@tonic-gate 		    usb_dev_descr->idVendor,
26807c478bd9Sstevel@tonic-gate 		    if_descr.bInterfaceClass);
26817c478bd9Sstevel@tonic-gate 
26827c478bd9Sstevel@tonic-gate 		/* 6) usbif,classIC.ISC.IPROTO */
26837c478bd9Sstevel@tonic-gate 		(void) sprintf(usba_name[n++],
26847c478bd9Sstevel@tonic-gate 		    "usbif,class%x.%x.%x",
26857c478bd9Sstevel@tonic-gate 		    if_descr.bInterfaceClass,
26867c478bd9Sstevel@tonic-gate 		    if_descr.bInterfaceSubClass,
26877c478bd9Sstevel@tonic-gate 		    if_descr.bInterfaceProtocol);
26887c478bd9Sstevel@tonic-gate 
26897c478bd9Sstevel@tonic-gate 		/* 7) usbif,classIC.ISC */
26907c478bd9Sstevel@tonic-gate 		(void) sprintf(usba_name[n++],
26917c478bd9Sstevel@tonic-gate 		    "usbif,class%x.%x",
26927c478bd9Sstevel@tonic-gate 		    if_descr.bInterfaceClass,
26937c478bd9Sstevel@tonic-gate 		    if_descr.bInterfaceSubClass);
26947c478bd9Sstevel@tonic-gate 
26957c478bd9Sstevel@tonic-gate 		/* 8) usbif,classIC */
26967c478bd9Sstevel@tonic-gate 		(void) sprintf(usba_name[n++],
26977c478bd9Sstevel@tonic-gate 		    "usbif,class%x",
26987c478bd9Sstevel@tonic-gate 		    if_descr.bInterfaceClass);
26997c478bd9Sstevel@tonic-gate 	}
27007c478bd9Sstevel@tonic-gate 
27017c478bd9Sstevel@tonic-gate 	if (usba_get_ugen_binding(child_dip) ==
27027c478bd9Sstevel@tonic-gate 	    USBA_UGEN_INTERFACE_BINDING) {
27037c478bd9Sstevel@tonic-gate 		/* 9) ugen */
27047c478bd9Sstevel@tonic-gate 		(void) sprintf(usba_name[n++], "ugen");
27057c478bd9Sstevel@tonic-gate 	}
27067c478bd9Sstevel@tonic-gate 
27077c478bd9Sstevel@tonic-gate 	for (i = 0; i < n; i += 2) {
27087c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
27093c91d182Slg150142 		    "compatible name:\t%s\t%s", usba_name[i],
27103c91d182Slg150142 		    (((i+1) < n)? usba_name[i+1] : ""));
27117c478bd9Sstevel@tonic-gate 	}
27127c478bd9Sstevel@tonic-gate 
27137c478bd9Sstevel@tonic-gate 	/* create compatible property */
27143c91d182Slg150142 	rval = ndi_prop_update_string_array(DDI_DEV_T_NONE, child_dip,
27153c91d182Slg150142 	    "compatible", (char **)usba_name, n);
27163c91d182Slg150142 
27173c91d182Slg150142 	kmem_free(usba_name_buf, USBA_MAX_COMPAT_NAMES *
27183c91d182Slg150142 	    USBA_MAX_COMPAT_NAME_LEN);
27197c478bd9Sstevel@tonic-gate 
27207c478bd9Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
27217c478bd9Sstevel@tonic-gate 
27227c478bd9Sstevel@tonic-gate 		goto fail;
27237c478bd9Sstevel@tonic-gate 	}
27247c478bd9Sstevel@tonic-gate 
27257c478bd9Sstevel@tonic-gate 	/* update the address property */
27267c478bd9Sstevel@tonic-gate 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
27277c478bd9Sstevel@tonic-gate 	    "assigned-address", child_ud->usb_addr);
27287c478bd9Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
2729d291d9f2Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
27307c478bd9Sstevel@tonic-gate 		    "usba_ready_interface_node: address update failed");
27317c478bd9Sstevel@tonic-gate 	}
27327c478bd9Sstevel@tonic-gate 
27337c478bd9Sstevel@tonic-gate 	/* create property with if number */
27347c478bd9Sstevel@tonic-gate 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
27357c478bd9Sstevel@tonic-gate 	    "interface", intf);
27367c478bd9Sstevel@tonic-gate 
27377c478bd9Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
27387c478bd9Sstevel@tonic-gate 
27397c478bd9Sstevel@tonic-gate 		goto fail;
27407c478bd9Sstevel@tonic-gate 	}
27417c478bd9Sstevel@tonic-gate 
27427c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
27437c478bd9Sstevel@tonic-gate 	    "%s%d port %d: %s, dip = 0x%p",
27447c478bd9Sstevel@tonic-gate 	    ddi_node_name(ddi_get_parent(dip)),
27457c478bd9Sstevel@tonic-gate 	    ddi_get_instance(ddi_get_parent(dip)),
2746112116d8Sfb209375 	    child_ud->usb_port, ddi_node_name(child_dip), (void *)child_dip);
27477c478bd9Sstevel@tonic-gate 
27487c478bd9Sstevel@tonic-gate 	usba_set_usba_device(child_dip, child_ud);
27497c478bd9Sstevel@tonic-gate 	ASSERT(!mutex_owned(&(usba_get_usba_device(child_dip)->usb_mutex)));
27507c478bd9Sstevel@tonic-gate 
27517c478bd9Sstevel@tonic-gate 	return (child_dip);
27527c478bd9Sstevel@tonic-gate 
27537c478bd9Sstevel@tonic-gate fail:
27547c478bd9Sstevel@tonic-gate 	(void) usba_destroy_child_devi(child_dip, NDI_DEVI_REMOVE);
27557c478bd9Sstevel@tonic-gate 
27567c478bd9Sstevel@tonic-gate 	return (NULL);
27577c478bd9Sstevel@tonic-gate }
27587c478bd9Sstevel@tonic-gate 
27597c478bd9Sstevel@tonic-gate 
27607c478bd9Sstevel@tonic-gate /*
27617c478bd9Sstevel@tonic-gate  * retrieve string descriptors for manufacturer, vendor and serial
27627c478bd9Sstevel@tonic-gate  * number
27637c478bd9Sstevel@tonic-gate  */
27647c478bd9Sstevel@tonic-gate void
usba_get_dev_string_descrs(dev_info_t * dip,usba_device_t * ud)27657c478bd9Sstevel@tonic-gate usba_get_dev_string_descrs(dev_info_t *dip, usba_device_t *ud)
27667c478bd9Sstevel@tonic-gate {
27677c478bd9Sstevel@tonic-gate 	char	*tmpbuf, *str;
27687c478bd9Sstevel@tonic-gate 	int	l;
27697c478bd9Sstevel@tonic-gate 	usb_dev_descr_t *usb_dev_descr = ud->usb_dev_descr;
27707c478bd9Sstevel@tonic-gate 
27717c478bd9Sstevel@tonic-gate 
27727c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
27737c478bd9Sstevel@tonic-gate 	    "usba_get_usb_string_descr: m=%d, p=%d, s=%d",
27747c478bd9Sstevel@tonic-gate 	    usb_dev_descr->iManufacturer,
27757c478bd9Sstevel@tonic-gate 	    usb_dev_descr->iProduct,
27767c478bd9Sstevel@tonic-gate 	    usb_dev_descr->iSerialNumber);
27777c478bd9Sstevel@tonic-gate 
27787c478bd9Sstevel@tonic-gate 	tmpbuf = kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP);
27797c478bd9Sstevel@tonic-gate 
27807c478bd9Sstevel@tonic-gate 	/* fetch manufacturer string */
27817c478bd9Sstevel@tonic-gate 	if ((ud->usb_mfg_str == NULL) && usb_dev_descr->iManufacturer &&
27827c478bd9Sstevel@tonic-gate 	    (usb_get_string_descr(dip, USB_LANG_ID,
27837c478bd9Sstevel@tonic-gate 	    usb_dev_descr->iManufacturer, tmpbuf, USB_MAXSTRINGLEN) ==
27847c478bd9Sstevel@tonic-gate 	    USB_SUCCESS)) {
27857c478bd9Sstevel@tonic-gate 
27867c478bd9Sstevel@tonic-gate 		l = strlen(tmpbuf);
27877c478bd9Sstevel@tonic-gate 		if (l > 0) {
27887c478bd9Sstevel@tonic-gate 			str = kmem_zalloc(l + 1, KM_SLEEP);
27897c478bd9Sstevel@tonic-gate 			mutex_enter(&ud->usb_mutex);
27907c478bd9Sstevel@tonic-gate 			ud->usb_mfg_str = str;
27917c478bd9Sstevel@tonic-gate 			(void) strcpy(ud->usb_mfg_str, tmpbuf);
27927c478bd9Sstevel@tonic-gate 			mutex_exit(&ud->usb_mutex);
27937c478bd9Sstevel@tonic-gate 		}
27947c478bd9Sstevel@tonic-gate 	}
27957c478bd9Sstevel@tonic-gate 
27967c478bd9Sstevel@tonic-gate 	/* fetch product string */
27977c478bd9Sstevel@tonic-gate 	if ((ud->usb_product_str == NULL) && usb_dev_descr->iProduct &&
27987c478bd9Sstevel@tonic-gate 	    (usb_get_string_descr(dip, USB_LANG_ID, usb_dev_descr->iProduct,
27997c478bd9Sstevel@tonic-gate 	    tmpbuf, USB_MAXSTRINGLEN) ==
28007c478bd9Sstevel@tonic-gate 	    USB_SUCCESS)) {
28017c478bd9Sstevel@tonic-gate 
28027c478bd9Sstevel@tonic-gate 		l = strlen(tmpbuf);
28037c478bd9Sstevel@tonic-gate 		if (l > 0) {
28047c478bd9Sstevel@tonic-gate 			str = kmem_zalloc(l + 1, KM_SLEEP);
28057c478bd9Sstevel@tonic-gate 			mutex_enter(&ud->usb_mutex);
28067c478bd9Sstevel@tonic-gate 			ud->usb_product_str = str;
28077c478bd9Sstevel@tonic-gate 			(void) strcpy(ud->usb_product_str, tmpbuf);
28087c478bd9Sstevel@tonic-gate 			mutex_exit(&ud->usb_mutex);
28097c478bd9Sstevel@tonic-gate 		}
28107c478bd9Sstevel@tonic-gate 	}
28117c478bd9Sstevel@tonic-gate 
28127c478bd9Sstevel@tonic-gate 	/* fetch device serial number string */
28137c478bd9Sstevel@tonic-gate 	if ((ud->usb_serialno_str == NULL) && usb_dev_descr->iSerialNumber &&
28147c478bd9Sstevel@tonic-gate 	    (usb_get_string_descr(dip, USB_LANG_ID,
28157c478bd9Sstevel@tonic-gate 	    usb_dev_descr->iSerialNumber, tmpbuf, USB_MAXSTRINGLEN) ==
28167c478bd9Sstevel@tonic-gate 	    USB_SUCCESS)) {
28177c478bd9Sstevel@tonic-gate 
28187c478bd9Sstevel@tonic-gate 		l = strlen(tmpbuf);
28197c478bd9Sstevel@tonic-gate 		if (l > 0) {
28207c478bd9Sstevel@tonic-gate 			str = kmem_zalloc(l + 1, KM_SLEEP);
28217c478bd9Sstevel@tonic-gate 			mutex_enter(&ud->usb_mutex);
28227c478bd9Sstevel@tonic-gate 			ud->usb_serialno_str = str;
28237c478bd9Sstevel@tonic-gate 			(void) strcpy(ud->usb_serialno_str, tmpbuf);
28247c478bd9Sstevel@tonic-gate 			mutex_exit(&ud->usb_mutex);
28257c478bd9Sstevel@tonic-gate 		}
28267c478bd9Sstevel@tonic-gate 	}
28277c478bd9Sstevel@tonic-gate 
28287c478bd9Sstevel@tonic-gate 	kmem_free(tmpbuf, USB_MAXSTRINGLEN);
28297c478bd9Sstevel@tonic-gate }
28307c478bd9Sstevel@tonic-gate 
28317c478bd9Sstevel@tonic-gate 
28327c478bd9Sstevel@tonic-gate /*
28337c478bd9Sstevel@tonic-gate  * usba_str_startcmp:
28347c478bd9Sstevel@tonic-gate  *	Return the number of characters duplicated from the beginning of the
28357c478bd9Sstevel@tonic-gate  *	string.  Return -1 if a complete duplicate.
28367c478bd9Sstevel@tonic-gate  *
28377c478bd9Sstevel@tonic-gate  * Arguments:
28387c478bd9Sstevel@tonic-gate  *	Two strings to compare.
28397c478bd9Sstevel@tonic-gate  */
usba_str_startcmp(char * first,char * second)28407c478bd9Sstevel@tonic-gate static int usba_str_startcmp(char *first, char *second)
28417c478bd9Sstevel@tonic-gate {
28427c478bd9Sstevel@tonic-gate 	int num_same_chars = 0;
28437c478bd9Sstevel@tonic-gate 	while (*first == *second++) {
28447c478bd9Sstevel@tonic-gate 		if (*first++ == '\0') {
28457c478bd9Sstevel@tonic-gate 			return (-1);
28467c478bd9Sstevel@tonic-gate 		}
28477c478bd9Sstevel@tonic-gate 		num_same_chars++;
28487c478bd9Sstevel@tonic-gate 	}
28497c478bd9Sstevel@tonic-gate 
28507c478bd9Sstevel@tonic-gate 	return (num_same_chars);
28517c478bd9Sstevel@tonic-gate }
28527c478bd9Sstevel@tonic-gate 
28537c478bd9Sstevel@tonic-gate 
28547c478bd9Sstevel@tonic-gate /*
28557c478bd9Sstevel@tonic-gate  * usba_get_mfg_prod_sn_str:
28567c478bd9Sstevel@tonic-gate  *	Return a string containing mfg, product, serial number strings.
28577c478bd9Sstevel@tonic-gate  *	Remove duplicates if some strings are the same.
28587c478bd9Sstevel@tonic-gate  *
28597c478bd9Sstevel@tonic-gate  * Arguments:
28607c478bd9Sstevel@tonic-gate  *	dip	- pointer to dev info
28617c478bd9Sstevel@tonic-gate  *	buffer	- Where string is returned
28627c478bd9Sstevel@tonic-gate  *	buflen	- Length of buffer
28637c478bd9Sstevel@tonic-gate  *
28647c478bd9Sstevel@tonic-gate  * Returns:
28657c478bd9Sstevel@tonic-gate  *	Same as second arg.
28667c478bd9Sstevel@tonic-gate  */
28677c478bd9Sstevel@tonic-gate char *
usba_get_mfg_prod_sn_str(dev_info_t * dip,char * buffer,int buflen)28687c478bd9Sstevel@tonic-gate usba_get_mfg_prod_sn_str(
28697c478bd9Sstevel@tonic-gate     dev_info_t	*dip,
28707c478bd9Sstevel@tonic-gate     char	*buffer,
28717c478bd9Sstevel@tonic-gate     int		buflen)
28727c478bd9Sstevel@tonic-gate {
28737c478bd9Sstevel@tonic-gate 	usba_device_t *usba_device = usba_get_usba_device(dip);
28747c478bd9Sstevel@tonic-gate 	int return_len = 0;
28757c478bd9Sstevel@tonic-gate 	int len = 0;
28767c478bd9Sstevel@tonic-gate 	int duplen;
28777c478bd9Sstevel@tonic-gate 
28787c478bd9Sstevel@tonic-gate 	buffer[0] = '\0';
28797c478bd9Sstevel@tonic-gate 	buffer[buflen-1] = '\0';
28807c478bd9Sstevel@tonic-gate 
28817c478bd9Sstevel@tonic-gate 	if ((usba_device->usb_mfg_str) &&
28827c478bd9Sstevel@tonic-gate 	    ((len = strlen(usba_device->usb_mfg_str)) != 0)) {
28837c478bd9Sstevel@tonic-gate 		(void) strncpy(buffer, usba_device->usb_mfg_str, buflen - 1);
28847c478bd9Sstevel@tonic-gate 		return_len = min(buflen - 1, len);
28857c478bd9Sstevel@tonic-gate 	}
28867c478bd9Sstevel@tonic-gate 
28877c478bd9Sstevel@tonic-gate 	/* Product string exists to append. */
28887c478bd9Sstevel@tonic-gate 	if ((usba_device->usb_product_str) &&
28897c478bd9Sstevel@tonic-gate 	    ((len = strlen(usba_device->usb_product_str)) != 0)) {
28907c478bd9Sstevel@tonic-gate 
28917c478bd9Sstevel@tonic-gate 		/* Append only parts of string that don't match mfg string. */
28927c478bd9Sstevel@tonic-gate 		duplen = usba_str_startcmp(buffer,
28937c478bd9Sstevel@tonic-gate 		    usba_device->usb_product_str);
28947c478bd9Sstevel@tonic-gate 
28957c478bd9Sstevel@tonic-gate 		if (duplen != -1) {		/* Not a complete match. */
28967c478bd9Sstevel@tonic-gate 			if (return_len > 0) {
28977c478bd9Sstevel@tonic-gate 				buffer[return_len++] = ' ';
28987c478bd9Sstevel@tonic-gate 			}
28997c478bd9Sstevel@tonic-gate 
29007c478bd9Sstevel@tonic-gate 			/* Skip over the dup part of the concat'ed string. */
29017c478bd9Sstevel@tonic-gate 			len -= duplen;
29027c478bd9Sstevel@tonic-gate 			(void) strncpy(&buffer[return_len],
29037c478bd9Sstevel@tonic-gate 			    &usba_device->usb_product_str[duplen],
29047c478bd9Sstevel@tonic-gate 			    buflen - return_len - 1);
29057c478bd9Sstevel@tonic-gate 			return_len = min(buflen - 1, return_len + len);
29067c478bd9Sstevel@tonic-gate 		}
29077c478bd9Sstevel@tonic-gate 	}
29087c478bd9Sstevel@tonic-gate 
29097c478bd9Sstevel@tonic-gate 	if ((usba_device->usb_serialno_str) &&
29107c478bd9Sstevel@tonic-gate 	    ((len = strlen(usba_device->usb_serialno_str)) != 0)) {
29117c478bd9Sstevel@tonic-gate 		if (return_len > 0) {
29127c478bd9Sstevel@tonic-gate 			buffer[return_len++] = ' ';
29137c478bd9Sstevel@tonic-gate 		}
29147c478bd9Sstevel@tonic-gate 		(void) strncpy(&buffer[return_len],
29157c478bd9Sstevel@tonic-gate 		    usba_device->usb_serialno_str,
29167c478bd9Sstevel@tonic-gate 		    buflen - return_len - 1);
29177c478bd9Sstevel@tonic-gate 	}
29187c478bd9Sstevel@tonic-gate 
29197c478bd9Sstevel@tonic-gate 	return (buffer);
29207c478bd9Sstevel@tonic-gate }
29217c478bd9Sstevel@tonic-gate 
29227c478bd9Sstevel@tonic-gate 
29237c478bd9Sstevel@tonic-gate /*
29247c478bd9Sstevel@tonic-gate  * USB enumeration statistic functions
29257c478bd9Sstevel@tonic-gate  */
29267c478bd9Sstevel@tonic-gate 
29277c478bd9Sstevel@tonic-gate /*
29287c478bd9Sstevel@tonic-gate  * Increments the hotplug statistics based on flags.
29297c478bd9Sstevel@tonic-gate  */
29307c478bd9Sstevel@tonic-gate void
usba_update_hotplug_stats(dev_info_t * dip,usb_flags_t flags)29317c478bd9Sstevel@tonic-gate usba_update_hotplug_stats(dev_info_t *dip, usb_flags_t flags)
29327c478bd9Sstevel@tonic-gate {
29337c478bd9Sstevel@tonic-gate 	usba_device_t	*usba_device = usba_get_usba_device(dip);
29347c478bd9Sstevel@tonic-gate 	usba_hcdi_t	*hcdi =
29357c478bd9Sstevel@tonic-gate 	    usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
29367c478bd9Sstevel@tonic-gate 
29377c478bd9Sstevel@tonic-gate 	mutex_enter(&hcdi->hcdi_mutex);
29387c478bd9Sstevel@tonic-gate 	if (flags & USBA_TOTAL_HOTPLUG_SUCCESS) {
29397c478bd9Sstevel@tonic-gate 		hcdi->hcdi_total_hotplug_success++;
29407c478bd9Sstevel@tonic-gate 		HCDI_HOTPLUG_STATS_DATA(hcdi)->
29417c478bd9Sstevel@tonic-gate 		    hcdi_hotplug_total_success.value.ui64++;
29427c478bd9Sstevel@tonic-gate 	}
29437c478bd9Sstevel@tonic-gate 	if (flags & USBA_HOTPLUG_SUCCESS) {
29447c478bd9Sstevel@tonic-gate 		hcdi->hcdi_hotplug_success++;
29457c478bd9Sstevel@tonic-gate 		HCDI_HOTPLUG_STATS_DATA(hcdi)->
29467c478bd9Sstevel@tonic-gate 		    hcdi_hotplug_success.value.ui64++;
29477c478bd9Sstevel@tonic-gate 	}
29487c478bd9Sstevel@tonic-gate 	if (flags & USBA_TOTAL_HOTPLUG_FAILURE) {
29497c478bd9Sstevel@tonic-gate 		hcdi->hcdi_total_hotplug_failure++;
29507c478bd9Sstevel@tonic-gate 		HCDI_HOTPLUG_STATS_DATA(hcdi)->
29517c478bd9Sstevel@tonic-gate 		    hcdi_hotplug_total_failure.value.ui64++;
29527c478bd9Sstevel@tonic-gate 	}
29537c478bd9Sstevel@tonic-gate 	if (flags & USBA_HOTPLUG_FAILURE) {
29547c478bd9Sstevel@tonic-gate 		hcdi->hcdi_hotplug_failure++;
29557c478bd9Sstevel@tonic-gate 		HCDI_HOTPLUG_STATS_DATA(hcdi)->
29567c478bd9Sstevel@tonic-gate 		    hcdi_hotplug_failure.value.ui64++;
29577c478bd9Sstevel@tonic-gate 	}
29587c478bd9Sstevel@tonic-gate 	mutex_exit(&hcdi->hcdi_mutex);
29597c478bd9Sstevel@tonic-gate }
29607c478bd9Sstevel@tonic-gate 
29617c478bd9Sstevel@tonic-gate 
29627c478bd9Sstevel@tonic-gate /*
29637c478bd9Sstevel@tonic-gate  * Retrieve the current enumeration statistics
29647c478bd9Sstevel@tonic-gate  */
29657c478bd9Sstevel@tonic-gate void
usba_get_hotplug_stats(dev_info_t * dip,ulong_t * total_success,ulong_t * success,ulong_t * total_failure,ulong_t * failure,uchar_t * device_count)29667c478bd9Sstevel@tonic-gate usba_get_hotplug_stats(dev_info_t *dip, ulong_t *total_success,
29677c478bd9Sstevel@tonic-gate     ulong_t *success, ulong_t *total_failure, ulong_t *failure,
29687c478bd9Sstevel@tonic-gate     uchar_t *device_count)
29697c478bd9Sstevel@tonic-gate {
29707c478bd9Sstevel@tonic-gate 	usba_device_t	*usba_device = usba_get_usba_device(dip);
29717c478bd9Sstevel@tonic-gate 	usba_hcdi_t	*hcdi =
29727c478bd9Sstevel@tonic-gate 	    usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
29737c478bd9Sstevel@tonic-gate 
29747c478bd9Sstevel@tonic-gate 	mutex_enter(&hcdi->hcdi_mutex);
29757c478bd9Sstevel@tonic-gate 	*total_success = hcdi->hcdi_total_hotplug_success;
29767c478bd9Sstevel@tonic-gate 	*success = hcdi->hcdi_hotplug_success;
29777c478bd9Sstevel@tonic-gate 	*total_failure = hcdi->hcdi_total_hotplug_failure;
29787c478bd9Sstevel@tonic-gate 	*failure = hcdi->hcdi_hotplug_failure;
29797c478bd9Sstevel@tonic-gate 	*device_count = hcdi->hcdi_device_count;
29807c478bd9Sstevel@tonic-gate 	mutex_exit(&hcdi->hcdi_mutex);
29817c478bd9Sstevel@tonic-gate }
29827c478bd9Sstevel@tonic-gate 
29837c478bd9Sstevel@tonic-gate 
29847c478bd9Sstevel@tonic-gate /*
29857c478bd9Sstevel@tonic-gate  * Reset the resetable hotplug stats
29867c478bd9Sstevel@tonic-gate  */
29877c478bd9Sstevel@tonic-gate void
usba_reset_hotplug_stats(dev_info_t * dip)29887c478bd9Sstevel@tonic-gate usba_reset_hotplug_stats(dev_info_t *dip)
29897c478bd9Sstevel@tonic-gate {
29907c478bd9Sstevel@tonic-gate 	usba_device_t	*usba_device = usba_get_usba_device(dip);
29917c478bd9Sstevel@tonic-gate 	usba_hcdi_t	*hcdi =
29927c478bd9Sstevel@tonic-gate 	    usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
29937c478bd9Sstevel@tonic-gate 	hcdi_hotplug_stats_t *hsp;
29947c478bd9Sstevel@tonic-gate 
29957c478bd9Sstevel@tonic-gate 	mutex_enter(&hcdi->hcdi_mutex);
29967c478bd9Sstevel@tonic-gate 	hcdi->hcdi_hotplug_success = 0;
29977c478bd9Sstevel@tonic-gate 	hcdi->hcdi_hotplug_failure = 0;
29987c478bd9Sstevel@tonic-gate 
29997c478bd9Sstevel@tonic-gate 	hsp = HCDI_HOTPLUG_STATS_DATA(hcdi);
30007c478bd9Sstevel@tonic-gate 	hsp->hcdi_hotplug_success.value.ui64 = 0;
30017c478bd9Sstevel@tonic-gate 	hsp->hcdi_hotplug_failure.value.ui64 = 0;
30027c478bd9Sstevel@tonic-gate 	mutex_exit(&hcdi->hcdi_mutex);
30037c478bd9Sstevel@tonic-gate }
30047c478bd9Sstevel@tonic-gate 
30057c478bd9Sstevel@tonic-gate 
30067c478bd9Sstevel@tonic-gate /*
30077c478bd9Sstevel@tonic-gate  * usba_bind_driver():
30087c478bd9Sstevel@tonic-gate  *	This function calls ndi_devi_bind_driver() which tries to
30097c478bd9Sstevel@tonic-gate  *	bind a driver to the device.  If the driver binding fails
30107c478bd9Sstevel@tonic-gate  *	we get an rval of NDI_UNBOUD and report an error to the
30117c478bd9Sstevel@tonic-gate  *	syslog that the driver failed binding.
30127c478bd9Sstevel@tonic-gate  *	If rval is something other than NDI_UNBOUND we report an
30137c478bd9Sstevel@tonic-gate  *	error to the console.
30147c478bd9Sstevel@tonic-gate  *
30157c478bd9Sstevel@tonic-gate  *	This function returns USB_SUCCESS if no errors were
30167c478bd9Sstevel@tonic-gate  *	encountered while binding.
30177c478bd9Sstevel@tonic-gate  */
30187c478bd9Sstevel@tonic-gate int
usba_bind_driver(dev_info_t * dip)30197c478bd9Sstevel@tonic-gate usba_bind_driver(dev_info_t *dip)
30207c478bd9Sstevel@tonic-gate {
30217c478bd9Sstevel@tonic-gate 	int	rval;
30227c478bd9Sstevel@tonic-gate 	char	*name;
30237c478bd9Sstevel@tonic-gate 	uint8_t if_num = usba_get_ifno(dip);
30247c478bd9Sstevel@tonic-gate 
30257c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
3026112116d8Sfb209375 	    "usba_bind_driver: dip = 0x%p, if_num = 0x%x", (void *)dip, if_num);
30277c478bd9Sstevel@tonic-gate 
30287c478bd9Sstevel@tonic-gate 	name = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
30297c478bd9Sstevel@tonic-gate 
30307c478bd9Sstevel@tonic-gate 	/* bind device to the driver */
30317c478bd9Sstevel@tonic-gate 	if ((rval = ndi_devi_bind_driver(dip, 0)) != NDI_SUCCESS) {
30327c478bd9Sstevel@tonic-gate 		/* if we fail to bind report an error */
30337c478bd9Sstevel@tonic-gate 		(void) usba_get_mfg_prod_sn_str(dip, name, MAXNAMELEN);
30347c478bd9Sstevel@tonic-gate 		if (name[0] != '\0') {
30357c478bd9Sstevel@tonic-gate 			if (!usb_owns_device(dip)) {
30367c478bd9Sstevel@tonic-gate 				USB_DPRINTF_L1(DPRINT_MASK_USBA,
30377c478bd9Sstevel@tonic-gate 				    usba_log_handle,
30387c478bd9Sstevel@tonic-gate 				    "no driver found for "
30397c478bd9Sstevel@tonic-gate 				    "interface %d (nodename: '%s') of %s",
30407c478bd9Sstevel@tonic-gate 				    if_num, ddi_node_name(dip), name);
30417c478bd9Sstevel@tonic-gate 			} else {
30427c478bd9Sstevel@tonic-gate 				USB_DPRINTF_L1(DPRINT_MASK_USBA,
30437c478bd9Sstevel@tonic-gate 				    usba_log_handle,
30447c478bd9Sstevel@tonic-gate 				    "no driver found for device %s", name);
30457c478bd9Sstevel@tonic-gate 			}
30467c478bd9Sstevel@tonic-gate 		} else {
30477c478bd9Sstevel@tonic-gate 			(void) ddi_pathname(dip, name);
30487c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_USBA,
30497c478bd9Sstevel@tonic-gate 			    usba_log_handle,
30507c478bd9Sstevel@tonic-gate 			    "no driver found for device %s", name);
30517c478bd9Sstevel@tonic-gate 		}
30527c478bd9Sstevel@tonic-gate 
30537c478bd9Sstevel@tonic-gate 		kmem_free(name, MAXNAMELEN);
30547c478bd9Sstevel@tonic-gate 
30557c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
30567c478bd9Sstevel@tonic-gate 	}
30577c478bd9Sstevel@tonic-gate 	kmem_free(name, MAXNAMELEN);
30587c478bd9Sstevel@tonic-gate 
30597c478bd9Sstevel@tonic-gate 	return ((rval == NDI_SUCCESS) ? USB_SUCCESS : USB_FAILURE);
30607c478bd9Sstevel@tonic-gate }
30617c478bd9Sstevel@tonic-gate 
30627c478bd9Sstevel@tonic-gate 
30637c478bd9Sstevel@tonic-gate /*
30647c478bd9Sstevel@tonic-gate  * usba_get_hc_dma_attr:
30657c478bd9Sstevel@tonic-gate  *	function returning dma attributes of the HCD
30667c478bd9Sstevel@tonic-gate  *
30677c478bd9Sstevel@tonic-gate  * Arguments:
30687c478bd9Sstevel@tonic-gate  *	dip	- pointer to devinfo of the client
30697c478bd9Sstevel@tonic-gate  *
30707c478bd9Sstevel@tonic-gate  * Return Values:
30717c478bd9Sstevel@tonic-gate  *	hcdi_dma_attr
30727c478bd9Sstevel@tonic-gate  */
30737c478bd9Sstevel@tonic-gate ddi_dma_attr_t *
usba_get_hc_dma_attr(dev_info_t * dip)30747c478bd9Sstevel@tonic-gate usba_get_hc_dma_attr(dev_info_t *dip)
30757c478bd9Sstevel@tonic-gate {
30767c478bd9Sstevel@tonic-gate 	usba_device_t *usba_device = usba_get_usba_device(dip);
30777c478bd9Sstevel@tonic-gate 	usba_hcdi_t *hcdi = usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
30787c478bd9Sstevel@tonic-gate 
30797c478bd9Sstevel@tonic-gate 	return (hcdi->hcdi_dma_attr);
30807c478bd9Sstevel@tonic-gate }
30817c478bd9Sstevel@tonic-gate 
30827c478bd9Sstevel@tonic-gate 
30837c478bd9Sstevel@tonic-gate /*
30847c478bd9Sstevel@tonic-gate  * usba_check_for_leaks:
30857c478bd9Sstevel@tonic-gate  *	check usba_device structure for leaks
30867c478bd9Sstevel@tonic-gate  *
30877c478bd9Sstevel@tonic-gate  * Arguments:
30887c478bd9Sstevel@tonic-gate  *	usba_device	- usba_device structure pointer
30897c478bd9Sstevel@tonic-gate  */
30907c478bd9Sstevel@tonic-gate void
usba_check_for_leaks(usba_device_t * usba_device)30917c478bd9Sstevel@tonic-gate usba_check_for_leaks(usba_device_t *usba_device)
30927c478bd9Sstevel@tonic-gate {
30937c478bd9Sstevel@tonic-gate 	int i, ph_open_cnt, req_wrp_leaks, iface;
30947c478bd9Sstevel@tonic-gate 	int leaks = 0;
30957c478bd9Sstevel@tonic-gate 
30967c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
30977c478bd9Sstevel@tonic-gate 	    "usba_check_for_leaks: %s%d usba_device=0x%p",
30987c478bd9Sstevel@tonic-gate 	    ddi_driver_name(usba_device->usb_dip),
3099112116d8Sfb209375 	    ddi_get_instance(usba_device->usb_dip), (void *)usba_device);
31007c478bd9Sstevel@tonic-gate 
31017c478bd9Sstevel@tonic-gate 	/*
31027c478bd9Sstevel@tonic-gate 	 * default pipe is still open
31037c478bd9Sstevel@tonic-gate 	 * all other pipes should be closed
31047c478bd9Sstevel@tonic-gate 	 */
31057c478bd9Sstevel@tonic-gate 	for (ph_open_cnt = 0, i = 1; i < USBA_N_ENDPOINTS; i++) {
31067c478bd9Sstevel@tonic-gate 		usba_ph_impl_t *ph_impl =
31077c478bd9Sstevel@tonic-gate 		    &usba_device->usb_ph_list[i];
31087c478bd9Sstevel@tonic-gate 		if (ph_impl->usba_ph_data) {
3109d291d9f2Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_USBA,
31107c478bd9Sstevel@tonic-gate 			    usba_log_handle,
31117c478bd9Sstevel@tonic-gate 			    "%s%d: leaking pipehandle=0x%p (0x%p) ep_addr=0x%x",
31127c478bd9Sstevel@tonic-gate 			    ddi_driver_name(ph_impl->usba_ph_data->p_dip),
31137c478bd9Sstevel@tonic-gate 			    ddi_get_instance(ph_impl->usba_ph_data->p_dip),
3114112116d8Sfb209375 			    (void *)ph_impl,
3115112116d8Sfb209375 			    (void *)ph_impl->usba_ph_data,
31167c478bd9Sstevel@tonic-gate 			    ph_impl->usba_ph_ep.bEndpointAddress);
31177c478bd9Sstevel@tonic-gate 			ph_open_cnt++;
31187c478bd9Sstevel@tonic-gate 			leaks++;
31197c478bd9Sstevel@tonic-gate #ifndef DEBUG
31207c478bd9Sstevel@tonic-gate 			usb_pipe_close(ph_impl->usba_ph_data->p_dip,
31217c478bd9Sstevel@tonic-gate 			    (usb_pipe_handle_t)ph_impl, USB_FLAGS_SLEEP,
31227c478bd9Sstevel@tonic-gate 			    NULL, NULL);
31237c478bd9Sstevel@tonic-gate #endif
31247c478bd9Sstevel@tonic-gate 		}
31257c478bd9Sstevel@tonic-gate 	}
31267c478bd9Sstevel@tonic-gate 	req_wrp_leaks =  usba_list_entry_leaks(&usba_device->
31277c478bd9Sstevel@tonic-gate 	    usb_allocated, "request wrappers");
31287c478bd9Sstevel@tonic-gate 
31297c478bd9Sstevel@tonic-gate 	ASSERT(ph_open_cnt == 0);
31307c478bd9Sstevel@tonic-gate 	ASSERT(req_wrp_leaks == 0);
31317c478bd9Sstevel@tonic-gate 
31327c478bd9Sstevel@tonic-gate 	if (req_wrp_leaks) {
31337c478bd9Sstevel@tonic-gate 		usba_list_entry_t *entry;
31347c478bd9Sstevel@tonic-gate 
31357c478bd9Sstevel@tonic-gate 		while ((entry = usba_rm_first_from_list(
31367c478bd9Sstevel@tonic-gate 		    &usba_device->usb_allocated)) != NULL) {
31377c478bd9Sstevel@tonic-gate 			usba_req_wrapper_t *wrp;
31387c478bd9Sstevel@tonic-gate 
31397c478bd9Sstevel@tonic-gate 			mutex_enter(&entry->list_mutex);
31407c478bd9Sstevel@tonic-gate 			wrp = (usba_req_wrapper_t *)entry->private;
31417c478bd9Sstevel@tonic-gate 			mutex_exit(&entry->list_mutex);
31427c478bd9Sstevel@tonic-gate 			leaks++;
31437c478bd9Sstevel@tonic-gate 
3144d291d9f2Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_USBA,
31457c478bd9Sstevel@tonic-gate 			    usba_log_handle,
31467c478bd9Sstevel@tonic-gate 			    "%s%d: leaking request 0x%p",
31477c478bd9Sstevel@tonic-gate 			    ddi_driver_name(wrp->wr_dip),
31487c478bd9Sstevel@tonic-gate 			    ddi_get_instance(wrp->wr_dip),
3149112116d8Sfb209375 			    (void *)wrp->wr_req);
31507c478bd9Sstevel@tonic-gate 
31517c478bd9Sstevel@tonic-gate 			/*
31527c478bd9Sstevel@tonic-gate 			 * put it back, usba_req_wrapper_free
31537c478bd9Sstevel@tonic-gate 			 * expects it on the list
31547c478bd9Sstevel@tonic-gate 			 */
31557c478bd9Sstevel@tonic-gate 			usba_add_to_list(&usba_device->usb_allocated,
31567c478bd9Sstevel@tonic-gate 			    &wrp->wr_allocated_list);
31577c478bd9Sstevel@tonic-gate 
31587c478bd9Sstevel@tonic-gate 			usba_req_wrapper_free(wrp);
31597c478bd9Sstevel@tonic-gate 		}
31607c478bd9Sstevel@tonic-gate 	}
31617c478bd9Sstevel@tonic-gate 
31627c478bd9Sstevel@tonic-gate 	mutex_enter(&usba_device->usb_mutex);
31637c478bd9Sstevel@tonic-gate 	for (iface = 0; iface < usba_device->usb_n_ifs; iface++) {
31647c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
31657c478bd9Sstevel@tonic-gate 		    "usba_check_for_leaks: if=%d client_flags=0x%x",
31667c478bd9Sstevel@tonic-gate 		    iface, usba_device->usb_client_flags[iface]);
31677c478bd9Sstevel@tonic-gate 
31687c478bd9Sstevel@tonic-gate 		if (usba_device->usb_client_flags[iface] &
31697c478bd9Sstevel@tonic-gate 		    USBA_CLIENT_FLAG_DEV_DATA) {
31707c478bd9Sstevel@tonic-gate 			usb_client_dev_data_list_t *entry =
31717c478bd9Sstevel@tonic-gate 			    usba_device->usb_client_dev_data_list.cddl_next;
31727c478bd9Sstevel@tonic-gate 			usb_client_dev_data_list_t *next;
31737c478bd9Sstevel@tonic-gate 			usb_client_dev_data_t *dev_data;
31747c478bd9Sstevel@tonic-gate 
31757c478bd9Sstevel@tonic-gate 			while (entry) {
31767c478bd9Sstevel@tonic-gate 				dev_info_t *dip = entry->cddl_dip;
31777c478bd9Sstevel@tonic-gate 				next = entry->cddl_next;
31787c478bd9Sstevel@tonic-gate 				dev_data = entry->cddl_dev_data;
31797c478bd9Sstevel@tonic-gate 
31807c478bd9Sstevel@tonic-gate 
3181737d277aScth 				if (!i_ddi_devi_attached(dip)) {
3182d291d9f2Sfrits 					USB_DPRINTF_L2(DPRINT_MASK_USBA,
31837c478bd9Sstevel@tonic-gate 					    usba_log_handle,
31847c478bd9Sstevel@tonic-gate 					    "%s%d: leaking dev_data 0x%p",
31857c478bd9Sstevel@tonic-gate 					    ddi_driver_name(dip),
31867c478bd9Sstevel@tonic-gate 					    ddi_get_instance(dip),
31877c478bd9Sstevel@tonic-gate 					    (void *)dev_data);
31887c478bd9Sstevel@tonic-gate 
31897c478bd9Sstevel@tonic-gate 					leaks++;
31907c478bd9Sstevel@tonic-gate 
31917c478bd9Sstevel@tonic-gate 					mutex_exit(&usba_device->usb_mutex);
31927c478bd9Sstevel@tonic-gate 					usb_free_dev_data(dip, dev_data);
31937c478bd9Sstevel@tonic-gate 					mutex_enter(&usba_device->usb_mutex);
31947c478bd9Sstevel@tonic-gate 				}
31957c478bd9Sstevel@tonic-gate 
31967c478bd9Sstevel@tonic-gate 				entry = next;
31977c478bd9Sstevel@tonic-gate 			}
31987c478bd9Sstevel@tonic-gate 		}
31997c478bd9Sstevel@tonic-gate 		if (usba_device->usb_client_flags[iface] &
32007c478bd9Sstevel@tonic-gate 		    USBA_CLIENT_FLAG_ATTACH) {
32017c478bd9Sstevel@tonic-gate 			dev_info_t *dip = usba_device->
32027c478bd9Sstevel@tonic-gate 			    usb_client_attach_list[iface].dip;
32037c478bd9Sstevel@tonic-gate 
3204d291d9f2Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_USBA,
32057c478bd9Sstevel@tonic-gate 			    usba_log_handle,
32067c478bd9Sstevel@tonic-gate 			    "%s%d: did no usb_client_detach",
32077c478bd9Sstevel@tonic-gate 			    ddi_driver_name(dip), ddi_get_instance(dip));
32087c478bd9Sstevel@tonic-gate 			leaks++;
32097c478bd9Sstevel@tonic-gate 
32107c478bd9Sstevel@tonic-gate 			mutex_exit(&usba_device->usb_mutex);
32117c478bd9Sstevel@tonic-gate 			usb_client_detach(dip, NULL);
32127c478bd9Sstevel@tonic-gate 			mutex_enter(&usba_device->usb_mutex);
32137c478bd9Sstevel@tonic-gate 
32147c478bd9Sstevel@tonic-gate 			usba_device->
32157c478bd9Sstevel@tonic-gate 			    usb_client_attach_list[iface].dip = NULL;
32167c478bd9Sstevel@tonic-gate 
32177c478bd9Sstevel@tonic-gate 			usba_device->usb_client_flags[iface] &=
32187c478bd9Sstevel@tonic-gate 			    ~USBA_CLIENT_FLAG_ATTACH;
32197c478bd9Sstevel@tonic-gate 
32207c478bd9Sstevel@tonic-gate 		}
32217c478bd9Sstevel@tonic-gate 		if (usba_device->usb_client_flags[iface] &
32227c478bd9Sstevel@tonic-gate 		    USBA_CLIENT_FLAG_EV_CBS) {
32237c478bd9Sstevel@tonic-gate 			dev_info_t *dip =
32247c478bd9Sstevel@tonic-gate 			    usba_device->usb_client_ev_cb_list[iface].
32257c478bd9Sstevel@tonic-gate 			    dip;
32267c478bd9Sstevel@tonic-gate 			usb_event_t *ev_data =
32277c478bd9Sstevel@tonic-gate 			    usba_device->usb_client_ev_cb_list[iface].
32287c478bd9Sstevel@tonic-gate 			    ev_data;
32297c478bd9Sstevel@tonic-gate 
3230d291d9f2Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_USBA,
32317c478bd9Sstevel@tonic-gate 			    usba_log_handle,
32327c478bd9Sstevel@tonic-gate 			    "%s%d: did no usb_unregister_event_cbs",
32337c478bd9Sstevel@tonic-gate 			    ddi_driver_name(dip), ddi_get_instance(dip));
32347c478bd9Sstevel@tonic-gate 			leaks++;
32357c478bd9Sstevel@tonic-gate 
32367c478bd9Sstevel@tonic-gate 			mutex_exit(&usba_device->usb_mutex);
32377c478bd9Sstevel@tonic-gate 			usb_unregister_event_cbs(dip, ev_data);
32387c478bd9Sstevel@tonic-gate 			mutex_enter(&usba_device->usb_mutex);
32397c478bd9Sstevel@tonic-gate 
32407c478bd9Sstevel@tonic-gate 			usba_device->usb_client_ev_cb_list[iface].
32417c478bd9Sstevel@tonic-gate 			    dip = NULL;
32427c478bd9Sstevel@tonic-gate 			usba_device->usb_client_ev_cb_list[iface].
32437c478bd9Sstevel@tonic-gate 			    ev_data = NULL;
32447c478bd9Sstevel@tonic-gate 			usba_device->usb_client_flags[iface] &=
32457c478bd9Sstevel@tonic-gate 			    ~USBA_CLIENT_FLAG_EV_CBS;
32467c478bd9Sstevel@tonic-gate 		}
32477c478bd9Sstevel@tonic-gate 	}
32487c478bd9Sstevel@tonic-gate 	mutex_exit(&usba_device->usb_mutex);
32497c478bd9Sstevel@tonic-gate 
32507c478bd9Sstevel@tonic-gate 	if (leaks) {
3251d291d9f2Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
32527c478bd9Sstevel@tonic-gate 		    "all %d leaks fixed", leaks);
32537c478bd9Sstevel@tonic-gate 	}
32547c478bd9Sstevel@tonic-gate }
3255