xref: /onnv-gate/usr/src/uts/common/io/usb/usba/usba.c (revision 10316:d68e26bd3bfd)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
52257Slg150142  * Common Development and Distribution License (the "License").
62257Slg150142  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
229094SVincent.Wang@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /*
280Sstevel@tonic-gate  * USBA: Solaris USB Architecture support
290Sstevel@tonic-gate  */
300Sstevel@tonic-gate #define	USBA_FRAMEWORK
310Sstevel@tonic-gate #include <sys/usb/usba/usba_impl.h>
320Sstevel@tonic-gate #include <sys/usb/usba/hcdi_impl.h>
330Sstevel@tonic-gate #include <sys/usb/hubd/hub.h>
340Sstevel@tonic-gate #include <sys/fs/dv_node.h>
350Sstevel@tonic-gate 
360Sstevel@tonic-gate static int usba_str_startcmp(char *, char *);
370Sstevel@tonic-gate 
380Sstevel@tonic-gate /*
390Sstevel@tonic-gate  * USBA private variables and tunables
400Sstevel@tonic-gate  */
410Sstevel@tonic-gate static kmutex_t	usba_mutex;
420Sstevel@tonic-gate 
439094SVincent.Wang@Sun.COM /* mutex to protect usba_root_hubs */
449094SVincent.Wang@Sun.COM static kmutex_t usba_hub_mutex;
459094SVincent.Wang@Sun.COM 
469094SVincent.Wang@Sun.COM typedef struct usba_root_hub_ent {
479094SVincent.Wang@Sun.COM 	dev_info_t *dip;
489094SVincent.Wang@Sun.COM 	struct usba_root_hub_ent *next;
499094SVincent.Wang@Sun.COM }usba_root_hub_ent_t;
509094SVincent.Wang@Sun.COM 
519094SVincent.Wang@Sun.COM static usba_root_hub_ent_t *usba_root_hubs = NULL;
529094SVincent.Wang@Sun.COM 
530Sstevel@tonic-gate /*
540Sstevel@tonic-gate  * ddivs forced binding:
550Sstevel@tonic-gate  *
560Sstevel@tonic-gate  *    usbc usbc_xhubs usbc_xaddress  node name
570Sstevel@tonic-gate  *
580Sstevel@tonic-gate  *	0	x	x	class name or "device"
590Sstevel@tonic-gate  *
600Sstevel@tonic-gate  *	1	0	0	ddivs_usbc
610Sstevel@tonic-gate  *	1	0	>1	ddivs_usbc except device
620Sstevel@tonic-gate  *				at usbc_xaddress
630Sstevel@tonic-gate  *	1	1	0	ddivs_usbc except hubs
640Sstevel@tonic-gate  *	1	1	>1	ddivs_usbc except hubs and
650Sstevel@tonic-gate  *				device at usbc_xaddress
660Sstevel@tonic-gate  */
670Sstevel@tonic-gate uint_t usba_ddivs_usbc;
680Sstevel@tonic-gate uint_t usba_ddivs_usbc_xhubs;
690Sstevel@tonic-gate uint_t usba_ddivs_usbc_xaddress;
700Sstevel@tonic-gate 
710Sstevel@tonic-gate uint_t usba_ugen_force_binding;
720Sstevel@tonic-gate 
730Sstevel@tonic-gate /*
740Sstevel@tonic-gate  * compatible name handling
750Sstevel@tonic-gate  */
76*10316SStrony.Zhang@Sun.COM /*
77*10316SStrony.Zhang@Sun.COM  * allowing for 15 compat names, plus one force bind name and
78*10316SStrony.Zhang@Sun.COM  * one possible specified client driver name
79*10316SStrony.Zhang@Sun.COM  */
80*10316SStrony.Zhang@Sun.COM #define	USBA_MAX_COMPAT_NAMES		17
810Sstevel@tonic-gate #define	USBA_MAX_COMPAT_NAME_LEN	64
820Sstevel@tonic-gate 
830Sstevel@tonic-gate /* double linked list for usba_devices */
840Sstevel@tonic-gate usba_list_entry_t	usba_device_list;
850Sstevel@tonic-gate 
860Sstevel@tonic-gate _NOTE(MUTEX_PROTECTS_DATA(usba_mutex, usba_device_list))
870Sstevel@tonic-gate 
880Sstevel@tonic-gate /*
890Sstevel@tonic-gate  * modload support
900Sstevel@tonic-gate  */
917767SJohn.Beck@Sun.COM 
927767SJohn.Beck@Sun.COM static struct modlmisc modlmisc	= {
930Sstevel@tonic-gate 	&mod_miscops,	/* Type	of module */
943341Sgc161489 	"USBA: USB Architecture 2.0 1.66"
950Sstevel@tonic-gate };
960Sstevel@tonic-gate 
977767SJohn.Beck@Sun.COM static struct modlinkage modlinkage = {
980Sstevel@tonic-gate 	MODREV_1, (void	*)&modlmisc, NULL
990Sstevel@tonic-gate };
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate static usb_log_handle_t	usba_log_handle;
103880Sfrits uint_t		usba_errlevel = USB_LOG_L4;
104880Sfrits uint_t		usba_errmask = (uint_t)-1;
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate extern usb_log_handle_t	hubdi_log_handle;
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate int
_init(void)1090Sstevel@tonic-gate _init(void)
1100Sstevel@tonic-gate {
1113630Slg150142 	int rval;
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate 	/*
1140Sstevel@tonic-gate 	 * usbai providing log support needs to be init'ed first
1150Sstevel@tonic-gate 	 * and destroyed last
1160Sstevel@tonic-gate 	 */
1170Sstevel@tonic-gate 	usba_usbai_initialization();
1180Sstevel@tonic-gate 	usba_usba_initialization();
1190Sstevel@tonic-gate 	usba_usbai_register_initialization();
1200Sstevel@tonic-gate 	usba_hcdi_initialization();
1210Sstevel@tonic-gate 	usba_hubdi_initialization();
1229430SRaymond.Chen@Sun.COM 	usba_whcdi_initialization();
1230Sstevel@tonic-gate 	usba_devdb_initialization();
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate 	if ((rval = mod_install(&modlinkage)) != 0) {
1260Sstevel@tonic-gate 		usba_devdb_destroy();
1279430SRaymond.Chen@Sun.COM 		usba_whcdi_destroy();
1280Sstevel@tonic-gate 		usba_hubdi_destroy();
1290Sstevel@tonic-gate 		usba_hcdi_destroy();
1300Sstevel@tonic-gate 		usba_usbai_register_destroy();
1310Sstevel@tonic-gate 		usba_usba_destroy();
1320Sstevel@tonic-gate 		usba_usbai_destroy();
1330Sstevel@tonic-gate 	}
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate 	return (rval);
1360Sstevel@tonic-gate }
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate int
_fini()1390Sstevel@tonic-gate _fini()
1400Sstevel@tonic-gate {
1410Sstevel@tonic-gate 	int rval;
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate 	if ((rval = mod_remove(&modlinkage)) == 0) {
1440Sstevel@tonic-gate 		usba_devdb_destroy();
1459430SRaymond.Chen@Sun.COM 		usba_whcdi_destroy();
1460Sstevel@tonic-gate 		usba_hubdi_destroy();
1470Sstevel@tonic-gate 		usba_hcdi_destroy();
1480Sstevel@tonic-gate 		usba_usbai_register_destroy();
1490Sstevel@tonic-gate 		usba_usba_destroy();
1500Sstevel@tonic-gate 		usba_usbai_destroy();
1510Sstevel@tonic-gate 	}
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate 	return (rval);
1540Sstevel@tonic-gate }
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate int
_info(struct modinfo * modinfop)1570Sstevel@tonic-gate _info(struct modinfo *modinfop)
1580Sstevel@tonic-gate {
1590Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
1600Sstevel@tonic-gate }
1610Sstevel@tonic-gate 
1623341Sgc161489 boolean_t
usba_owns_ia(dev_info_t * dip)1633341Sgc161489 usba_owns_ia(dev_info_t *dip)
1643341Sgc161489 {
1653341Sgc161489 	int if_count = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1663341Sgc161489 	    "interface-count", 0);
1673341Sgc161489 
1683341Sgc161489 	return ((if_count) ? B_TRUE : B_FALSE);
1693341Sgc161489 }
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate /*
1720Sstevel@tonic-gate  * common bus ctl for hcd, usb_mid, and hubd
1730Sstevel@tonic-gate  */
1740Sstevel@tonic-gate int
usba_bus_ctl(dev_info_t * dip,dev_info_t * rdip,ddi_ctl_enum_t op,void * arg,void * result)1750Sstevel@tonic-gate usba_bus_ctl(dev_info_t	*dip,
1760Sstevel@tonic-gate 	dev_info_t		*rdip,
1770Sstevel@tonic-gate 	ddi_ctl_enum_t		op,
1780Sstevel@tonic-gate 	void			*arg,
1790Sstevel@tonic-gate 	void			*result)
1800Sstevel@tonic-gate {
1810Sstevel@tonic-gate 	dev_info_t		*child_dip = (dev_info_t *)arg;
1820Sstevel@tonic-gate 	usba_device_t		*usba_device;
1830Sstevel@tonic-gate 	usba_hcdi_t		*usba_hcdi;
1840Sstevel@tonic-gate 	usba_hcdi_ops_t		*usba_hcdi_ops;
1850Sstevel@tonic-gate 
1860Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, hubdi_log_handle,
1870Sstevel@tonic-gate 	    "usba_bus_ctl: %s%d %s%d op=%d", ddi_node_name(rdip),
1880Sstevel@tonic-gate 	    ddi_get_instance(rdip), ddi_node_name(dip),
1890Sstevel@tonic-gate 	    ddi_get_instance(dip), op);
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate 	switch (op) {
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate 	case DDI_CTLOPS_REPORTDEV:
1940Sstevel@tonic-gate 	{
1950Sstevel@tonic-gate 		char *name, compat_name[64], *speed;
1960Sstevel@tonic-gate 		usba_device_t	*hub_usba_device;
1970Sstevel@tonic-gate 		dev_info_t	*hubdip;
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate 		usba_device = usba_get_usba_device(rdip);
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate 		/* find the parent hub */
2020Sstevel@tonic-gate 		hubdip = ddi_get_parent(rdip);
2030Sstevel@tonic-gate 		while ((strcmp(ddi_driver_name(hubdip), "hubd") != 0) &&
2040Sstevel@tonic-gate 		    !(usba_is_root_hub(hubdip))) {
2050Sstevel@tonic-gate 			hubdip = ddi_get_parent(hubdip);
2060Sstevel@tonic-gate 		}
2070Sstevel@tonic-gate 
2080Sstevel@tonic-gate 		hub_usba_device = usba_get_usba_device(hubdip);
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 		if (usba_device) {
2110Sstevel@tonic-gate 			if (usb_owns_device(rdip)) {
2120Sstevel@tonic-gate 				(void) snprintf(compat_name,
2130Sstevel@tonic-gate 				    sizeof (compat_name),
2140Sstevel@tonic-gate 				    "usb%x,%x",
2150Sstevel@tonic-gate 				    usba_device->usb_dev_descr->idVendor,
2160Sstevel@tonic-gate 				    usba_device->usb_dev_descr->idProduct);
2173341Sgc161489 			} else if (usba_owns_ia(rdip)) {
2183341Sgc161489 				(void) snprintf(compat_name,
2193341Sgc161489 				    sizeof (compat_name),
2203341Sgc161489 				    "usbia%x,%x.config%x.%x",
2213341Sgc161489 				    usba_device->usb_dev_descr->idVendor,
2223341Sgc161489 				    usba_device->usb_dev_descr->idProduct,
2233341Sgc161489 				    usba_device->usb_cfg_value,
2243341Sgc161489 				    usb_get_if_number(rdip));
2250Sstevel@tonic-gate 			} else {
2260Sstevel@tonic-gate 				(void) snprintf(compat_name,
2270Sstevel@tonic-gate 				    sizeof (compat_name),
2280Sstevel@tonic-gate 				    "usbif%x,%x.config%x.%x",
2290Sstevel@tonic-gate 				    usba_device->usb_dev_descr->idVendor,
2300Sstevel@tonic-gate 				    usba_device->usb_dev_descr->idProduct,
2310Sstevel@tonic-gate 				    usba_device->usb_cfg_value,
2320Sstevel@tonic-gate 				    usb_get_if_number(rdip));
2330Sstevel@tonic-gate 			}
2340Sstevel@tonic-gate 			switch (usba_device->usb_port_status) {
2350Sstevel@tonic-gate 			case USBA_HIGH_SPEED_DEV:
2360Sstevel@tonic-gate 				speed = "hi speed (USB 2.x)";
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate 				break;
2390Sstevel@tonic-gate 			case USBA_LOW_SPEED_DEV:
2400Sstevel@tonic-gate 				speed = "low speed (USB 1.x)";
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate 				break;
2430Sstevel@tonic-gate 			case USBA_FULL_SPEED_DEV:
2440Sstevel@tonic-gate 			default:
2450Sstevel@tonic-gate 				speed = "full speed (USB 1.x)";
2460Sstevel@tonic-gate 
2470Sstevel@tonic-gate 				break;
2480Sstevel@tonic-gate 			}
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate 			cmn_err(CE_CONT,
2510Sstevel@tonic-gate 			    "?USB %x.%x %s (%s) operating at %s on "
2520Sstevel@tonic-gate 			    "USB %x.%x %s hub: "
2530Sstevel@tonic-gate 			    "%s@%s, %s%d at bus address %d\n",
2540Sstevel@tonic-gate 			    (usba_device->usb_dev_descr->bcdUSB & 0xff00) >> 8,
2550Sstevel@tonic-gate 			    usba_device->usb_dev_descr->bcdUSB & 0xff,
2563341Sgc161489 			    (usb_owns_device(rdip) ? "device" :
2573341Sgc161489 			    ((usba_owns_ia(rdip) ? "interface-association" :
2583341Sgc161489 			    "interface"))),
2590Sstevel@tonic-gate 			    compat_name, speed,
2600Sstevel@tonic-gate 			    (hub_usba_device->usb_dev_descr->bcdUSB &
2610Sstevel@tonic-gate 			    0xff00) >> 8,
2620Sstevel@tonic-gate 			    hub_usba_device->usb_dev_descr->bcdUSB & 0xff,
2630Sstevel@tonic-gate 			    usba_is_root_hub(hubdip) ? "root" : "external",
2640Sstevel@tonic-gate 			    ddi_node_name(rdip), ddi_get_name_addr(rdip),
2650Sstevel@tonic-gate 			    ddi_driver_name(rdip),
2660Sstevel@tonic-gate 			    ddi_get_instance(rdip), usba_device->usb_addr);
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate 			name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
2690Sstevel@tonic-gate 			(void) usba_get_mfg_prod_sn_str(rdip, name, MAXNAMELEN);
2700Sstevel@tonic-gate 			if (name[0] != '\0') {
2710Sstevel@tonic-gate 				cmn_err(CE_CONT, "?\t%s\n", name);
2720Sstevel@tonic-gate 			}
2730Sstevel@tonic-gate 			kmem_free(name, MAXNAMELEN);
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate 		} else { /* harden USBA against this case; if it happens */
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate 			cmn_err(CE_CONT,
2780Sstevel@tonic-gate 			    "?USB-device: %s@%s, %s%d\n",
2790Sstevel@tonic-gate 			    ddi_node_name(rdip), ddi_get_name_addr(rdip),
2800Sstevel@tonic-gate 			    ddi_driver_name(rdip), ddi_get_instance(rdip));
2810Sstevel@tonic-gate 		}
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate 		return (DDI_SUCCESS);
2840Sstevel@tonic-gate 	}
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate 	case DDI_CTLOPS_INITCHILD:
2870Sstevel@tonic-gate 	{
2880Sstevel@tonic-gate 		int			usb_addr;
2890Sstevel@tonic-gate 		uint_t			n;
2900Sstevel@tonic-gate 		char			name[32];
2910Sstevel@tonic-gate 		int			*data;
2920Sstevel@tonic-gate 		int			rval;
2930Sstevel@tonic-gate 		int			len = sizeof (usb_addr);
2940Sstevel@tonic-gate 
2950Sstevel@tonic-gate 		usba_hcdi	= usba_hcdi_get_hcdi(dip);
2960Sstevel@tonic-gate 		usba_hcdi_ops	= usba_hcdi->hcdi_ops;
2970Sstevel@tonic-gate 		ASSERT(usba_hcdi_ops != NULL);
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate 		/*
3000Sstevel@tonic-gate 		 * as long as the dip exists, it should have
3010Sstevel@tonic-gate 		 * usba_device structure associated with it
3020Sstevel@tonic-gate 		 */
3030Sstevel@tonic-gate 		usba_device = usba_get_usba_device(child_dip);
3040Sstevel@tonic-gate 		if (usba_device == NULL) {
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_USBA, hubdi_log_handle,
3070Sstevel@tonic-gate 			    "usba_bus_ctl: DDI_NOT_WELL_FORMED (%s (0x%p))",
3080Sstevel@tonic-gate 			    ddi_node_name(child_dip), (void *)child_dip);
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 			return (DDI_NOT_WELL_FORMED);
3110Sstevel@tonic-gate 		}
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate 		/* the dip should have an address and reg property */
3140Sstevel@tonic-gate 		if (ddi_prop_op(DDI_DEV_T_NONE, child_dip, PROP_LEN_AND_VAL_BUF,
3150Sstevel@tonic-gate 		    DDI_PROP_DONTPASS |	DDI_PROP_CANSLEEP, "assigned-address",
3160Sstevel@tonic-gate 		    (caddr_t)&usb_addr,	&len) != DDI_SUCCESS) {
3170Sstevel@tonic-gate 
318978Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_USBA, hubdi_log_handle,
3190Sstevel@tonic-gate 			    "usba_bus_ctl:\n\t"
3200Sstevel@tonic-gate 			    "%s%d %s%d op=%d rdip = 0x%p dip = 0x%p",
3210Sstevel@tonic-gate 			    ddi_node_name(rdip), ddi_get_instance(rdip),
3220Sstevel@tonic-gate 			    ddi_node_name(dip), ddi_get_instance(dip), op,
3236898Sfb209375 			    (void *)rdip, (void *)dip);
3240Sstevel@tonic-gate 
325978Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_USBA, hubdi_log_handle,
3260Sstevel@tonic-gate 			    "usba_bus_ctl: DDI_NOT_WELL_FORMED (%s (0x%p))",
3270Sstevel@tonic-gate 			    ddi_node_name(child_dip), (void *)child_dip);
3280Sstevel@tonic-gate 
3290Sstevel@tonic-gate 			return (DDI_NOT_WELL_FORMED);
3300Sstevel@tonic-gate 		}
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 		if ((rval = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child_dip,
3330Sstevel@tonic-gate 		    DDI_PROP_DONTPASS, "reg",
3340Sstevel@tonic-gate 		    &data, &n)) != DDI_SUCCESS) {
3350Sstevel@tonic-gate 
336978Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_USBA, hubdi_log_handle,
3370Sstevel@tonic-gate 			    "usba_bus_ctl: %d, DDI_NOT_WELL_FORMED", rval);
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 			return (DDI_NOT_WELL_FORMED);
3400Sstevel@tonic-gate 		}
3410Sstevel@tonic-gate 
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate 		/*
3440Sstevel@tonic-gate 		 * if the configuration is 1, the unit address is
3450Sstevel@tonic-gate 		 * just the interface number
3460Sstevel@tonic-gate 		 */
3470Sstevel@tonic-gate 		if ((n == 1) || ((n > 1) && (data[1] == 1))) {
3480Sstevel@tonic-gate 			(void) sprintf(name, "%x", data[0]);
3490Sstevel@tonic-gate 		} else {
3500Sstevel@tonic-gate 			(void) sprintf(name, "%x,%x", data[0], data[1]);
3510Sstevel@tonic-gate 		}
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 		USB_DPRINTF_L3(DPRINT_MASK_USBA,
3540Sstevel@tonic-gate 		    hubdi_log_handle, "usba_bus_ctl: name = %s", name);
3550Sstevel@tonic-gate 
3560Sstevel@tonic-gate 		ddi_prop_free(data);
3570Sstevel@tonic-gate 		ddi_set_name_addr(child_dip, name);
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate 		/*
3600Sstevel@tonic-gate 		 * increment the reference count for each child using this
3610Sstevel@tonic-gate 		 * usba_device structure
3620Sstevel@tonic-gate 		 */
3630Sstevel@tonic-gate 		mutex_enter(&usba_device->usb_mutex);
3640Sstevel@tonic-gate 		usba_device->usb_ref_count++;
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate 		USB_DPRINTF_L3(DPRINT_MASK_USBA, hubdi_log_handle,
3670Sstevel@tonic-gate 		    "usba_bus_ctl: init usba_device = 0x%p ref_count = %d",
3680Sstevel@tonic-gate 		    (void *)usba_device, usba_device->usb_ref_count);
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate 		return (DDI_SUCCESS);
3730Sstevel@tonic-gate 	}
3740Sstevel@tonic-gate 
3750Sstevel@tonic-gate 	case DDI_CTLOPS_UNINITCHILD:
3760Sstevel@tonic-gate 	{
3770Sstevel@tonic-gate 		usba_device = usba_get_usba_device(child_dip);
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate 		if (usba_device != NULL) {
3800Sstevel@tonic-gate 			/*
3810Sstevel@tonic-gate 			 * decrement the reference count for each child
3820Sstevel@tonic-gate 			 * using this  usba_device structure
3830Sstevel@tonic-gate 			 */
3840Sstevel@tonic-gate 			mutex_enter(&usba_device->usb_mutex);
3850Sstevel@tonic-gate 			usba_device->usb_ref_count--;
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate 			USB_DPRINTF_L3(DPRINT_MASK_USBA, hubdi_log_handle,
3880Sstevel@tonic-gate 			    "usba_hcdi_bus_ctl: uninit usba_device=0x%p "
3890Sstevel@tonic-gate 			    "ref_count=%d",
3906898Sfb209375 			    (void *)usba_device, usba_device->usb_ref_count);
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate 			mutex_exit(&usba_device->usb_mutex);
3930Sstevel@tonic-gate 		}
3940Sstevel@tonic-gate 		ddi_set_name_addr(child_dip, NULL);
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 		return (DDI_SUCCESS);
3970Sstevel@tonic-gate 	}
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate 	case DDI_CTLOPS_IOMIN:
4000Sstevel@tonic-gate 		/* Do nothing */
4010Sstevel@tonic-gate 		return (DDI_SUCCESS);
4020Sstevel@tonic-gate 
4030Sstevel@tonic-gate 	/*
4040Sstevel@tonic-gate 	 * These ops correspond	to functions that "shouldn't" be called
4050Sstevel@tonic-gate 	 * by a	USB client driver.  So	we whine when we're called.
4060Sstevel@tonic-gate 	 */
4070Sstevel@tonic-gate 	case DDI_CTLOPS_DMAPMAPC:
4080Sstevel@tonic-gate 	case DDI_CTLOPS_REPORTINT:
4090Sstevel@tonic-gate 	case DDI_CTLOPS_REGSIZE:
4100Sstevel@tonic-gate 	case DDI_CTLOPS_NREGS:
4110Sstevel@tonic-gate 	case DDI_CTLOPS_SIDDEV:
4120Sstevel@tonic-gate 	case DDI_CTLOPS_SLAVEONLY:
4130Sstevel@tonic-gate 	case DDI_CTLOPS_AFFINITY:
4140Sstevel@tonic-gate 	case DDI_CTLOPS_POKE:
4150Sstevel@tonic-gate 	case DDI_CTLOPS_PEEK:
4160Sstevel@tonic-gate 		cmn_err(CE_CONT, "%s%d:	invalid	op (%d)	from %s%d",
4176112Sqz150045 		    ddi_node_name(dip), ddi_get_instance(dip),
4186112Sqz150045 		    op, ddi_node_name(rdip), ddi_get_instance(rdip));
4190Sstevel@tonic-gate 		return (DDI_FAILURE);
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate 	/*
4220Sstevel@tonic-gate 	 * Everything else (e.g. PTOB/BTOP/BTOPR requests) we pass up
4230Sstevel@tonic-gate 	 */
4240Sstevel@tonic-gate 	default:
4250Sstevel@tonic-gate 		return (ddi_ctlops(dip,	rdip, op, arg, result));
4260Sstevel@tonic-gate 	}
4270Sstevel@tonic-gate }
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate /*
4310Sstevel@tonic-gate  * initialize and destroy USBA module
4320Sstevel@tonic-gate  */
4330Sstevel@tonic-gate void
usba_usba_initialization()4340Sstevel@tonic-gate usba_usba_initialization()
4350Sstevel@tonic-gate {
4360Sstevel@tonic-gate 	usba_log_handle = usb_alloc_log_hdl(NULL, "usba", &usba_errlevel,
4376112Sqz150045 	    &usba_errmask, NULL, 0);
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA,
4400Sstevel@tonic-gate 	    usba_log_handle, "usba_usba_initialization");
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate 	mutex_init(&usba_mutex, NULL, MUTEX_DRIVER, NULL);
4439094SVincent.Wang@Sun.COM 	mutex_init(&usba_hub_mutex, NULL, MUTEX_DRIVER, NULL);
4440Sstevel@tonic-gate 	usba_init_list(&usba_device_list, NULL, NULL);
4450Sstevel@tonic-gate }
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate void
usba_usba_destroy()4490Sstevel@tonic-gate usba_usba_destroy()
4500Sstevel@tonic-gate {
4510Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle, "usba_usba_destroy");
4520Sstevel@tonic-gate 
4539094SVincent.Wang@Sun.COM 	mutex_destroy(&usba_hub_mutex);
4540Sstevel@tonic-gate 	mutex_destroy(&usba_mutex);
4550Sstevel@tonic-gate 	usba_destroy_list(&usba_device_list);
4560Sstevel@tonic-gate 
4570Sstevel@tonic-gate 	usb_free_log_hdl(usba_log_handle);
4580Sstevel@tonic-gate }
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate 
4610Sstevel@tonic-gate /*
4620Sstevel@tonic-gate  * usba_set_usb_address:
4630Sstevel@tonic-gate  *	set usb address in usba_device structure
4640Sstevel@tonic-gate  */
4650Sstevel@tonic-gate int
usba_set_usb_address(usba_device_t * usba_device)4660Sstevel@tonic-gate usba_set_usb_address(usba_device_t *usba_device)
4670Sstevel@tonic-gate {
4680Sstevel@tonic-gate 	usb_addr_t address;
4690Sstevel@tonic-gate 	uchar_t s = 8;
4700Sstevel@tonic-gate 	usba_hcdi_t *hcdi;
4710Sstevel@tonic-gate 	char *usb_address_in_use;
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate 	mutex_enter(&usba_device->usb_mutex);
4740Sstevel@tonic-gate 
4750Sstevel@tonic-gate 	hcdi = usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
4760Sstevel@tonic-gate 
4770Sstevel@tonic-gate 	mutex_enter(&hcdi->hcdi_mutex);
4780Sstevel@tonic-gate 	usb_address_in_use = hcdi->hcdi_usb_address_in_use;
4790Sstevel@tonic-gate 
4800Sstevel@tonic-gate 	for (address = ROOT_HUB_ADDR + 1;
4810Sstevel@tonic-gate 	    address <= USBA_MAX_ADDRESS; address++) {
4820Sstevel@tonic-gate 		if (usb_address_in_use[address/s] & (1 << (address % s))) {
4830Sstevel@tonic-gate 			continue;
4840Sstevel@tonic-gate 		}
4850Sstevel@tonic-gate 		usb_address_in_use[address/s] |= (1 << (address % s));
4860Sstevel@tonic-gate 		hcdi->hcdi_device_count++;
4870Sstevel@tonic-gate 		HCDI_HOTPLUG_STATS_DATA(hcdi)->hcdi_device_count.value.ui64++;
4880Sstevel@tonic-gate 		mutex_exit(&hcdi->hcdi_mutex);
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate 		USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
4910Sstevel@tonic-gate 		    "usba_set_usb_address: %d", address);
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate 		usba_device->usb_addr = address;
4940Sstevel@tonic-gate 
4950Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate 		return (USB_SUCCESS);
4980Sstevel@tonic-gate 	}
4990Sstevel@tonic-gate 
5000Sstevel@tonic-gate 	usba_device->usb_addr = 0;
5010Sstevel@tonic-gate 
502978Sfrits 	USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
5030Sstevel@tonic-gate 	    "no usb address available");
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 	mutex_exit(&hcdi->hcdi_mutex);
5060Sstevel@tonic-gate 	mutex_exit(&usba_device->usb_mutex);
5070Sstevel@tonic-gate 
5080Sstevel@tonic-gate 	return (USB_FAILURE);
5090Sstevel@tonic-gate }
5100Sstevel@tonic-gate 
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate /*
5130Sstevel@tonic-gate  * usba_unset_usb_address:
5140Sstevel@tonic-gate  *	unset usb_address in usba_device structure
5150Sstevel@tonic-gate  */
5160Sstevel@tonic-gate void
usba_unset_usb_address(usba_device_t * usba_device)5170Sstevel@tonic-gate usba_unset_usb_address(usba_device_t *usba_device)
5180Sstevel@tonic-gate {
5190Sstevel@tonic-gate 	usb_addr_t address;
5200Sstevel@tonic-gate 	usba_hcdi_t *hcdi;
5210Sstevel@tonic-gate 	uchar_t s = 8;
5220Sstevel@tonic-gate 	char *usb_address_in_use;
5230Sstevel@tonic-gate 
5240Sstevel@tonic-gate 	mutex_enter(&usba_device->usb_mutex);
5250Sstevel@tonic-gate 	address = usba_device->usb_addr;
5260Sstevel@tonic-gate 	hcdi = usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 	if (address > ROOT_HUB_ADDR) {
5290Sstevel@tonic-gate 		USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
5300Sstevel@tonic-gate 		    "usba_unset_usb_address: address=%d", address);
5310Sstevel@tonic-gate 
5320Sstevel@tonic-gate 		mutex_enter(&hcdi->hcdi_mutex);
5330Sstevel@tonic-gate 		usb_address_in_use = hcdi->hcdi_usb_address_in_use;
5340Sstevel@tonic-gate 
5350Sstevel@tonic-gate 		ASSERT(usb_address_in_use[address/s] & (1 << (address % s)));
5360Sstevel@tonic-gate 
5370Sstevel@tonic-gate 		usb_address_in_use[address/s] &= ~(1 << (address % s));
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate 		hcdi->hcdi_device_count--;
5400Sstevel@tonic-gate 		HCDI_HOTPLUG_STATS_DATA(hcdi)->hcdi_device_count.value.ui64--;
5410Sstevel@tonic-gate 
5420Sstevel@tonic-gate 		mutex_exit(&hcdi->hcdi_mutex);
5430Sstevel@tonic-gate 
5440Sstevel@tonic-gate 		usba_device->usb_addr = 0;
5450Sstevel@tonic-gate 	}
5460Sstevel@tonic-gate 	mutex_exit(&usba_device->usb_mutex);
5470Sstevel@tonic-gate }
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate 
5500Sstevel@tonic-gate struct usba_evdata *
usba_get_evdata(dev_info_t * dip)5510Sstevel@tonic-gate usba_get_evdata(dev_info_t *dip)
5520Sstevel@tonic-gate {
5530Sstevel@tonic-gate 	usba_evdata_t *evdata;
5540Sstevel@tonic-gate 	usba_device_t *usba_device = usba_get_usba_device(dip);
5550Sstevel@tonic-gate 
5560Sstevel@tonic-gate 	/* called when dip attaches */
5570Sstevel@tonic-gate 	ASSERT(usba_device != NULL);
5580Sstevel@tonic-gate 
5590Sstevel@tonic-gate 	mutex_enter(&usba_device->usb_mutex);
5600Sstevel@tonic-gate 	evdata = usba_device->usb_evdata;
5610Sstevel@tonic-gate 	while (evdata) {
5620Sstevel@tonic-gate 		if (evdata->ev_dip == dip) {
5630Sstevel@tonic-gate 			mutex_exit(&usba_device->usb_mutex);
5640Sstevel@tonic-gate 
5650Sstevel@tonic-gate 			return (evdata);
5660Sstevel@tonic-gate 		}
5670Sstevel@tonic-gate 		evdata = evdata->ev_next;
5680Sstevel@tonic-gate 	}
5690Sstevel@tonic-gate 
5700Sstevel@tonic-gate 	evdata = kmem_zalloc(sizeof (usba_evdata_t), KM_SLEEP);
5710Sstevel@tonic-gate 	evdata->ev_dip = dip;
5720Sstevel@tonic-gate 	evdata->ev_next = usba_device->usb_evdata;
5730Sstevel@tonic-gate 	usba_device->usb_evdata = evdata;
5740Sstevel@tonic-gate 	mutex_exit(&usba_device->usb_mutex);
5750Sstevel@tonic-gate 
5760Sstevel@tonic-gate 	return (evdata);
5770Sstevel@tonic-gate }
5780Sstevel@tonic-gate 
5790Sstevel@tonic-gate 
5800Sstevel@tonic-gate /*
5810Sstevel@tonic-gate  * allocate a usb device structure and link it in the list
5820Sstevel@tonic-gate  */
5830Sstevel@tonic-gate usba_device_t *
usba_alloc_usba_device(dev_info_t * root_hub_dip)5840Sstevel@tonic-gate usba_alloc_usba_device(dev_info_t *root_hub_dip)
5850Sstevel@tonic-gate {
5860Sstevel@tonic-gate 	usba_device_t	*usba_device;
5870Sstevel@tonic-gate 	int		ep_idx;
5880Sstevel@tonic-gate 	ddi_iblock_cookie_t iblock_cookie =
5890Sstevel@tonic-gate 	    usba_hcdi_get_hcdi(root_hub_dip)->hcdi_iblock_cookie;
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate 	/*
5920Sstevel@tonic-gate 	 * create a new usba_device structure
5930Sstevel@tonic-gate 	 */
5940Sstevel@tonic-gate 	usba_device = kmem_zalloc(sizeof (usba_device_t), KM_SLEEP);
5950Sstevel@tonic-gate 
5960Sstevel@tonic-gate 	/*
5970Sstevel@tonic-gate 	 * initialize usba_device
5980Sstevel@tonic-gate 	 */
5990Sstevel@tonic-gate 	mutex_init(&usba_device->usb_mutex, NULL, MUTEX_DRIVER,
6006112Sqz150045 	    iblock_cookie);
6010Sstevel@tonic-gate 
6020Sstevel@tonic-gate 	usba_init_list(&usba_device->usb_device_list, (usb_opaque_t)usba_device,
6036112Sqz150045 	    iblock_cookie);
6040Sstevel@tonic-gate 	usba_init_list(&usba_device->usb_allocated, (usb_opaque_t)usba_device,
6056112Sqz150045 	    iblock_cookie);
6060Sstevel@tonic-gate 	mutex_enter(&usba_device->usb_mutex);
6070Sstevel@tonic-gate 	usba_device->usb_root_hub_dip = root_hub_dip;
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate 	/*
6100Sstevel@tonic-gate 	 * add to list of usba_devices
6110Sstevel@tonic-gate 	 */
6120Sstevel@tonic-gate 	usba_add_to_list(&usba_device_list, &usba_device->usb_device_list);
6130Sstevel@tonic-gate 
6140Sstevel@tonic-gate 	/* init mutex in each usba_ph_impl structure */
6150Sstevel@tonic-gate 	for (ep_idx = 0; ep_idx < USBA_N_ENDPOINTS; ep_idx++) {
6160Sstevel@tonic-gate 		mutex_init(&usba_device->usb_ph_list[ep_idx].usba_ph_mutex,
6170Sstevel@tonic-gate 		    NULL, MUTEX_DRIVER, iblock_cookie);
6180Sstevel@tonic-gate 	}
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
6210Sstevel@tonic-gate 	    "allocated usba_device 0x%p", (void *)usba_device);
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate 	mutex_exit(&usba_device->usb_mutex);
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate 	return (usba_device);
6260Sstevel@tonic-gate }
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate /* free NDI event data associated with usba_device */
6300Sstevel@tonic-gate void
usba_free_evdata(usba_evdata_t * evdata)6310Sstevel@tonic-gate usba_free_evdata(usba_evdata_t *evdata)
6320Sstevel@tonic-gate {
6330Sstevel@tonic-gate 	usba_evdata_t *next;
6340Sstevel@tonic-gate 
6350Sstevel@tonic-gate 	while (evdata) {
6360Sstevel@tonic-gate 		next = evdata->ev_next;
6370Sstevel@tonic-gate 		kmem_free(evdata, sizeof (usba_evdata_t));
6380Sstevel@tonic-gate 		evdata = next;
6390Sstevel@tonic-gate 	}
6400Sstevel@tonic-gate }
6410Sstevel@tonic-gate 
6420Sstevel@tonic-gate 
6430Sstevel@tonic-gate /*
6449430SRaymond.Chen@Sun.COM  * free wireless usb specific structure
6459430SRaymond.Chen@Sun.COM  */
6469430SRaymond.Chen@Sun.COM void
usba_free_wireless_data(usba_wireless_data_t * wireless_data)6479430SRaymond.Chen@Sun.COM usba_free_wireless_data(usba_wireless_data_t *wireless_data)
6489430SRaymond.Chen@Sun.COM {
6499430SRaymond.Chen@Sun.COM 	if (wireless_data == NULL) {
6509430SRaymond.Chen@Sun.COM 
6519430SRaymond.Chen@Sun.COM 		return;
6529430SRaymond.Chen@Sun.COM 	}
6539430SRaymond.Chen@Sun.COM 
6549430SRaymond.Chen@Sun.COM 	if (wireless_data->wusb_bos) {
6559430SRaymond.Chen@Sun.COM 		kmem_free(wireless_data->wusb_bos,
6569430SRaymond.Chen@Sun.COM 		    wireless_data->wusb_bos_length);
6579430SRaymond.Chen@Sun.COM 	}
6589430SRaymond.Chen@Sun.COM 
6599430SRaymond.Chen@Sun.COM 	kmem_free(wireless_data, sizeof (usba_wireless_data_t));
6609430SRaymond.Chen@Sun.COM }
6619430SRaymond.Chen@Sun.COM 
6629430SRaymond.Chen@Sun.COM 
6639430SRaymond.Chen@Sun.COM /*
6640Sstevel@tonic-gate  * free usb device structure
6650Sstevel@tonic-gate  */
6660Sstevel@tonic-gate void
usba_free_usba_device(usba_device_t * usba_device)6670Sstevel@tonic-gate usba_free_usba_device(usba_device_t *usba_device)
6680Sstevel@tonic-gate {
6690Sstevel@tonic-gate 	int			i, ep_idx;
6700Sstevel@tonic-gate 	usb_pipe_handle_t	def_ph;
6710Sstevel@tonic-gate 
6720Sstevel@tonic-gate 	if (usba_device == NULL) {
6730Sstevel@tonic-gate 
6740Sstevel@tonic-gate 		return;
6750Sstevel@tonic-gate 	}
6760Sstevel@tonic-gate 
6770Sstevel@tonic-gate 	mutex_enter(&usba_device->usb_mutex);
6780Sstevel@tonic-gate 	if (usba_device->usb_ref_count) {
6790Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
6800Sstevel@tonic-gate 
6810Sstevel@tonic-gate 		return;
6820Sstevel@tonic-gate 	}
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
6850Sstevel@tonic-gate 	    "usba_free_usba_device 0x%p, address=0x%x, ref cnt=%d",
6860Sstevel@tonic-gate 	    (void *)usba_device, usba_device->usb_addr,
6870Sstevel@tonic-gate 	    usba_device->usb_ref_count);
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate 	usba_free_evdata(usba_device->usb_evdata);
6900Sstevel@tonic-gate 	mutex_exit(&usba_device->usb_mutex);
6910Sstevel@tonic-gate 
6920Sstevel@tonic-gate 	def_ph = usba_usbdev_to_dflt_pipe_handle(usba_device);
6930Sstevel@tonic-gate 	if (def_ph != NULL) {
6940Sstevel@tonic-gate 		usba_pipe_handle_data_t	*ph_data = usba_get_ph_data(def_ph);
6950Sstevel@tonic-gate 
6960Sstevel@tonic-gate 		if (ph_data) {
6970Sstevel@tonic-gate 			usb_pipe_close(ph_data->p_dip, def_ph,
6980Sstevel@tonic-gate 			    USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED,
6990Sstevel@tonic-gate 			    NULL, NULL);
7000Sstevel@tonic-gate 		}
7010Sstevel@tonic-gate 	}
7020Sstevel@tonic-gate 
7030Sstevel@tonic-gate 	mutex_enter(&usba_mutex);
7040Sstevel@tonic-gate 
7050Sstevel@tonic-gate 	/* destroy mutex in each usba_ph_impl structure */
7060Sstevel@tonic-gate 	for (ep_idx = 0; ep_idx < USBA_N_ENDPOINTS; ep_idx++) {
7070Sstevel@tonic-gate 		mutex_destroy(&usba_device->usb_ph_list[ep_idx].usba_ph_mutex);
7080Sstevel@tonic-gate 	}
7090Sstevel@tonic-gate 
7100Sstevel@tonic-gate 	(void) usba_rm_from_list(&usba_device_list,
7116112Sqz150045 	    &usba_device->usb_device_list);
7120Sstevel@tonic-gate 
7130Sstevel@tonic-gate 	mutex_exit(&usba_mutex);
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate 	usba_destroy_list(&usba_device->usb_device_list);
7160Sstevel@tonic-gate 	usba_destroy_list(&usba_device->usb_allocated);
7170Sstevel@tonic-gate 
7180Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
7190Sstevel@tonic-gate 	    "deallocating usba_device = 0x%p, address = 0x%x",
7200Sstevel@tonic-gate 	    (void *)usba_device, usba_device->usb_addr);
7210Sstevel@tonic-gate 
7220Sstevel@tonic-gate 	/*
7230Sstevel@tonic-gate 	 * ohci allocates descriptors for root hub so we can't
7240Sstevel@tonic-gate 	 * deallocate these here
7250Sstevel@tonic-gate 	 */
7260Sstevel@tonic-gate 
7270Sstevel@tonic-gate 	if (usba_device->usb_addr != ROOT_HUB_ADDR) {
7280Sstevel@tonic-gate 		if (usba_device->usb_cfg_array) {
7290Sstevel@tonic-gate 			USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
7300Sstevel@tonic-gate 			    "deallocating usb_config_array: 0x%p",
7316898Sfb209375 			    (void *)usba_device->usb_cfg_array);
7320Sstevel@tonic-gate 			mutex_enter(&usba_device->usb_mutex);
7330Sstevel@tonic-gate 			for (i = 0;
7340Sstevel@tonic-gate 			    i < usba_device->usb_dev_descr->bNumConfigurations;
7350Sstevel@tonic-gate 			    i++) {
7360Sstevel@tonic-gate 				if (usba_device->usb_cfg_array[i]) {
7370Sstevel@tonic-gate 					kmem_free(
7380Sstevel@tonic-gate 					    usba_device->usb_cfg_array[i],
7390Sstevel@tonic-gate 					    usba_device->usb_cfg_array_len[i]);
7400Sstevel@tonic-gate 				}
7410Sstevel@tonic-gate 			}
7420Sstevel@tonic-gate 
7430Sstevel@tonic-gate 			/* free the array pointers */
7440Sstevel@tonic-gate 			kmem_free(usba_device->usb_cfg_array,
7450Sstevel@tonic-gate 			    usba_device->usb_cfg_array_length);
7460Sstevel@tonic-gate 			kmem_free(usba_device->usb_cfg_array_len,
7470Sstevel@tonic-gate 			    usba_device->usb_cfg_array_len_length);
7480Sstevel@tonic-gate 
7490Sstevel@tonic-gate 			mutex_exit(&usba_device->usb_mutex);
7500Sstevel@tonic-gate 		}
7510Sstevel@tonic-gate 
7520Sstevel@tonic-gate 		if (usba_device->usb_cfg_str_descr) {
7530Sstevel@tonic-gate 			USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
7540Sstevel@tonic-gate 			    "deallocating usb_cfg_str_descr: 0x%p",
7556898Sfb209375 			    (void *)usba_device->usb_cfg_str_descr);
7560Sstevel@tonic-gate 			for (i = 0;
7570Sstevel@tonic-gate 			    i < usba_device->usb_dev_descr->bNumConfigurations;
7580Sstevel@tonic-gate 			    i++) {
7590Sstevel@tonic-gate 				if (usba_device->usb_cfg_str_descr[i]) {
7600Sstevel@tonic-gate 					kmem_free(
7610Sstevel@tonic-gate 					    usba_device->usb_cfg_str_descr[i],
7620Sstevel@tonic-gate 					    strlen(usba_device->
7636112Sqz150045 					    usb_cfg_str_descr[i]) + 1);
7640Sstevel@tonic-gate 				}
7650Sstevel@tonic-gate 			}
7660Sstevel@tonic-gate 			/* free the array pointers */
7670Sstevel@tonic-gate 			kmem_free(usba_device->usb_cfg_str_descr,
7680Sstevel@tonic-gate 			    sizeof (uchar_t *) * usba_device->usb_n_cfgs);
7690Sstevel@tonic-gate 		}
7700Sstevel@tonic-gate 
7710Sstevel@tonic-gate 		if (usba_device->usb_dev_descr) {
7720Sstevel@tonic-gate 			kmem_free(usba_device->usb_dev_descr,
7736112Sqz150045 			    sizeof (usb_dev_descr_t));
7740Sstevel@tonic-gate 		}
7750Sstevel@tonic-gate 
7760Sstevel@tonic-gate 		if (usba_device->usb_mfg_str) {
7770Sstevel@tonic-gate 			kmem_free(usba_device->usb_mfg_str,
7786112Sqz150045 			    strlen(usba_device->usb_mfg_str) + 1);
7790Sstevel@tonic-gate 		}
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate 		if (usba_device->usb_product_str) {
7820Sstevel@tonic-gate 			kmem_free(usba_device->usb_product_str,
7836112Sqz150045 			    strlen(usba_device->usb_product_str) + 1);
7840Sstevel@tonic-gate 		}
7850Sstevel@tonic-gate 
7860Sstevel@tonic-gate 		if (usba_device->usb_serialno_str) {
7870Sstevel@tonic-gate 			kmem_free(usba_device->usb_serialno_str,
7886112Sqz150045 			    strlen(usba_device->usb_serialno_str) + 1);
7890Sstevel@tonic-gate 		}
7900Sstevel@tonic-gate 
7919430SRaymond.Chen@Sun.COM 		if (usba_device->usb_wireless_data) {
7929430SRaymond.Chen@Sun.COM 			mutex_enter(&usba_device->usb_mutex);
7939430SRaymond.Chen@Sun.COM 			usba_free_wireless_data(
7949430SRaymond.Chen@Sun.COM 			    usba_device->usb_wireless_data);
7959430SRaymond.Chen@Sun.COM 			mutex_exit(&usba_device->usb_mutex);
7969430SRaymond.Chen@Sun.COM 		}
7979430SRaymond.Chen@Sun.COM 
7989430SRaymond.Chen@Sun.COM 		/*
7999430SRaymond.Chen@Sun.COM 		 * The device address on the wireless bus is assigned
8009430SRaymond.Chen@Sun.COM 		 * by the wireless host controller driver(whci or hwahc),
8019430SRaymond.Chen@Sun.COM 		 * not by USBA framework, so skip this for wireless
8029430SRaymond.Chen@Sun.COM 		 * USB devices.
8039430SRaymond.Chen@Sun.COM 		 */
8049430SRaymond.Chen@Sun.COM 		if (!usba_device->usb_is_wireless) {
8059430SRaymond.Chen@Sun.COM 			usba_unset_usb_address(usba_device);
8069430SRaymond.Chen@Sun.COM 		}
8070Sstevel@tonic-gate 	}
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate #ifndef __lock_lint
8100Sstevel@tonic-gate 	ASSERT(usba_device->usb_client_dev_data_list.cddl_next == NULL);
8110Sstevel@tonic-gate #endif
8120Sstevel@tonic-gate 
8130Sstevel@tonic-gate 	if (usba_device->usb_client_flags) {
8140Sstevel@tonic-gate #ifndef __lock_lint
8150Sstevel@tonic-gate 		int i;
8160Sstevel@tonic-gate 
8170Sstevel@tonic-gate 		for (i = 0; i < usba_device->usb_n_ifs; i++) {
8180Sstevel@tonic-gate 			ASSERT(usba_device->usb_client_flags[i] == 0);
8190Sstevel@tonic-gate 		}
8200Sstevel@tonic-gate #endif
8210Sstevel@tonic-gate 		kmem_free(usba_device->usb_client_flags,
8220Sstevel@tonic-gate 		    usba_device->usb_n_ifs * USBA_CLIENT_FLAG_SIZE);
8230Sstevel@tonic-gate 	}
8240Sstevel@tonic-gate 
8250Sstevel@tonic-gate 
8260Sstevel@tonic-gate 	if (usba_device->usb_client_attach_list) {
8270Sstevel@tonic-gate 		kmem_free(usba_device->usb_client_attach_list,
8280Sstevel@tonic-gate 		    usba_device->usb_n_ifs *
8290Sstevel@tonic-gate 		    sizeof (*usba_device->usb_client_attach_list));
8300Sstevel@tonic-gate 	}
8310Sstevel@tonic-gate 	if (usba_device->usb_client_ev_cb_list) {
8320Sstevel@tonic-gate 		kmem_free(usba_device->usb_client_ev_cb_list,
8330Sstevel@tonic-gate 		    usba_device->usb_n_ifs *
8340Sstevel@tonic-gate 		    sizeof (*usba_device->usb_client_ev_cb_list));
8350Sstevel@tonic-gate 	}
8360Sstevel@tonic-gate 
8370Sstevel@tonic-gate 	/*
8380Sstevel@tonic-gate 	 * finally ready to destroy the structure
8390Sstevel@tonic-gate 	 */
8400Sstevel@tonic-gate 	mutex_destroy(&usba_device->usb_mutex);
8410Sstevel@tonic-gate 
8420Sstevel@tonic-gate 	kmem_free((caddr_t)usba_device, sizeof (usba_device_t));
8430Sstevel@tonic-gate }
8440Sstevel@tonic-gate 
8450Sstevel@tonic-gate 
8460Sstevel@tonic-gate /* clear the data toggle for all endpoints on this device */
8470Sstevel@tonic-gate void
usba_clear_data_toggle(usba_device_t * usba_device)8480Sstevel@tonic-gate usba_clear_data_toggle(usba_device_t *usba_device)
8490Sstevel@tonic-gate {
8500Sstevel@tonic-gate 	int	i;
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate 	if (usba_device != NULL) {
8530Sstevel@tonic-gate 		mutex_enter(&usba_device->usb_mutex);
8540Sstevel@tonic-gate 		for (i = 0; i < USBA_N_ENDPOINTS; i++) {
8550Sstevel@tonic-gate 			usba_device->usb_ph_list[i].usba_ph_flags &=
8560Sstevel@tonic-gate 			    ~USBA_PH_DATA_TOGGLE;
8570Sstevel@tonic-gate 		}
8580Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
8590Sstevel@tonic-gate 	}
8600Sstevel@tonic-gate }
8610Sstevel@tonic-gate 
8620Sstevel@tonic-gate 
8630Sstevel@tonic-gate /*
8640Sstevel@tonic-gate  * usba_create_child_devi():
8650Sstevel@tonic-gate  *	create a child devinfo node, usba_device, attach properties.
8660Sstevel@tonic-gate  *	the usba_device structure is shared between all interfaces
8670Sstevel@tonic-gate  */
8680Sstevel@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)8690Sstevel@tonic-gate usba_create_child_devi(dev_info_t	*dip,
8700Sstevel@tonic-gate 		char			*node_name,
8710Sstevel@tonic-gate 		usba_hcdi_ops_t		*usba_hcdi_ops,
8720Sstevel@tonic-gate 		dev_info_t		*usb_root_hub_dip,
8730Sstevel@tonic-gate 		usb_port_status_t	port_status,
8740Sstevel@tonic-gate 		usba_device_t		*usba_device,
8750Sstevel@tonic-gate 		dev_info_t		**child_dip)
8760Sstevel@tonic-gate {
8770Sstevel@tonic-gate 	int rval = USB_FAILURE;
8780Sstevel@tonic-gate 	int usba_device_allocated = 0;
8790Sstevel@tonic-gate 	usb_addr_t	address;
8800Sstevel@tonic-gate 
8810Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
8820Sstevel@tonic-gate 	    "usba_create_child_devi: %s usba_device=0x%p "
8830Sstevel@tonic-gate 	    "port status=0x%x", node_name,
8840Sstevel@tonic-gate 	    (void *)usba_device, port_status);
8850Sstevel@tonic-gate 
886789Sahrens 	ndi_devi_alloc_sleep(dip, node_name, (pnode_t)DEVI_SID_NODEID,
8876112Sqz150045 	    child_dip);
8880Sstevel@tonic-gate 
8890Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
8906898Sfb209375 	    "child dip=0x%p", (void *)*child_dip);
8910Sstevel@tonic-gate 
8920Sstevel@tonic-gate 	if (usba_device == NULL) {
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate 		usba_device = usba_alloc_usba_device(usb_root_hub_dip);
8950Sstevel@tonic-gate 
8960Sstevel@tonic-gate 		/* grab the mutex to keep warlock happy */
8970Sstevel@tonic-gate 		mutex_enter(&usba_device->usb_mutex);
8980Sstevel@tonic-gate 		usba_device->usb_hcdi_ops	= usba_hcdi_ops;
8990Sstevel@tonic-gate 		usba_device->usb_port_status	= port_status;
9000Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
9010Sstevel@tonic-gate 
9020Sstevel@tonic-gate 		usba_device_allocated++;
9030Sstevel@tonic-gate 	} else {
9040Sstevel@tonic-gate 		mutex_enter(&usba_device->usb_mutex);
9050Sstevel@tonic-gate 		if (usba_hcdi_ops) {
9060Sstevel@tonic-gate 			ASSERT(usba_device->usb_hcdi_ops == usba_hcdi_ops);
9070Sstevel@tonic-gate 		}
9080Sstevel@tonic-gate 		if (usb_root_hub_dip) {
9090Sstevel@tonic-gate 			ASSERT(usba_device->usb_root_hub_dip ==
9106112Sqz150045 			    usb_root_hub_dip);
9110Sstevel@tonic-gate 		}
9120Sstevel@tonic-gate 
9130Sstevel@tonic-gate 		usba_device->usb_port_status	= port_status;
9140Sstevel@tonic-gate 
9150Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
9160Sstevel@tonic-gate 	}
9170Sstevel@tonic-gate 
9180Sstevel@tonic-gate 	if (usba_device->usb_addr == 0) {
9190Sstevel@tonic-gate 		if (usba_set_usb_address(usba_device) == USB_FAILURE) {
9200Sstevel@tonic-gate 			address = 0;
9210Sstevel@tonic-gate 
9220Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
9236112Sqz150045 			    "cannot set usb address for dip=0x%p",
9246898Sfb209375 			    (void *)*child_dip);
9250Sstevel@tonic-gate 
9260Sstevel@tonic-gate 			goto fail;
9270Sstevel@tonic-gate 		}
9280Sstevel@tonic-gate 	}
9290Sstevel@tonic-gate 	address = usba_device->usb_addr;
9300Sstevel@tonic-gate 
9310Sstevel@tonic-gate 	/* attach properties */
9320Sstevel@tonic-gate 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, *child_dip,
9336112Sqz150045 	    "assigned-address", address);
9340Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
9350Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
9366112Sqz150045 		    "cannot set usb address property for dip=0x%p",
9376898Sfb209375 		    (void *)*child_dip);
9380Sstevel@tonic-gate 		rval = USB_FAILURE;
9390Sstevel@tonic-gate 
9400Sstevel@tonic-gate 		goto fail;
9410Sstevel@tonic-gate 	}
9420Sstevel@tonic-gate 
9430Sstevel@tonic-gate 	/*
9440Sstevel@tonic-gate 	 * store the usba_device point in the dip
9450Sstevel@tonic-gate 	 */
9460Sstevel@tonic-gate 	usba_set_usba_device(*child_dip, usba_device);
9470Sstevel@tonic-gate 
9480Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
9490Sstevel@tonic-gate 	    "usba_create_child_devi: devi=0x%p (%s) ud=0x%p",
9506898Sfb209375 	    (void *)*child_dip, ddi_driver_name(*child_dip),
9516898Sfb209375 	    (void *)usba_device);
9520Sstevel@tonic-gate 
9530Sstevel@tonic-gate 	return (USB_SUCCESS);
9540Sstevel@tonic-gate 
9550Sstevel@tonic-gate fail:
9560Sstevel@tonic-gate 	if (*child_dip) {
9570Sstevel@tonic-gate 		int rval = usba_destroy_child_devi(*child_dip, NDI_DEVI_REMOVE);
9580Sstevel@tonic-gate 		ASSERT(rval == USB_SUCCESS);
9590Sstevel@tonic-gate 		*child_dip = NULL;
9600Sstevel@tonic-gate 	}
9610Sstevel@tonic-gate 
9620Sstevel@tonic-gate 	if (usba_device_allocated) {
9630Sstevel@tonic-gate 		usba_free_usba_device(usba_device);
9640Sstevel@tonic-gate 	} else if (address && usba_device) {
9650Sstevel@tonic-gate 		usba_unset_usb_address(usba_device);
9660Sstevel@tonic-gate 	}
9670Sstevel@tonic-gate 
968978Sfrits 	USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
9690Sstevel@tonic-gate 	    "usba_create_child_devi failed: rval=%d", rval);
9700Sstevel@tonic-gate 
9710Sstevel@tonic-gate 	return (rval);
9720Sstevel@tonic-gate }
9730Sstevel@tonic-gate 
9740Sstevel@tonic-gate 
9750Sstevel@tonic-gate int
usba_destroy_child_devi(dev_info_t * dip,uint_t flag)9760Sstevel@tonic-gate usba_destroy_child_devi(dev_info_t *dip, uint_t flag)
9770Sstevel@tonic-gate {
9780Sstevel@tonic-gate 	usba_device_t	*usba_device;
9790Sstevel@tonic-gate 	int		rval = NDI_SUCCESS;
9800Sstevel@tonic-gate 
9810Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
9820Sstevel@tonic-gate 	    "usba_destroy_child_devi: %s%d (0x%p)",
9836898Sfb209375 	    ddi_driver_name(dip), ddi_get_instance(dip), (void *)dip);
9840Sstevel@tonic-gate 
9850Sstevel@tonic-gate 	usba_device = usba_get_usba_device(dip);
9860Sstevel@tonic-gate 
9870Sstevel@tonic-gate 	/*
9880Sstevel@tonic-gate 	 * if the child hasn't been bound yet, we can just
9890Sstevel@tonic-gate 	 * free the dip
9900Sstevel@tonic-gate 	 */
9910Sstevel@tonic-gate 	if (i_ddi_node_state(dip) < DS_INITIALIZED) {
9920Sstevel@tonic-gate 		/*
9930Sstevel@tonic-gate 		 * do not call ndi_devi_free() since it might
9940Sstevel@tonic-gate 		 * deadlock
9950Sstevel@tonic-gate 		 */
9960Sstevel@tonic-gate 		rval = ddi_remove_child(dip, 0);
9970Sstevel@tonic-gate 
9980Sstevel@tonic-gate 	} else {
9990Sstevel@tonic-gate 		char *devnm = kmem_alloc(MAXNAMELEN + 1, KM_SLEEP);
10000Sstevel@tonic-gate 		dev_info_t *pdip = ddi_get_parent(dip);
10010Sstevel@tonic-gate 
10020Sstevel@tonic-gate 		(void) ddi_deviname(dip, devnm);
10030Sstevel@tonic-gate 
10040Sstevel@tonic-gate 		USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
10050Sstevel@tonic-gate 		    "usba_destroy_child_devi:\n\t"
10066898Sfb209375 		    "offlining dip 0x%p usba_device=0x%p (%s)", (void *)dip,
10070Sstevel@tonic-gate 		    (void *)usba_device, devnm);
10080Sstevel@tonic-gate 
10090Sstevel@tonic-gate 		(void) devfs_clean(pdip, NULL, DV_CLEAN_FORCE);
10100Sstevel@tonic-gate 		rval =	ndi_devi_unconfig_one(pdip, devnm + 1, NULL,
10110Sstevel@tonic-gate 		    flag | NDI_UNCONFIG | NDI_DEVI_OFFLINE);
10120Sstevel@tonic-gate 		if (rval != NDI_SUCCESS) {
10130Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
10140Sstevel@tonic-gate 			    " ndi_devi_unconfig_one %s%d failed (%d)",
10150Sstevel@tonic-gate 			    ddi_driver_name(dip), ddi_get_instance(dip),
10160Sstevel@tonic-gate 			    rval);
10170Sstevel@tonic-gate 		}
10180Sstevel@tonic-gate 		kmem_free(devnm, MAXNAMELEN + 1);
10190Sstevel@tonic-gate 	}
10200Sstevel@tonic-gate 
10210Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
10220Sstevel@tonic-gate 	    "usba_destroy_child_devi: rval=%d", rval);
10230Sstevel@tonic-gate 
10240Sstevel@tonic-gate 	return (rval == NDI_SUCCESS ? USB_SUCCESS : USB_FAILURE);
10250Sstevel@tonic-gate }
10260Sstevel@tonic-gate 
10270Sstevel@tonic-gate 
10280Sstevel@tonic-gate /*
10290Sstevel@tonic-gate  * list management
10300Sstevel@tonic-gate  */
10310Sstevel@tonic-gate void
usba_init_list(usba_list_entry_t * element,usb_opaque_t private,ddi_iblock_cookie_t iblock_cookie)10320Sstevel@tonic-gate usba_init_list(usba_list_entry_t *element, usb_opaque_t private,
10330Sstevel@tonic-gate 	ddi_iblock_cookie_t	iblock_cookie)
10340Sstevel@tonic-gate {
10350Sstevel@tonic-gate 	mutex_init(&element->list_mutex, NULL, MUTEX_DRIVER,
10366112Sqz150045 	    iblock_cookie);
10370Sstevel@tonic-gate 	mutex_enter(&element->list_mutex);
10380Sstevel@tonic-gate 	element->private = private;
10390Sstevel@tonic-gate 	mutex_exit(&element->list_mutex);
10400Sstevel@tonic-gate }
10410Sstevel@tonic-gate 
10420Sstevel@tonic-gate 
10430Sstevel@tonic-gate void
usba_destroy_list(usba_list_entry_t * head)10440Sstevel@tonic-gate usba_destroy_list(usba_list_entry_t *head)
10450Sstevel@tonic-gate {
10460Sstevel@tonic-gate 	mutex_enter(&head->list_mutex);
10470Sstevel@tonic-gate 	ASSERT(head->next == NULL);
10480Sstevel@tonic-gate 	ASSERT(head->prev == NULL);
10490Sstevel@tonic-gate 	mutex_exit(&head->list_mutex);
10500Sstevel@tonic-gate 
10510Sstevel@tonic-gate 	mutex_destroy(&head->list_mutex);
10520Sstevel@tonic-gate }
10530Sstevel@tonic-gate 
10540Sstevel@tonic-gate 
10550Sstevel@tonic-gate void
usba_add_to_list(usba_list_entry_t * head,usba_list_entry_t * element)10560Sstevel@tonic-gate usba_add_to_list(usba_list_entry_t *head, usba_list_entry_t *element)
10570Sstevel@tonic-gate {
10580Sstevel@tonic-gate 	usba_list_entry_t *next;
10590Sstevel@tonic-gate 	int		remaining;
10600Sstevel@tonic-gate 
10610Sstevel@tonic-gate 	mutex_enter(&head->list_mutex);
10620Sstevel@tonic-gate 	mutex_enter(&element->list_mutex);
10630Sstevel@tonic-gate 
10640Sstevel@tonic-gate 	remaining = head->count;
10650Sstevel@tonic-gate 
10660Sstevel@tonic-gate 	/* check if it is not in another list */
10670Sstevel@tonic-gate 	ASSERT(element->next == NULL);
10680Sstevel@tonic-gate 	ASSERT(element->prev == NULL);
10690Sstevel@tonic-gate 
10700Sstevel@tonic-gate #ifdef DEBUG
10710Sstevel@tonic-gate 	/*
10720Sstevel@tonic-gate 	 * only verify the list when not in interrupt context, we
10730Sstevel@tonic-gate 	 * have to trust the HCD
10740Sstevel@tonic-gate 	 */
10750Sstevel@tonic-gate 	if (!servicing_interrupt()) {
10760Sstevel@tonic-gate 
10770Sstevel@tonic-gate 		/* check if not already in this list */
10780Sstevel@tonic-gate 		for (next = head->next; (next != NULL);
10790Sstevel@tonic-gate 		    next = next->next) {
10800Sstevel@tonic-gate 			if (next == element) {
10810Sstevel@tonic-gate 				USB_DPRINTF_L0(DPRINT_MASK_USBA,
10820Sstevel@tonic-gate 				    usba_log_handle,
10830Sstevel@tonic-gate 				    "Attempt to corrupt USB list at 0x%p",
10840Sstevel@tonic-gate 				    (void *)head);
10850Sstevel@tonic-gate 				ASSERT(next == element);
10860Sstevel@tonic-gate 
10870Sstevel@tonic-gate 				goto done;
10880Sstevel@tonic-gate 			}
10890Sstevel@tonic-gate 			remaining--;
10900Sstevel@tonic-gate 
10910Sstevel@tonic-gate 			/*
10920Sstevel@tonic-gate 			 * Detect incorrect circ links or found
10930Sstevel@tonic-gate 			 * unexpected elements.
10940Sstevel@tonic-gate 			 */
10950Sstevel@tonic-gate 			if ((next->next && (remaining == 0)) ||
10960Sstevel@tonic-gate 			    ((next->next == NULL) && remaining)) {
10970Sstevel@tonic-gate 				panic("Corrupted USB list at 0x%p",
10980Sstevel@tonic-gate 				    (void *)head);
10990Sstevel@tonic-gate 				/*NOTREACHED*/
11000Sstevel@tonic-gate 			}
11010Sstevel@tonic-gate 		}
11020Sstevel@tonic-gate 	}
11030Sstevel@tonic-gate #endif
11040Sstevel@tonic-gate 
11050Sstevel@tonic-gate 	if (head->next == NULL) {
11060Sstevel@tonic-gate 		head->prev = head->next = element;
11070Sstevel@tonic-gate 	} else {
11080Sstevel@tonic-gate 		/* add to tail */
11090Sstevel@tonic-gate 		head->prev->next = element;
11100Sstevel@tonic-gate 		element->prev = head->prev;
11110Sstevel@tonic-gate 		head->prev = element;
11120Sstevel@tonic-gate 	}
11130Sstevel@tonic-gate 
11140Sstevel@tonic-gate 	head->count++;
11150Sstevel@tonic-gate 
11160Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
11170Sstevel@tonic-gate 	    "usba_add_to_list: head=0x%p element=0x%p count=%d",
11186898Sfb209375 	    (void *)head, (void *)element, head->count);
11190Sstevel@tonic-gate 
11200Sstevel@tonic-gate done:
11210Sstevel@tonic-gate 	mutex_exit(&head->list_mutex);
11220Sstevel@tonic-gate 	mutex_exit(&element->list_mutex);
11230Sstevel@tonic-gate }
11240Sstevel@tonic-gate 
11250Sstevel@tonic-gate 
11260Sstevel@tonic-gate int
usba_rm_from_list(usba_list_entry_t * head,usba_list_entry_t * element)11270Sstevel@tonic-gate usba_rm_from_list(usba_list_entry_t *head, usba_list_entry_t *element)
11280Sstevel@tonic-gate {
11290Sstevel@tonic-gate 	usba_list_entry_t *e;
11300Sstevel@tonic-gate 	int		found = 0;
11310Sstevel@tonic-gate 	int		remaining;
11320Sstevel@tonic-gate 
11330Sstevel@tonic-gate 	/* find the element in the list first */
11340Sstevel@tonic-gate 	mutex_enter(&head->list_mutex);
11350Sstevel@tonic-gate 
11360Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
11370Sstevel@tonic-gate 	    "usba_rm_from_list: head=0x%p element=0x%p count=%d",
11386898Sfb209375 	    (void *)head, (void *)element, head->count);
11390Sstevel@tonic-gate 
11400Sstevel@tonic-gate 	remaining = head->count;
11410Sstevel@tonic-gate 	e = head->next;
11420Sstevel@tonic-gate 
11430Sstevel@tonic-gate 	while (e) {
11440Sstevel@tonic-gate 		if (e == element) {
11450Sstevel@tonic-gate 			found++;
11460Sstevel@tonic-gate 			break;
11470Sstevel@tonic-gate 		}
11480Sstevel@tonic-gate 		e = e->next;
11490Sstevel@tonic-gate 
11500Sstevel@tonic-gate 		remaining--;
11510Sstevel@tonic-gate 
11520Sstevel@tonic-gate 		/* Detect incorrect circ links or found unexpected elements. */
11530Sstevel@tonic-gate 		if ((e && (remaining == 0)) ||
11540Sstevel@tonic-gate 		    ((e == NULL) && (remaining))) {
11550Sstevel@tonic-gate 			panic("Corrupted USB list at 0x%p", (void *)head);
11560Sstevel@tonic-gate 			/*NOTREACHED*/
11570Sstevel@tonic-gate 		}
11580Sstevel@tonic-gate 	}
11590Sstevel@tonic-gate 
11600Sstevel@tonic-gate 	if (!found) {
11610Sstevel@tonic-gate 		mutex_exit(&head->list_mutex);
11620Sstevel@tonic-gate 
11630Sstevel@tonic-gate 		return (USB_FAILURE);
11640Sstevel@tonic-gate 	}
11650Sstevel@tonic-gate 
11660Sstevel@tonic-gate 	/* now remove the element */
11670Sstevel@tonic-gate 	mutex_enter(&element->list_mutex);
11680Sstevel@tonic-gate 
11690Sstevel@tonic-gate 	if (element->next) {
11700Sstevel@tonic-gate 		element->next->prev = element->prev;
11710Sstevel@tonic-gate 	}
11720Sstevel@tonic-gate 	if (element->prev) {
11730Sstevel@tonic-gate 		element->prev->next = element->next;
11740Sstevel@tonic-gate 	}
11750Sstevel@tonic-gate 	if (head->next == element) {
11760Sstevel@tonic-gate 		head->next = element->next;
11770Sstevel@tonic-gate 	}
11780Sstevel@tonic-gate 	if (head->prev == element) {
11790Sstevel@tonic-gate 		head->prev = element->prev;
11800Sstevel@tonic-gate 	}
11810Sstevel@tonic-gate 
11820Sstevel@tonic-gate 	element->prev = element->next = NULL;
11830Sstevel@tonic-gate 	if (head->next == NULL) {
11840Sstevel@tonic-gate 		ASSERT(head->prev == NULL);
11850Sstevel@tonic-gate 	} else {
11860Sstevel@tonic-gate 		ASSERT(head->next->prev == NULL);
11870Sstevel@tonic-gate 	}
11880Sstevel@tonic-gate 	if (head->prev == NULL) {
11890Sstevel@tonic-gate 		ASSERT(head->next == NULL);
11900Sstevel@tonic-gate 	} else {
11910Sstevel@tonic-gate 		ASSERT(head->prev->next == NULL);
11920Sstevel@tonic-gate 	}
11930Sstevel@tonic-gate 
11940Sstevel@tonic-gate 	head->count--;
11950Sstevel@tonic-gate 
11960Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
11970Sstevel@tonic-gate 	    "usba_rm_from_list success: head=0x%p element=0x%p cnt=%d",
11986898Sfb209375 	    (void *)head, (void *)element, head->count);
11990Sstevel@tonic-gate 
12000Sstevel@tonic-gate 	mutex_exit(&element->list_mutex);
12010Sstevel@tonic-gate 	mutex_exit(&head->list_mutex);
12020Sstevel@tonic-gate 
12030Sstevel@tonic-gate 	return (USB_SUCCESS);
12040Sstevel@tonic-gate }
12050Sstevel@tonic-gate 
12060Sstevel@tonic-gate 
12070Sstevel@tonic-gate usba_list_entry_t *
usba_rm_first_from_list(usba_list_entry_t * head)12080Sstevel@tonic-gate usba_rm_first_from_list(usba_list_entry_t *head)
12090Sstevel@tonic-gate {
12100Sstevel@tonic-gate 	usba_list_entry_t *element = NULL;
12110Sstevel@tonic-gate 
12120Sstevel@tonic-gate 	if (head) {
12130Sstevel@tonic-gate 		mutex_enter(&head->list_mutex);
12140Sstevel@tonic-gate 		element = head->next;
12150Sstevel@tonic-gate 		if (element) {
12160Sstevel@tonic-gate 			/* now remove the element */
12170Sstevel@tonic-gate 			mutex_enter(&element->list_mutex);
12180Sstevel@tonic-gate 			head->next = element->next;
12190Sstevel@tonic-gate 			if (head->next) {
12200Sstevel@tonic-gate 				head->next->prev = NULL;
12210Sstevel@tonic-gate 			}
12220Sstevel@tonic-gate 			if (head->prev == element) {
12230Sstevel@tonic-gate 				head->prev = element->next;
12240Sstevel@tonic-gate 			}
12250Sstevel@tonic-gate 			element->prev = element->next = NULL;
12260Sstevel@tonic-gate 			mutex_exit(&element->list_mutex);
12270Sstevel@tonic-gate 			head->count--;
12280Sstevel@tonic-gate 		}
12290Sstevel@tonic-gate 		if (head->next == NULL) {
12300Sstevel@tonic-gate 			ASSERT(head->prev == NULL);
12310Sstevel@tonic-gate 		} else {
12320Sstevel@tonic-gate 			ASSERT(head->next->prev == NULL);
12330Sstevel@tonic-gate 		}
12340Sstevel@tonic-gate 		if (head->prev == NULL) {
12350Sstevel@tonic-gate 			ASSERT(head->next == NULL);
12360Sstevel@tonic-gate 		} else {
12370Sstevel@tonic-gate 			ASSERT(head->prev->next == NULL);
12380Sstevel@tonic-gate 		}
12390Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
12400Sstevel@tonic-gate 		    "usba_rm_first_from_list: head=0x%p el=0x%p cnt=%d",
12416898Sfb209375 		    (void *)head, (void *)element, head->count);
12420Sstevel@tonic-gate 
12430Sstevel@tonic-gate 		mutex_exit(&head->list_mutex);
12440Sstevel@tonic-gate 	}
12450Sstevel@tonic-gate 
12460Sstevel@tonic-gate 	return (element);
12470Sstevel@tonic-gate }
12480Sstevel@tonic-gate 
12490Sstevel@tonic-gate 
12500Sstevel@tonic-gate usb_opaque_t
usba_rm_first_pvt_from_list(usba_list_entry_t * head)12510Sstevel@tonic-gate usba_rm_first_pvt_from_list(usba_list_entry_t *head)
12520Sstevel@tonic-gate {
12530Sstevel@tonic-gate 	usba_list_entry_t *element = usba_rm_first_from_list(head);
12540Sstevel@tonic-gate 	usb_opaque_t private = NULL;
12550Sstevel@tonic-gate 
12560Sstevel@tonic-gate 	if (element) {
12570Sstevel@tonic-gate 		mutex_enter(&element->list_mutex);
12580Sstevel@tonic-gate 		private = element->private;
12590Sstevel@tonic-gate 		mutex_exit(&element->list_mutex);
12600Sstevel@tonic-gate 	}
12610Sstevel@tonic-gate 
12620Sstevel@tonic-gate 	return (private);
12630Sstevel@tonic-gate }
12640Sstevel@tonic-gate 
12650Sstevel@tonic-gate 
12660Sstevel@tonic-gate /*
12670Sstevel@tonic-gate  * move list to new list and zero original list
12680Sstevel@tonic-gate  */
12690Sstevel@tonic-gate void
usba_move_list(usba_list_entry_t * head,usba_list_entry_t * new,ddi_iblock_cookie_t iblock_cookie)12700Sstevel@tonic-gate usba_move_list(usba_list_entry_t *head, usba_list_entry_t *new,
12710Sstevel@tonic-gate 	ddi_iblock_cookie_t iblock_cookie)
12720Sstevel@tonic-gate {
12730Sstevel@tonic-gate 	usba_init_list(new, NULL, iblock_cookie);
12740Sstevel@tonic-gate 	mutex_enter(&head->list_mutex);
12750Sstevel@tonic-gate 	mutex_enter(&new->list_mutex);
12760Sstevel@tonic-gate 
12770Sstevel@tonic-gate 	new->next = head->next;
12780Sstevel@tonic-gate 	new->prev = head->prev;
12790Sstevel@tonic-gate 	new->count = head->count;
12800Sstevel@tonic-gate 	new->private = head->private;
12810Sstevel@tonic-gate 
12820Sstevel@tonic-gate 	head->next = NULL;
12830Sstevel@tonic-gate 	head->prev = NULL;
12840Sstevel@tonic-gate 	head->count = 0;
12850Sstevel@tonic-gate 	head->private = NULL;
12860Sstevel@tonic-gate 	mutex_exit(&head->list_mutex);
12870Sstevel@tonic-gate 	mutex_exit(&new->list_mutex);
12880Sstevel@tonic-gate }
12890Sstevel@tonic-gate 
12900Sstevel@tonic-gate 
12910Sstevel@tonic-gate int
usba_check_in_list(usba_list_entry_t * head,usba_list_entry_t * element)12920Sstevel@tonic-gate usba_check_in_list(usba_list_entry_t *head, usba_list_entry_t *element)
12930Sstevel@tonic-gate {
12940Sstevel@tonic-gate 	int		rval = USB_FAILURE;
12950Sstevel@tonic-gate 	int		remaining;
12960Sstevel@tonic-gate 	usba_list_entry_t *next;
12970Sstevel@tonic-gate 
12980Sstevel@tonic-gate 	mutex_enter(&head->list_mutex);
12990Sstevel@tonic-gate 	remaining = head->count;
13000Sstevel@tonic-gate 
13010Sstevel@tonic-gate 	mutex_enter(&element->list_mutex);
13020Sstevel@tonic-gate 	for (next = head->next; next != NULL; next = next->next) {
13030Sstevel@tonic-gate 		if (next == element) {
13040Sstevel@tonic-gate 			rval = USB_SUCCESS;
13050Sstevel@tonic-gate 			break;
13060Sstevel@tonic-gate 		}
13070Sstevel@tonic-gate 		remaining--;
13080Sstevel@tonic-gate 
13090Sstevel@tonic-gate 		/* Detect incorrect circ links or found unexpected elements. */
13100Sstevel@tonic-gate 		if ((next->next && (remaining == 0)) ||
13110Sstevel@tonic-gate 		    ((next->next == NULL) && remaining)) {
13120Sstevel@tonic-gate 			panic("Corrupted USB list at 0x%p", (void *)head);
13130Sstevel@tonic-gate 			/*NOTREACHED*/
13140Sstevel@tonic-gate 		}
13150Sstevel@tonic-gate 	}
13160Sstevel@tonic-gate 	mutex_exit(&element->list_mutex);
13170Sstevel@tonic-gate 	mutex_exit(&head->list_mutex);
13180Sstevel@tonic-gate 
13190Sstevel@tonic-gate 	return (rval);
13200Sstevel@tonic-gate }
13210Sstevel@tonic-gate 
13220Sstevel@tonic-gate 
13230Sstevel@tonic-gate int
usba_list_entry_leaks(usba_list_entry_t * head,char * what)13240Sstevel@tonic-gate usba_list_entry_leaks(usba_list_entry_t *head, char *what)
13250Sstevel@tonic-gate {
13260Sstevel@tonic-gate 	int		count = 0;
13270Sstevel@tonic-gate 	int		remaining;
13280Sstevel@tonic-gate 	usba_list_entry_t *next;
13290Sstevel@tonic-gate 
13300Sstevel@tonic-gate 	mutex_enter(&head->list_mutex);
13310Sstevel@tonic-gate 	remaining = head->count;
13320Sstevel@tonic-gate 	for (next = head->next; next != NULL; next = next->next) {
13330Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_HCDI, usba_log_handle,
13346898Sfb209375 		    "leaking %s 0x%p", what, (void *)next->private);
13350Sstevel@tonic-gate 		count++;
13360Sstevel@tonic-gate 
13370Sstevel@tonic-gate 		remaining--;
13380Sstevel@tonic-gate 
13390Sstevel@tonic-gate 		/* Detect incorrect circ links or found unexpected elements. */
13400Sstevel@tonic-gate 		if ((next->next && (remaining == 0)) ||
13410Sstevel@tonic-gate 		    ((next->next == NULL) && remaining)) {
13420Sstevel@tonic-gate 			panic("Corrupted USB list at 0x%p", (void *)head);
13430Sstevel@tonic-gate 			/*NOTREACHED*/
13440Sstevel@tonic-gate 		}
13450Sstevel@tonic-gate 	}
13460Sstevel@tonic-gate 	ASSERT(count == head->count);
13470Sstevel@tonic-gate 	mutex_exit(&head->list_mutex);
13480Sstevel@tonic-gate 
13490Sstevel@tonic-gate 	if (count) {
13500Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_HCDI, usba_log_handle,
13510Sstevel@tonic-gate 		    "usba_list_entry_count: leaking %d", count);
13520Sstevel@tonic-gate 	}
13530Sstevel@tonic-gate 
13540Sstevel@tonic-gate 	return (count);
13550Sstevel@tonic-gate }
13560Sstevel@tonic-gate 
13570Sstevel@tonic-gate 
13580Sstevel@tonic-gate int
usba_list_entry_count(usba_list_entry_t * head)13590Sstevel@tonic-gate usba_list_entry_count(usba_list_entry_t *head)
13600Sstevel@tonic-gate {
13610Sstevel@tonic-gate 	int count;
13620Sstevel@tonic-gate 
13630Sstevel@tonic-gate 	mutex_enter(&head->list_mutex);
13640Sstevel@tonic-gate 	count = head->count;
13650Sstevel@tonic-gate 	mutex_exit(&head->list_mutex);
13660Sstevel@tonic-gate 
13670Sstevel@tonic-gate 	return (count);
13680Sstevel@tonic-gate }
13690Sstevel@tonic-gate 
13709094SVincent.Wang@Sun.COM /* add a new root hub to the usba_root_hubs list */
13719094SVincent.Wang@Sun.COM 
13729094SVincent.Wang@Sun.COM void
usba_add_root_hub(dev_info_t * dip)13739094SVincent.Wang@Sun.COM usba_add_root_hub(dev_info_t *dip)
13749094SVincent.Wang@Sun.COM {
13759094SVincent.Wang@Sun.COM 	usba_root_hub_ent_t *hub;
13769094SVincent.Wang@Sun.COM 
13779094SVincent.Wang@Sun.COM 	hub = (usba_root_hub_ent_t *)
13789094SVincent.Wang@Sun.COM 	    kmem_zalloc(sizeof (usba_root_hub_ent_t), KM_SLEEP);
13799094SVincent.Wang@Sun.COM 
13809094SVincent.Wang@Sun.COM 	mutex_enter(&usba_hub_mutex);
13819094SVincent.Wang@Sun.COM 	hub->dip = dip;
13829094SVincent.Wang@Sun.COM 	hub->next = usba_root_hubs;
13839094SVincent.Wang@Sun.COM 	usba_root_hubs = hub;
13849094SVincent.Wang@Sun.COM 	mutex_exit(&usba_hub_mutex);
13859094SVincent.Wang@Sun.COM }
13869094SVincent.Wang@Sun.COM 
13879094SVincent.Wang@Sun.COM /* remove a root hub from the usba_root_hubs list */
13889094SVincent.Wang@Sun.COM 
13899094SVincent.Wang@Sun.COM void
usba_rem_root_hub(dev_info_t * dip)13909094SVincent.Wang@Sun.COM usba_rem_root_hub(dev_info_t *dip)
13919094SVincent.Wang@Sun.COM {
13929094SVincent.Wang@Sun.COM 	usba_root_hub_ent_t **hubp, *hub;
13939094SVincent.Wang@Sun.COM 
13949094SVincent.Wang@Sun.COM 	mutex_enter(&usba_hub_mutex);
13959094SVincent.Wang@Sun.COM 	hubp = &usba_root_hubs;
13969094SVincent.Wang@Sun.COM 	while (*hubp) {
13979094SVincent.Wang@Sun.COM 		if ((*hubp)->dip == dip) {
13989094SVincent.Wang@Sun.COM 			hub = *hubp;
13999094SVincent.Wang@Sun.COM 			*hubp = hub->next;
14009094SVincent.Wang@Sun.COM 			kmem_free(hub, sizeof (struct usba_root_hub_ent));
14019094SVincent.Wang@Sun.COM 			mutex_exit(&usba_hub_mutex);
14029094SVincent.Wang@Sun.COM 
14039094SVincent.Wang@Sun.COM 			return;
14049094SVincent.Wang@Sun.COM 		}
14059094SVincent.Wang@Sun.COM 		hubp = &(*hubp)->next;
14069094SVincent.Wang@Sun.COM 	}
14079094SVincent.Wang@Sun.COM 	mutex_exit(&usba_hub_mutex);
14089094SVincent.Wang@Sun.COM }
14090Sstevel@tonic-gate 
14100Sstevel@tonic-gate /*
14119094SVincent.Wang@Sun.COM  * check whether this dip is the root hub. Any root hub known by
14129094SVincent.Wang@Sun.COM  * usba is recorded in the linked list pointed to by usba_root_hubs
14130Sstevel@tonic-gate  */
14140Sstevel@tonic-gate int
usba_is_root_hub(dev_info_t * dip)14150Sstevel@tonic-gate usba_is_root_hub(dev_info_t *dip)
14160Sstevel@tonic-gate {
14179094SVincent.Wang@Sun.COM 	usba_root_hub_ent_t *hub;
14189094SVincent.Wang@Sun.COM 
14199094SVincent.Wang@Sun.COM 	mutex_enter(&usba_hub_mutex);
14209094SVincent.Wang@Sun.COM 	hub = usba_root_hubs;
14219094SVincent.Wang@Sun.COM 	while (hub) {
14229094SVincent.Wang@Sun.COM 		if (hub->dip == dip) {
14239094SVincent.Wang@Sun.COM 			mutex_exit(&usba_hub_mutex);
14249094SVincent.Wang@Sun.COM 
14259094SVincent.Wang@Sun.COM 			return (1);
14269094SVincent.Wang@Sun.COM 		}
14279094SVincent.Wang@Sun.COM 		hub = hub->next;
14280Sstevel@tonic-gate 	}
14299094SVincent.Wang@Sun.COM 	mutex_exit(&usba_hub_mutex);
14309094SVincent.Wang@Sun.COM 
14310Sstevel@tonic-gate 	return (0);
14320Sstevel@tonic-gate }
14330Sstevel@tonic-gate 
14349430SRaymond.Chen@Sun.COM /*
14359430SRaymond.Chen@Sun.COM  * check whether this dip is a wire adapter device
14369430SRaymond.Chen@Sun.COM  */
14379430SRaymond.Chen@Sun.COM int
usba_is_wa(dev_info_t * dip)14389430SRaymond.Chen@Sun.COM usba_is_wa(dev_info_t *dip)
14399430SRaymond.Chen@Sun.COM {
14409430SRaymond.Chen@Sun.COM 	if (dip) {
14419430SRaymond.Chen@Sun.COM 		usba_device_t *usba_device;
14429430SRaymond.Chen@Sun.COM 
14439430SRaymond.Chen@Sun.COM 		usba_device = usba_get_usba_device(dip);
14449430SRaymond.Chen@Sun.COM 
14459430SRaymond.Chen@Sun.COM 		return (usba_device->usb_is_wa? 1:0);
14469430SRaymond.Chen@Sun.COM 	}
14479430SRaymond.Chen@Sun.COM 
14489430SRaymond.Chen@Sun.COM 	return (0);
14499430SRaymond.Chen@Sun.COM }
14509430SRaymond.Chen@Sun.COM 
14519430SRaymond.Chen@Sun.COM /*
14529430SRaymond.Chen@Sun.COM  * check whether this dip is a host wire adapter device node
14539430SRaymond.Chen@Sun.COM  */
14549430SRaymond.Chen@Sun.COM int
usba_is_hwa(dev_info_t * dip)14559430SRaymond.Chen@Sun.COM usba_is_hwa(dev_info_t *dip)
14569430SRaymond.Chen@Sun.COM {
14579430SRaymond.Chen@Sun.COM 	dev_info_t	*cdip;
14589430SRaymond.Chen@Sun.COM 
14599430SRaymond.Chen@Sun.COM 	if (dip == NULL) {
14609430SRaymond.Chen@Sun.COM 
14619430SRaymond.Chen@Sun.COM 		return (0);
14629430SRaymond.Chen@Sun.COM 	}
14639430SRaymond.Chen@Sun.COM 
14649430SRaymond.Chen@Sun.COM 	if (strcmp(ddi_driver_name(dip), "usb_mid") != 0) {
14659430SRaymond.Chen@Sun.COM 
14669430SRaymond.Chen@Sun.COM 		return (0);
14679430SRaymond.Chen@Sun.COM 	}
14689430SRaymond.Chen@Sun.COM 
14699430SRaymond.Chen@Sun.COM 	for (cdip = ddi_get_child(dip); cdip;
14709430SRaymond.Chen@Sun.COM 	    cdip = ddi_get_next_sibling(cdip)) {
14719430SRaymond.Chen@Sun.COM 		if (strcmp(ddi_driver_name(cdip), "hwarc") == 0) {
14729430SRaymond.Chen@Sun.COM 
14739430SRaymond.Chen@Sun.COM 			return (1);
14749430SRaymond.Chen@Sun.COM 		}
14759430SRaymond.Chen@Sun.COM 	}
14769430SRaymond.Chen@Sun.COM 
14779430SRaymond.Chen@Sun.COM 	return (0);
14789430SRaymond.Chen@Sun.COM }
14790Sstevel@tonic-gate 
14800Sstevel@tonic-gate /*
14810Sstevel@tonic-gate  * get and store usba_device pointer in the devi
14820Sstevel@tonic-gate  */
14830Sstevel@tonic-gate usba_device_t *
usba_get_usba_device(dev_info_t * dip)14840Sstevel@tonic-gate usba_get_usba_device(dev_info_t *dip)
14850Sstevel@tonic-gate {
14860Sstevel@tonic-gate 	/*
14870Sstevel@tonic-gate 	 * we cannot use parent_data in the usb node because its
14880Sstevel@tonic-gate 	 * bus parent (eg. PCI nexus driver) uses this data
14890Sstevel@tonic-gate 	 *
14900Sstevel@tonic-gate 	 * we cannot use driver data in the other usb nodes since
14910Sstevel@tonic-gate 	 * usb drivers may need to use this
14920Sstevel@tonic-gate 	 */
14930Sstevel@tonic-gate 	if (usba_is_root_hub(dip)) {
14940Sstevel@tonic-gate 		usba_hcdi_t *hcdi = usba_hcdi_get_hcdi(dip);
14950Sstevel@tonic-gate 
14960Sstevel@tonic-gate 		return (hcdi->hcdi_usba_device);
14970Sstevel@tonic-gate 	} else {
14980Sstevel@tonic-gate 
14990Sstevel@tonic-gate 		return (ddi_get_parent_data(dip));
15000Sstevel@tonic-gate 	}
15010Sstevel@tonic-gate }
15020Sstevel@tonic-gate 
15030Sstevel@tonic-gate 
15040Sstevel@tonic-gate /*
15050Sstevel@tonic-gate  * Retrieve the usba_device pointer from the dev without checking for
15060Sstevel@tonic-gate  * the root hub first.	This function is only used in polled mode.
15070Sstevel@tonic-gate  */
15080Sstevel@tonic-gate usba_device_t *
usba_polled_get_usba_device(dev_info_t * dip)15090Sstevel@tonic-gate usba_polled_get_usba_device(dev_info_t *dip)
15100Sstevel@tonic-gate {
15110Sstevel@tonic-gate 	/*
15120Sstevel@tonic-gate 	 * Don't call usba_is_root_hub() to find out if this is
15130Sstevel@tonic-gate 	 * the root hub  usba_is_root_hub() calls into the DDI
15140Sstevel@tonic-gate 	 * where there are locking issues. The dip sent in during
15150Sstevel@tonic-gate 	 * polled mode will never be the root hub, so just get
15160Sstevel@tonic-gate 	 * the usba_device pointer from the dip.
15170Sstevel@tonic-gate 	 */
15180Sstevel@tonic-gate 	return (ddi_get_parent_data(dip));
15190Sstevel@tonic-gate }
15200Sstevel@tonic-gate 
15210Sstevel@tonic-gate 
15220Sstevel@tonic-gate void
usba_set_usba_device(dev_info_t * dip,usba_device_t * usba_device)15230Sstevel@tonic-gate usba_set_usba_device(dev_info_t *dip, usba_device_t *usba_device)
15240Sstevel@tonic-gate {
15250Sstevel@tonic-gate 	if (usba_is_root_hub(dip)) {
15260Sstevel@tonic-gate 		usba_hcdi_t *hcdi = usba_hcdi_get_hcdi(dip);
15270Sstevel@tonic-gate 		/* no locking is needed here */
15280Sstevel@tonic-gate 		_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(hcdi->hcdi_usba_device))
15290Sstevel@tonic-gate 		hcdi->hcdi_usba_device = usba_device;
15300Sstevel@tonic-gate 		_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(hcdi->hcdi_usba_device))
15310Sstevel@tonic-gate 	} else {
15320Sstevel@tonic-gate 		ddi_set_parent_data(dip, usba_device);
15330Sstevel@tonic-gate 	}
15340Sstevel@tonic-gate }
15350Sstevel@tonic-gate 
15360Sstevel@tonic-gate 
15370Sstevel@tonic-gate /*
15380Sstevel@tonic-gate  * usba_set_node_name() according to class, subclass, and protocol
15390Sstevel@tonic-gate  * following the 1275 USB binding tables.
15400Sstevel@tonic-gate  */
15410Sstevel@tonic-gate 
15420Sstevel@tonic-gate /* device node table, refer to section 3.2.2.1 of 1275 binding */
15430Sstevel@tonic-gate static node_name_entry_t device_node_name_table[] = {
15440Sstevel@tonic-gate { USB_CLASS_COMM,	DONTCARE,	DONTCARE,	"communications" },
15450Sstevel@tonic-gate { USB_CLASS_HUB,	DONTCARE,	DONTCARE,	"hub" },
15463341Sgc161489 { USB_CLASS_DIAG,	DONTCARE,	DONTCARE,	"diagnostics" },
15473341Sgc161489 { USB_CLASS_MISC,	DONTCARE,	DONTCARE,	"miscellaneous" },
15480Sstevel@tonic-gate { DONTCARE,		DONTCARE,	DONTCARE,	"device" }
15490Sstevel@tonic-gate };
15500Sstevel@tonic-gate 
15513341Sgc161489 /* interface-association node table */
15523341Sgc161489 static node_name_entry_t ia_node_name_table[] = {
15533341Sgc161489 { USB_CLASS_AUDIO,	DONTCARE,	DONTCARE, "audio" },
15543341Sgc161489 { USB_CLASS_VIDEO,	DONTCARE,	DONTCARE, "video" },
15553341Sgc161489 { USB_CLASS_WIRELESS,	USB_SUBCLS_WUSB_2, USB_PROTO_WUSB_DWA,
15563341Sgc161489 						"device-wire-adaptor" },
15573341Sgc161489 { USB_CLASS_WIRELESS,	DONTCARE,	DONTCARE, "wireless-controller" },
15583341Sgc161489 { DONTCARE,		DONTCARE,	DONTCARE, "interface-association" }
15593341Sgc161489 };
15603341Sgc161489 
15610Sstevel@tonic-gate /* interface node table, refer to section 3.3.2.1 */
15620Sstevel@tonic-gate static node_name_entry_t if_node_name_table[] = {
15630Sstevel@tonic-gate { USB_CLASS_AUDIO, USB_SUBCLS_AUD_CONTROL, DONTCARE,	"sound-control" },
15640Sstevel@tonic-gate { USB_CLASS_AUDIO, USB_SUBCLS_AUD_STREAMING, DONTCARE, "sound" },
15650Sstevel@tonic-gate { USB_CLASS_AUDIO, USB_SUBCLS_AUD_MIDI_STREAMING, DONTCARE, "midi" },
15660Sstevel@tonic-gate { USB_CLASS_AUDIO, DONTCARE,		DONTCARE,	"sound" },
15670Sstevel@tonic-gate 
15680Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_DIRECT_LINE,	DONTCARE, "line" },
15690Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_ABSTRCT_CTRL,	DONTCARE, "modem" },
15700Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_PHONE_CTRL, DONTCARE, "telephone" },
15710Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_MULTCNL_ISDN, DONTCARE, "isdn" },
15720Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_ISDN,		DONTCARE, "isdn" },
15730Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_ETHERNET,	DONTCARE, "ethernet" },
15740Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_ATM_NETWORK, DONTCARE, "atm-network" },
15753341Sgc161489 { USB_CLASS_COMM, DONTCARE,		DONTCARE,	"communications" },
15760Sstevel@tonic-gate 
15770Sstevel@tonic-gate { USB_CLASS_HID, USB_SUBCLS_HID_1, USB_PROTO_HID_KEYBOARD,	"keyboard" },
15780Sstevel@tonic-gate { USB_CLASS_HID, USB_SUBCLS_HID_1, USB_PROTO_HID_MOUSE,	"mouse" },
15790Sstevel@tonic-gate { USB_CLASS_HID,	DONTCARE,	DONTCARE,	"input" },
15800Sstevel@tonic-gate 
15810Sstevel@tonic-gate { USB_CLASS_HUB,	DONTCARE,	DONTCARE,	"hub" },
15820Sstevel@tonic-gate 
15830Sstevel@tonic-gate { USB_CLASS_PHYSICAL,	DONTCARE,	DONTCARE,	"physical" },
15840Sstevel@tonic-gate 
15853341Sgc161489 { USB_CLASS_IMAGE,	DONTCARE,	DONTCARE,	"image" },
15863341Sgc161489 
15870Sstevel@tonic-gate { USB_CLASS_PRINTER,	DONTCARE,	DONTCARE,	"printer" },
15880Sstevel@tonic-gate 
15890Sstevel@tonic-gate { USB_CLASS_MASS_STORAGE, DONTCARE,	DONTCARE,	"storage" },
15900Sstevel@tonic-gate 
15910Sstevel@tonic-gate { USB_CLASS_CDC_DATA,	DONTCARE,	DONTCARE,	"data" },
15920Sstevel@tonic-gate 
15930Sstevel@tonic-gate { USB_CLASS_SECURITY,	DONTCARE,	DONTCARE,	"security" },
15940Sstevel@tonic-gate 
15953341Sgc161489 { USB_CLASS_VIDEO, USB_SUBCLS_VIDEO_CONTROL, DONTCARE,	"video-control" },
15963341Sgc161489 { USB_CLASS_VIDEO, USB_SUBCLS_VIDEO_STREAM,  DONTCARE,	"video-stream" },
15973341Sgc161489 { USB_CLASS_VIDEO,	DONTCARE,	DONTCARE,	"video" },
15983341Sgc161489 
15990Sstevel@tonic-gate { USB_CLASS_APP,	USB_SUBCLS_APP_FIRMWARE, DONTCARE, "firmware" },
16000Sstevel@tonic-gate { USB_CLASS_APP,	USB_SUBCLS_APP_IRDA,	DONTCARE, "IrDa" },
16010Sstevel@tonic-gate { USB_CLASS_APP,	USB_SUBCLS_APP_TEST,	DONTCARE, "test" },
16020Sstevel@tonic-gate 
16039430SRaymond.Chen@Sun.COM { USB_CLASS_MISC,	USB_SUBCLS_CBAF, USB_PROTO_CBAF,  "wusb_ca"},
16049430SRaymond.Chen@Sun.COM { USB_CLASS_WIRELESS, USB_SUBCLS_WUSB_1, USB_PROTO_WUSB_RC, "hwa-radio" },
16059430SRaymond.Chen@Sun.COM { USB_CLASS_WIRELESS, USB_SUBCLS_WUSB_2, USB_PROTO_WUSB_HWA, "hwa-host" },
16069430SRaymond.Chen@Sun.COM { USB_CLASS_WIRELESS, USB_SUBCLS_WUSB_2, USB_PROTO_WUSB_DWA, "dwa-control" },
16079430SRaymond.Chen@Sun.COM { USB_CLASS_WIRELESS, USB_SUBCLS_WUSB_2, USB_PROTO_WUSB_DWA_ISO, "dwa-isoc" },
16089430SRaymond.Chen@Sun.COM { USB_CLASS_WIRELESS, DONTCARE, DONTCARE, "wireless" },
16099430SRaymond.Chen@Sun.COM 
16100Sstevel@tonic-gate { DONTCARE,		DONTCARE,	DONTCARE,	"interface" },
16110Sstevel@tonic-gate 
16120Sstevel@tonic-gate };
16130Sstevel@tonic-gate 
16140Sstevel@tonic-gate /* combined node table, refer to section 3.4.2.1 */
16150Sstevel@tonic-gate static node_name_entry_t combined_node_name_table[] = {
16160Sstevel@tonic-gate { USB_CLASS_AUDIO, USB_SUBCLS_AUD_CONTROL, DONTCARE,	"sound-control" },
16170Sstevel@tonic-gate { USB_CLASS_AUDIO, USB_SUBCLS_AUD_STREAMING, DONTCARE, "sound" },
16180Sstevel@tonic-gate { USB_CLASS_AUDIO, USB_SUBCLS_AUD_MIDI_STREAMING, DONTCARE, "midi" },
16190Sstevel@tonic-gate { USB_CLASS_AUDIO, DONTCARE,		DONTCARE,	"sound" },
16200Sstevel@tonic-gate 
16210Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_DIRECT_LINE,	DONTCARE, "line" },
16220Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_ABSTRCT_CTRL,	DONTCARE, "modem" },
16230Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_PHONE_CTRL, DONTCARE, "telephone" },
16240Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_MULTCNL_ISDN, DONTCARE, "isdn" },
16250Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_ISDN,		DONTCARE, "isdn" },
16260Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_ETHERNET,	DONTCARE, "ethernet" },
16270Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_ATM_NETWORK, DONTCARE, "atm-network" },
16283341Sgc161489 { USB_CLASS_COMM, DONTCARE,		DONTCARE,	"communications" },
16290Sstevel@tonic-gate 
16300Sstevel@tonic-gate { USB_CLASS_HID, USB_SUBCLS_HID_1, USB_PROTO_HID_KEYBOARD, "keyboard" },
16310Sstevel@tonic-gate { USB_CLASS_HID, USB_SUBCLS_HID_1, USB_PROTO_HID_MOUSE,	"mouse" },
16320Sstevel@tonic-gate { USB_CLASS_HID,	DONTCARE,	DONTCARE,	"input" },
16330Sstevel@tonic-gate 
16340Sstevel@tonic-gate { USB_CLASS_PHYSICAL,	DONTCARE,	DONTCARE,	"physical" },
16350Sstevel@tonic-gate 
16363341Sgc161489 { USB_CLASS_IMAGE,	DONTCARE,	DONTCARE,	"image" },
16373341Sgc161489 
16380Sstevel@tonic-gate { USB_CLASS_PRINTER,	DONTCARE,	DONTCARE,	"printer" },
16390Sstevel@tonic-gate 
16403341Sgc161489 { USB_CLASS_MASS_STORAGE, USB_SUBCLS_MS_RBC_T10,	DONTCARE, "storage" },
16413341Sgc161489 { USB_CLASS_MASS_STORAGE, USB_SUBCLS_MS_SFF8020I,	DONTCARE, "cdrom" },
16423341Sgc161489 { USB_CLASS_MASS_STORAGE, USB_SUBCLS_MS_QIC_157,	DONTCARE, "tape" },
16433341Sgc161489 { USB_CLASS_MASS_STORAGE, USB_SUBCLS_MS_UFI,		DONTCARE, "floppy" },
16443341Sgc161489 { USB_CLASS_MASS_STORAGE, USB_SUBCLS_MS_SFF8070I,	DONTCARE, "storage" },
16453341Sgc161489 { USB_CLASS_MASS_STORAGE, USB_SUBCLS_MS_SCSI,		DONTCARE, "storage" },
16460Sstevel@tonic-gate { USB_CLASS_MASS_STORAGE, DONTCARE,	DONTCARE,	"storage" },
16470Sstevel@tonic-gate 
16480Sstevel@tonic-gate { USB_CLASS_CDC_DATA,	DONTCARE,	DONTCARE,	"data" },
16490Sstevel@tonic-gate 
16500Sstevel@tonic-gate { USB_CLASS_SECURITY,	DONTCARE,	DONTCARE,	"security" },
16510Sstevel@tonic-gate 
16523341Sgc161489 { USB_CLASS_VIDEO, USB_SUBCLS_VIDEO_CONTROL, DONTCARE,	"video-control" },
16533341Sgc161489 { USB_CLASS_VIDEO, USB_SUBCLS_VIDEO_STREAM,  DONTCARE,	"video-stream" },
16543341Sgc161489 { USB_CLASS_VIDEO,	DONTCARE,	DONTCARE,	"video" },
16553341Sgc161489 
16560Sstevel@tonic-gate { USB_CLASS_APP,	USB_SUBCLS_APP_FIRMWARE, DONTCARE, "firmware" },
16570Sstevel@tonic-gate { USB_CLASS_APP,	USB_SUBCLS_APP_IRDA,	DONTCARE, "IrDa" },
16580Sstevel@tonic-gate { USB_CLASS_APP,	USB_SUBCLS_APP_TEST,	DONTCARE, "test" },
16590Sstevel@tonic-gate 
16603341Sgc161489 { USB_CLASS_COMM,	DONTCARE,	DONTCARE,	"communications" },
16610Sstevel@tonic-gate { USB_CLASS_HUB,	DONTCARE,	DONTCARE,	"hub" },
16623341Sgc161489 { USB_CLASS_DIAG,	DONTCARE,	DONTCARE,	"diagnostics" },
16633341Sgc161489 { USB_CLASS_MISC,	DONTCARE,	DONTCARE,	"miscellaneous" },
16643341Sgc161489 { DONTCARE,		DONTCARE,	DONTCARE,	"device" }
16650Sstevel@tonic-gate };
16660Sstevel@tonic-gate 
16670Sstevel@tonic-gate static size_t device_node_name_table_size =
16680Sstevel@tonic-gate 	sizeof (device_node_name_table)/sizeof (struct node_name_entry);
16693341Sgc161489 static size_t ia_node_name_table_size =
16703341Sgc161489 	sizeof (ia_node_name_table)/sizeof (struct node_name_entry);
16710Sstevel@tonic-gate static size_t if_node_name_table_size =
16720Sstevel@tonic-gate 	sizeof (if_node_name_table)/sizeof (struct node_name_entry);
16730Sstevel@tonic-gate static size_t combined_node_name_table_size =
16740Sstevel@tonic-gate 	sizeof (combined_node_name_table)/sizeof (struct node_name_entry);
16750Sstevel@tonic-gate 
16760Sstevel@tonic-gate 
16770Sstevel@tonic-gate static void
usba_set_node_name(dev_info_t * dip,uint8_t class,uint8_t subclass,uint8_t protocol,uint_t flag)16780Sstevel@tonic-gate usba_set_node_name(dev_info_t *dip, uint8_t class, uint8_t subclass,
16790Sstevel@tonic-gate     uint8_t protocol, uint_t flag)
16800Sstevel@tonic-gate {
16810Sstevel@tonic-gate 	int i;
16820Sstevel@tonic-gate 	size_t size;
16830Sstevel@tonic-gate 	node_name_entry_t *node_name_table;
16840Sstevel@tonic-gate 
16850Sstevel@tonic-gate 	switch (flag) {
16863341Sgc161489 	/* interface share node names with interface-association */
16873341Sgc161489 	case FLAG_INTERFACE_ASSOCIATION_NODE:
16883341Sgc161489 		node_name_table = ia_node_name_table;
16893341Sgc161489 		size = ia_node_name_table_size;
16903341Sgc161489 		break;
16910Sstevel@tonic-gate 	case FLAG_INTERFACE_NODE:
16920Sstevel@tonic-gate 		node_name_table = if_node_name_table;
16930Sstevel@tonic-gate 		size = if_node_name_table_size;
16940Sstevel@tonic-gate 		break;
16950Sstevel@tonic-gate 	case FLAG_DEVICE_NODE:
16960Sstevel@tonic-gate 		node_name_table = device_node_name_table;
16970Sstevel@tonic-gate 		size = device_node_name_table_size;
16980Sstevel@tonic-gate 		break;
16990Sstevel@tonic-gate 	case FLAG_COMBINED_NODE:
17000Sstevel@tonic-gate 		node_name_table = combined_node_name_table;
17010Sstevel@tonic-gate 		size = combined_node_name_table_size;
17020Sstevel@tonic-gate 		break;
17030Sstevel@tonic-gate 	default:
17040Sstevel@tonic-gate 
17050Sstevel@tonic-gate 		return;
17060Sstevel@tonic-gate 	}
17070Sstevel@tonic-gate 
17080Sstevel@tonic-gate 	for (i = 0; i < size; i++) {
17090Sstevel@tonic-gate 		int16_t c = node_name_table[i].class;
17100Sstevel@tonic-gate 		int16_t s = node_name_table[i].subclass;
17110Sstevel@tonic-gate 		int16_t p = node_name_table[i].protocol;
17120Sstevel@tonic-gate 
17130Sstevel@tonic-gate 		if (((c == DONTCARE) || (c == class)) &&
17140Sstevel@tonic-gate 		    ((s == DONTCARE) || (s == subclass)) &&
17150Sstevel@tonic-gate 		    ((p == DONTCARE) || (p == protocol))) {
17160Sstevel@tonic-gate 			char *name = node_name_table[i].name;
17173341Sgc161489 
17180Sstevel@tonic-gate 			(void) ndi_devi_set_nodename(dip, name, 0);
17190Sstevel@tonic-gate 			break;
17200Sstevel@tonic-gate 		}
17210Sstevel@tonic-gate 	}
17220Sstevel@tonic-gate }
17230Sstevel@tonic-gate 
17240Sstevel@tonic-gate 
17250Sstevel@tonic-gate #ifdef DEBUG
17260Sstevel@tonic-gate /*
17270Sstevel@tonic-gate  * walk the children of the parent of this devi and compare the
17280Sstevel@tonic-gate  * name and  reg property of each child. If there is a match
17290Sstevel@tonic-gate  * return this node
17300Sstevel@tonic-gate  */
17310Sstevel@tonic-gate static dev_info_t *
usba_find_existing_node(dev_info_t * odip)17320Sstevel@tonic-gate usba_find_existing_node(dev_info_t *odip)
17330Sstevel@tonic-gate {
17340Sstevel@tonic-gate 	dev_info_t *ndip, *child, *pdip;
17350Sstevel@tonic-gate 	int	*odata, *ndata;
17360Sstevel@tonic-gate 	uint_t	n_odata, n_ndata;
17370Sstevel@tonic-gate 	int	circular;
17380Sstevel@tonic-gate 
17390Sstevel@tonic-gate 	pdip = ddi_get_parent(odip);
17400Sstevel@tonic-gate 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY,
17410Sstevel@tonic-gate 	    odip, DDI_PROP_DONTPASS, "reg",
17420Sstevel@tonic-gate 	    &odata, &n_odata) != DDI_SUCCESS) {
1743978Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_HCDI, usba_log_handle,
17440Sstevel@tonic-gate 		    "usba_find_existing_node: "
17450Sstevel@tonic-gate 		    "%s: DDI_NOT_WELL_FORMED", ddi_driver_name(odip));
17460Sstevel@tonic-gate 
17470Sstevel@tonic-gate 		return (NULL);
17480Sstevel@tonic-gate 	}
17490Sstevel@tonic-gate 
17500Sstevel@tonic-gate 	ndi_devi_enter(pdip, &circular);
17510Sstevel@tonic-gate 	ndip = (dev_info_t *)(DEVI(pdip)->devi_child);
17520Sstevel@tonic-gate 	while ((child = ndip) != NULL) {
17530Sstevel@tonic-gate 
17540Sstevel@tonic-gate 		ndip = (dev_info_t *)(DEVI(child)->devi_sibling);
17550Sstevel@tonic-gate 
17560Sstevel@tonic-gate 		if (child == odip) {
17570Sstevel@tonic-gate 			continue;
17580Sstevel@tonic-gate 		}
17590Sstevel@tonic-gate 
17600Sstevel@tonic-gate 		if (strcmp(DEVI(child)->devi_node_name,
17610Sstevel@tonic-gate 		    DEVI(odip)->devi_node_name)) {
17620Sstevel@tonic-gate 			continue;
17630Sstevel@tonic-gate 		}
17640Sstevel@tonic-gate 
17650Sstevel@tonic-gate 		if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY,
17660Sstevel@tonic-gate 		    child, DDI_PROP_DONTPASS, "reg",
17670Sstevel@tonic-gate 		    &ndata, &n_ndata) != DDI_SUCCESS) {
17680Sstevel@tonic-gate 
1769978Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_HCDI, usba_log_handle,
17700Sstevel@tonic-gate 			    "usba_find_existing_node: "
17710Sstevel@tonic-gate 			    "%s DDI_NOT_WELL_FORMED", ddi_driver_name(child));
17720Sstevel@tonic-gate 
17730Sstevel@tonic-gate 		} else if (n_ndata && n_odata && (bcmp(odata, ndata,
17740Sstevel@tonic-gate 		    max(n_odata, n_ndata) * sizeof (int)) == 0)) {
17750Sstevel@tonic-gate 
17760Sstevel@tonic-gate 			USB_DPRINTF_L3(DPRINT_MASK_HCDI, usba_log_handle,
17770Sstevel@tonic-gate 			    "usba_find_existing_node: found %s%d (%p)",
17780Sstevel@tonic-gate 			    ddi_driver_name(child),
17790Sstevel@tonic-gate 			    ddi_get_instance(child), (void *)child);
17800Sstevel@tonic-gate 
17810Sstevel@tonic-gate 			USB_DPRINTF_L3(DPRINT_MASK_HCDI, usba_log_handle,
17820Sstevel@tonic-gate 			    "usba_find_existing_node: "
17830Sstevel@tonic-gate 			    "reg: %x %x %x - %x %x %x",
17840Sstevel@tonic-gate 			    n_odata, odata[0], odata[1],
17850Sstevel@tonic-gate 			    n_ndata, ndata[0], ndata[1]);
17860Sstevel@tonic-gate 
17870Sstevel@tonic-gate 			ddi_prop_free(ndata);
17880Sstevel@tonic-gate 			break;
17890Sstevel@tonic-gate 
17900Sstevel@tonic-gate 		} else {
17910Sstevel@tonic-gate 			ddi_prop_free(ndata);
17920Sstevel@tonic-gate 		}
17930Sstevel@tonic-gate 	}
17940Sstevel@tonic-gate 
17950Sstevel@tonic-gate 	ndi_devi_exit(pdip, circular);
17960Sstevel@tonic-gate 
17970Sstevel@tonic-gate 	ddi_prop_free(odata);
17980Sstevel@tonic-gate 
17990Sstevel@tonic-gate 	return (child);
18000Sstevel@tonic-gate }
18010Sstevel@tonic-gate #endif
18020Sstevel@tonic-gate 
18030Sstevel@tonic-gate /* change all unprintable characters to spaces */
18040Sstevel@tonic-gate static void
usba_filter_string(char * instr,char * outstr)18050Sstevel@tonic-gate usba_filter_string(char *instr, char *outstr)
18060Sstevel@tonic-gate {
18070Sstevel@tonic-gate 	while (*instr) {
18080Sstevel@tonic-gate 		if ((*instr >= ' ') && (*instr <= '~')) {
18090Sstevel@tonic-gate 			*outstr = *instr;
18100Sstevel@tonic-gate 		} else {
18110Sstevel@tonic-gate 			*outstr = ' ';
18120Sstevel@tonic-gate 		}
18130Sstevel@tonic-gate 		outstr++;
18140Sstevel@tonic-gate 		instr++;
18150Sstevel@tonic-gate 	}
18160Sstevel@tonic-gate 	*outstr = '\0';
18170Sstevel@tonic-gate }
18180Sstevel@tonic-gate 
18190Sstevel@tonic-gate 
18200Sstevel@tonic-gate /*
18210Sstevel@tonic-gate  * lookup ugen binding specified in property in
18220Sstevel@tonic-gate  * hcd.conf files
18230Sstevel@tonic-gate  */
18240Sstevel@tonic-gate int
usba_get_ugen_binding(dev_info_t * dip)18250Sstevel@tonic-gate usba_get_ugen_binding(dev_info_t *dip)
18260Sstevel@tonic-gate {
18270Sstevel@tonic-gate 	usba_device_t	*usba_device = usba_get_usba_device(dip);
18280Sstevel@tonic-gate 	usba_hcdi_t	*hcdi =
18296112Sqz150045 	    usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
18300Sstevel@tonic-gate 
18310Sstevel@tonic-gate 	return (hcdi->hcdi_ugen_default_binding);
18320Sstevel@tonic-gate }
18330Sstevel@tonic-gate 
18340Sstevel@tonic-gate 
18350Sstevel@tonic-gate /*
18360Sstevel@tonic-gate  * driver binding support at device level
18370Sstevel@tonic-gate  */
18380Sstevel@tonic-gate dev_info_t *
usba_ready_device_node(dev_info_t * child_dip)18390Sstevel@tonic-gate usba_ready_device_node(dev_info_t *child_dip)
18400Sstevel@tonic-gate {
18410Sstevel@tonic-gate 	int		rval, i;
18420Sstevel@tonic-gate 	int		n = 0;
18430Sstevel@tonic-gate 	usba_device_t	*usba_device = usba_get_usba_device(child_dip);
18440Sstevel@tonic-gate 	usb_dev_descr_t	*usb_dev_descr;
18450Sstevel@tonic-gate 	uint_t		n_cfgs;	/* number of configs */
18460Sstevel@tonic-gate 	uint_t		n_ifs;	/* number of interfaces */
1847*10316SStrony.Zhang@Sun.COM 	uint_t		port, bus_num;
18480Sstevel@tonic-gate 	size_t		usb_config_length;
18490Sstevel@tonic-gate 	uchar_t 	*usb_config;
18500Sstevel@tonic-gate 	int		reg[1];
18510Sstevel@tonic-gate 	usb_addr_t	address = usb_get_addr(child_dip);
18520Sstevel@tonic-gate 	usb_if_descr_t	if_descr;
18530Sstevel@tonic-gate 	size_t		size;
18540Sstevel@tonic-gate 	int		combined_node = 0;
18550Sstevel@tonic-gate 	int		is_hub;
18560Sstevel@tonic-gate 	char		*devprop_str;
18570Sstevel@tonic-gate 	char		*force_bind = NULL;
18583630Slg150142 	char		*usba_name_buf = NULL;
18593630Slg150142 	char		*usba_name[USBA_MAX_COMPAT_NAMES];
18600Sstevel@tonic-gate 
18610Sstevel@tonic-gate 	usb_config = usb_get_raw_cfg_data(child_dip, &usb_config_length);
18620Sstevel@tonic-gate 
18630Sstevel@tonic-gate 	mutex_enter(&usba_device->usb_mutex);
18640Sstevel@tonic-gate 	mutex_enter(&usba_mutex);
18650Sstevel@tonic-gate 
18660Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
18670Sstevel@tonic-gate 	    "usba_ready_device_node: child=0x%p", (void *)child_dip);
18680Sstevel@tonic-gate 
18690Sstevel@tonic-gate 	port = usba_device->usb_port;
18700Sstevel@tonic-gate 	usb_dev_descr = usba_device->usb_dev_descr;
18710Sstevel@tonic-gate 	n_cfgs = usba_device->usb_n_cfgs;
18720Sstevel@tonic-gate 	n_ifs = usba_device->usb_n_ifs;
1873*10316SStrony.Zhang@Sun.COM 	bus_num = usba_device->usb_addr;
18740Sstevel@tonic-gate 
18750Sstevel@tonic-gate 	if (address != ROOT_HUB_ADDR) {
18760Sstevel@tonic-gate 		size = usb_parse_if_descr(
18776112Sqz150045 		    usb_config,
18786112Sqz150045 		    usb_config_length,
18796112Sqz150045 		    0,		/* interface index */
18806112Sqz150045 		    0,		/* alt interface index */
18816112Sqz150045 		    &if_descr,
18826112Sqz150045 		    USB_IF_DESCR_SIZE);
18830Sstevel@tonic-gate 
18840Sstevel@tonic-gate 		if (size != USB_IF_DESCR_SIZE) {
1885978Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
18860Sstevel@tonic-gate 			    "parsing interface: "
18870Sstevel@tonic-gate 			    "size (%lu) != USB_IF_DESCR_SIZE (%d)",
18880Sstevel@tonic-gate 			    size, USB_IF_DESCR_SIZE);
18890Sstevel@tonic-gate 
18900Sstevel@tonic-gate 			mutex_exit(&usba_mutex);
18910Sstevel@tonic-gate 			mutex_exit(&usba_device->usb_mutex);
18920Sstevel@tonic-gate 
18930Sstevel@tonic-gate 			return (child_dip);
18940Sstevel@tonic-gate 		}
18950Sstevel@tonic-gate 	} else {
18960Sstevel@tonic-gate 		/* fake an interface descriptor for the root hub */
18970Sstevel@tonic-gate 		bzero(&if_descr, sizeof (if_descr));
18980Sstevel@tonic-gate 
18990Sstevel@tonic-gate 		if_descr.bInterfaceClass = USB_CLASS_HUB;
19000Sstevel@tonic-gate 	}
19010Sstevel@tonic-gate 
19020Sstevel@tonic-gate 	reg[0] = port;
19030Sstevel@tonic-gate 
19040Sstevel@tonic-gate 	mutex_exit(&usba_mutex);
19050Sstevel@tonic-gate 	mutex_exit(&usba_device->usb_mutex);
19060Sstevel@tonic-gate 
19070Sstevel@tonic-gate 	rval = ndi_prop_update_int_array(
19086112Sqz150045 	    DDI_DEV_T_NONE, child_dip, "reg", reg, 1);
19090Sstevel@tonic-gate 
19100Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
1911978Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
19120Sstevel@tonic-gate 		    "usba_ready_device_node: property update failed");
19130Sstevel@tonic-gate 
19140Sstevel@tonic-gate 		return (child_dip);
19150Sstevel@tonic-gate 	}
19160Sstevel@tonic-gate 
19170Sstevel@tonic-gate 	combined_node = ((n_cfgs == 1) && (n_ifs == 1) &&
19180Sstevel@tonic-gate 	    ((usb_dev_descr->bDeviceClass == USB_CLASS_HUB) ||
19190Sstevel@tonic-gate 	    (usb_dev_descr->bDeviceClass == 0)));
19200Sstevel@tonic-gate 
19210Sstevel@tonic-gate 	is_hub = (if_descr.bInterfaceClass == USB_CLASS_HUB) ||
19226112Sqz150045 	    (usb_dev_descr->bDeviceClass == USB_CLASS_HUB);
19230Sstevel@tonic-gate 
19240Sstevel@tonic-gate 	/* set node name */
19250Sstevel@tonic-gate 	if (combined_node) {
19260Sstevel@tonic-gate 		usba_set_node_name(child_dip,
19270Sstevel@tonic-gate 		    if_descr.bInterfaceClass,
19280Sstevel@tonic-gate 		    if_descr.bInterfaceSubClass,
19290Sstevel@tonic-gate 		    if_descr.bInterfaceProtocol,
19300Sstevel@tonic-gate 		    FLAG_COMBINED_NODE);
19310Sstevel@tonic-gate 	} else {
19320Sstevel@tonic-gate 		usba_set_node_name(child_dip,
19330Sstevel@tonic-gate 		    usb_dev_descr->bDeviceClass,
19340Sstevel@tonic-gate 		    usb_dev_descr->bDeviceSubClass,
19350Sstevel@tonic-gate 		    usb_dev_descr->bDeviceProtocol,
19360Sstevel@tonic-gate 		    FLAG_DEVICE_NODE);
19370Sstevel@tonic-gate 	}
19380Sstevel@tonic-gate 
19390Sstevel@tonic-gate 	/*
19400Sstevel@tonic-gate 	 * check force binding rules
19410Sstevel@tonic-gate 	 */
19420Sstevel@tonic-gate 	if ((address != ROOT_HUB_ADDR) && usba_ddivs_usbc &&
19430Sstevel@tonic-gate 	    (address != usba_ddivs_usbc_xaddress) &&
19440Sstevel@tonic-gate 	    (!(usba_ddivs_usbc_xhubs && is_hub))) {
19450Sstevel@tonic-gate 		force_bind = "ddivs_usbc";
19460Sstevel@tonic-gate 		(void) ndi_devi_set_nodename(child_dip, "ddivs_usbc", 0);
19470Sstevel@tonic-gate 
19480Sstevel@tonic-gate 	} else if (usba_device->usb_preferred_driver) {
19490Sstevel@tonic-gate 		force_bind = usba_device->usb_preferred_driver;
19500Sstevel@tonic-gate 
19510Sstevel@tonic-gate 	} else if ((address != ROOT_HUB_ADDR) &&
19520Sstevel@tonic-gate 	    ((usba_ugen_force_binding == USBA_UGEN_DEVICE_BINDING) ||
19530Sstevel@tonic-gate 	    ((usba_ugen_force_binding == USBA_UGEN_INTERFACE_BINDING) &&
19540Sstevel@tonic-gate 	    combined_node)) && (!is_hub)) {
19550Sstevel@tonic-gate 		force_bind = "ugen";
19560Sstevel@tonic-gate 	}
19570Sstevel@tonic-gate 
19580Sstevel@tonic-gate #ifdef DEBUG
19590Sstevel@tonic-gate 	/*
19600Sstevel@tonic-gate 	 * check whether there is another dip with this name and address
19610Sstevel@tonic-gate 	 * If the dip contains usba_device, it is held by the previous
19620Sstevel@tonic-gate 	 * round of configuration.
19630Sstevel@tonic-gate 	 */
19640Sstevel@tonic-gate 	ASSERT(usba_find_existing_node(child_dip) == NULL);
19650Sstevel@tonic-gate #endif
19663630Slg150142 
19673630Slg150142 	usba_name_buf = kmem_zalloc(USBA_MAX_COMPAT_NAMES *
19683630Slg150142 	    USBA_MAX_COMPAT_NAME_LEN, KM_SLEEP);
19693630Slg150142 
19703630Slg150142 	for (i = 0; i < USBA_MAX_COMPAT_NAMES; i++) {
19713630Slg150142 		usba_name[i] = usba_name_buf + (i * USBA_MAX_COMPAT_NAME_LEN);
19723630Slg150142 	}
19730Sstevel@tonic-gate 
19740Sstevel@tonic-gate 	if (force_bind) {
19750Sstevel@tonic-gate 		(void) ndi_devi_set_nodename(child_dip, force_bind, 0);
19760Sstevel@tonic-gate 		(void) strncpy(usba_name[n++], force_bind,
19776112Sqz150045 		    USBA_MAX_COMPAT_NAME_LEN);
19780Sstevel@tonic-gate 	}
19790Sstevel@tonic-gate 
1980*10316SStrony.Zhang@Sun.COM 	/*
1981*10316SStrony.Zhang@Sun.COM 	 * If the callback function of specified driver is registered,
1982*10316SStrony.Zhang@Sun.COM 	 * it will be called here to check whether to take over the device.
1983*10316SStrony.Zhang@Sun.COM 	 */
1984*10316SStrony.Zhang@Sun.COM 	if (usb_cap.usba_dev_driver_cb != NULL) {
1985*10316SStrony.Zhang@Sun.COM 		char		*dev_drv = NULL;
1986*10316SStrony.Zhang@Sun.COM 		usb_dev_str_t	dev_str;
1987*10316SStrony.Zhang@Sun.COM 		char		*pathname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1988*10316SStrony.Zhang@Sun.COM 
1989*10316SStrony.Zhang@Sun.COM 		dev_str.usb_mfg = usba_device->usb_mfg_str;
1990*10316SStrony.Zhang@Sun.COM 		dev_str.usb_product = usba_device->usb_product_str;
1991*10316SStrony.Zhang@Sun.COM 		dev_str.usb_serialno = usba_device->usb_serialno_str;
1992*10316SStrony.Zhang@Sun.COM 
1993*10316SStrony.Zhang@Sun.COM 		(void) ddi_pathname(child_dip, pathname);
1994*10316SStrony.Zhang@Sun.COM 
1995*10316SStrony.Zhang@Sun.COM 		if ((usb_cap.usba_dev_driver_cb(usb_dev_descr, &dev_str,
1996*10316SStrony.Zhang@Sun.COM 		    pathname, bus_num, port, &dev_drv, NULL) == USB_SUCCESS) &&
1997*10316SStrony.Zhang@Sun.COM 		    (dev_drv != NULL)) {
1998*10316SStrony.Zhang@Sun.COM 			USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
1999*10316SStrony.Zhang@Sun.COM 			    "usba_ready_device_node: dev_driver=%s, port =%d,"
2000*10316SStrony.Zhang@Sun.COM 			    "bus =%d, path=%s\n\t",
2001*10316SStrony.Zhang@Sun.COM 			    dev_drv, port, bus_num, pathname);
2002*10316SStrony.Zhang@Sun.COM 
2003*10316SStrony.Zhang@Sun.COM 			(void) strncpy(usba_name[n++], dev_drv,
2004*10316SStrony.Zhang@Sun.COM 			    USBA_MAX_COMPAT_NAME_LEN);
2005*10316SStrony.Zhang@Sun.COM 		}
2006*10316SStrony.Zhang@Sun.COM 		kmem_free(pathname, MAXPATHLEN);
2007*10316SStrony.Zhang@Sun.COM 	}
2008*10316SStrony.Zhang@Sun.COM 
20090Sstevel@tonic-gate 	/* create compatible names */
20100Sstevel@tonic-gate 	if (combined_node) {
20110Sstevel@tonic-gate 
20120Sstevel@tonic-gate 		/* 1. usbVID,PID.REV */
20130Sstevel@tonic-gate 		(void) sprintf(usba_name[n++],
20146112Sqz150045 		    "usb%x,%x.%x",
20156112Sqz150045 		    usb_dev_descr->idVendor,
20166112Sqz150045 		    usb_dev_descr->idProduct,
20176112Sqz150045 		    usb_dev_descr->bcdDevice);
20180Sstevel@tonic-gate 
20190Sstevel@tonic-gate 		/* 2. usbVID,PID */
20200Sstevel@tonic-gate 		(void) sprintf(usba_name[n++],
20216112Sqz150045 		    "usb%x,%x",
20226112Sqz150045 		    usb_dev_descr->idVendor,
20236112Sqz150045 		    usb_dev_descr->idProduct);
20240Sstevel@tonic-gate 
20250Sstevel@tonic-gate 		if (usb_dev_descr->bDeviceClass != 0) {
20260Sstevel@tonic-gate 			/* 3. usbVID,classDC.DSC.DPROTO */
20270Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
20286112Sqz150045 			    "usb%x,class%x.%x.%x",
20296112Sqz150045 			    usb_dev_descr->idVendor,
20306112Sqz150045 			    usb_dev_descr->bDeviceClass,
20316112Sqz150045 			    usb_dev_descr->bDeviceSubClass,
20326112Sqz150045 			    usb_dev_descr->bDeviceProtocol);
20330Sstevel@tonic-gate 
20340Sstevel@tonic-gate 			/* 4. usbVID,classDC.DSC */
20350Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
20366112Sqz150045 			    "usb%x,class%x.%x",
20376112Sqz150045 			    usb_dev_descr->idVendor,
20386112Sqz150045 			    usb_dev_descr->bDeviceClass,
20396112Sqz150045 			    usb_dev_descr->bDeviceSubClass);
20400Sstevel@tonic-gate 
20410Sstevel@tonic-gate 			/* 5. usbVID,classDC */
20420Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
20436112Sqz150045 			    "usb%x,class%x",
20446112Sqz150045 			    usb_dev_descr->idVendor,
20456112Sqz150045 			    usb_dev_descr->bDeviceClass);
20460Sstevel@tonic-gate 
20470Sstevel@tonic-gate 			/* 6. usb,classDC.DSC.DPROTO */
20480Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
20496112Sqz150045 			    "usb,class%x.%x.%x",
20506112Sqz150045 			    usb_dev_descr->bDeviceClass,
20516112Sqz150045 			    usb_dev_descr->bDeviceSubClass,
20526112Sqz150045 			    usb_dev_descr->bDeviceProtocol);
20530Sstevel@tonic-gate 
20540Sstevel@tonic-gate 			/* 7. usb,classDC.DSC */
20550Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
20566112Sqz150045 			    "usb,class%x.%x",
20576112Sqz150045 			    usb_dev_descr->bDeviceClass,
20586112Sqz150045 			    usb_dev_descr->bDeviceSubClass);
20590Sstevel@tonic-gate 
20600Sstevel@tonic-gate 			/* 8. usb,classDC */
20610Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
20626112Sqz150045 			    "usb,class%x",
20636112Sqz150045 			    usb_dev_descr->bDeviceClass);
20640Sstevel@tonic-gate 		}
20650Sstevel@tonic-gate 
20660Sstevel@tonic-gate 		if (if_descr.bInterfaceClass != 0) {
20670Sstevel@tonic-gate 			/* 9. usbifVID,classIC.ISC.IPROTO */
20680Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
20696112Sqz150045 			    "usbif%x,class%x.%x.%x",
20706112Sqz150045 			    usb_dev_descr->idVendor,
20716112Sqz150045 			    if_descr.bInterfaceClass,
20726112Sqz150045 			    if_descr.bInterfaceSubClass,
20736112Sqz150045 			    if_descr.bInterfaceProtocol);
20740Sstevel@tonic-gate 
20750Sstevel@tonic-gate 			/* 10. usbifVID,classIC.ISC */
20760Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
20776112Sqz150045 			    "usbif%x,class%x.%x",
20786112Sqz150045 			    usb_dev_descr->idVendor,
20796112Sqz150045 			    if_descr.bInterfaceClass,
20806112Sqz150045 			    if_descr.bInterfaceSubClass);
20810Sstevel@tonic-gate 
20820Sstevel@tonic-gate 			/* 11. usbifVID,classIC */
20830Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
20846112Sqz150045 			    "usbif%x,class%x",
20856112Sqz150045 			    usb_dev_descr->idVendor,
20866112Sqz150045 			    if_descr.bInterfaceClass);
20870Sstevel@tonic-gate 
20880Sstevel@tonic-gate 			/* 12. usbif,classIC.ISC.IPROTO */
20890Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
20906112Sqz150045 			    "usbif,class%x.%x.%x",
20916112Sqz150045 			    if_descr.bInterfaceClass,
20926112Sqz150045 			    if_descr.bInterfaceSubClass,
20936112Sqz150045 			    if_descr.bInterfaceProtocol);
20940Sstevel@tonic-gate 
20950Sstevel@tonic-gate 			/* 13. usbif,classIC.ISC */
20960Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
20976112Sqz150045 			    "usbif,class%x.%x",
20986112Sqz150045 			    if_descr.bInterfaceClass,
20996112Sqz150045 			    if_descr.bInterfaceSubClass);
21000Sstevel@tonic-gate 
21010Sstevel@tonic-gate 			/* 14. usbif,classIC */
21020Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
21036112Sqz150045 			    "usbif,class%x",
21046112Sqz150045 			    if_descr.bInterfaceClass);
21050Sstevel@tonic-gate 		}
21060Sstevel@tonic-gate 
21070Sstevel@tonic-gate 		/* 15. ugen or usb_mid */
21080Sstevel@tonic-gate 		if (usba_get_ugen_binding(child_dip) ==
21090Sstevel@tonic-gate 		    USBA_UGEN_DEVICE_BINDING) {
21100Sstevel@tonic-gate 			(void) sprintf(usba_name[n++], "ugen");
21110Sstevel@tonic-gate 		} else {
21120Sstevel@tonic-gate 			(void) sprintf(usba_name[n++], "usb,device");
21130Sstevel@tonic-gate 		}
21140Sstevel@tonic-gate 
21150Sstevel@tonic-gate 	} else {
21160Sstevel@tonic-gate 		if (n_cfgs > 1) {
21170Sstevel@tonic-gate 			/* 1. usbVID,PID.REV.configCN */
21180Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
21196112Sqz150045 			    "usb%x,%x.%x.config%x",
21206112Sqz150045 			    usb_dev_descr->idVendor,
21216112Sqz150045 			    usb_dev_descr->idProduct,
21226112Sqz150045 			    usb_dev_descr->bcdDevice,
21236112Sqz150045 			    usba_device->usb_cfg_value);
21240Sstevel@tonic-gate 		}
21250Sstevel@tonic-gate 
21260Sstevel@tonic-gate 		/* 2. usbVID,PID.REV */
21270Sstevel@tonic-gate 		(void) sprintf(usba_name[n++],
21286112Sqz150045 		    "usb%x,%x.%x",
21296112Sqz150045 		    usb_dev_descr->idVendor,
21306112Sqz150045 		    usb_dev_descr->idProduct,
21316112Sqz150045 		    usb_dev_descr->bcdDevice);
21320Sstevel@tonic-gate 
21330Sstevel@tonic-gate 		/* 3. usbVID,PID.configCN */
21340Sstevel@tonic-gate 		if (n_cfgs > 1) {
21350Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
21366112Sqz150045 			    "usb%x,%x.%x",
21376112Sqz150045 			    usb_dev_descr->idVendor,
21386112Sqz150045 			    usb_dev_descr->idProduct,
21396112Sqz150045 			    usba_device->usb_cfg_value);
21400Sstevel@tonic-gate 		}
21410Sstevel@tonic-gate 
21420Sstevel@tonic-gate 		/* 4. usbVID,PID */
21430Sstevel@tonic-gate 		(void) sprintf(usba_name[n++],
21446112Sqz150045 		    "usb%x,%x",
21456112Sqz150045 		    usb_dev_descr->idVendor,
21466112Sqz150045 		    usb_dev_descr->idProduct);
21470Sstevel@tonic-gate 
21480Sstevel@tonic-gate 		if (usb_dev_descr->bDeviceClass != 0) {
21490Sstevel@tonic-gate 			/* 5. usbVID,classDC.DSC.DPROTO */
21500Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
21516112Sqz150045 			    "usb%x,class%x.%x.%x",
21526112Sqz150045 			    usb_dev_descr->idVendor,
21536112Sqz150045 			    usb_dev_descr->bDeviceClass,
21546112Sqz150045 			    usb_dev_descr->bDeviceSubClass,
21556112Sqz150045 			    usb_dev_descr->bDeviceProtocol);
21560Sstevel@tonic-gate 
21570Sstevel@tonic-gate 			/* 6. usbVID,classDC.DSC */
21580Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
21596112Sqz150045 			    "usb%x.class%x.%x",
21606112Sqz150045 			    usb_dev_descr->idVendor,
21616112Sqz150045 			    usb_dev_descr->bDeviceClass,
21626112Sqz150045 			    usb_dev_descr->bDeviceSubClass);
21630Sstevel@tonic-gate 
21640Sstevel@tonic-gate 			/* 7. usbVID,classDC */
21650Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
21666112Sqz150045 			    "usb%x.class%x",
21676112Sqz150045 			    usb_dev_descr->idVendor,
21686112Sqz150045 			    usb_dev_descr->bDeviceClass);
21690Sstevel@tonic-gate 
21700Sstevel@tonic-gate 			/* 8. usb,classDC.DSC.DPROTO */
21710Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
21726112Sqz150045 			    "usb,class%x.%x.%x",
21736112Sqz150045 			    usb_dev_descr->bDeviceClass,
21746112Sqz150045 			    usb_dev_descr->bDeviceSubClass,
21756112Sqz150045 			    usb_dev_descr->bDeviceProtocol);
21760Sstevel@tonic-gate 
21770Sstevel@tonic-gate 			/* 9. usb,classDC.DSC */
21780Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
21796112Sqz150045 			    "usb,class%x.%x",
21806112Sqz150045 			    usb_dev_descr->bDeviceClass,
21816112Sqz150045 			    usb_dev_descr->bDeviceSubClass);
21820Sstevel@tonic-gate 
21830Sstevel@tonic-gate 			/* 10. usb,classDC */
21840Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
21856112Sqz150045 			    "usb,class%x",
21866112Sqz150045 			    usb_dev_descr->bDeviceClass);
21870Sstevel@tonic-gate 		}
21880Sstevel@tonic-gate 
21890Sstevel@tonic-gate 		if (usba_get_ugen_binding(child_dip) ==
21900Sstevel@tonic-gate 		    USBA_UGEN_DEVICE_BINDING) {
21910Sstevel@tonic-gate 			/* 11. ugen */
21920Sstevel@tonic-gate 			(void) sprintf(usba_name[n++], "ugen");
21930Sstevel@tonic-gate 		} else {
21940Sstevel@tonic-gate 			/* 11. usb,device */
21950Sstevel@tonic-gate 			(void) sprintf(usba_name[n++], "usb,device");
21960Sstevel@tonic-gate 		}
21970Sstevel@tonic-gate 	}
21980Sstevel@tonic-gate 
21990Sstevel@tonic-gate 	for (i = 0; i < n; i += 2) {
22000Sstevel@tonic-gate 		USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
22013630Slg150142 		    "compatible name:\t%s\t%s", usba_name[i],
22023630Slg150142 		    (((i+1) < n)? usba_name[i+1] : ""));
22030Sstevel@tonic-gate 	}
22043630Slg150142 
22053630Slg150142 	rval = ndi_prop_update_string_array(DDI_DEV_T_NONE, child_dip,
22063630Slg150142 	    "compatible", (char **)usba_name, n);
22073630Slg150142 
22083630Slg150142 	kmem_free(usba_name_buf, USBA_MAX_COMPAT_NAMES *
22093630Slg150142 	    USBA_MAX_COMPAT_NAME_LEN);
22103630Slg150142 
22113630Slg150142 	if (rval != DDI_PROP_SUCCESS) {
22123630Slg150142 
22133630Slg150142 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
22143630Slg150142 		    "usba_ready_device_node: property update failed");
22153630Slg150142 
22163630Slg150142 		return (child_dip);
22170Sstevel@tonic-gate 	}
22180Sstevel@tonic-gate 
22190Sstevel@tonic-gate 	/* update the address property */
22200Sstevel@tonic-gate 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
22216112Sqz150045 	    "assigned-address", usba_device->usb_addr);
22220Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
2223978Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
22240Sstevel@tonic-gate 		    "usba_ready_device_node: address update failed");
22250Sstevel@tonic-gate 	}
22260Sstevel@tonic-gate 
22270Sstevel@tonic-gate 	/* update the usb device properties (PSARC/2000/454) */
22280Sstevel@tonic-gate 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
22290Sstevel@tonic-gate 	    "usb-vendor-id", usb_dev_descr->idVendor);
22300Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
2231978Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
22320Sstevel@tonic-gate 		    "usba_ready_device_node: usb-vendor-id update failed");
22330Sstevel@tonic-gate 	}
22340Sstevel@tonic-gate 
22350Sstevel@tonic-gate 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
22360Sstevel@tonic-gate 	    "usb-product-id", usb_dev_descr->idProduct);
22370Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
2238978Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
22390Sstevel@tonic-gate 		    "usba_ready_device_node: usb-product-id update failed");
22400Sstevel@tonic-gate 	}
22410Sstevel@tonic-gate 
22420Sstevel@tonic-gate 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
22430Sstevel@tonic-gate 	    "usb-revision-id", usb_dev_descr->bcdDevice);
22440Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
2245978Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
22460Sstevel@tonic-gate 		    "usba_ready_device_node: usb-revision-id update failed");
22470Sstevel@tonic-gate 	}
22480Sstevel@tonic-gate 
22490Sstevel@tonic-gate 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
22500Sstevel@tonic-gate 	    "usb-num-configs", usb_dev_descr->bNumConfigurations);
22510Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
2252978Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
22530Sstevel@tonic-gate 		    "usba_ready_device_node: usb-num-configs update failed");
22540Sstevel@tonic-gate 	}
22550Sstevel@tonic-gate 
22560Sstevel@tonic-gate 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
22570Sstevel@tonic-gate 	    "usb-release", usb_dev_descr->bcdUSB);
22580Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
2259978Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
22600Sstevel@tonic-gate 		    "usba_ready_device_node: usb-release update failed");
22610Sstevel@tonic-gate 	}
22620Sstevel@tonic-gate 
22636112Sqz150045 	rval = ndi_prop_update_byte_array(DDI_DEV_T_NONE, child_dip,
22646112Sqz150045 	    "usb-dev-descriptor", (uchar_t *)usb_dev_descr,
22656112Sqz150045 	    sizeof (usb_dev_descr_t));
22666112Sqz150045 	if (rval != DDI_PROP_SUCCESS) {
22676112Sqz150045 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
22686112Sqz150045 		    "usba_ready_device_node: usb-descriptor update failed");
22696112Sqz150045 	}
22706112Sqz150045 
22716112Sqz150045 	rval = ndi_prop_update_byte_array(DDI_DEV_T_NONE, child_dip,
22726112Sqz150045 	    "usb-raw-cfg-descriptors", usb_config, usb_config_length);
22736112Sqz150045 	if (rval != DDI_PROP_SUCCESS) {
22746112Sqz150045 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
22756112Sqz150045 		    "usba_ready_device_node: usb-raw-cfg-descriptors update "
22766112Sqz150045 		    "failed");
22776112Sqz150045 	}
22786112Sqz150045 
22790Sstevel@tonic-gate 	devprop_str = kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP);
22800Sstevel@tonic-gate 
22810Sstevel@tonic-gate 	if (usba_device->usb_serialno_str) {
22820Sstevel@tonic-gate 		usba_filter_string(usba_device->usb_serialno_str, devprop_str);
22830Sstevel@tonic-gate 		rval = ndi_prop_update_string(DDI_DEV_T_NONE, child_dip,
22840Sstevel@tonic-gate 		    "usb-serialno", devprop_str);
22850Sstevel@tonic-gate 		if (rval != DDI_PROP_SUCCESS) {
2286978Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
22870Sstevel@tonic-gate 			    "usba_ready_device_node: "
22880Sstevel@tonic-gate 			    "usb-serialno update failed");
22890Sstevel@tonic-gate 		}
22900Sstevel@tonic-gate 	}
22910Sstevel@tonic-gate 
22920Sstevel@tonic-gate 	if (usba_device->usb_mfg_str) {
22930Sstevel@tonic-gate 		usba_filter_string(usba_device->usb_mfg_str, devprop_str);
22940Sstevel@tonic-gate 		rval = ndi_prop_update_string(DDI_DEV_T_NONE, child_dip,
22950Sstevel@tonic-gate 		    "usb-vendor-name", devprop_str);
22960Sstevel@tonic-gate 		if (rval != DDI_PROP_SUCCESS) {
2297978Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
22980Sstevel@tonic-gate 			    "usba_ready_device_node: "
22990Sstevel@tonic-gate 			    "usb-vendor-name update failed");
23000Sstevel@tonic-gate 		}
23010Sstevel@tonic-gate 	}
23020Sstevel@tonic-gate 
23030Sstevel@tonic-gate 	if (usba_device->usb_product_str) {
23040Sstevel@tonic-gate 		usba_filter_string(usba_device->usb_product_str, devprop_str);
23050Sstevel@tonic-gate 		rval = ndi_prop_update_string(DDI_DEV_T_NONE, child_dip,
23060Sstevel@tonic-gate 		    "usb-product-name", devprop_str);
23070Sstevel@tonic-gate 		if (rval != DDI_PROP_SUCCESS) {
2308978Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
23090Sstevel@tonic-gate 			    "usba_ready_device_node: "
23100Sstevel@tonic-gate 			    "usb-product-name update failed");
23110Sstevel@tonic-gate 		}
23120Sstevel@tonic-gate 	}
23130Sstevel@tonic-gate 
23140Sstevel@tonic-gate 	kmem_free(devprop_str, USB_MAXSTRINGLEN);
23150Sstevel@tonic-gate 
23160Sstevel@tonic-gate 	if (!combined_node) {
23170Sstevel@tonic-gate 		/* update the configuration property */
23180Sstevel@tonic-gate 		rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
23196112Sqz150045 		    "configuration#", usba_device->usb_cfg_value);
23200Sstevel@tonic-gate 		if (rval != DDI_PROP_SUCCESS) {
23210Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
23220Sstevel@tonic-gate 			    "usba_ready_device_node: "
23230Sstevel@tonic-gate 			    "config prop update failed");
23240Sstevel@tonic-gate 		}
23250Sstevel@tonic-gate 	}
23260Sstevel@tonic-gate 
23270Sstevel@tonic-gate 	if (usba_device->usb_port_status == USBA_LOW_SPEED_DEV) {
23280Sstevel@tonic-gate 		/* create boolean property */
23290Sstevel@tonic-gate 		rval = ndi_prop_create_boolean(DDI_DEV_T_NONE, child_dip,
23306112Sqz150045 		    "low-speed");
23310Sstevel@tonic-gate 		if (rval != DDI_PROP_SUCCESS) {
2332978Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
23330Sstevel@tonic-gate 			    "usba_ready_device_node: "
23340Sstevel@tonic-gate 			    "low speed prop update failed");
23350Sstevel@tonic-gate 		}
23360Sstevel@tonic-gate 	}
23370Sstevel@tonic-gate 
23386112Sqz150045 	if (usba_device->usb_port_status == USBA_HIGH_SPEED_DEV) {
23396112Sqz150045 		/* create boolean property */
23406112Sqz150045 		rval = ndi_prop_create_boolean(DDI_DEV_T_NONE, child_dip,
23416112Sqz150045 		    "high-speed");
23426112Sqz150045 		if (rval != DDI_PROP_SUCCESS) {
23436112Sqz150045 			USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
23446112Sqz150045 			    "usba_ready_device_node: "
23456112Sqz150045 			    "high speed prop update failed");
23466112Sqz150045 		}
23476112Sqz150045 	}
23486112Sqz150045 
23490Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
23500Sstevel@tonic-gate 	    "%s%d at port %d: %s, dip=0x%p",
23510Sstevel@tonic-gate 	    ddi_node_name(ddi_get_parent(child_dip)),
23520Sstevel@tonic-gate 	    ddi_get_instance(ddi_get_parent(child_dip)),
23536898Sfb209375 	    port, ddi_node_name(child_dip), (void *)child_dip);
23540Sstevel@tonic-gate 
23550Sstevel@tonic-gate 	usba_set_usba_device(child_dip, usba_device);
23560Sstevel@tonic-gate 
23570Sstevel@tonic-gate 	ASSERT(!mutex_owned(&(usba_get_usba_device(child_dip)->usb_mutex)));
23580Sstevel@tonic-gate 
23590Sstevel@tonic-gate 	return (child_dip);
23600Sstevel@tonic-gate }
23610Sstevel@tonic-gate 
23620Sstevel@tonic-gate 
23630Sstevel@tonic-gate /*
23643341Sgc161489  * driver binding at interface association level. the first arg is the parent
23653341Sgc161489  * dip. if_count returns amount of interfaces which are associated within
23663341Sgc161489  * this interface-association that starts from first_if.
23673341Sgc161489  */
23683341Sgc161489 /*ARGSUSED*/
23693341Sgc161489 dev_info_t *
usba_ready_interface_association_node(dev_info_t * dip,uint_t first_if,uint_t * if_count)23703341Sgc161489 usba_ready_interface_association_node(dev_info_t	*dip,
23713341Sgc161489 					uint_t		first_if,
23723341Sgc161489 					uint_t		*if_count)
23733341Sgc161489 {
23743341Sgc161489 	dev_info_t		*child_dip = NULL;
23753341Sgc161489 	usba_device_t		*child_ud = usba_get_usba_device(dip);
23763341Sgc161489 	usb_dev_descr_t		*usb_dev_descr;
23773341Sgc161489 	size_t			usb_cfg_length;
23783341Sgc161489 	uchar_t			*usb_cfg;
23793341Sgc161489 	usb_ia_descr_t		ia_descr;
23803341Sgc161489 	int			i, n, rval;
23813341Sgc161489 	int			reg[2];
23823341Sgc161489 	size_t			size;
23833341Sgc161489 	usb_port_status_t	port_status;
23843341Sgc161489 	char			*force_bind = NULL;
23853630Slg150142 	char			*usba_name_buf = NULL;
23863630Slg150142 	char			*usba_name[USBA_MAX_COMPAT_NAMES];
23873341Sgc161489 
23883341Sgc161489 	usb_cfg = usb_get_raw_cfg_data(dip, &usb_cfg_length);
23893341Sgc161489 
23903341Sgc161489 	mutex_enter(&child_ud->usb_mutex);
23913341Sgc161489 
23923341Sgc161489 	usb_dev_descr = child_ud->usb_dev_descr;
23933341Sgc161489 
23943341Sgc161489 	/*
23953341Sgc161489 	 * for each interface association, determine all compatible names
23963341Sgc161489 	 */
23973341Sgc161489 	USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
23983341Sgc161489 	    "usba_ready_ia_node: "
23993341Sgc161489 	    "port %d, interface = %d, port_status = %x",
24003341Sgc161489 	    child_ud->usb_port, first_if, child_ud->usb_port_status);
24013341Sgc161489 
24023341Sgc161489 	/* Parse the interface descriptor */
24033341Sgc161489 	size = usb_parse_ia_descr(
24046112Sqz150045 	    usb_cfg,
24056112Sqz150045 	    usb_cfg_length,
24066112Sqz150045 	    first_if,	/* interface index */
24076112Sqz150045 	    &ia_descr,
24086112Sqz150045 	    USB_IA_DESCR_SIZE);
24093341Sgc161489 
24103341Sgc161489 	*if_count = 1;
24113341Sgc161489 	if (size != USB_IA_DESCR_SIZE) {
24123341Sgc161489 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
24133341Sgc161489 		    "parsing ia: size (%lu) != USB_IA_DESCR_SIZE (%d)",
24143341Sgc161489 		    size, USB_IA_DESCR_SIZE);
24153341Sgc161489 		mutex_exit(&child_ud->usb_mutex);
24163341Sgc161489 
24173341Sgc161489 		return (NULL);
24183341Sgc161489 	}
24193341Sgc161489 
24203341Sgc161489 	port_status = child_ud->usb_port_status;
24213341Sgc161489 
24223341Sgc161489 	/* create reg property */
24233341Sgc161489 	reg[0] = first_if;
24243341Sgc161489 	reg[1] = child_ud->usb_cfg_value;
24253341Sgc161489 
24263341Sgc161489 	mutex_exit(&child_ud->usb_mutex);
24273341Sgc161489 
24283341Sgc161489 	/* clone this dip */
24293341Sgc161489 	rval =	usba_create_child_devi(dip,
24306112Sqz150045 	    "interface-association",
24316112Sqz150045 	    NULL,		/* usba_hcdi ops */
24326112Sqz150045 	    NULL,		/* root hub dip */
24336112Sqz150045 	    port_status,	/* port status */
24346112Sqz150045 	    child_ud,	/* share this usba_device */
24356112Sqz150045 	    &child_dip);
24363341Sgc161489 
24373341Sgc161489 	if (rval != USB_SUCCESS) {
24383341Sgc161489 
24393341Sgc161489 		goto fail;
24403341Sgc161489 	}
24413341Sgc161489 
24423341Sgc161489 	rval = ndi_prop_update_int_array(
24436112Sqz150045 	    DDI_DEV_T_NONE, child_dip, "reg", reg, 2);
24443341Sgc161489 
24453341Sgc161489 	if (rval != DDI_PROP_SUCCESS) {
24463341Sgc161489 
24473341Sgc161489 		goto fail;
24483341Sgc161489 	}
24493341Sgc161489 
24503341Sgc161489 	usba_set_node_name(child_dip, ia_descr.bFunctionClass,
24513341Sgc161489 	    ia_descr.bFunctionSubClass, ia_descr.bFunctionProtocol,
24523341Sgc161489 	    FLAG_INTERFACE_ASSOCIATION_NODE);
24533341Sgc161489 
24543341Sgc161489 	/* check force binding */
24553341Sgc161489 	if (usba_ugen_force_binding ==
24563341Sgc161489 	    USBA_UGEN_INTERFACE_ASSOCIATION_BINDING) {
24573341Sgc161489 		force_bind = "ugen";
24583341Sgc161489 	}
24593341Sgc161489 
24603341Sgc161489 	/*
24613341Sgc161489 	 * check whether there is another dip with this name and address
24623341Sgc161489 	 */
24633341Sgc161489 	ASSERT(usba_find_existing_node(child_dip) == NULL);
24643341Sgc161489 
24653630Slg150142 	usba_name_buf = kmem_zalloc(USBA_MAX_COMPAT_NAMES *
24663630Slg150142 	    USBA_MAX_COMPAT_NAME_LEN, KM_SLEEP);
24673630Slg150142 
24683630Slg150142 	for (i = 0; i < USBA_MAX_COMPAT_NAMES; i++) {
24693630Slg150142 		usba_name[i] = usba_name_buf + (i * USBA_MAX_COMPAT_NAME_LEN);
24703630Slg150142 	}
24713630Slg150142 
24723341Sgc161489 	n = 0;
24733341Sgc161489 
24743341Sgc161489 	if (force_bind) {
24753341Sgc161489 		(void) ndi_devi_set_nodename(child_dip, force_bind, 0);
24763341Sgc161489 		(void) strncpy(usba_name[n++], force_bind,
24776112Sqz150045 		    USBA_MAX_COMPAT_NAME_LEN);
24783341Sgc161489 	}
24793341Sgc161489 
24803341Sgc161489 	/* 1) usbiaVID,PID.REV.configCN.FN */
24813341Sgc161489 	(void) sprintf(usba_name[n++],
24826112Sqz150045 	    "usbia%x,%x.%x.config%x.%x",
24836112Sqz150045 	    usb_dev_descr->idVendor,
24846112Sqz150045 	    usb_dev_descr->idProduct,
24856112Sqz150045 	    usb_dev_descr->bcdDevice,
24866112Sqz150045 	    child_ud->usb_cfg_value,
24876112Sqz150045 	    first_if);
24883341Sgc161489 
24893341Sgc161489 	/* 2) usbiaVID,PID.configCN.FN */
24903341Sgc161489 	(void) sprintf(usba_name[n++],
24916112Sqz150045 	    "usbia%x,%x.config%x.%x",
24926112Sqz150045 	    usb_dev_descr->idVendor,
24936112Sqz150045 	    usb_dev_descr->idProduct,
24946112Sqz150045 	    child_ud->usb_cfg_value,
24956112Sqz150045 	    first_if);
24963341Sgc161489 
24973341Sgc161489 
24983341Sgc161489 	if (ia_descr.bFunctionClass) {
24993341Sgc161489 		/* 3) usbiaVID,classFC.FSC.FPROTO */
25003341Sgc161489 		(void) sprintf(usba_name[n++],
25016112Sqz150045 		    "usbia%x,class%x.%x.%x",
25026112Sqz150045 		    usb_dev_descr->idVendor,
25036112Sqz150045 		    ia_descr.bFunctionClass,
25046112Sqz150045 		    ia_descr.bFunctionSubClass,
25056112Sqz150045 		    ia_descr.bFunctionProtocol);
25063341Sgc161489 
25073341Sgc161489 		/* 4) usbiaVID,classFC.FSC */
25083341Sgc161489 		(void) sprintf(usba_name[n++],
25096112Sqz150045 		    "usbia%x,class%x.%x",
25106112Sqz150045 		    usb_dev_descr->idVendor,
25116112Sqz150045 		    ia_descr.bFunctionClass,
25126112Sqz150045 		    ia_descr.bFunctionSubClass);
25133341Sgc161489 
25143341Sgc161489 		/* 5) usbiaVID,classFC */
25153341Sgc161489 		(void) sprintf(usba_name[n++],
25166112Sqz150045 		    "usbia%x,class%x",
25176112Sqz150045 		    usb_dev_descr->idVendor,
25186112Sqz150045 		    ia_descr.bFunctionClass);
25193341Sgc161489 
25203341Sgc161489 		/* 6) usbia,classFC.FSC.FPROTO */
25213341Sgc161489 		(void) sprintf(usba_name[n++],
25226112Sqz150045 		    "usbia,class%x.%x.%x",
25236112Sqz150045 		    ia_descr.bFunctionClass,
25246112Sqz150045 		    ia_descr.bFunctionSubClass,
25256112Sqz150045 		    ia_descr.bFunctionProtocol);
25263341Sgc161489 
25273341Sgc161489 		/* 7) usbia,classFC.FSC */
25283341Sgc161489 		(void) sprintf(usba_name[n++],
25296112Sqz150045 		    "usbia,class%x.%x",
25306112Sqz150045 		    ia_descr.bFunctionClass,
25316112Sqz150045 		    ia_descr.bFunctionSubClass);
25323341Sgc161489 
25333341Sgc161489 		/* 8) usbia,classFC */
25343341Sgc161489 		(void) sprintf(usba_name[n++],
25356112Sqz150045 		    "usbia,class%x",
25366112Sqz150045 		    ia_descr.bFunctionClass);
25373341Sgc161489 	}
25383341Sgc161489 
25393341Sgc161489 	if (usba_get_ugen_binding(child_dip) ==
25403341Sgc161489 	    USBA_UGEN_INTERFACE_ASSOCIATION_BINDING) {
25413341Sgc161489 		/* 9) ugen */
25423341Sgc161489 		(void) sprintf(usba_name[n++], "ugen");
25433341Sgc161489 	} else {
25443341Sgc161489 
25453341Sgc161489 		(void) sprintf(usba_name[n++], "usb,ia");
25463341Sgc161489 	}
25473341Sgc161489 
25483341Sgc161489 	for (i = 0; i < n; i += 2) {
25493341Sgc161489 		USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
25503630Slg150142 		    "compatible name:\t%s\t%s", usba_name[i],
25513630Slg150142 		    (((i+1) < n)? usba_name[i+1] : ""));
25523341Sgc161489 	}
25533341Sgc161489 
25543341Sgc161489 	/* create compatible property */
25553630Slg150142 	rval = ndi_prop_update_string_array(DDI_DEV_T_NONE, child_dip,
25563630Slg150142 	    "compatible", (char **)usba_name, n);
25573630Slg150142 
25583630Slg150142 	kmem_free(usba_name_buf, USBA_MAX_COMPAT_NAMES *
25593630Slg150142 	    USBA_MAX_COMPAT_NAME_LEN);
25603630Slg150142 
25613630Slg150142 	if (rval != DDI_PROP_SUCCESS) {
25623630Slg150142 
25633630Slg150142 		goto fail;
25643341Sgc161489 	}
25653341Sgc161489 
25663341Sgc161489 	/* update the address property */
25673341Sgc161489 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
25683341Sgc161489 	    "assigned-address", child_ud->usb_addr);
25693341Sgc161489 	if (rval != DDI_PROP_SUCCESS) {
25703341Sgc161489 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
25713341Sgc161489 		    "usba_ready_interface_node: address update failed");
25723341Sgc161489 	}
25733341Sgc161489 
25743341Sgc161489 	/* create property with first interface number */
25753341Sgc161489 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
25763341Sgc161489 	    "interface", ia_descr.bFirstInterface);
25773341Sgc161489 
25783341Sgc161489 	if (rval != DDI_PROP_SUCCESS) {
25793341Sgc161489 
25803341Sgc161489 		goto fail;
25813341Sgc161489 	}
25823341Sgc161489 
25833341Sgc161489 	/* create property with the count of interfaces in this ia */
25843341Sgc161489 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
25853341Sgc161489 	    "interface-count", ia_descr.bInterfaceCount);
25863341Sgc161489 
25873341Sgc161489 	if (rval != DDI_PROP_SUCCESS) {
25883341Sgc161489 
25893341Sgc161489 		goto fail;
25903341Sgc161489 	}
25913341Sgc161489 
25923341Sgc161489 	USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
25933341Sgc161489 	    "%s%d port %d: %s, dip = 0x%p",
25943341Sgc161489 	    ddi_node_name(ddi_get_parent(dip)),
25953341Sgc161489 	    ddi_get_instance(ddi_get_parent(dip)),
25966898Sfb209375 	    child_ud->usb_port, ddi_node_name(child_dip), (void *)child_dip);
25973341Sgc161489 
25983341Sgc161489 	*if_count = ia_descr.bInterfaceCount;
25993341Sgc161489 	usba_set_usba_device(child_dip, child_ud);
26003341Sgc161489 	ASSERT(!mutex_owned(&(usba_get_usba_device(child_dip)->usb_mutex)));
26013341Sgc161489 
26023341Sgc161489 	return (child_dip);
26033341Sgc161489 
26043341Sgc161489 fail:
26053341Sgc161489 	(void) usba_destroy_child_devi(child_dip, NDI_DEVI_REMOVE);
26063341Sgc161489 
26073341Sgc161489 	return (NULL);
26083341Sgc161489 }
26093341Sgc161489 
26103341Sgc161489 
26113341Sgc161489 /*
26120Sstevel@tonic-gate  * driver binding at interface level, the first arg will be the
26130Sstevel@tonic-gate  * the parent dip
26140Sstevel@tonic-gate  */
26150Sstevel@tonic-gate /*ARGSUSED*/
26160Sstevel@tonic-gate dev_info_t *
usba_ready_interface_node(dev_info_t * dip,uint_t intf)26170Sstevel@tonic-gate usba_ready_interface_node(dev_info_t *dip, uint_t intf)
26180Sstevel@tonic-gate {
26190Sstevel@tonic-gate 	dev_info_t		*child_dip = NULL;
26200Sstevel@tonic-gate 	usba_device_t		*child_ud = usba_get_usba_device(dip);
26210Sstevel@tonic-gate 	usb_dev_descr_t	*usb_dev_descr;
26220Sstevel@tonic-gate 	size_t			usb_cfg_length;
26230Sstevel@tonic-gate 	uchar_t 		*usb_cfg;
26240Sstevel@tonic-gate 	usb_if_descr_t	if_descr;
26250Sstevel@tonic-gate 	int			i, n, rval;
26260Sstevel@tonic-gate 	int			reg[2];
26270Sstevel@tonic-gate 	size_t			size;
26280Sstevel@tonic-gate 	usb_port_status_t	port_status;
26290Sstevel@tonic-gate 	char			*force_bind = NULL;
26303630Slg150142 	char			*usba_name_buf = NULL;
26313630Slg150142 	char			*usba_name[USBA_MAX_COMPAT_NAMES];
26320Sstevel@tonic-gate 
26330Sstevel@tonic-gate 	usb_cfg = usb_get_raw_cfg_data(dip, &usb_cfg_length);
26340Sstevel@tonic-gate 
26350Sstevel@tonic-gate 	mutex_enter(&child_ud->usb_mutex);
26360Sstevel@tonic-gate 
26370Sstevel@tonic-gate 	usb_dev_descr = child_ud->usb_dev_descr;
26380Sstevel@tonic-gate 
26390Sstevel@tonic-gate 	/*
26400Sstevel@tonic-gate 	 * for each interface, determine all compatible names
26410Sstevel@tonic-gate 	 */
26420Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
26430Sstevel@tonic-gate 	    "usba_ready_interface_node: "
26440Sstevel@tonic-gate 	    "port %d, interface = %d port status = %x",
26450Sstevel@tonic-gate 	    child_ud->usb_port, intf, child_ud->usb_port_status);
26460Sstevel@tonic-gate 
26470Sstevel@tonic-gate 	/* Parse the interface descriptor */
26480Sstevel@tonic-gate 	size = usb_parse_if_descr(
26496112Sqz150045 	    usb_cfg,
26506112Sqz150045 	    usb_cfg_length,
26516112Sqz150045 	    intf,		/* interface index */
26526112Sqz150045 	    0,		/* alt interface index */
26536112Sqz150045 	    &if_descr,
26546112Sqz150045 	    USB_IF_DESCR_SIZE);
26550Sstevel@tonic-gate 
26560Sstevel@tonic-gate 	if (size != USB_IF_DESCR_SIZE) {
2657978Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
26580Sstevel@tonic-gate 		    "parsing interface: size (%lu) != USB_IF_DESCR_SIZE (%d)",
26590Sstevel@tonic-gate 		    size, USB_IF_DESCR_SIZE);
26600Sstevel@tonic-gate 		mutex_exit(&child_ud->usb_mutex);
26610Sstevel@tonic-gate 
26620Sstevel@tonic-gate 		return (NULL);
26630Sstevel@tonic-gate 	}
26640Sstevel@tonic-gate 
26650Sstevel@tonic-gate 	port_status = child_ud->usb_port_status;
26660Sstevel@tonic-gate 
26670Sstevel@tonic-gate 	/* create reg property */
26680Sstevel@tonic-gate 	reg[0] = intf;
26690Sstevel@tonic-gate 	reg[1] = child_ud->usb_cfg_value;
26700Sstevel@tonic-gate 
26710Sstevel@tonic-gate 	mutex_exit(&child_ud->usb_mutex);
26720Sstevel@tonic-gate 
26730Sstevel@tonic-gate 	/* clone this dip */
26740Sstevel@tonic-gate 	rval =	usba_create_child_devi(dip,
26756112Sqz150045 	    "interface",
26766112Sqz150045 	    NULL,		/* usba_hcdi ops */
26776112Sqz150045 	    NULL,		/* root hub dip */
26786112Sqz150045 	    port_status,	/* port status */
26796112Sqz150045 	    child_ud,	/* share this usba_device */
26806112Sqz150045 	    &child_dip);
26810Sstevel@tonic-gate 
26820Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
26830Sstevel@tonic-gate 
26840Sstevel@tonic-gate 		goto fail;
26850Sstevel@tonic-gate 	}
26860Sstevel@tonic-gate 
26870Sstevel@tonic-gate 	rval = ndi_prop_update_int_array(
26886112Sqz150045 	    DDI_DEV_T_NONE, child_dip, "reg", reg, 2);
26890Sstevel@tonic-gate 
26900Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
26910Sstevel@tonic-gate 
26920Sstevel@tonic-gate 		goto fail;
26930Sstevel@tonic-gate 	}
26940Sstevel@tonic-gate 
26950Sstevel@tonic-gate 	usba_set_node_name(child_dip, if_descr.bInterfaceClass,
26960Sstevel@tonic-gate 	    if_descr.bInterfaceSubClass, if_descr.bInterfaceProtocol,
26970Sstevel@tonic-gate 	    FLAG_INTERFACE_NODE);
26980Sstevel@tonic-gate 
26990Sstevel@tonic-gate 	/* check force binding */
27000Sstevel@tonic-gate 	if (usba_ugen_force_binding == USBA_UGEN_INTERFACE_BINDING) {
27010Sstevel@tonic-gate 		force_bind = "ugen";
27020Sstevel@tonic-gate 	}
27030Sstevel@tonic-gate 
27040Sstevel@tonic-gate 	/*
27050Sstevel@tonic-gate 	 * check whether there is another dip with this name and address
27060Sstevel@tonic-gate 	 */
27070Sstevel@tonic-gate 	ASSERT(usba_find_existing_node(child_dip) == NULL);
27080Sstevel@tonic-gate 
27093630Slg150142 	usba_name_buf = kmem_zalloc(USBA_MAX_COMPAT_NAMES *
27103630Slg150142 	    USBA_MAX_COMPAT_NAME_LEN, KM_SLEEP);
27113630Slg150142 
27123630Slg150142 	for (i = 0; i < USBA_MAX_COMPAT_NAMES; i++) {
27133630Slg150142 		usba_name[i] = usba_name_buf + (i * USBA_MAX_COMPAT_NAME_LEN);
27143630Slg150142 	}
27153630Slg150142 
27160Sstevel@tonic-gate 	n = 0;
27170Sstevel@tonic-gate 
27180Sstevel@tonic-gate 	if (force_bind) {
27190Sstevel@tonic-gate 		(void) ndi_devi_set_nodename(child_dip, force_bind, 0);
27200Sstevel@tonic-gate 		(void) strncpy(usba_name[n++], force_bind,
27216112Sqz150045 		    USBA_MAX_COMPAT_NAME_LEN);
27220Sstevel@tonic-gate 	}
27230Sstevel@tonic-gate 
27240Sstevel@tonic-gate 	/* 1) usbifVID,PID.REV.configCN.IN */
27250Sstevel@tonic-gate 	(void) sprintf(usba_name[n++],
27266112Sqz150045 	    "usbif%x,%x.%x.config%x.%x",
27276112Sqz150045 	    usb_dev_descr->idVendor,
27286112Sqz150045 	    usb_dev_descr->idProduct,
27296112Sqz150045 	    usb_dev_descr->bcdDevice,
27306112Sqz150045 	    child_ud->usb_cfg_value,
27316112Sqz150045 	    intf);
27320Sstevel@tonic-gate 
27330Sstevel@tonic-gate 	/* 2) usbifVID,PID.configCN.IN */
27340Sstevel@tonic-gate 	(void) sprintf(usba_name[n++],
27356112Sqz150045 	    "usbif%x,%x.config%x.%x",
27366112Sqz150045 	    usb_dev_descr->idVendor,
27376112Sqz150045 	    usb_dev_descr->idProduct,
27386112Sqz150045 	    child_ud->usb_cfg_value,
27396112Sqz150045 	    intf);
27400Sstevel@tonic-gate 
27410Sstevel@tonic-gate 
27420Sstevel@tonic-gate 	if (if_descr.bInterfaceClass) {
27430Sstevel@tonic-gate 		/* 3) usbifVID,classIC.ISC.IPROTO */
27440Sstevel@tonic-gate 		(void) sprintf(usba_name[n++],
27456112Sqz150045 		    "usbif%x,class%x.%x.%x",
27466112Sqz150045 		    usb_dev_descr->idVendor,
27476112Sqz150045 		    if_descr.bInterfaceClass,
27486112Sqz150045 		    if_descr.bInterfaceSubClass,
27496112Sqz150045 		    if_descr.bInterfaceProtocol);
27500Sstevel@tonic-gate 
27510Sstevel@tonic-gate 		/* 4) usbifVID,classIC.ISC */
27520Sstevel@tonic-gate 		(void) sprintf(usba_name[n++],
27536112Sqz150045 		    "usbif%x,class%x.%x",
27546112Sqz150045 		    usb_dev_descr->idVendor,
27556112Sqz150045 		    if_descr.bInterfaceClass,
27566112Sqz150045 		    if_descr.bInterfaceSubClass);
27570Sstevel@tonic-gate 
27580Sstevel@tonic-gate 		/* 5) usbifVID,classIC */
27590Sstevel@tonic-gate 		(void) sprintf(usba_name[n++],
27606112Sqz150045 		    "usbif%x,class%x",
27616112Sqz150045 		    usb_dev_descr->idVendor,
27626112Sqz150045 		    if_descr.bInterfaceClass);
27630Sstevel@tonic-gate 
27640Sstevel@tonic-gate 		/* 6) usbif,classIC.ISC.IPROTO */
27650Sstevel@tonic-gate 		(void) sprintf(usba_name[n++],
27666112Sqz150045 		    "usbif,class%x.%x.%x",
27676112Sqz150045 		    if_descr.bInterfaceClass,
27686112Sqz150045 		    if_descr.bInterfaceSubClass,
27696112Sqz150045 		    if_descr.bInterfaceProtocol);
27700Sstevel@tonic-gate 
27710Sstevel@tonic-gate 		/* 7) usbif,classIC.ISC */
27720Sstevel@tonic-gate 		(void) sprintf(usba_name[n++],
27736112Sqz150045 		    "usbif,class%x.%x",
27746112Sqz150045 		    if_descr.bInterfaceClass,
27756112Sqz150045 		    if_descr.bInterfaceSubClass);
27760Sstevel@tonic-gate 
27770Sstevel@tonic-gate 		/* 8) usbif,classIC */
27780Sstevel@tonic-gate 		(void) sprintf(usba_name[n++],
27796112Sqz150045 		    "usbif,class%x",
27806112Sqz150045 		    if_descr.bInterfaceClass);
27810Sstevel@tonic-gate 	}
27820Sstevel@tonic-gate 
27830Sstevel@tonic-gate 	if (usba_get_ugen_binding(child_dip) ==
27840Sstevel@tonic-gate 	    USBA_UGEN_INTERFACE_BINDING) {
27850Sstevel@tonic-gate 		/* 9) ugen */
27860Sstevel@tonic-gate 		(void) sprintf(usba_name[n++], "ugen");
27870Sstevel@tonic-gate 	}
27880Sstevel@tonic-gate 
27890Sstevel@tonic-gate 	for (i = 0; i < n; i += 2) {
27900Sstevel@tonic-gate 		USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
27913630Slg150142 		    "compatible name:\t%s\t%s", usba_name[i],
27923630Slg150142 		    (((i+1) < n)? usba_name[i+1] : ""));
27930Sstevel@tonic-gate 	}
27940Sstevel@tonic-gate 
27950Sstevel@tonic-gate 	/* create compatible property */
27963630Slg150142 	rval = ndi_prop_update_string_array(DDI_DEV_T_NONE, child_dip,
27973630Slg150142 	    "compatible", (char **)usba_name, n);
27983630Slg150142 
27993630Slg150142 	kmem_free(usba_name_buf, USBA_MAX_COMPAT_NAMES *
28003630Slg150142 	    USBA_MAX_COMPAT_NAME_LEN);
28013630Slg150142 
28023630Slg150142 	if (rval != DDI_PROP_SUCCESS) {
28033630Slg150142 
28043630Slg150142 		goto fail;
28050Sstevel@tonic-gate 	}
28060Sstevel@tonic-gate 
28070Sstevel@tonic-gate 	/* update the address property */
28080Sstevel@tonic-gate 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
28096112Sqz150045 	    "assigned-address", child_ud->usb_addr);
28100Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
2811978Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
28120Sstevel@tonic-gate 		    "usba_ready_interface_node: address update failed");
28130Sstevel@tonic-gate 	}
28140Sstevel@tonic-gate 
28150Sstevel@tonic-gate 	/* create property with if number */
28160Sstevel@tonic-gate 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
28176112Sqz150045 	    "interface", intf);
28180Sstevel@tonic-gate 
28190Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
28200Sstevel@tonic-gate 
28210Sstevel@tonic-gate 		goto fail;
28220Sstevel@tonic-gate 	}
28230Sstevel@tonic-gate 
28240Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
28250Sstevel@tonic-gate 	    "%s%d port %d: %s, dip = 0x%p",
28260Sstevel@tonic-gate 	    ddi_node_name(ddi_get_parent(dip)),
28270Sstevel@tonic-gate 	    ddi_get_instance(ddi_get_parent(dip)),
28286898Sfb209375 	    child_ud->usb_port, ddi_node_name(child_dip), (void *)child_dip);
28290Sstevel@tonic-gate 
28300Sstevel@tonic-gate 	usba_set_usba_device(child_dip, child_ud);
28310Sstevel@tonic-gate 	ASSERT(!mutex_owned(&(usba_get_usba_device(child_dip)->usb_mutex)));
28320Sstevel@tonic-gate 
28330Sstevel@tonic-gate 	return (child_dip);
28340Sstevel@tonic-gate 
28350Sstevel@tonic-gate fail:
28360Sstevel@tonic-gate 	(void) usba_destroy_child_devi(child_dip, NDI_DEVI_REMOVE);
28370Sstevel@tonic-gate 
28380Sstevel@tonic-gate 	return (NULL);
28390Sstevel@tonic-gate }
28400Sstevel@tonic-gate 
28410Sstevel@tonic-gate 
28420Sstevel@tonic-gate /*
28430Sstevel@tonic-gate  * retrieve string descriptors for manufacturer, vendor and serial
28440Sstevel@tonic-gate  * number
28450Sstevel@tonic-gate  */
28460Sstevel@tonic-gate void
usba_get_dev_string_descrs(dev_info_t * dip,usba_device_t * ud)28470Sstevel@tonic-gate usba_get_dev_string_descrs(dev_info_t *dip, usba_device_t *ud)
28480Sstevel@tonic-gate {
28490Sstevel@tonic-gate 	char	*tmpbuf, *str;
28500Sstevel@tonic-gate 	int	l;
28510Sstevel@tonic-gate 	usb_dev_descr_t *usb_dev_descr = ud->usb_dev_descr;
28520Sstevel@tonic-gate 
28530Sstevel@tonic-gate 
28540Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
28550Sstevel@tonic-gate 	    "usba_get_usb_string_descr: m=%d, p=%d, s=%d",
28560Sstevel@tonic-gate 	    usb_dev_descr->iManufacturer,
28570Sstevel@tonic-gate 	    usb_dev_descr->iProduct,
28580Sstevel@tonic-gate 	    usb_dev_descr->iSerialNumber);
28590Sstevel@tonic-gate 
28600Sstevel@tonic-gate 	tmpbuf = kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP);
28610Sstevel@tonic-gate 
28620Sstevel@tonic-gate 	/* fetch manufacturer string */
28630Sstevel@tonic-gate 	if ((ud->usb_mfg_str == NULL) && usb_dev_descr->iManufacturer &&
28640Sstevel@tonic-gate 	    (usb_get_string_descr(dip, USB_LANG_ID,
28656112Sqz150045 	    usb_dev_descr->iManufacturer, tmpbuf, USB_MAXSTRINGLEN) ==
28666112Sqz150045 	    USB_SUCCESS)) {
28670Sstevel@tonic-gate 
28680Sstevel@tonic-gate 		l = strlen(tmpbuf);
28690Sstevel@tonic-gate 		if (l > 0) {
28700Sstevel@tonic-gate 			str = kmem_zalloc(l + 1, KM_SLEEP);
28710Sstevel@tonic-gate 			mutex_enter(&ud->usb_mutex);
28720Sstevel@tonic-gate 			ud->usb_mfg_str = str;
28730Sstevel@tonic-gate 			(void) strcpy(ud->usb_mfg_str, tmpbuf);
28740Sstevel@tonic-gate 			mutex_exit(&ud->usb_mutex);
28750Sstevel@tonic-gate 		}
28760Sstevel@tonic-gate 	}
28770Sstevel@tonic-gate 
28780Sstevel@tonic-gate 	/* fetch product string */
28790Sstevel@tonic-gate 	if ((ud->usb_product_str == NULL) && usb_dev_descr->iProduct &&
28800Sstevel@tonic-gate 	    (usb_get_string_descr(dip, USB_LANG_ID, usb_dev_descr->iProduct,
28810Sstevel@tonic-gate 	    tmpbuf, USB_MAXSTRINGLEN) ==
28826112Sqz150045 	    USB_SUCCESS)) {
28830Sstevel@tonic-gate 
28840Sstevel@tonic-gate 		l = strlen(tmpbuf);
28850Sstevel@tonic-gate 		if (l > 0) {
28860Sstevel@tonic-gate 			str = kmem_zalloc(l + 1, KM_SLEEP);
28870Sstevel@tonic-gate 			mutex_enter(&ud->usb_mutex);
28880Sstevel@tonic-gate 			ud->usb_product_str = str;
28890Sstevel@tonic-gate 			(void) strcpy(ud->usb_product_str, tmpbuf);
28900Sstevel@tonic-gate 			mutex_exit(&ud->usb_mutex);
28910Sstevel@tonic-gate 		}
28920Sstevel@tonic-gate 	}
28930Sstevel@tonic-gate 
28940Sstevel@tonic-gate 	/* fetch device serial number string */
28950Sstevel@tonic-gate 	if ((ud->usb_serialno_str == NULL) && usb_dev_descr->iSerialNumber &&
28960Sstevel@tonic-gate 	    (usb_get_string_descr(dip, USB_LANG_ID,
28976112Sqz150045 	    usb_dev_descr->iSerialNumber, tmpbuf, USB_MAXSTRINGLEN) ==
28986112Sqz150045 	    USB_SUCCESS)) {
28990Sstevel@tonic-gate 
29000Sstevel@tonic-gate 		l = strlen(tmpbuf);
29010Sstevel@tonic-gate 		if (l > 0) {
29020Sstevel@tonic-gate 			str = kmem_zalloc(l + 1, KM_SLEEP);
29030Sstevel@tonic-gate 			mutex_enter(&ud->usb_mutex);
29040Sstevel@tonic-gate 			ud->usb_serialno_str = str;
29050Sstevel@tonic-gate 			(void) strcpy(ud->usb_serialno_str, tmpbuf);
29060Sstevel@tonic-gate 			mutex_exit(&ud->usb_mutex);
29070Sstevel@tonic-gate 		}
29080Sstevel@tonic-gate 	}
29090Sstevel@tonic-gate 
29100Sstevel@tonic-gate 	kmem_free(tmpbuf, USB_MAXSTRINGLEN);
29110Sstevel@tonic-gate }
29120Sstevel@tonic-gate 
29130Sstevel@tonic-gate 
29140Sstevel@tonic-gate /*
29150Sstevel@tonic-gate  * usba_str_startcmp:
29160Sstevel@tonic-gate  *	Return the number of characters duplicated from the beginning of the
29170Sstevel@tonic-gate  *	string.  Return -1 if a complete duplicate.
29180Sstevel@tonic-gate  *
29190Sstevel@tonic-gate  * Arguments:
29200Sstevel@tonic-gate  *	Two strings to compare.
29210Sstevel@tonic-gate  */
usba_str_startcmp(char * first,char * second)29220Sstevel@tonic-gate static int usba_str_startcmp(char *first, char *second)
29230Sstevel@tonic-gate {
29240Sstevel@tonic-gate 	int num_same_chars = 0;
29250Sstevel@tonic-gate 	while (*first == *second++) {
29260Sstevel@tonic-gate 		if (*first++ == '\0') {
29270Sstevel@tonic-gate 			return (-1);
29280Sstevel@tonic-gate 		}
29290Sstevel@tonic-gate 		num_same_chars++;
29300Sstevel@tonic-gate 	}
29310Sstevel@tonic-gate 
29320Sstevel@tonic-gate 	return (num_same_chars);
29330Sstevel@tonic-gate }
29340Sstevel@tonic-gate 
29350Sstevel@tonic-gate 
29360Sstevel@tonic-gate /*
29370Sstevel@tonic-gate  * usba_get_mfg_prod_sn_str:
29380Sstevel@tonic-gate  *	Return a string containing mfg, product, serial number strings.
29390Sstevel@tonic-gate  *	Remove duplicates if some strings are the same.
29400Sstevel@tonic-gate  *
29410Sstevel@tonic-gate  * Arguments:
29420Sstevel@tonic-gate  *	dip	- pointer to dev info
29430Sstevel@tonic-gate  *	buffer	- Where string is returned
29440Sstevel@tonic-gate  *	buflen	- Length of buffer
29450Sstevel@tonic-gate  *
29460Sstevel@tonic-gate  * Returns:
29470Sstevel@tonic-gate  *	Same as second arg.
29480Sstevel@tonic-gate  */
29490Sstevel@tonic-gate char *
usba_get_mfg_prod_sn_str(dev_info_t * dip,char * buffer,int buflen)29500Sstevel@tonic-gate usba_get_mfg_prod_sn_str(
29510Sstevel@tonic-gate     dev_info_t	*dip,
29520Sstevel@tonic-gate     char	*buffer,
29530Sstevel@tonic-gate     int		buflen)
29540Sstevel@tonic-gate {
29550Sstevel@tonic-gate 	usba_device_t *usba_device = usba_get_usba_device(dip);
29560Sstevel@tonic-gate 	int return_len = 0;
29570Sstevel@tonic-gate 	int len = 0;
29580Sstevel@tonic-gate 	int duplen;
29590Sstevel@tonic-gate 
29600Sstevel@tonic-gate 	buffer[0] = '\0';
29610Sstevel@tonic-gate 	buffer[buflen-1] = '\0';
29620Sstevel@tonic-gate 
29630Sstevel@tonic-gate 	if ((usba_device->usb_mfg_str) &&
29640Sstevel@tonic-gate 	    ((len = strlen(usba_device->usb_mfg_str)) != 0)) {
29650Sstevel@tonic-gate 		(void) strncpy(buffer, usba_device->usb_mfg_str, buflen - 1);
29660Sstevel@tonic-gate 		return_len = min(buflen - 1, len);
29670Sstevel@tonic-gate 	}
29680Sstevel@tonic-gate 
29690Sstevel@tonic-gate 	/* Product string exists to append. */
29700Sstevel@tonic-gate 	if ((usba_device->usb_product_str) &&
29710Sstevel@tonic-gate 	    ((len = strlen(usba_device->usb_product_str)) != 0)) {
29720Sstevel@tonic-gate 
29730Sstevel@tonic-gate 		/* Append only parts of string that don't match mfg string. */
29740Sstevel@tonic-gate 		duplen = usba_str_startcmp(buffer,
29756112Sqz150045 		    usba_device->usb_product_str);
29760Sstevel@tonic-gate 
29770Sstevel@tonic-gate 		if (duplen != -1) {		/* Not a complete match. */
29780Sstevel@tonic-gate 			if (return_len > 0) {
29790Sstevel@tonic-gate 				buffer[return_len++] = ' ';
29800Sstevel@tonic-gate 			}
29810Sstevel@tonic-gate 
29820Sstevel@tonic-gate 			/* Skip over the dup part of the concat'ed string. */
29830Sstevel@tonic-gate 			len -= duplen;
29840Sstevel@tonic-gate 			(void) strncpy(&buffer[return_len],
29850Sstevel@tonic-gate 			    &usba_device->usb_product_str[duplen],
29860Sstevel@tonic-gate 			    buflen - return_len - 1);
29870Sstevel@tonic-gate 			return_len = min(buflen - 1, return_len + len);
29880Sstevel@tonic-gate 		}
29890Sstevel@tonic-gate 	}
29900Sstevel@tonic-gate 
29910Sstevel@tonic-gate 	if ((usba_device->usb_serialno_str) &&
29920Sstevel@tonic-gate 	    ((len = strlen(usba_device->usb_serialno_str)) != 0)) {
29930Sstevel@tonic-gate 		if (return_len > 0) {
29940Sstevel@tonic-gate 			buffer[return_len++] = ' ';
29950Sstevel@tonic-gate 		}
29960Sstevel@tonic-gate 		(void) strncpy(&buffer[return_len],
29976112Sqz150045 		    usba_device->usb_serialno_str,
29986112Sqz150045 		    buflen - return_len - 1);
29990Sstevel@tonic-gate 	}
30000Sstevel@tonic-gate 
30010Sstevel@tonic-gate 	return (buffer);
30020Sstevel@tonic-gate }
30030Sstevel@tonic-gate 
30040Sstevel@tonic-gate 
30050Sstevel@tonic-gate /*
30060Sstevel@tonic-gate  * USB enumeration statistic functions
30070Sstevel@tonic-gate  */
30080Sstevel@tonic-gate 
30090Sstevel@tonic-gate /*
30100Sstevel@tonic-gate  * Increments the hotplug statistics based on flags.
30110Sstevel@tonic-gate  */
30120Sstevel@tonic-gate void
usba_update_hotplug_stats(dev_info_t * dip,usb_flags_t flags)30130Sstevel@tonic-gate usba_update_hotplug_stats(dev_info_t *dip, usb_flags_t flags)
30140Sstevel@tonic-gate {
30150Sstevel@tonic-gate 	usba_device_t	*usba_device = usba_get_usba_device(dip);
30160Sstevel@tonic-gate 	usba_hcdi_t	*hcdi =
30176112Sqz150045 	    usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
30180Sstevel@tonic-gate 
30190Sstevel@tonic-gate 	mutex_enter(&hcdi->hcdi_mutex);
30200Sstevel@tonic-gate 	if (flags & USBA_TOTAL_HOTPLUG_SUCCESS) {
30210Sstevel@tonic-gate 		hcdi->hcdi_total_hotplug_success++;
30220Sstevel@tonic-gate 		HCDI_HOTPLUG_STATS_DATA(hcdi)->
30230Sstevel@tonic-gate 		    hcdi_hotplug_total_success.value.ui64++;
30240Sstevel@tonic-gate 	}
30250Sstevel@tonic-gate 	if (flags & USBA_HOTPLUG_SUCCESS) {
30260Sstevel@tonic-gate 		hcdi->hcdi_hotplug_success++;
30270Sstevel@tonic-gate 		HCDI_HOTPLUG_STATS_DATA(hcdi)->
30280Sstevel@tonic-gate 		    hcdi_hotplug_success.value.ui64++;
30290Sstevel@tonic-gate 	}
30300Sstevel@tonic-gate 	if (flags & USBA_TOTAL_HOTPLUG_FAILURE) {
30310Sstevel@tonic-gate 		hcdi->hcdi_total_hotplug_failure++;
30320Sstevel@tonic-gate 		HCDI_HOTPLUG_STATS_DATA(hcdi)->
30330Sstevel@tonic-gate 		    hcdi_hotplug_total_failure.value.ui64++;
30340Sstevel@tonic-gate 	}
30350Sstevel@tonic-gate 	if (flags & USBA_HOTPLUG_FAILURE) {
30360Sstevel@tonic-gate 		hcdi->hcdi_hotplug_failure++;
30370Sstevel@tonic-gate 		HCDI_HOTPLUG_STATS_DATA(hcdi)->
30380Sstevel@tonic-gate 		    hcdi_hotplug_failure.value.ui64++;
30390Sstevel@tonic-gate 	}
30400Sstevel@tonic-gate 	mutex_exit(&hcdi->hcdi_mutex);
30410Sstevel@tonic-gate }
30420Sstevel@tonic-gate 
30430Sstevel@tonic-gate 
30440Sstevel@tonic-gate /*
30450Sstevel@tonic-gate  * Retrieve the current enumeration statistics
30460Sstevel@tonic-gate  */
30470Sstevel@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)30480Sstevel@tonic-gate usba_get_hotplug_stats(dev_info_t *dip, ulong_t *total_success,
30490Sstevel@tonic-gate     ulong_t *success, ulong_t *total_failure, ulong_t *failure,
30500Sstevel@tonic-gate     uchar_t *device_count)
30510Sstevel@tonic-gate {
30520Sstevel@tonic-gate 	usba_device_t	*usba_device = usba_get_usba_device(dip);
30530Sstevel@tonic-gate 	usba_hcdi_t	*hcdi =
30546112Sqz150045 	    usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
30550Sstevel@tonic-gate 
30560Sstevel@tonic-gate 	mutex_enter(&hcdi->hcdi_mutex);
30570Sstevel@tonic-gate 	*total_success = hcdi->hcdi_total_hotplug_success;
30580Sstevel@tonic-gate 	*success = hcdi->hcdi_hotplug_success;
30590Sstevel@tonic-gate 	*total_failure = hcdi->hcdi_total_hotplug_failure;
30600Sstevel@tonic-gate 	*failure = hcdi->hcdi_hotplug_failure;
30610Sstevel@tonic-gate 	*device_count = hcdi->hcdi_device_count;
30620Sstevel@tonic-gate 	mutex_exit(&hcdi->hcdi_mutex);
30630Sstevel@tonic-gate }
30640Sstevel@tonic-gate 
30650Sstevel@tonic-gate 
30660Sstevel@tonic-gate /*
30670Sstevel@tonic-gate  * Reset the resetable hotplug stats
30680Sstevel@tonic-gate  */
30690Sstevel@tonic-gate void
usba_reset_hotplug_stats(dev_info_t * dip)30700Sstevel@tonic-gate usba_reset_hotplug_stats(dev_info_t *dip)
30710Sstevel@tonic-gate {
30720Sstevel@tonic-gate 	usba_device_t	*usba_device = usba_get_usba_device(dip);
30730Sstevel@tonic-gate 	usba_hcdi_t	*hcdi =
30746112Sqz150045 	    usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
30750Sstevel@tonic-gate 	hcdi_hotplug_stats_t *hsp;
30760Sstevel@tonic-gate 
30770Sstevel@tonic-gate 	mutex_enter(&hcdi->hcdi_mutex);
30780Sstevel@tonic-gate 	hcdi->hcdi_hotplug_success = 0;
30790Sstevel@tonic-gate 	hcdi->hcdi_hotplug_failure = 0;
30800Sstevel@tonic-gate 
30810Sstevel@tonic-gate 	hsp = HCDI_HOTPLUG_STATS_DATA(hcdi);
30820Sstevel@tonic-gate 	hsp->hcdi_hotplug_success.value.ui64 = 0;
30830Sstevel@tonic-gate 	hsp->hcdi_hotplug_failure.value.ui64 = 0;
30840Sstevel@tonic-gate 	mutex_exit(&hcdi->hcdi_mutex);
30850Sstevel@tonic-gate }
30860Sstevel@tonic-gate 
30870Sstevel@tonic-gate 
30880Sstevel@tonic-gate /*
30890Sstevel@tonic-gate  * usba_bind_driver():
30900Sstevel@tonic-gate  *	This function calls ndi_devi_bind_driver() which tries to
30910Sstevel@tonic-gate  *	bind a driver to the device.  If the driver binding fails
30920Sstevel@tonic-gate  *	we get an rval of NDI_UNBOUD and report an error to the
30930Sstevel@tonic-gate  *	syslog that the driver failed binding.
30940Sstevel@tonic-gate  *	If rval is something other than NDI_UNBOUND we report an
30950Sstevel@tonic-gate  *	error to the console.
30960Sstevel@tonic-gate  *
30970Sstevel@tonic-gate  *	This function returns USB_SUCCESS if no errors were
30980Sstevel@tonic-gate  *	encountered while binding.
30990Sstevel@tonic-gate  */
31000Sstevel@tonic-gate int
usba_bind_driver(dev_info_t * dip)31010Sstevel@tonic-gate usba_bind_driver(dev_info_t *dip)
31020Sstevel@tonic-gate {
31030Sstevel@tonic-gate 	int	rval;
31040Sstevel@tonic-gate 	char	*name;
31050Sstevel@tonic-gate 	uint8_t if_num = usba_get_ifno(dip);
31060Sstevel@tonic-gate 
31070Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
31086898Sfb209375 	    "usba_bind_driver: dip = 0x%p, if_num = 0x%x", (void *)dip, if_num);
31090Sstevel@tonic-gate 
31100Sstevel@tonic-gate 	name = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
31110Sstevel@tonic-gate 
31120Sstevel@tonic-gate 	/* bind device to the driver */
31130Sstevel@tonic-gate 	if ((rval = ndi_devi_bind_driver(dip, 0)) != NDI_SUCCESS) {
31140Sstevel@tonic-gate 		/* if we fail to bind report an error */
31150Sstevel@tonic-gate 		(void) usba_get_mfg_prod_sn_str(dip, name, MAXNAMELEN);
31160Sstevel@tonic-gate 		if (name[0] != '\0') {
31170Sstevel@tonic-gate 			if (!usb_owns_device(dip)) {
31180Sstevel@tonic-gate 				USB_DPRINTF_L1(DPRINT_MASK_USBA,
31190Sstevel@tonic-gate 				    usba_log_handle,
31200Sstevel@tonic-gate 				    "no driver found for "
31210Sstevel@tonic-gate 				    "interface %d (nodename: '%s') of %s",
31220Sstevel@tonic-gate 				    if_num, ddi_node_name(dip), name);
31230Sstevel@tonic-gate 			} else {
31240Sstevel@tonic-gate 				USB_DPRINTF_L1(DPRINT_MASK_USBA,
31250Sstevel@tonic-gate 				    usba_log_handle,
31260Sstevel@tonic-gate 				    "no driver found for device %s", name);
31270Sstevel@tonic-gate 			}
31280Sstevel@tonic-gate 		} else {
31290Sstevel@tonic-gate 			(void) ddi_pathname(dip, name);
31300Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_USBA,
31310Sstevel@tonic-gate 			    usba_log_handle,
31320Sstevel@tonic-gate 			    "no driver found for device %s", name);
31330Sstevel@tonic-gate 		}
31340Sstevel@tonic-gate 
31350Sstevel@tonic-gate 		kmem_free(name, MAXNAMELEN);
31360Sstevel@tonic-gate 
31370Sstevel@tonic-gate 		return (USB_FAILURE);
31380Sstevel@tonic-gate 	}
31390Sstevel@tonic-gate 	kmem_free(name, MAXNAMELEN);
31400Sstevel@tonic-gate 
31410Sstevel@tonic-gate 	return ((rval == NDI_SUCCESS) ? USB_SUCCESS : USB_FAILURE);
31420Sstevel@tonic-gate }
31430Sstevel@tonic-gate 
31440Sstevel@tonic-gate 
31450Sstevel@tonic-gate /*
31460Sstevel@tonic-gate  * usba_get_hc_dma_attr:
31470Sstevel@tonic-gate  *	function returning dma attributes of the HCD
31480Sstevel@tonic-gate  *
31490Sstevel@tonic-gate  * Arguments:
31500Sstevel@tonic-gate  *	dip	- pointer to devinfo of the client
31510Sstevel@tonic-gate  *
31520Sstevel@tonic-gate  * Return Values:
31530Sstevel@tonic-gate  *	hcdi_dma_attr
31540Sstevel@tonic-gate  */
31550Sstevel@tonic-gate ddi_dma_attr_t *
usba_get_hc_dma_attr(dev_info_t * dip)31560Sstevel@tonic-gate usba_get_hc_dma_attr(dev_info_t *dip)
31570Sstevel@tonic-gate {
31580Sstevel@tonic-gate 	usba_device_t *usba_device = usba_get_usba_device(dip);
31590Sstevel@tonic-gate 	usba_hcdi_t *hcdi = usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
31600Sstevel@tonic-gate 
31610Sstevel@tonic-gate 	return (hcdi->hcdi_dma_attr);
31620Sstevel@tonic-gate }
31630Sstevel@tonic-gate 
31640Sstevel@tonic-gate 
31650Sstevel@tonic-gate /*
31660Sstevel@tonic-gate  * usba_check_for_leaks:
31670Sstevel@tonic-gate  *	check usba_device structure for leaks
31680Sstevel@tonic-gate  *
31690Sstevel@tonic-gate  * Arguments:
31700Sstevel@tonic-gate  *	usba_device	- usba_device structure pointer
31710Sstevel@tonic-gate  */
31720Sstevel@tonic-gate void
usba_check_for_leaks(usba_device_t * usba_device)31730Sstevel@tonic-gate usba_check_for_leaks(usba_device_t *usba_device)
31740Sstevel@tonic-gate {
31750Sstevel@tonic-gate 	int i, ph_open_cnt, req_wrp_leaks, iface;
31760Sstevel@tonic-gate 	int leaks = 0;
31770Sstevel@tonic-gate 
31780Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
31790Sstevel@tonic-gate 	    "usba_check_for_leaks: %s%d usba_device=0x%p",
31800Sstevel@tonic-gate 	    ddi_driver_name(usba_device->usb_dip),
31816898Sfb209375 	    ddi_get_instance(usba_device->usb_dip), (void *)usba_device);
31820Sstevel@tonic-gate 
31830Sstevel@tonic-gate 	/*
31840Sstevel@tonic-gate 	 * default pipe is still open
31850Sstevel@tonic-gate 	 * all other pipes should be closed
31860Sstevel@tonic-gate 	 */
31870Sstevel@tonic-gate 	for (ph_open_cnt = 0, i = 1; i < USBA_N_ENDPOINTS; i++) {
31880Sstevel@tonic-gate 		usba_ph_impl_t *ph_impl =
31890Sstevel@tonic-gate 		    &usba_device->usb_ph_list[i];
31900Sstevel@tonic-gate 		if (ph_impl->usba_ph_data) {
3191978Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_USBA,
31920Sstevel@tonic-gate 			    usba_log_handle,
31930Sstevel@tonic-gate 			    "%s%d: leaking pipehandle=0x%p (0x%p) ep_addr=0x%x",
31940Sstevel@tonic-gate 			    ddi_driver_name(ph_impl->usba_ph_data->p_dip),
31950Sstevel@tonic-gate 			    ddi_get_instance(ph_impl->usba_ph_data->p_dip),
31966898Sfb209375 			    (void *)ph_impl,
31976898Sfb209375 			    (void *)ph_impl->usba_ph_data,
31980Sstevel@tonic-gate 			    ph_impl->usba_ph_ep.bEndpointAddress);
31990Sstevel@tonic-gate 			ph_open_cnt++;
32000Sstevel@tonic-gate 			leaks++;
32010Sstevel@tonic-gate #ifndef DEBUG
32020Sstevel@tonic-gate 			usb_pipe_close(ph_impl->usba_ph_data->p_dip,
32030Sstevel@tonic-gate 			    (usb_pipe_handle_t)ph_impl, USB_FLAGS_SLEEP,
32040Sstevel@tonic-gate 			    NULL, NULL);
32050Sstevel@tonic-gate #endif
32060Sstevel@tonic-gate 		}
32070Sstevel@tonic-gate 	}
32080Sstevel@tonic-gate 	req_wrp_leaks =  usba_list_entry_leaks(&usba_device->
32090Sstevel@tonic-gate 	    usb_allocated, "request wrappers");
32100Sstevel@tonic-gate 
32110Sstevel@tonic-gate 	ASSERT(ph_open_cnt == 0);
32120Sstevel@tonic-gate 	ASSERT(req_wrp_leaks == 0);
32130Sstevel@tonic-gate 
32140Sstevel@tonic-gate 	if (req_wrp_leaks) {
32150Sstevel@tonic-gate 		usba_list_entry_t *entry;
32160Sstevel@tonic-gate 
32170Sstevel@tonic-gate 		while ((entry = usba_rm_first_from_list(
32180Sstevel@tonic-gate 		    &usba_device->usb_allocated)) != NULL) {
32190Sstevel@tonic-gate 			usba_req_wrapper_t *wrp;
32200Sstevel@tonic-gate 
32210Sstevel@tonic-gate 			mutex_enter(&entry->list_mutex);
32220Sstevel@tonic-gate 			wrp = (usba_req_wrapper_t *)entry->private;
32230Sstevel@tonic-gate 			mutex_exit(&entry->list_mutex);
32240Sstevel@tonic-gate 			leaks++;
32250Sstevel@tonic-gate 
3226978Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_USBA,
32270Sstevel@tonic-gate 			    usba_log_handle,
32280Sstevel@tonic-gate 			    "%s%d: leaking request 0x%p",
32290Sstevel@tonic-gate 			    ddi_driver_name(wrp->wr_dip),
32300Sstevel@tonic-gate 			    ddi_get_instance(wrp->wr_dip),
32316898Sfb209375 			    (void *)wrp->wr_req);
32320Sstevel@tonic-gate 
32330Sstevel@tonic-gate 			/*
32340Sstevel@tonic-gate 			 * put it back, usba_req_wrapper_free
32350Sstevel@tonic-gate 			 * expects it on the list
32360Sstevel@tonic-gate 			 */
32370Sstevel@tonic-gate 			usba_add_to_list(&usba_device->usb_allocated,
32380Sstevel@tonic-gate 			    &wrp->wr_allocated_list);
32390Sstevel@tonic-gate 
32400Sstevel@tonic-gate 			usba_req_wrapper_free(wrp);
32410Sstevel@tonic-gate 		}
32420Sstevel@tonic-gate 	}
32430Sstevel@tonic-gate 
32440Sstevel@tonic-gate 	mutex_enter(&usba_device->usb_mutex);
32450Sstevel@tonic-gate 	for (iface = 0; iface < usba_device->usb_n_ifs; iface++) {
32460Sstevel@tonic-gate 		USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
32470Sstevel@tonic-gate 		    "usba_check_for_leaks: if=%d client_flags=0x%x",
32480Sstevel@tonic-gate 		    iface, usba_device->usb_client_flags[iface]);
32490Sstevel@tonic-gate 
32500Sstevel@tonic-gate 		if (usba_device->usb_client_flags[iface] &
32510Sstevel@tonic-gate 		    USBA_CLIENT_FLAG_DEV_DATA) {
32520Sstevel@tonic-gate 			usb_client_dev_data_list_t *entry =
32530Sstevel@tonic-gate 			    usba_device->usb_client_dev_data_list.cddl_next;
32540Sstevel@tonic-gate 			usb_client_dev_data_list_t *next;
32550Sstevel@tonic-gate 			usb_client_dev_data_t *dev_data;
32560Sstevel@tonic-gate 
32570Sstevel@tonic-gate 			while (entry) {
32580Sstevel@tonic-gate 				dev_info_t *dip = entry->cddl_dip;
32590Sstevel@tonic-gate 				next = entry->cddl_next;
32600Sstevel@tonic-gate 				dev_data = entry->cddl_dev_data;
32610Sstevel@tonic-gate 
32620Sstevel@tonic-gate 
32631333Scth 				if (!i_ddi_devi_attached(dip)) {
3264978Sfrits 					USB_DPRINTF_L2(DPRINT_MASK_USBA,
32650Sstevel@tonic-gate 					    usba_log_handle,
32660Sstevel@tonic-gate 					    "%s%d: leaking dev_data 0x%p",
32670Sstevel@tonic-gate 					    ddi_driver_name(dip),
32680Sstevel@tonic-gate 					    ddi_get_instance(dip),
32690Sstevel@tonic-gate 					    (void *)dev_data);
32700Sstevel@tonic-gate 
32710Sstevel@tonic-gate 					leaks++;
32720Sstevel@tonic-gate 
32730Sstevel@tonic-gate 					mutex_exit(&usba_device->usb_mutex);
32740Sstevel@tonic-gate 					usb_free_dev_data(dip, dev_data);
32750Sstevel@tonic-gate 					mutex_enter(&usba_device->usb_mutex);
32760Sstevel@tonic-gate 				}
32770Sstevel@tonic-gate 
32780Sstevel@tonic-gate 				entry = next;
32790Sstevel@tonic-gate 			}
32800Sstevel@tonic-gate 		}
32810Sstevel@tonic-gate 		if (usba_device->usb_client_flags[iface] &
32820Sstevel@tonic-gate 		    USBA_CLIENT_FLAG_ATTACH) {
32830Sstevel@tonic-gate 			dev_info_t *dip = usba_device->
32846112Sqz150045 			    usb_client_attach_list[iface].dip;
32850Sstevel@tonic-gate 
3286978Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_USBA,
32870Sstevel@tonic-gate 			    usba_log_handle,
32880Sstevel@tonic-gate 			    "%s%d: did no usb_client_detach",
32890Sstevel@tonic-gate 			    ddi_driver_name(dip), ddi_get_instance(dip));
32900Sstevel@tonic-gate 			leaks++;
32910Sstevel@tonic-gate 
32920Sstevel@tonic-gate 			mutex_exit(&usba_device->usb_mutex);
32930Sstevel@tonic-gate 			usb_client_detach(dip, NULL);
32940Sstevel@tonic-gate 			mutex_enter(&usba_device->usb_mutex);
32950Sstevel@tonic-gate 
32960Sstevel@tonic-gate 			usba_device->
32970Sstevel@tonic-gate 			    usb_client_attach_list[iface].dip = NULL;
32980Sstevel@tonic-gate 
32990Sstevel@tonic-gate 			usba_device->usb_client_flags[iface] &=
33000Sstevel@tonic-gate 			    ~USBA_CLIENT_FLAG_ATTACH;
33010Sstevel@tonic-gate 
33020Sstevel@tonic-gate 		}
33030Sstevel@tonic-gate 		if (usba_device->usb_client_flags[iface] &
33040Sstevel@tonic-gate 		    USBA_CLIENT_FLAG_EV_CBS) {
33050Sstevel@tonic-gate 			dev_info_t *dip =
33060Sstevel@tonic-gate 			    usba_device->usb_client_ev_cb_list[iface].
33076112Sqz150045 			    dip;
33080Sstevel@tonic-gate 			usb_event_t *ev_data =
33090Sstevel@tonic-gate 			    usba_device->usb_client_ev_cb_list[iface].
33106112Sqz150045 			    ev_data;
33110Sstevel@tonic-gate 
3312978Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_USBA,
33130Sstevel@tonic-gate 			    usba_log_handle,
33140Sstevel@tonic-gate 			    "%s%d: did no usb_unregister_event_cbs",
33150Sstevel@tonic-gate 			    ddi_driver_name(dip), ddi_get_instance(dip));
33160Sstevel@tonic-gate 			leaks++;
33170Sstevel@tonic-gate 
33180Sstevel@tonic-gate 			mutex_exit(&usba_device->usb_mutex);
33190Sstevel@tonic-gate 			usb_unregister_event_cbs(dip, ev_data);
33200Sstevel@tonic-gate 			mutex_enter(&usba_device->usb_mutex);
33210Sstevel@tonic-gate 
33220Sstevel@tonic-gate 			usba_device->usb_client_ev_cb_list[iface].
33236112Sqz150045 			    dip = NULL;
33240Sstevel@tonic-gate 			usba_device->usb_client_ev_cb_list[iface].
33256112Sqz150045 			    ev_data = NULL;
33260Sstevel@tonic-gate 			usba_device->usb_client_flags[iface] &=
33270Sstevel@tonic-gate 			    ~USBA_CLIENT_FLAG_EV_CBS;
33280Sstevel@tonic-gate 		}
33290Sstevel@tonic-gate 	}
33300Sstevel@tonic-gate 	mutex_exit(&usba_device->usb_mutex);
33310Sstevel@tonic-gate 
33320Sstevel@tonic-gate 	if (leaks) {
3333978Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
33340Sstevel@tonic-gate 		    "all %d leaks fixed", leaks);
33350Sstevel@tonic-gate 	}
33360Sstevel@tonic-gate }
3337