xref: /onnv-gate/usr/src/uts/common/io/usb/usba/usba.c (revision 880:0f8e93fcf632)
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
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
230Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate  * USBA: Solaris USB Architecture support
310Sstevel@tonic-gate  */
320Sstevel@tonic-gate #define	USBA_FRAMEWORK
330Sstevel@tonic-gate #include <sys/usb/usba/usba_impl.h>
340Sstevel@tonic-gate #include <sys/usb/usba/hcdi_impl.h>
350Sstevel@tonic-gate #include <sys/usb/hubd/hub.h>
360Sstevel@tonic-gate #include <sys/fs/dv_node.h>
370Sstevel@tonic-gate 
380Sstevel@tonic-gate static int usba_str_startcmp(char *, char *);
390Sstevel@tonic-gate 
400Sstevel@tonic-gate /*
410Sstevel@tonic-gate  * USBA private variables and tunables
420Sstevel@tonic-gate  */
430Sstevel@tonic-gate static kmutex_t	usba_mutex;
440Sstevel@tonic-gate 
450Sstevel@tonic-gate /*
460Sstevel@tonic-gate  * ddivs forced binding:
470Sstevel@tonic-gate  *
480Sstevel@tonic-gate  *    usbc usbc_xhubs usbc_xaddress  node name
490Sstevel@tonic-gate  *
500Sstevel@tonic-gate  *	0	x	x	class name or "device"
510Sstevel@tonic-gate  *
520Sstevel@tonic-gate  *	1	0	0	ddivs_usbc
530Sstevel@tonic-gate  *	1	0	>1	ddivs_usbc except device
540Sstevel@tonic-gate  *				at usbc_xaddress
550Sstevel@tonic-gate  *	1	1	0	ddivs_usbc except hubs
560Sstevel@tonic-gate  *	1	1	>1	ddivs_usbc except hubs and
570Sstevel@tonic-gate  *				device at usbc_xaddress
580Sstevel@tonic-gate  */
590Sstevel@tonic-gate uint_t usba_ddivs_usbc;
600Sstevel@tonic-gate uint_t usba_ddivs_usbc_xhubs;
610Sstevel@tonic-gate uint_t usba_ddivs_usbc_xaddress;
620Sstevel@tonic-gate 
630Sstevel@tonic-gate uint_t usba_ugen_force_binding;
640Sstevel@tonic-gate 
650Sstevel@tonic-gate /*
660Sstevel@tonic-gate  * compatible name handling
670Sstevel@tonic-gate  */
680Sstevel@tonic-gate #define	USBA_MAX_COMPAT_NAMES		15
690Sstevel@tonic-gate #define	USBA_MAX_COMPAT_NAME_LEN	64
700Sstevel@tonic-gate static char	usba_name[USBA_MAX_COMPAT_NAMES][USBA_MAX_COMPAT_NAME_LEN];
710Sstevel@tonic-gate static char	*usba_compatible[USBA_MAX_COMPAT_NAMES];
720Sstevel@tonic-gate 
730Sstevel@tonic-gate _NOTE(MUTEX_PROTECTS_DATA(usba_mutex, usba_name usba_compatible))
740Sstevel@tonic-gate 
750Sstevel@tonic-gate /* double linked list for usba_devices */
760Sstevel@tonic-gate usba_list_entry_t	usba_device_list;
770Sstevel@tonic-gate 
780Sstevel@tonic-gate _NOTE(MUTEX_PROTECTS_DATA(usba_mutex, usba_device_list))
790Sstevel@tonic-gate 
800Sstevel@tonic-gate /*
810Sstevel@tonic-gate  * modload support
820Sstevel@tonic-gate  */
830Sstevel@tonic-gate extern struct mod_ops mod_miscops;
840Sstevel@tonic-gate 
850Sstevel@tonic-gate struct modlmisc modlmisc	= {
860Sstevel@tonic-gate 	&mod_miscops,	/* Type	of module */
870Sstevel@tonic-gate 	"USBA: USB Architecture 2.0 %I%"
880Sstevel@tonic-gate };
890Sstevel@tonic-gate 
900Sstevel@tonic-gate struct modlinkage modlinkage = {
910Sstevel@tonic-gate 	MODREV_1, (void	*)&modlmisc, NULL
920Sstevel@tonic-gate };
930Sstevel@tonic-gate 
940Sstevel@tonic-gate 
950Sstevel@tonic-gate static usb_log_handle_t	usba_log_handle;
96*880Sfrits uint_t		usba_errlevel = USB_LOG_L4;
97*880Sfrits uint_t		usba_errmask = (uint_t)-1;
980Sstevel@tonic-gate 
990Sstevel@tonic-gate extern usb_log_handle_t	hubdi_log_handle;
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate int
1020Sstevel@tonic-gate _init(void)
1030Sstevel@tonic-gate {
1040Sstevel@tonic-gate 	int i, rval;
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate 	/*
1070Sstevel@tonic-gate 	 * usbai providing log support needs to be init'ed first
1080Sstevel@tonic-gate 	 * and destroyed last
1090Sstevel@tonic-gate 	 */
1100Sstevel@tonic-gate 	usba_usbai_initialization();
1110Sstevel@tonic-gate 	usba_usba_initialization();
1120Sstevel@tonic-gate 	usba_usbai_register_initialization();
1130Sstevel@tonic-gate 	usba_hcdi_initialization();
1140Sstevel@tonic-gate 	usba_hubdi_initialization();
1150Sstevel@tonic-gate 	usba_devdb_initialization();
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate 	if ((rval = mod_install(&modlinkage)) != 0) {
1180Sstevel@tonic-gate 		usba_devdb_destroy();
1190Sstevel@tonic-gate 		usba_hubdi_destroy();
1200Sstevel@tonic-gate 		usba_hcdi_destroy();
1210Sstevel@tonic-gate 		usba_usbai_register_destroy();
1220Sstevel@tonic-gate 		usba_usba_destroy();
1230Sstevel@tonic-gate 		usba_usbai_destroy();
1240Sstevel@tonic-gate 	}
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate 	for (i = 0; i < USBA_MAX_COMPAT_NAMES; i++) {
1270Sstevel@tonic-gate 		usba_compatible[i] = usba_name[i];
1280Sstevel@tonic-gate 	}
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate 	return (rval);
1310Sstevel@tonic-gate }
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate int
1340Sstevel@tonic-gate _fini()
1350Sstevel@tonic-gate {
1360Sstevel@tonic-gate 	int rval;
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate 	if ((rval = mod_remove(&modlinkage)) == 0) {
1390Sstevel@tonic-gate 		usba_devdb_destroy();
1400Sstevel@tonic-gate 		usba_hubdi_destroy();
1410Sstevel@tonic-gate 		usba_hcdi_destroy();
1420Sstevel@tonic-gate 		usba_usbai_register_destroy();
1430Sstevel@tonic-gate 		usba_usba_destroy();
1440Sstevel@tonic-gate 		usba_usbai_destroy();
1450Sstevel@tonic-gate 	}
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate 	return (rval);
1480Sstevel@tonic-gate }
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate int
1510Sstevel@tonic-gate _info(struct modinfo *modinfop)
1520Sstevel@tonic-gate {
1530Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
1540Sstevel@tonic-gate }
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate /*
1580Sstevel@tonic-gate  * common bus ctl for hcd, usb_mid, and hubd
1590Sstevel@tonic-gate  */
1600Sstevel@tonic-gate int
1610Sstevel@tonic-gate usba_bus_ctl(dev_info_t	*dip,
1620Sstevel@tonic-gate 	dev_info_t		*rdip,
1630Sstevel@tonic-gate 	ddi_ctl_enum_t		op,
1640Sstevel@tonic-gate 	void			*arg,
1650Sstevel@tonic-gate 	void			*result)
1660Sstevel@tonic-gate {
1670Sstevel@tonic-gate 	dev_info_t		*child_dip = (dev_info_t *)arg;
1680Sstevel@tonic-gate 	usba_device_t		*usba_device;
1690Sstevel@tonic-gate 	usba_hcdi_t		*usba_hcdi;
1700Sstevel@tonic-gate 	usba_hcdi_ops_t		*usba_hcdi_ops;
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, hubdi_log_handle,
1730Sstevel@tonic-gate 	    "usba_bus_ctl: %s%d %s%d op=%d", ddi_node_name(rdip),
1740Sstevel@tonic-gate 	    ddi_get_instance(rdip), ddi_node_name(dip),
1750Sstevel@tonic-gate 	    ddi_get_instance(dip), op);
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate 	switch (op) {
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate 	case DDI_CTLOPS_REPORTDEV:
1800Sstevel@tonic-gate 	{
1810Sstevel@tonic-gate 		char *name, compat_name[64], *speed;
1820Sstevel@tonic-gate 		usba_device_t	*hub_usba_device;
1830Sstevel@tonic-gate 		dev_info_t	*hubdip;
1840Sstevel@tonic-gate 
1850Sstevel@tonic-gate 		usba_device = usba_get_usba_device(rdip);
1860Sstevel@tonic-gate 
1870Sstevel@tonic-gate 		/* find the parent hub */
1880Sstevel@tonic-gate 		hubdip = ddi_get_parent(rdip);
1890Sstevel@tonic-gate 		while ((strcmp(ddi_driver_name(hubdip), "hubd") != 0) &&
1900Sstevel@tonic-gate 		    !(usba_is_root_hub(hubdip))) {
1910Sstevel@tonic-gate 			hubdip = ddi_get_parent(hubdip);
1920Sstevel@tonic-gate 		}
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate 		hub_usba_device = usba_get_usba_device(hubdip);
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate 		if (usba_device) {
1970Sstevel@tonic-gate 			if (usb_owns_device(rdip)) {
1980Sstevel@tonic-gate 				(void) snprintf(compat_name,
1990Sstevel@tonic-gate 				    sizeof (compat_name),
2000Sstevel@tonic-gate 				    "usb%x,%x",
2010Sstevel@tonic-gate 				    usba_device->usb_dev_descr->idVendor,
2020Sstevel@tonic-gate 				    usba_device->usb_dev_descr->idProduct);
2030Sstevel@tonic-gate 			} else {
2040Sstevel@tonic-gate 				(void) snprintf(compat_name,
2050Sstevel@tonic-gate 				    sizeof (compat_name),
2060Sstevel@tonic-gate 				    "usbif%x,%x.config%x.%x",
2070Sstevel@tonic-gate 				    usba_device->usb_dev_descr->idVendor,
2080Sstevel@tonic-gate 				    usba_device->usb_dev_descr->idProduct,
2090Sstevel@tonic-gate 				    usba_device->usb_cfg_value,
2100Sstevel@tonic-gate 				    usb_get_if_number(rdip));
2110Sstevel@tonic-gate 			}
2120Sstevel@tonic-gate 			switch (usba_device->usb_port_status) {
2130Sstevel@tonic-gate 			case USBA_HIGH_SPEED_DEV:
2140Sstevel@tonic-gate 				speed = "hi speed (USB 2.x)";
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate 				break;
2170Sstevel@tonic-gate 			case USBA_LOW_SPEED_DEV:
2180Sstevel@tonic-gate 				speed = "low speed (USB 1.x)";
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate 				break;
2210Sstevel@tonic-gate 			case USBA_FULL_SPEED_DEV:
2220Sstevel@tonic-gate 			default:
2230Sstevel@tonic-gate 				speed = "full speed (USB 1.x)";
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate 				break;
2260Sstevel@tonic-gate 			}
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate 			cmn_err(CE_CONT,
2290Sstevel@tonic-gate 			    "?USB %x.%x %s (%s) operating at %s on "
2300Sstevel@tonic-gate 			    "USB %x.%x %s hub: "
2310Sstevel@tonic-gate 			    "%s@%s, %s%d at bus address %d\n",
2320Sstevel@tonic-gate 			    (usba_device->usb_dev_descr->bcdUSB & 0xff00) >> 8,
2330Sstevel@tonic-gate 			    usba_device->usb_dev_descr->bcdUSB & 0xff,
2340Sstevel@tonic-gate 			    (usb_owns_device(rdip) ? "device" : "interface"),
2350Sstevel@tonic-gate 			    compat_name, speed,
2360Sstevel@tonic-gate 			    (hub_usba_device->usb_dev_descr->bcdUSB &
2370Sstevel@tonic-gate 			    0xff00) >> 8,
2380Sstevel@tonic-gate 			    hub_usba_device->usb_dev_descr->bcdUSB & 0xff,
2390Sstevel@tonic-gate 			    usba_is_root_hub(hubdip) ? "root" : "external",
2400Sstevel@tonic-gate 			    ddi_node_name(rdip), ddi_get_name_addr(rdip),
2410Sstevel@tonic-gate 			    ddi_driver_name(rdip),
2420Sstevel@tonic-gate 			    ddi_get_instance(rdip), usba_device->usb_addr);
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate 			name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
2450Sstevel@tonic-gate 			(void) usba_get_mfg_prod_sn_str(rdip, name, MAXNAMELEN);
2460Sstevel@tonic-gate 			if (name[0] != '\0') {
2470Sstevel@tonic-gate 				cmn_err(CE_CONT, "?\t%s\n", name);
2480Sstevel@tonic-gate 			}
2490Sstevel@tonic-gate 			kmem_free(name, MAXNAMELEN);
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate 		} else { /* harden USBA against this case; if it happens */
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate 			cmn_err(CE_CONT,
2540Sstevel@tonic-gate 			    "?USB-device: %s@%s, %s%d\n",
2550Sstevel@tonic-gate 			    ddi_node_name(rdip), ddi_get_name_addr(rdip),
2560Sstevel@tonic-gate 			    ddi_driver_name(rdip), ddi_get_instance(rdip));
2570Sstevel@tonic-gate 		}
2580Sstevel@tonic-gate 
2590Sstevel@tonic-gate 		return (DDI_SUCCESS);
2600Sstevel@tonic-gate 	}
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate 	case DDI_CTLOPS_INITCHILD:
2630Sstevel@tonic-gate 	{
2640Sstevel@tonic-gate 		int			usb_addr;
2650Sstevel@tonic-gate 		uint_t			n;
2660Sstevel@tonic-gate 		char			name[32];
2670Sstevel@tonic-gate 		int			*data;
2680Sstevel@tonic-gate 		int			rval;
2690Sstevel@tonic-gate 		int			len = sizeof (usb_addr);
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate 		usba_hcdi	= usba_hcdi_get_hcdi(dip);
2720Sstevel@tonic-gate 		usba_hcdi_ops	= usba_hcdi->hcdi_ops;
2730Sstevel@tonic-gate 		ASSERT(usba_hcdi_ops != NULL);
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate 		/*
2760Sstevel@tonic-gate 		 * as long as the dip exists, it should have
2770Sstevel@tonic-gate 		 * usba_device structure associated with it
2780Sstevel@tonic-gate 		 */
2790Sstevel@tonic-gate 		usba_device = usba_get_usba_device(child_dip);
2800Sstevel@tonic-gate 		if (usba_device == NULL) {
2810Sstevel@tonic-gate 
2820Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_USBA, hubdi_log_handle,
2830Sstevel@tonic-gate 			    "usba_bus_ctl: DDI_NOT_WELL_FORMED (%s (0x%p))",
2840Sstevel@tonic-gate 			    ddi_node_name(child_dip), (void *)child_dip);
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate 			return (DDI_NOT_WELL_FORMED);
2870Sstevel@tonic-gate 		}
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate 		/* the dip should have an address and reg property */
2900Sstevel@tonic-gate 		if (ddi_prop_op(DDI_DEV_T_NONE, child_dip, PROP_LEN_AND_VAL_BUF,
2910Sstevel@tonic-gate 		    DDI_PROP_DONTPASS |	DDI_PROP_CANSLEEP, "assigned-address",
2920Sstevel@tonic-gate 		    (caddr_t)&usb_addr,	&len) != DDI_SUCCESS) {
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_USBA, hubdi_log_handle,
2950Sstevel@tonic-gate 			    "usba_bus_ctl:\n\t"
2960Sstevel@tonic-gate 			    "%s%d %s%d op=%d rdip = 0x%p dip = 0x%p",
2970Sstevel@tonic-gate 			    ddi_node_name(rdip), ddi_get_instance(rdip),
2980Sstevel@tonic-gate 			    ddi_node_name(dip), ddi_get_instance(dip), op,
2990Sstevel@tonic-gate 			    rdip, dip);
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_USBA, hubdi_log_handle,
3020Sstevel@tonic-gate 			    "usba_bus_ctl: DDI_NOT_WELL_FORMED (%s (0x%p))",
3030Sstevel@tonic-gate 			    ddi_node_name(child_dip), (void *)child_dip);
3040Sstevel@tonic-gate 
3050Sstevel@tonic-gate 			return (DDI_NOT_WELL_FORMED);
3060Sstevel@tonic-gate 		}
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate 		if ((rval = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child_dip,
3090Sstevel@tonic-gate 		    DDI_PROP_DONTPASS, "reg",
3100Sstevel@tonic-gate 		    &data, &n)) != DDI_SUCCESS) {
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_USBA, hubdi_log_handle,
3130Sstevel@tonic-gate 			    "usba_bus_ctl: %d, DDI_NOT_WELL_FORMED", rval);
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate 			return (DDI_NOT_WELL_FORMED);
3160Sstevel@tonic-gate 		}
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 		/*
3200Sstevel@tonic-gate 		 * if the configuration is 1, the unit address is
3210Sstevel@tonic-gate 		 * just the interface number
3220Sstevel@tonic-gate 		 */
3230Sstevel@tonic-gate 		if ((n == 1) || ((n > 1) && (data[1] == 1))) {
3240Sstevel@tonic-gate 			(void) sprintf(name, "%x", data[0]);
3250Sstevel@tonic-gate 		} else {
3260Sstevel@tonic-gate 			(void) sprintf(name, "%x,%x", data[0], data[1]);
3270Sstevel@tonic-gate 		}
3280Sstevel@tonic-gate 
3290Sstevel@tonic-gate 		USB_DPRINTF_L3(DPRINT_MASK_USBA,
3300Sstevel@tonic-gate 		    hubdi_log_handle, "usba_bus_ctl: name = %s", name);
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 		ddi_prop_free(data);
3330Sstevel@tonic-gate 		ddi_set_name_addr(child_dip, name);
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate 		/*
3360Sstevel@tonic-gate 		 * increment the reference count for each child using this
3370Sstevel@tonic-gate 		 * usba_device structure
3380Sstevel@tonic-gate 		 */
3390Sstevel@tonic-gate 		mutex_enter(&usba_device->usb_mutex);
3400Sstevel@tonic-gate 		usba_device->usb_ref_count++;
3410Sstevel@tonic-gate 
3420Sstevel@tonic-gate 		USB_DPRINTF_L3(DPRINT_MASK_USBA, hubdi_log_handle,
3430Sstevel@tonic-gate 		    "usba_bus_ctl: init usba_device = 0x%p ref_count = %d",
3440Sstevel@tonic-gate 		    (void *)usba_device, usba_device->usb_ref_count);
3450Sstevel@tonic-gate 
3460Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate 		return (DDI_SUCCESS);
3490Sstevel@tonic-gate 	}
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate 	case DDI_CTLOPS_UNINITCHILD:
3520Sstevel@tonic-gate 	{
3530Sstevel@tonic-gate 		usba_device = usba_get_usba_device(child_dip);
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate 		if (usba_device != NULL) {
3560Sstevel@tonic-gate 			/*
3570Sstevel@tonic-gate 			 * decrement the reference count for each child
3580Sstevel@tonic-gate 			 * using this  usba_device structure
3590Sstevel@tonic-gate 			 */
3600Sstevel@tonic-gate 			mutex_enter(&usba_device->usb_mutex);
3610Sstevel@tonic-gate 			usba_device->usb_ref_count--;
3620Sstevel@tonic-gate 
3630Sstevel@tonic-gate 			USB_DPRINTF_L3(DPRINT_MASK_USBA, hubdi_log_handle,
3640Sstevel@tonic-gate 			    "usba_hcdi_bus_ctl: uninit usba_device=0x%p "
3650Sstevel@tonic-gate 			    "ref_count=%d",
3660Sstevel@tonic-gate 			    usba_device, usba_device->usb_ref_count);
3670Sstevel@tonic-gate 
3680Sstevel@tonic-gate 			mutex_exit(&usba_device->usb_mutex);
3690Sstevel@tonic-gate 		}
3700Sstevel@tonic-gate 		ddi_set_name_addr(child_dip, NULL);
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate 		return (DDI_SUCCESS);
3730Sstevel@tonic-gate 	}
3740Sstevel@tonic-gate 
3750Sstevel@tonic-gate 	case DDI_CTLOPS_IOMIN:
3760Sstevel@tonic-gate 		/* Do nothing */
3770Sstevel@tonic-gate 		return (DDI_SUCCESS);
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate 	/*
3800Sstevel@tonic-gate 	 * These ops correspond	to functions that "shouldn't" be called
3810Sstevel@tonic-gate 	 * by a	USB client driver.  So	we whine when we're called.
3820Sstevel@tonic-gate 	 */
3830Sstevel@tonic-gate 	case DDI_CTLOPS_DMAPMAPC:
3840Sstevel@tonic-gate 	case DDI_CTLOPS_REPORTINT:
3850Sstevel@tonic-gate 	case DDI_CTLOPS_REGSIZE:
3860Sstevel@tonic-gate 	case DDI_CTLOPS_NREGS:
3870Sstevel@tonic-gate 	case DDI_CTLOPS_SIDDEV:
3880Sstevel@tonic-gate 	case DDI_CTLOPS_SLAVEONLY:
3890Sstevel@tonic-gate 	case DDI_CTLOPS_AFFINITY:
3900Sstevel@tonic-gate 	case DDI_CTLOPS_POKE:
3910Sstevel@tonic-gate 	case DDI_CTLOPS_PEEK:
3920Sstevel@tonic-gate 		cmn_err(CE_CONT, "%s%d:	invalid	op (%d)	from %s%d",
3930Sstevel@tonic-gate 			ddi_node_name(dip), ddi_get_instance(dip),
3940Sstevel@tonic-gate 			op, ddi_node_name(rdip), ddi_get_instance(rdip));
3950Sstevel@tonic-gate 		return (DDI_FAILURE);
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate 	/*
3980Sstevel@tonic-gate 	 * Everything else (e.g. PTOB/BTOP/BTOPR requests) we pass up
3990Sstevel@tonic-gate 	 */
4000Sstevel@tonic-gate 	default:
4010Sstevel@tonic-gate 		return (ddi_ctlops(dip,	rdip, op, arg, result));
4020Sstevel@tonic-gate 	}
4030Sstevel@tonic-gate }
4040Sstevel@tonic-gate 
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate /*
4070Sstevel@tonic-gate  * initialize and destroy USBA module
4080Sstevel@tonic-gate  */
4090Sstevel@tonic-gate void
4100Sstevel@tonic-gate usba_usba_initialization()
4110Sstevel@tonic-gate {
4120Sstevel@tonic-gate 	usba_log_handle = usb_alloc_log_hdl(NULL, "usba", &usba_errlevel,
4130Sstevel@tonic-gate 				&usba_errmask, NULL, 0);
4140Sstevel@tonic-gate 
4150Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA,
4160Sstevel@tonic-gate 	    usba_log_handle, "usba_usba_initialization");
4170Sstevel@tonic-gate 
4180Sstevel@tonic-gate 	mutex_init(&usba_mutex, NULL, MUTEX_DRIVER, NULL);
4190Sstevel@tonic-gate 	usba_init_list(&usba_device_list, NULL, NULL);
4200Sstevel@tonic-gate }
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate 
4230Sstevel@tonic-gate void
4240Sstevel@tonic-gate usba_usba_destroy()
4250Sstevel@tonic-gate {
4260Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle, "usba_usba_destroy");
4270Sstevel@tonic-gate 
4280Sstevel@tonic-gate 	mutex_destroy(&usba_mutex);
4290Sstevel@tonic-gate 	usba_destroy_list(&usba_device_list);
4300Sstevel@tonic-gate 
4310Sstevel@tonic-gate 	usb_free_log_hdl(usba_log_handle);
4320Sstevel@tonic-gate }
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate /*
4360Sstevel@tonic-gate  * usba_set_usb_address:
4370Sstevel@tonic-gate  *	set usb address in usba_device structure
4380Sstevel@tonic-gate  */
4390Sstevel@tonic-gate int
4400Sstevel@tonic-gate usba_set_usb_address(usba_device_t *usba_device)
4410Sstevel@tonic-gate {
4420Sstevel@tonic-gate 	usb_addr_t address;
4430Sstevel@tonic-gate 	uchar_t s = 8;
4440Sstevel@tonic-gate 	usba_hcdi_t *hcdi;
4450Sstevel@tonic-gate 	char *usb_address_in_use;
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate 	mutex_enter(&usba_device->usb_mutex);
4480Sstevel@tonic-gate 
4490Sstevel@tonic-gate 	hcdi = usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
4500Sstevel@tonic-gate 
4510Sstevel@tonic-gate 	mutex_enter(&hcdi->hcdi_mutex);
4520Sstevel@tonic-gate 	usb_address_in_use = hcdi->hcdi_usb_address_in_use;
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 	for (address = ROOT_HUB_ADDR + 1;
4550Sstevel@tonic-gate 	    address <= USBA_MAX_ADDRESS; address++) {
4560Sstevel@tonic-gate 		if (usb_address_in_use[address/s] & (1 << (address % s))) {
4570Sstevel@tonic-gate 			continue;
4580Sstevel@tonic-gate 		}
4590Sstevel@tonic-gate 		usb_address_in_use[address/s] |= (1 << (address % s));
4600Sstevel@tonic-gate 		hcdi->hcdi_device_count++;
4610Sstevel@tonic-gate 		HCDI_HOTPLUG_STATS_DATA(hcdi)->hcdi_device_count.value.ui64++;
4620Sstevel@tonic-gate 		mutex_exit(&hcdi->hcdi_mutex);
4630Sstevel@tonic-gate 
4640Sstevel@tonic-gate 		USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
4650Sstevel@tonic-gate 		    "usba_set_usb_address: %d", address);
4660Sstevel@tonic-gate 
4670Sstevel@tonic-gate 		usba_device->usb_addr = address;
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
4700Sstevel@tonic-gate 
4710Sstevel@tonic-gate 		return (USB_SUCCESS);
4720Sstevel@tonic-gate 	}
4730Sstevel@tonic-gate 
4740Sstevel@tonic-gate 	usba_device->usb_addr = 0;
4750Sstevel@tonic-gate 
4760Sstevel@tonic-gate 	USB_DPRINTF_L1(DPRINT_MASK_USBA, usba_log_handle,
4770Sstevel@tonic-gate 	    "no usb address available");
4780Sstevel@tonic-gate 
4790Sstevel@tonic-gate 	mutex_exit(&hcdi->hcdi_mutex);
4800Sstevel@tonic-gate 	mutex_exit(&usba_device->usb_mutex);
4810Sstevel@tonic-gate 
4820Sstevel@tonic-gate 	return (USB_FAILURE);
4830Sstevel@tonic-gate }
4840Sstevel@tonic-gate 
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate /*
4870Sstevel@tonic-gate  * usba_unset_usb_address:
4880Sstevel@tonic-gate  *	unset usb_address in usba_device structure
4890Sstevel@tonic-gate  */
4900Sstevel@tonic-gate void
4910Sstevel@tonic-gate usba_unset_usb_address(usba_device_t *usba_device)
4920Sstevel@tonic-gate {
4930Sstevel@tonic-gate 	usb_addr_t address;
4940Sstevel@tonic-gate 	usba_hcdi_t *hcdi;
4950Sstevel@tonic-gate 	uchar_t s = 8;
4960Sstevel@tonic-gate 	char *usb_address_in_use;
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate 	mutex_enter(&usba_device->usb_mutex);
4990Sstevel@tonic-gate 	address = usba_device->usb_addr;
5000Sstevel@tonic-gate 	hcdi = usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate 	if (address > ROOT_HUB_ADDR) {
5030Sstevel@tonic-gate 		USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
5040Sstevel@tonic-gate 		    "usba_unset_usb_address: address=%d", address);
5050Sstevel@tonic-gate 
5060Sstevel@tonic-gate 		mutex_enter(&hcdi->hcdi_mutex);
5070Sstevel@tonic-gate 		usb_address_in_use = hcdi->hcdi_usb_address_in_use;
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate 		ASSERT(usb_address_in_use[address/s] & (1 << (address % s)));
5100Sstevel@tonic-gate 
5110Sstevel@tonic-gate 		usb_address_in_use[address/s] &= ~(1 << (address % s));
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate 		hcdi->hcdi_device_count--;
5140Sstevel@tonic-gate 		HCDI_HOTPLUG_STATS_DATA(hcdi)->hcdi_device_count.value.ui64--;
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate 		mutex_exit(&hcdi->hcdi_mutex);
5170Sstevel@tonic-gate 
5180Sstevel@tonic-gate 		usba_device->usb_addr = 0;
5190Sstevel@tonic-gate 	}
5200Sstevel@tonic-gate 	mutex_exit(&usba_device->usb_mutex);
5210Sstevel@tonic-gate }
5220Sstevel@tonic-gate 
5230Sstevel@tonic-gate 
5240Sstevel@tonic-gate struct usba_evdata *
5250Sstevel@tonic-gate usba_get_evdata(dev_info_t *dip)
5260Sstevel@tonic-gate {
5270Sstevel@tonic-gate 	usba_evdata_t *evdata;
5280Sstevel@tonic-gate 	usba_device_t *usba_device = usba_get_usba_device(dip);
5290Sstevel@tonic-gate 
5300Sstevel@tonic-gate 	/* called when dip attaches */
5310Sstevel@tonic-gate 	ASSERT(usba_device != NULL);
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate 	mutex_enter(&usba_device->usb_mutex);
5340Sstevel@tonic-gate 	evdata = usba_device->usb_evdata;
5350Sstevel@tonic-gate 	while (evdata) {
5360Sstevel@tonic-gate 		if (evdata->ev_dip == dip) {
5370Sstevel@tonic-gate 			mutex_exit(&usba_device->usb_mutex);
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate 			return (evdata);
5400Sstevel@tonic-gate 		}
5410Sstevel@tonic-gate 		evdata = evdata->ev_next;
5420Sstevel@tonic-gate 	}
5430Sstevel@tonic-gate 
5440Sstevel@tonic-gate 	evdata = kmem_zalloc(sizeof (usba_evdata_t), KM_SLEEP);
5450Sstevel@tonic-gate 	evdata->ev_dip = dip;
5460Sstevel@tonic-gate 	evdata->ev_next = usba_device->usb_evdata;
5470Sstevel@tonic-gate 	usba_device->usb_evdata = evdata;
5480Sstevel@tonic-gate 	mutex_exit(&usba_device->usb_mutex);
5490Sstevel@tonic-gate 
5500Sstevel@tonic-gate 	return (evdata);
5510Sstevel@tonic-gate }
5520Sstevel@tonic-gate 
5530Sstevel@tonic-gate 
5540Sstevel@tonic-gate /*
5550Sstevel@tonic-gate  * allocate a usb device structure and link it in the list
5560Sstevel@tonic-gate  */
5570Sstevel@tonic-gate usba_device_t *
5580Sstevel@tonic-gate usba_alloc_usba_device(dev_info_t *root_hub_dip)
5590Sstevel@tonic-gate {
5600Sstevel@tonic-gate 	usba_device_t	*usba_device;
5610Sstevel@tonic-gate 	int		ep_idx;
5620Sstevel@tonic-gate 	ddi_iblock_cookie_t iblock_cookie =
5630Sstevel@tonic-gate 	    usba_hcdi_get_hcdi(root_hub_dip)->hcdi_iblock_cookie;
5640Sstevel@tonic-gate 
5650Sstevel@tonic-gate 	/*
5660Sstevel@tonic-gate 	 * create a new usba_device structure
5670Sstevel@tonic-gate 	 */
5680Sstevel@tonic-gate 	usba_device = kmem_zalloc(sizeof (usba_device_t), KM_SLEEP);
5690Sstevel@tonic-gate 
5700Sstevel@tonic-gate 	/*
5710Sstevel@tonic-gate 	 * initialize usba_device
5720Sstevel@tonic-gate 	 */
5730Sstevel@tonic-gate 	mutex_init(&usba_device->usb_mutex, NULL, MUTEX_DRIVER,
5740Sstevel@tonic-gate 							iblock_cookie);
5750Sstevel@tonic-gate 
5760Sstevel@tonic-gate 	usba_init_list(&usba_device->usb_device_list, (usb_opaque_t)usba_device,
5770Sstevel@tonic-gate 							iblock_cookie);
5780Sstevel@tonic-gate 	usba_init_list(&usba_device->usb_allocated, (usb_opaque_t)usba_device,
5790Sstevel@tonic-gate 							iblock_cookie);
5800Sstevel@tonic-gate 	mutex_enter(&usba_device->usb_mutex);
5810Sstevel@tonic-gate 	usba_device->usb_root_hub_dip = root_hub_dip;
5820Sstevel@tonic-gate 
5830Sstevel@tonic-gate 	/*
5840Sstevel@tonic-gate 	 * add to list of usba_devices
5850Sstevel@tonic-gate 	 */
5860Sstevel@tonic-gate 	usba_add_to_list(&usba_device_list, &usba_device->usb_device_list);
5870Sstevel@tonic-gate 
5880Sstevel@tonic-gate 	/* init mutex in each usba_ph_impl structure */
5890Sstevel@tonic-gate 	for (ep_idx = 0; ep_idx < USBA_N_ENDPOINTS; ep_idx++) {
5900Sstevel@tonic-gate 		mutex_init(&usba_device->usb_ph_list[ep_idx].usba_ph_mutex,
5910Sstevel@tonic-gate 		    NULL, MUTEX_DRIVER, iblock_cookie);
5920Sstevel@tonic-gate 	}
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
5950Sstevel@tonic-gate 	    "allocated usba_device 0x%p", (void *)usba_device);
5960Sstevel@tonic-gate 
5970Sstevel@tonic-gate 	mutex_exit(&usba_device->usb_mutex);
5980Sstevel@tonic-gate 
5990Sstevel@tonic-gate 	return (usba_device);
6000Sstevel@tonic-gate }
6010Sstevel@tonic-gate 
6020Sstevel@tonic-gate 
6030Sstevel@tonic-gate /* free NDI event data associated with usba_device */
6040Sstevel@tonic-gate void
6050Sstevel@tonic-gate usba_free_evdata(usba_evdata_t *evdata)
6060Sstevel@tonic-gate {
6070Sstevel@tonic-gate 	usba_evdata_t *next;
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate 	while (evdata) {
6100Sstevel@tonic-gate 		next = evdata->ev_next;
6110Sstevel@tonic-gate 		kmem_free(evdata, sizeof (usba_evdata_t));
6120Sstevel@tonic-gate 		evdata = next;
6130Sstevel@tonic-gate 	}
6140Sstevel@tonic-gate }
6150Sstevel@tonic-gate 
6160Sstevel@tonic-gate 
6170Sstevel@tonic-gate /*
6180Sstevel@tonic-gate  * free usb device structure
6190Sstevel@tonic-gate  */
6200Sstevel@tonic-gate void
6210Sstevel@tonic-gate usba_free_usba_device(usba_device_t *usba_device)
6220Sstevel@tonic-gate {
6230Sstevel@tonic-gate 	int			i, ep_idx;
6240Sstevel@tonic-gate 	usb_pipe_handle_t	def_ph;
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate 	if (usba_device == NULL) {
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate 		return;
6290Sstevel@tonic-gate 	}
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 	mutex_enter(&usba_device->usb_mutex);
6320Sstevel@tonic-gate 	if (usba_device->usb_ref_count) {
6330Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
6340Sstevel@tonic-gate 
6350Sstevel@tonic-gate 		return;
6360Sstevel@tonic-gate 	}
6370Sstevel@tonic-gate 
6380Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
6390Sstevel@tonic-gate 	    "usba_free_usba_device 0x%p, address=0x%x, ref cnt=%d",
6400Sstevel@tonic-gate 	    (void *)usba_device, usba_device->usb_addr,
6410Sstevel@tonic-gate 	    usba_device->usb_ref_count);
6420Sstevel@tonic-gate 
6430Sstevel@tonic-gate 	usba_free_evdata(usba_device->usb_evdata);
6440Sstevel@tonic-gate 	mutex_exit(&usba_device->usb_mutex);
6450Sstevel@tonic-gate 
6460Sstevel@tonic-gate 	def_ph = usba_usbdev_to_dflt_pipe_handle(usba_device);
6470Sstevel@tonic-gate 	if (def_ph != NULL) {
6480Sstevel@tonic-gate 		usba_pipe_handle_data_t	*ph_data = usba_get_ph_data(def_ph);
6490Sstevel@tonic-gate 
6500Sstevel@tonic-gate 		if (ph_data) {
6510Sstevel@tonic-gate 			usb_pipe_close(ph_data->p_dip, def_ph,
6520Sstevel@tonic-gate 			    USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED,
6530Sstevel@tonic-gate 			    NULL, NULL);
6540Sstevel@tonic-gate 		}
6550Sstevel@tonic-gate 	}
6560Sstevel@tonic-gate 
6570Sstevel@tonic-gate 	mutex_enter(&usba_mutex);
6580Sstevel@tonic-gate 
6590Sstevel@tonic-gate 	/* destroy mutex in each usba_ph_impl structure */
6600Sstevel@tonic-gate 	for (ep_idx = 0; ep_idx < USBA_N_ENDPOINTS; ep_idx++) {
6610Sstevel@tonic-gate 		mutex_destroy(&usba_device->usb_ph_list[ep_idx].usba_ph_mutex);
6620Sstevel@tonic-gate 	}
6630Sstevel@tonic-gate 
6640Sstevel@tonic-gate 	(void) usba_rm_from_list(&usba_device_list,
6650Sstevel@tonic-gate 				&usba_device->usb_device_list);
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate 	mutex_exit(&usba_mutex);
6680Sstevel@tonic-gate 
6690Sstevel@tonic-gate 	usba_destroy_list(&usba_device->usb_device_list);
6700Sstevel@tonic-gate 	usba_destroy_list(&usba_device->usb_allocated);
6710Sstevel@tonic-gate 
6720Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
6730Sstevel@tonic-gate 	    "deallocating usba_device = 0x%p, address = 0x%x",
6740Sstevel@tonic-gate 	    (void *)usba_device, usba_device->usb_addr);
6750Sstevel@tonic-gate 
6760Sstevel@tonic-gate 	/*
6770Sstevel@tonic-gate 	 * ohci allocates descriptors for root hub so we can't
6780Sstevel@tonic-gate 	 * deallocate these here
6790Sstevel@tonic-gate 	 */
6800Sstevel@tonic-gate 
6810Sstevel@tonic-gate 	if (usba_device->usb_addr != ROOT_HUB_ADDR) {
6820Sstevel@tonic-gate 		if (usba_device->usb_cfg_array) {
6830Sstevel@tonic-gate 			USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
6840Sstevel@tonic-gate 			    "deallocating usb_config_array: 0x%p",
6850Sstevel@tonic-gate 			    usba_device->usb_cfg_array);
6860Sstevel@tonic-gate 			mutex_enter(&usba_device->usb_mutex);
6870Sstevel@tonic-gate 			for (i = 0;
6880Sstevel@tonic-gate 			    i < usba_device->usb_dev_descr->bNumConfigurations;
6890Sstevel@tonic-gate 			    i++) {
6900Sstevel@tonic-gate 				if (usba_device->usb_cfg_array[i]) {
6910Sstevel@tonic-gate 					kmem_free(
6920Sstevel@tonic-gate 					    usba_device->usb_cfg_array[i],
6930Sstevel@tonic-gate 					    usba_device->usb_cfg_array_len[i]);
6940Sstevel@tonic-gate 				}
6950Sstevel@tonic-gate 			}
6960Sstevel@tonic-gate 
6970Sstevel@tonic-gate 			/* free the array pointers */
6980Sstevel@tonic-gate 			kmem_free(usba_device->usb_cfg_array,
6990Sstevel@tonic-gate 			    usba_device->usb_cfg_array_length);
7000Sstevel@tonic-gate 			kmem_free(usba_device->usb_cfg_array_len,
7010Sstevel@tonic-gate 			    usba_device->usb_cfg_array_len_length);
7020Sstevel@tonic-gate 
7030Sstevel@tonic-gate 			mutex_exit(&usba_device->usb_mutex);
7040Sstevel@tonic-gate 		}
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate 		if (usba_device->usb_cfg_str_descr) {
7070Sstevel@tonic-gate 			USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
7080Sstevel@tonic-gate 			    "deallocating usb_cfg_str_descr: 0x%p",
7090Sstevel@tonic-gate 			    usba_device->usb_cfg_str_descr);
7100Sstevel@tonic-gate 			for (i = 0;
7110Sstevel@tonic-gate 			    i < usba_device->usb_dev_descr->bNumConfigurations;
7120Sstevel@tonic-gate 			    i++) {
7130Sstevel@tonic-gate 				if (usba_device->usb_cfg_str_descr[i]) {
7140Sstevel@tonic-gate 					kmem_free(
7150Sstevel@tonic-gate 					    usba_device->usb_cfg_str_descr[i],
7160Sstevel@tonic-gate 					    strlen(usba_device->
7170Sstevel@tonic-gate 						usb_cfg_str_descr[i]) + 1);
7180Sstevel@tonic-gate 				}
7190Sstevel@tonic-gate 			}
7200Sstevel@tonic-gate 			/* free the array pointers */
7210Sstevel@tonic-gate 			kmem_free(usba_device->usb_cfg_str_descr,
7220Sstevel@tonic-gate 			    sizeof (uchar_t *) * usba_device->usb_n_cfgs);
7230Sstevel@tonic-gate 		}
7240Sstevel@tonic-gate 
7250Sstevel@tonic-gate 		if (usba_device->usb_dev_descr) {
7260Sstevel@tonic-gate 			kmem_free(usba_device->usb_dev_descr,
7270Sstevel@tonic-gate 				    sizeof (usb_dev_descr_t));
7280Sstevel@tonic-gate 		}
7290Sstevel@tonic-gate 
7300Sstevel@tonic-gate 		if (usba_device->usb_mfg_str) {
7310Sstevel@tonic-gate 			kmem_free(usba_device->usb_mfg_str,
7320Sstevel@tonic-gate 				strlen(usba_device->usb_mfg_str) + 1);
7330Sstevel@tonic-gate 		}
7340Sstevel@tonic-gate 
7350Sstevel@tonic-gate 		if (usba_device->usb_product_str) {
7360Sstevel@tonic-gate 			kmem_free(usba_device->usb_product_str,
7370Sstevel@tonic-gate 				strlen(usba_device->usb_product_str) + 1);
7380Sstevel@tonic-gate 		}
7390Sstevel@tonic-gate 
7400Sstevel@tonic-gate 		if (usba_device->usb_serialno_str) {
7410Sstevel@tonic-gate 			kmem_free(usba_device->usb_serialno_str,
7420Sstevel@tonic-gate 				strlen(usba_device->usb_serialno_str) + 1);
7430Sstevel@tonic-gate 		}
7440Sstevel@tonic-gate 
7450Sstevel@tonic-gate 		usba_unset_usb_address(usba_device);
7460Sstevel@tonic-gate 	}
7470Sstevel@tonic-gate 
7480Sstevel@tonic-gate #ifndef __lock_lint
7490Sstevel@tonic-gate 	ASSERT(usba_device->usb_client_dev_data_list.cddl_next == NULL);
7500Sstevel@tonic-gate #endif
7510Sstevel@tonic-gate 
7520Sstevel@tonic-gate 	if (usba_device->usb_client_flags) {
7530Sstevel@tonic-gate #ifndef __lock_lint
7540Sstevel@tonic-gate 		int i;
7550Sstevel@tonic-gate 
7560Sstevel@tonic-gate 		for (i = 0; i < usba_device->usb_n_ifs; i++) {
7570Sstevel@tonic-gate 			ASSERT(usba_device->usb_client_flags[i] == 0);
7580Sstevel@tonic-gate 		}
7590Sstevel@tonic-gate #endif
7600Sstevel@tonic-gate 		kmem_free(usba_device->usb_client_flags,
7610Sstevel@tonic-gate 		    usba_device->usb_n_ifs * USBA_CLIENT_FLAG_SIZE);
7620Sstevel@tonic-gate 	}
7630Sstevel@tonic-gate 
7640Sstevel@tonic-gate 
7650Sstevel@tonic-gate 	if (usba_device->usb_client_attach_list) {
7660Sstevel@tonic-gate 		kmem_free(usba_device->usb_client_attach_list,
7670Sstevel@tonic-gate 		    usba_device->usb_n_ifs *
7680Sstevel@tonic-gate 		    sizeof (*usba_device->usb_client_attach_list));
7690Sstevel@tonic-gate 	}
7700Sstevel@tonic-gate 	if (usba_device->usb_client_ev_cb_list) {
7710Sstevel@tonic-gate 		kmem_free(usba_device->usb_client_ev_cb_list,
7720Sstevel@tonic-gate 		    usba_device->usb_n_ifs *
7730Sstevel@tonic-gate 		    sizeof (*usba_device->usb_client_ev_cb_list));
7740Sstevel@tonic-gate 	}
7750Sstevel@tonic-gate 
7760Sstevel@tonic-gate 	/*
7770Sstevel@tonic-gate 	 * finally ready to destroy the structure
7780Sstevel@tonic-gate 	 */
7790Sstevel@tonic-gate 	mutex_destroy(&usba_device->usb_mutex);
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate 	kmem_free((caddr_t)usba_device, sizeof (usba_device_t));
7820Sstevel@tonic-gate }
7830Sstevel@tonic-gate 
7840Sstevel@tonic-gate 
7850Sstevel@tonic-gate /* clear the data toggle for all endpoints on this device */
7860Sstevel@tonic-gate void
7870Sstevel@tonic-gate usba_clear_data_toggle(usba_device_t *usba_device)
7880Sstevel@tonic-gate {
7890Sstevel@tonic-gate 	int	i;
7900Sstevel@tonic-gate 
7910Sstevel@tonic-gate 	if (usba_device != NULL) {
7920Sstevel@tonic-gate 		mutex_enter(&usba_device->usb_mutex);
7930Sstevel@tonic-gate 		for (i = 0; i < USBA_N_ENDPOINTS; i++) {
7940Sstevel@tonic-gate 			usba_device->usb_ph_list[i].usba_ph_flags &=
7950Sstevel@tonic-gate 			    ~USBA_PH_DATA_TOGGLE;
7960Sstevel@tonic-gate 		}
7970Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
7980Sstevel@tonic-gate 	}
7990Sstevel@tonic-gate }
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate 
8020Sstevel@tonic-gate /*
8030Sstevel@tonic-gate  * usba_create_child_devi():
8040Sstevel@tonic-gate  *	create a child devinfo node, usba_device, attach properties.
8050Sstevel@tonic-gate  *	the usba_device structure is shared between all interfaces
8060Sstevel@tonic-gate  */
8070Sstevel@tonic-gate int
8080Sstevel@tonic-gate usba_create_child_devi(dev_info_t	*dip,
8090Sstevel@tonic-gate 		char			*node_name,
8100Sstevel@tonic-gate 		usba_hcdi_ops_t		*usba_hcdi_ops,
8110Sstevel@tonic-gate 		dev_info_t		*usb_root_hub_dip,
8120Sstevel@tonic-gate 		usb_port_status_t	port_status,
8130Sstevel@tonic-gate 		usba_device_t		*usba_device,
8140Sstevel@tonic-gate 		dev_info_t		**child_dip)
8150Sstevel@tonic-gate {
8160Sstevel@tonic-gate 	int rval = USB_FAILURE;
8170Sstevel@tonic-gate 	int usba_device_allocated = 0;
8180Sstevel@tonic-gate 	usb_addr_t	address;
8190Sstevel@tonic-gate 
8200Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
8210Sstevel@tonic-gate 	    "usba_create_child_devi: %s usba_device=0x%p "
8220Sstevel@tonic-gate 	    "port status=0x%x", node_name,
8230Sstevel@tonic-gate 	    (void *)usba_device, port_status);
8240Sstevel@tonic-gate 
825789Sahrens 	ndi_devi_alloc_sleep(dip, node_name, (pnode_t)DEVI_SID_NODEID,
8260Sstevel@tonic-gate 				child_dip);
8270Sstevel@tonic-gate 
8280Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
8290Sstevel@tonic-gate 	    "child dip=0x%p", *child_dip);
8300Sstevel@tonic-gate 
8310Sstevel@tonic-gate 	if (usba_device == NULL) {
8320Sstevel@tonic-gate 
8330Sstevel@tonic-gate 		usba_device = usba_alloc_usba_device(usb_root_hub_dip);
8340Sstevel@tonic-gate 
8350Sstevel@tonic-gate 		/* grab the mutex to keep warlock happy */
8360Sstevel@tonic-gate 		mutex_enter(&usba_device->usb_mutex);
8370Sstevel@tonic-gate 		usba_device->usb_hcdi_ops	= usba_hcdi_ops;
8380Sstevel@tonic-gate 		usba_device->usb_port_status	= port_status;
8390Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
8400Sstevel@tonic-gate 
8410Sstevel@tonic-gate 		usba_device_allocated++;
8420Sstevel@tonic-gate 	} else {
8430Sstevel@tonic-gate 		mutex_enter(&usba_device->usb_mutex);
8440Sstevel@tonic-gate 		if (usba_hcdi_ops) {
8450Sstevel@tonic-gate 			ASSERT(usba_device->usb_hcdi_ops == usba_hcdi_ops);
8460Sstevel@tonic-gate 		}
8470Sstevel@tonic-gate 		if (usb_root_hub_dip) {
8480Sstevel@tonic-gate 			ASSERT(usba_device->usb_root_hub_dip ==
8490Sstevel@tonic-gate 						usb_root_hub_dip);
8500Sstevel@tonic-gate 		}
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate 		usba_device->usb_port_status	= port_status;
8530Sstevel@tonic-gate 
8540Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
8550Sstevel@tonic-gate 	}
8560Sstevel@tonic-gate 
8570Sstevel@tonic-gate 	if (usba_device->usb_addr == 0) {
8580Sstevel@tonic-gate 		if (usba_set_usb_address(usba_device) == USB_FAILURE) {
8590Sstevel@tonic-gate 			address = 0;
8600Sstevel@tonic-gate 
8610Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
8620Sstevel@tonic-gate 				"cannot set usb address for dip=0x%p",
8630Sstevel@tonic-gate 				*child_dip);
8640Sstevel@tonic-gate 
8650Sstevel@tonic-gate 			goto fail;
8660Sstevel@tonic-gate 		}
8670Sstevel@tonic-gate 	}
8680Sstevel@tonic-gate 	address = usba_device->usb_addr;
8690Sstevel@tonic-gate 
8700Sstevel@tonic-gate 	/* attach properties */
8710Sstevel@tonic-gate 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, *child_dip,
8720Sstevel@tonic-gate 		"assigned-address", address);
8730Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
8740Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
8750Sstevel@tonic-gate 			"cannot set usb address property for dip=0x%p",
8760Sstevel@tonic-gate 			*child_dip);
8770Sstevel@tonic-gate 		rval = USB_FAILURE;
8780Sstevel@tonic-gate 
8790Sstevel@tonic-gate 		goto fail;
8800Sstevel@tonic-gate 	}
8810Sstevel@tonic-gate 
8820Sstevel@tonic-gate 	/*
8830Sstevel@tonic-gate 	 * store the usba_device point in the dip
8840Sstevel@tonic-gate 	 */
8850Sstevel@tonic-gate 	usba_set_usba_device(*child_dip, usba_device);
8860Sstevel@tonic-gate 
8870Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
8880Sstevel@tonic-gate 	    "usba_create_child_devi: devi=0x%p (%s) ud=0x%p",
8890Sstevel@tonic-gate 		*child_dip, ddi_driver_name(*child_dip), usba_device);
8900Sstevel@tonic-gate 
8910Sstevel@tonic-gate 	return (USB_SUCCESS);
8920Sstevel@tonic-gate 
8930Sstevel@tonic-gate fail:
8940Sstevel@tonic-gate 	if (*child_dip) {
8950Sstevel@tonic-gate 		int rval = usba_destroy_child_devi(*child_dip, NDI_DEVI_REMOVE);
8960Sstevel@tonic-gate 		ASSERT(rval == USB_SUCCESS);
8970Sstevel@tonic-gate 		*child_dip = NULL;
8980Sstevel@tonic-gate 	}
8990Sstevel@tonic-gate 
9000Sstevel@tonic-gate 	if (usba_device_allocated) {
9010Sstevel@tonic-gate 		usba_free_usba_device(usba_device);
9020Sstevel@tonic-gate 	} else if (address && usba_device) {
9030Sstevel@tonic-gate 		usba_unset_usb_address(usba_device);
9040Sstevel@tonic-gate 	}
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate 	USB_DPRINTF_L1(DPRINT_MASK_USBA, usba_log_handle,
9070Sstevel@tonic-gate 	    "usba_create_child_devi failed: rval=%d", rval);
9080Sstevel@tonic-gate 
9090Sstevel@tonic-gate 	return (rval);
9100Sstevel@tonic-gate }
9110Sstevel@tonic-gate 
9120Sstevel@tonic-gate 
9130Sstevel@tonic-gate int
9140Sstevel@tonic-gate usba_destroy_child_devi(dev_info_t *dip, uint_t flag)
9150Sstevel@tonic-gate {
9160Sstevel@tonic-gate 	usba_device_t	*usba_device;
9170Sstevel@tonic-gate 	int		rval = NDI_SUCCESS;
9180Sstevel@tonic-gate 
9190Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
9200Sstevel@tonic-gate 	    "usba_destroy_child_devi: %s%d (0x%p)",
9210Sstevel@tonic-gate 	    ddi_driver_name(dip), ddi_get_instance(dip), dip);
9220Sstevel@tonic-gate 
9230Sstevel@tonic-gate 	usba_device = usba_get_usba_device(dip);
9240Sstevel@tonic-gate 
9250Sstevel@tonic-gate 	/*
9260Sstevel@tonic-gate 	 * if the child hasn't been bound yet, we can just
9270Sstevel@tonic-gate 	 * free the dip
9280Sstevel@tonic-gate 	 */
9290Sstevel@tonic-gate 	if (i_ddi_node_state(dip) < DS_INITIALIZED) {
9300Sstevel@tonic-gate 		/*
9310Sstevel@tonic-gate 		 * do not call ndi_devi_free() since it might
9320Sstevel@tonic-gate 		 * deadlock
9330Sstevel@tonic-gate 		 */
9340Sstevel@tonic-gate 		rval = ddi_remove_child(dip, 0);
9350Sstevel@tonic-gate 
9360Sstevel@tonic-gate 	} else {
9370Sstevel@tonic-gate 		char *devnm = kmem_alloc(MAXNAMELEN + 1, KM_SLEEP);
9380Sstevel@tonic-gate 		dev_info_t *pdip = ddi_get_parent(dip);
9390Sstevel@tonic-gate 
9400Sstevel@tonic-gate 		(void) ddi_deviname(dip, devnm);
9410Sstevel@tonic-gate 
9420Sstevel@tonic-gate 		USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
9430Sstevel@tonic-gate 		    "usba_destroy_child_devi:\n\t"
9440Sstevel@tonic-gate 		    "offlining dip 0x%p usba_device=0x%p (%s)", dip,
9450Sstevel@tonic-gate 		    (void *)usba_device, devnm);
9460Sstevel@tonic-gate 
9470Sstevel@tonic-gate 		(void) devfs_clean(pdip, NULL, DV_CLEAN_FORCE);
9480Sstevel@tonic-gate 		rval =	ndi_devi_unconfig_one(pdip, devnm + 1, NULL,
9490Sstevel@tonic-gate 		    flag | NDI_UNCONFIG | NDI_DEVI_OFFLINE);
9500Sstevel@tonic-gate 		if (rval != NDI_SUCCESS) {
9510Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
9520Sstevel@tonic-gate 			    " ndi_devi_unconfig_one %s%d failed (%d)",
9530Sstevel@tonic-gate 			    ddi_driver_name(dip), ddi_get_instance(dip),
9540Sstevel@tonic-gate 			    rval);
9550Sstevel@tonic-gate 		}
9560Sstevel@tonic-gate 		kmem_free(devnm, MAXNAMELEN + 1);
9570Sstevel@tonic-gate 	}
9580Sstevel@tonic-gate 
9590Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
9600Sstevel@tonic-gate 	    "usba_destroy_child_devi: rval=%d", rval);
9610Sstevel@tonic-gate 
9620Sstevel@tonic-gate 	return (rval == NDI_SUCCESS ? USB_SUCCESS : USB_FAILURE);
9630Sstevel@tonic-gate }
9640Sstevel@tonic-gate 
9650Sstevel@tonic-gate 
9660Sstevel@tonic-gate /*
9670Sstevel@tonic-gate  * list management
9680Sstevel@tonic-gate  */
9690Sstevel@tonic-gate void
9700Sstevel@tonic-gate usba_init_list(usba_list_entry_t *element, usb_opaque_t private,
9710Sstevel@tonic-gate 	ddi_iblock_cookie_t	iblock_cookie)
9720Sstevel@tonic-gate {
9730Sstevel@tonic-gate 	mutex_init(&element->list_mutex, NULL, MUTEX_DRIVER,
9740Sstevel@tonic-gate 						iblock_cookie);
9750Sstevel@tonic-gate 	mutex_enter(&element->list_mutex);
9760Sstevel@tonic-gate 	element->private = private;
9770Sstevel@tonic-gate 	mutex_exit(&element->list_mutex);
9780Sstevel@tonic-gate }
9790Sstevel@tonic-gate 
9800Sstevel@tonic-gate 
9810Sstevel@tonic-gate void
9820Sstevel@tonic-gate usba_destroy_list(usba_list_entry_t *head)
9830Sstevel@tonic-gate {
9840Sstevel@tonic-gate 	mutex_enter(&head->list_mutex);
9850Sstevel@tonic-gate 	ASSERT(head->next == NULL);
9860Sstevel@tonic-gate 	ASSERT(head->prev == NULL);
9870Sstevel@tonic-gate 	mutex_exit(&head->list_mutex);
9880Sstevel@tonic-gate 
9890Sstevel@tonic-gate 	mutex_destroy(&head->list_mutex);
9900Sstevel@tonic-gate }
9910Sstevel@tonic-gate 
9920Sstevel@tonic-gate 
9930Sstevel@tonic-gate void
9940Sstevel@tonic-gate usba_add_to_list(usba_list_entry_t *head, usba_list_entry_t *element)
9950Sstevel@tonic-gate {
9960Sstevel@tonic-gate 	usba_list_entry_t *next;
9970Sstevel@tonic-gate 	int		remaining;
9980Sstevel@tonic-gate 
9990Sstevel@tonic-gate 	mutex_enter(&head->list_mutex);
10000Sstevel@tonic-gate 	mutex_enter(&element->list_mutex);
10010Sstevel@tonic-gate 
10020Sstevel@tonic-gate 	remaining = head->count;
10030Sstevel@tonic-gate 
10040Sstevel@tonic-gate 	/* check if it is not in another list */
10050Sstevel@tonic-gate 	ASSERT(element->next == NULL);
10060Sstevel@tonic-gate 	ASSERT(element->prev == NULL);
10070Sstevel@tonic-gate 
10080Sstevel@tonic-gate #ifdef DEBUG
10090Sstevel@tonic-gate 	/*
10100Sstevel@tonic-gate 	 * only verify the list when not in interrupt context, we
10110Sstevel@tonic-gate 	 * have to trust the HCD
10120Sstevel@tonic-gate 	 */
10130Sstevel@tonic-gate 	if (!servicing_interrupt()) {
10140Sstevel@tonic-gate 
10150Sstevel@tonic-gate 		/* check if not already in this list */
10160Sstevel@tonic-gate 		for (next = head->next; (next != NULL);
10170Sstevel@tonic-gate 		    next = next->next) {
10180Sstevel@tonic-gate 			if (next == element) {
10190Sstevel@tonic-gate 				USB_DPRINTF_L0(DPRINT_MASK_USBA,
10200Sstevel@tonic-gate 				    usba_log_handle,
10210Sstevel@tonic-gate 				    "Attempt to corrupt USB list at 0x%p",
10220Sstevel@tonic-gate 				    (void *)head);
10230Sstevel@tonic-gate 				ASSERT(next == element);
10240Sstevel@tonic-gate 
10250Sstevel@tonic-gate 				goto done;
10260Sstevel@tonic-gate 			}
10270Sstevel@tonic-gate 			remaining--;
10280Sstevel@tonic-gate 
10290Sstevel@tonic-gate 			/*
10300Sstevel@tonic-gate 			 * Detect incorrect circ links or found
10310Sstevel@tonic-gate 			 * unexpected elements.
10320Sstevel@tonic-gate 			 */
10330Sstevel@tonic-gate 			if ((next->next && (remaining == 0)) ||
10340Sstevel@tonic-gate 			    ((next->next == NULL) && remaining)) {
10350Sstevel@tonic-gate 				panic("Corrupted USB list at 0x%p",
10360Sstevel@tonic-gate 				    (void *)head);
10370Sstevel@tonic-gate 				/*NOTREACHED*/
10380Sstevel@tonic-gate 			}
10390Sstevel@tonic-gate 		}
10400Sstevel@tonic-gate 	}
10410Sstevel@tonic-gate #endif
10420Sstevel@tonic-gate 
10430Sstevel@tonic-gate 	if (head->next == NULL) {
10440Sstevel@tonic-gate 		head->prev = head->next = element;
10450Sstevel@tonic-gate 	} else {
10460Sstevel@tonic-gate 		/* add to tail */
10470Sstevel@tonic-gate 		head->prev->next = element;
10480Sstevel@tonic-gate 		element->prev = head->prev;
10490Sstevel@tonic-gate 		head->prev = element;
10500Sstevel@tonic-gate 	}
10510Sstevel@tonic-gate 
10520Sstevel@tonic-gate 	head->count++;
10530Sstevel@tonic-gate 
10540Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
10550Sstevel@tonic-gate 	    "usba_add_to_list: head=0x%p element=0x%p count=%d",
10560Sstevel@tonic-gate 	    head, element, head->count);
10570Sstevel@tonic-gate 
10580Sstevel@tonic-gate done:
10590Sstevel@tonic-gate 	mutex_exit(&head->list_mutex);
10600Sstevel@tonic-gate 	mutex_exit(&element->list_mutex);
10610Sstevel@tonic-gate }
10620Sstevel@tonic-gate 
10630Sstevel@tonic-gate 
10640Sstevel@tonic-gate int
10650Sstevel@tonic-gate usba_rm_from_list(usba_list_entry_t *head, usba_list_entry_t *element)
10660Sstevel@tonic-gate {
10670Sstevel@tonic-gate 	usba_list_entry_t *e;
10680Sstevel@tonic-gate 	int		found = 0;
10690Sstevel@tonic-gate 	int		remaining;
10700Sstevel@tonic-gate 
10710Sstevel@tonic-gate 	/* find the element in the list first */
10720Sstevel@tonic-gate 	mutex_enter(&head->list_mutex);
10730Sstevel@tonic-gate 
10740Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
10750Sstevel@tonic-gate 	    "usba_rm_from_list: head=0x%p element=0x%p count=%d",
10760Sstevel@tonic-gate 	    head, element, head->count);
10770Sstevel@tonic-gate 
10780Sstevel@tonic-gate 	remaining = head->count;
10790Sstevel@tonic-gate 	e = head->next;
10800Sstevel@tonic-gate 
10810Sstevel@tonic-gate 	while (e) {
10820Sstevel@tonic-gate 		if (e == element) {
10830Sstevel@tonic-gate 			found++;
10840Sstevel@tonic-gate 			break;
10850Sstevel@tonic-gate 		}
10860Sstevel@tonic-gate 		e = e->next;
10870Sstevel@tonic-gate 
10880Sstevel@tonic-gate 		remaining--;
10890Sstevel@tonic-gate 
10900Sstevel@tonic-gate 		/* Detect incorrect circ links or found unexpected elements. */
10910Sstevel@tonic-gate 		if ((e && (remaining == 0)) ||
10920Sstevel@tonic-gate 		    ((e == NULL) && (remaining))) {
10930Sstevel@tonic-gate 			panic("Corrupted USB list at 0x%p", (void *)head);
10940Sstevel@tonic-gate 			/*NOTREACHED*/
10950Sstevel@tonic-gate 		}
10960Sstevel@tonic-gate 	}
10970Sstevel@tonic-gate 
10980Sstevel@tonic-gate 	if (!found) {
10990Sstevel@tonic-gate 		mutex_exit(&head->list_mutex);
11000Sstevel@tonic-gate 
11010Sstevel@tonic-gate 		return (USB_FAILURE);
11020Sstevel@tonic-gate 	}
11030Sstevel@tonic-gate 
11040Sstevel@tonic-gate 	/* now remove the element */
11050Sstevel@tonic-gate 	mutex_enter(&element->list_mutex);
11060Sstevel@tonic-gate 
11070Sstevel@tonic-gate 	if (element->next) {
11080Sstevel@tonic-gate 		element->next->prev = element->prev;
11090Sstevel@tonic-gate 	}
11100Sstevel@tonic-gate 	if (element->prev) {
11110Sstevel@tonic-gate 		element->prev->next = element->next;
11120Sstevel@tonic-gate 	}
11130Sstevel@tonic-gate 	if (head->next == element) {
11140Sstevel@tonic-gate 		head->next = element->next;
11150Sstevel@tonic-gate 	}
11160Sstevel@tonic-gate 	if (head->prev == element) {
11170Sstevel@tonic-gate 		head->prev = element->prev;
11180Sstevel@tonic-gate 	}
11190Sstevel@tonic-gate 
11200Sstevel@tonic-gate 	element->prev = element->next = NULL;
11210Sstevel@tonic-gate 	if (head->next == NULL) {
11220Sstevel@tonic-gate 		ASSERT(head->prev == NULL);
11230Sstevel@tonic-gate 	} else {
11240Sstevel@tonic-gate 		ASSERT(head->next->prev == NULL);
11250Sstevel@tonic-gate 	}
11260Sstevel@tonic-gate 	if (head->prev == NULL) {
11270Sstevel@tonic-gate 		ASSERT(head->next == NULL);
11280Sstevel@tonic-gate 	} else {
11290Sstevel@tonic-gate 		ASSERT(head->prev->next == NULL);
11300Sstevel@tonic-gate 	}
11310Sstevel@tonic-gate 
11320Sstevel@tonic-gate 	head->count--;
11330Sstevel@tonic-gate 
11340Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
11350Sstevel@tonic-gate 	    "usba_rm_from_list success: head=0x%p element=0x%p cnt=%d",
11360Sstevel@tonic-gate 	    head, element, head->count);
11370Sstevel@tonic-gate 
11380Sstevel@tonic-gate 	mutex_exit(&element->list_mutex);
11390Sstevel@tonic-gate 	mutex_exit(&head->list_mutex);
11400Sstevel@tonic-gate 
11410Sstevel@tonic-gate 	return (USB_SUCCESS);
11420Sstevel@tonic-gate }
11430Sstevel@tonic-gate 
11440Sstevel@tonic-gate 
11450Sstevel@tonic-gate usba_list_entry_t *
11460Sstevel@tonic-gate usba_rm_first_from_list(usba_list_entry_t *head)
11470Sstevel@tonic-gate {
11480Sstevel@tonic-gate 	usba_list_entry_t *element = NULL;
11490Sstevel@tonic-gate 
11500Sstevel@tonic-gate 	if (head) {
11510Sstevel@tonic-gate 		mutex_enter(&head->list_mutex);
11520Sstevel@tonic-gate 		element = head->next;
11530Sstevel@tonic-gate 		if (element) {
11540Sstevel@tonic-gate 			/* now remove the element */
11550Sstevel@tonic-gate 			mutex_enter(&element->list_mutex);
11560Sstevel@tonic-gate 			head->next = element->next;
11570Sstevel@tonic-gate 			if (head->next) {
11580Sstevel@tonic-gate 				head->next->prev = NULL;
11590Sstevel@tonic-gate 			}
11600Sstevel@tonic-gate 			if (head->prev == element) {
11610Sstevel@tonic-gate 				head->prev = element->next;
11620Sstevel@tonic-gate 			}
11630Sstevel@tonic-gate 			element->prev = element->next = NULL;
11640Sstevel@tonic-gate 			mutex_exit(&element->list_mutex);
11650Sstevel@tonic-gate 			head->count--;
11660Sstevel@tonic-gate 		}
11670Sstevel@tonic-gate 		if (head->next == NULL) {
11680Sstevel@tonic-gate 			ASSERT(head->prev == NULL);
11690Sstevel@tonic-gate 		} else {
11700Sstevel@tonic-gate 			ASSERT(head->next->prev == NULL);
11710Sstevel@tonic-gate 		}
11720Sstevel@tonic-gate 		if (head->prev == NULL) {
11730Sstevel@tonic-gate 			ASSERT(head->next == NULL);
11740Sstevel@tonic-gate 		} else {
11750Sstevel@tonic-gate 			ASSERT(head->prev->next == NULL);
11760Sstevel@tonic-gate 		}
11770Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
11780Sstevel@tonic-gate 		    "usba_rm_first_from_list: head=0x%p el=0x%p cnt=%d",
11790Sstevel@tonic-gate 		    head, element, head->count);
11800Sstevel@tonic-gate 
11810Sstevel@tonic-gate 		mutex_exit(&head->list_mutex);
11820Sstevel@tonic-gate 	}
11830Sstevel@tonic-gate 
11840Sstevel@tonic-gate 	return (element);
11850Sstevel@tonic-gate }
11860Sstevel@tonic-gate 
11870Sstevel@tonic-gate 
11880Sstevel@tonic-gate usb_opaque_t
11890Sstevel@tonic-gate usba_rm_first_pvt_from_list(usba_list_entry_t *head)
11900Sstevel@tonic-gate {
11910Sstevel@tonic-gate 	usba_list_entry_t *element = usba_rm_first_from_list(head);
11920Sstevel@tonic-gate 	usb_opaque_t private = NULL;
11930Sstevel@tonic-gate 
11940Sstevel@tonic-gate 	if (element) {
11950Sstevel@tonic-gate 		mutex_enter(&element->list_mutex);
11960Sstevel@tonic-gate 		private = element->private;
11970Sstevel@tonic-gate 		mutex_exit(&element->list_mutex);
11980Sstevel@tonic-gate 	}
11990Sstevel@tonic-gate 
12000Sstevel@tonic-gate 	return (private);
12010Sstevel@tonic-gate }
12020Sstevel@tonic-gate 
12030Sstevel@tonic-gate 
12040Sstevel@tonic-gate /*
12050Sstevel@tonic-gate  * move list to new list and zero original list
12060Sstevel@tonic-gate  */
12070Sstevel@tonic-gate void
12080Sstevel@tonic-gate usba_move_list(usba_list_entry_t *head, usba_list_entry_t *new,
12090Sstevel@tonic-gate 	ddi_iblock_cookie_t iblock_cookie)
12100Sstevel@tonic-gate {
12110Sstevel@tonic-gate 	usba_init_list(new, NULL, iblock_cookie);
12120Sstevel@tonic-gate 	mutex_enter(&head->list_mutex);
12130Sstevel@tonic-gate 	mutex_enter(&new->list_mutex);
12140Sstevel@tonic-gate 
12150Sstevel@tonic-gate 	new->next = head->next;
12160Sstevel@tonic-gate 	new->prev = head->prev;
12170Sstevel@tonic-gate 	new->count = head->count;
12180Sstevel@tonic-gate 	new->private = head->private;
12190Sstevel@tonic-gate 
12200Sstevel@tonic-gate 	head->next = NULL;
12210Sstevel@tonic-gate 	head->prev = NULL;
12220Sstevel@tonic-gate 	head->count = 0;
12230Sstevel@tonic-gate 	head->private = NULL;
12240Sstevel@tonic-gate 	mutex_exit(&head->list_mutex);
12250Sstevel@tonic-gate 	mutex_exit(&new->list_mutex);
12260Sstevel@tonic-gate }
12270Sstevel@tonic-gate 
12280Sstevel@tonic-gate 
12290Sstevel@tonic-gate int
12300Sstevel@tonic-gate usba_check_in_list(usba_list_entry_t *head, usba_list_entry_t *element)
12310Sstevel@tonic-gate {
12320Sstevel@tonic-gate 	int		rval = USB_FAILURE;
12330Sstevel@tonic-gate 	int		remaining;
12340Sstevel@tonic-gate 	usba_list_entry_t *next;
12350Sstevel@tonic-gate 
12360Sstevel@tonic-gate 	mutex_enter(&head->list_mutex);
12370Sstevel@tonic-gate 	remaining = head->count;
12380Sstevel@tonic-gate 
12390Sstevel@tonic-gate 	mutex_enter(&element->list_mutex);
12400Sstevel@tonic-gate 	for (next = head->next; next != NULL; next = next->next) {
12410Sstevel@tonic-gate 		if (next == element) {
12420Sstevel@tonic-gate 			rval = USB_SUCCESS;
12430Sstevel@tonic-gate 			break;
12440Sstevel@tonic-gate 		}
12450Sstevel@tonic-gate 		remaining--;
12460Sstevel@tonic-gate 
12470Sstevel@tonic-gate 		/* Detect incorrect circ links or found unexpected elements. */
12480Sstevel@tonic-gate 		if ((next->next && (remaining == 0)) ||
12490Sstevel@tonic-gate 		    ((next->next == NULL) && remaining)) {
12500Sstevel@tonic-gate 			panic("Corrupted USB list at 0x%p", (void *)head);
12510Sstevel@tonic-gate 			/*NOTREACHED*/
12520Sstevel@tonic-gate 		}
12530Sstevel@tonic-gate 	}
12540Sstevel@tonic-gate 	mutex_exit(&element->list_mutex);
12550Sstevel@tonic-gate 	mutex_exit(&head->list_mutex);
12560Sstevel@tonic-gate 
12570Sstevel@tonic-gate 	return (rval);
12580Sstevel@tonic-gate }
12590Sstevel@tonic-gate 
12600Sstevel@tonic-gate 
12610Sstevel@tonic-gate int
12620Sstevel@tonic-gate usba_list_entry_leaks(usba_list_entry_t *head, char *what)
12630Sstevel@tonic-gate {
12640Sstevel@tonic-gate 	int		count = 0;
12650Sstevel@tonic-gate 	int		remaining;
12660Sstevel@tonic-gate 	usba_list_entry_t *next;
12670Sstevel@tonic-gate 
12680Sstevel@tonic-gate 	mutex_enter(&head->list_mutex);
12690Sstevel@tonic-gate 	remaining = head->count;
12700Sstevel@tonic-gate 	for (next = head->next; next != NULL; next = next->next) {
12710Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_HCDI, usba_log_handle,
12720Sstevel@tonic-gate 		    "leaking %s 0x%p", what, next->private);
12730Sstevel@tonic-gate 		count++;
12740Sstevel@tonic-gate 
12750Sstevel@tonic-gate 		remaining--;
12760Sstevel@tonic-gate 
12770Sstevel@tonic-gate 		/* Detect incorrect circ links or found unexpected elements. */
12780Sstevel@tonic-gate 		if ((next->next && (remaining == 0)) ||
12790Sstevel@tonic-gate 		    ((next->next == NULL) && remaining)) {
12800Sstevel@tonic-gate 			panic("Corrupted USB list at 0x%p", (void *)head);
12810Sstevel@tonic-gate 			/*NOTREACHED*/
12820Sstevel@tonic-gate 		}
12830Sstevel@tonic-gate 	}
12840Sstevel@tonic-gate 	ASSERT(count == head->count);
12850Sstevel@tonic-gate 	mutex_exit(&head->list_mutex);
12860Sstevel@tonic-gate 
12870Sstevel@tonic-gate 	if (count) {
12880Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_HCDI, usba_log_handle,
12890Sstevel@tonic-gate 		    "usba_list_entry_count: leaking %d", count);
12900Sstevel@tonic-gate 	}
12910Sstevel@tonic-gate 
12920Sstevel@tonic-gate 	return (count);
12930Sstevel@tonic-gate }
12940Sstevel@tonic-gate 
12950Sstevel@tonic-gate 
12960Sstevel@tonic-gate int
12970Sstevel@tonic-gate usba_list_entry_count(usba_list_entry_t *head)
12980Sstevel@tonic-gate {
12990Sstevel@tonic-gate 	int count;
13000Sstevel@tonic-gate 
13010Sstevel@tonic-gate 	mutex_enter(&head->list_mutex);
13020Sstevel@tonic-gate 	count = head->count;
13030Sstevel@tonic-gate 	mutex_exit(&head->list_mutex);
13040Sstevel@tonic-gate 
13050Sstevel@tonic-gate 	return (count);
13060Sstevel@tonic-gate }
13070Sstevel@tonic-gate 
13080Sstevel@tonic-gate 
13090Sstevel@tonic-gate /*
13100Sstevel@tonic-gate  * check whether this dip is the root hub. instead of doing a
13110Sstevel@tonic-gate  * strcmp on the node name we could also check the address
13120Sstevel@tonic-gate  */
13130Sstevel@tonic-gate int
13140Sstevel@tonic-gate usba_is_root_hub(dev_info_t *dip)
13150Sstevel@tonic-gate {
13160Sstevel@tonic-gate 	if (dip) {
13170Sstevel@tonic-gate 		return (ddi_prop_exists(DDI_DEV_T_ANY, dip,
13180Sstevel@tonic-gate 		    DDI_PROP_DONTPASS|DDI_PROP_NOTPROM, "root-hub"));
13190Sstevel@tonic-gate 	}
13200Sstevel@tonic-gate 	return (0);
13210Sstevel@tonic-gate }
13220Sstevel@tonic-gate 
13230Sstevel@tonic-gate 
13240Sstevel@tonic-gate /*
13250Sstevel@tonic-gate  * get and store usba_device pointer in the devi
13260Sstevel@tonic-gate  */
13270Sstevel@tonic-gate usba_device_t *
13280Sstevel@tonic-gate usba_get_usba_device(dev_info_t *dip)
13290Sstevel@tonic-gate {
13300Sstevel@tonic-gate 	/*
13310Sstevel@tonic-gate 	 * we cannot use parent_data in the usb node because its
13320Sstevel@tonic-gate 	 * bus parent (eg. PCI nexus driver) uses this data
13330Sstevel@tonic-gate 	 *
13340Sstevel@tonic-gate 	 * we cannot use driver data in the other usb nodes since
13350Sstevel@tonic-gate 	 * usb drivers may need to use this
13360Sstevel@tonic-gate 	 */
13370Sstevel@tonic-gate 	if (usba_is_root_hub(dip)) {
13380Sstevel@tonic-gate 		usba_hcdi_t *hcdi = usba_hcdi_get_hcdi(dip);
13390Sstevel@tonic-gate 
13400Sstevel@tonic-gate 		return (hcdi->hcdi_usba_device);
13410Sstevel@tonic-gate 	} else {
13420Sstevel@tonic-gate 
13430Sstevel@tonic-gate 		return (ddi_get_parent_data(dip));
13440Sstevel@tonic-gate 	}
13450Sstevel@tonic-gate }
13460Sstevel@tonic-gate 
13470Sstevel@tonic-gate 
13480Sstevel@tonic-gate /*
13490Sstevel@tonic-gate  * Retrieve the usba_device pointer from the dev without checking for
13500Sstevel@tonic-gate  * the root hub first.	This function is only used in polled mode.
13510Sstevel@tonic-gate  */
13520Sstevel@tonic-gate usba_device_t *
13530Sstevel@tonic-gate usba_polled_get_usba_device(dev_info_t *dip)
13540Sstevel@tonic-gate {
13550Sstevel@tonic-gate 	/*
13560Sstevel@tonic-gate 	 * Don't call usba_is_root_hub() to find out if this is
13570Sstevel@tonic-gate 	 * the root hub  usba_is_root_hub() calls into the DDI
13580Sstevel@tonic-gate 	 * where there are locking issues. The dip sent in during
13590Sstevel@tonic-gate 	 * polled mode will never be the root hub, so just get
13600Sstevel@tonic-gate 	 * the usba_device pointer from the dip.
13610Sstevel@tonic-gate 	 */
13620Sstevel@tonic-gate 	return (ddi_get_parent_data(dip));
13630Sstevel@tonic-gate }
13640Sstevel@tonic-gate 
13650Sstevel@tonic-gate 
13660Sstevel@tonic-gate void
13670Sstevel@tonic-gate usba_set_usba_device(dev_info_t *dip, usba_device_t *usba_device)
13680Sstevel@tonic-gate {
13690Sstevel@tonic-gate 	if (usba_is_root_hub(dip)) {
13700Sstevel@tonic-gate 		usba_hcdi_t *hcdi = usba_hcdi_get_hcdi(dip);
13710Sstevel@tonic-gate 		/* no locking is needed here */
13720Sstevel@tonic-gate 		_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(hcdi->hcdi_usba_device))
13730Sstevel@tonic-gate 		hcdi->hcdi_usba_device = usba_device;
13740Sstevel@tonic-gate 		_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(hcdi->hcdi_usba_device))
13750Sstevel@tonic-gate 	} else {
13760Sstevel@tonic-gate 		ddi_set_parent_data(dip, usba_device);
13770Sstevel@tonic-gate 	}
13780Sstevel@tonic-gate }
13790Sstevel@tonic-gate 
13800Sstevel@tonic-gate 
13810Sstevel@tonic-gate /*
13820Sstevel@tonic-gate  * usba_set_node_name() according to class, subclass, and protocol
13830Sstevel@tonic-gate  * following the 1275 USB binding tables.
13840Sstevel@tonic-gate  */
13850Sstevel@tonic-gate 
13860Sstevel@tonic-gate /* device node table, refer to section 3.2.2.1 of 1275 binding */
13870Sstevel@tonic-gate static node_name_entry_t device_node_name_table[] = {
13880Sstevel@tonic-gate { USB_CLASS_COMM,	DONTCARE,	DONTCARE,	"communications" },
13890Sstevel@tonic-gate { USB_CLASS_HUB,	DONTCARE,	DONTCARE,	"hub" },
13900Sstevel@tonic-gate { DONTCARE,		DONTCARE,	DONTCARE,	"device" }
13910Sstevel@tonic-gate };
13920Sstevel@tonic-gate 
13930Sstevel@tonic-gate /* interface node table, refer to section 3.3.2.1 */
13940Sstevel@tonic-gate static node_name_entry_t if_node_name_table[] = {
13950Sstevel@tonic-gate { USB_CLASS_AUDIO, USB_SUBCLS_AUD_CONTROL, DONTCARE,	"sound-control" },
13960Sstevel@tonic-gate { USB_CLASS_AUDIO, USB_SUBCLS_AUD_STREAMING, DONTCARE, "sound" },
13970Sstevel@tonic-gate { USB_CLASS_AUDIO, USB_SUBCLS_AUD_MIDI_STREAMING, DONTCARE, "midi" },
13980Sstevel@tonic-gate { USB_CLASS_AUDIO, DONTCARE,		DONTCARE,	"sound" },
13990Sstevel@tonic-gate 
14000Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_DIRECT_LINE,	DONTCARE, "line" },
14010Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_ABSTRCT_CTRL,	DONTCARE, "modem" },
14020Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_PHONE_CTRL, DONTCARE, "telephone" },
14030Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_MULTCNL_ISDN, DONTCARE, "isdn" },
14040Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_ISDN,		DONTCARE, "isdn" },
14050Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_ETHERNET,	DONTCARE, "ethernet" },
14060Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_ATM_NETWORK, DONTCARE, "atm-network" },
14070Sstevel@tonic-gate { USB_CLASS_COMM, DONTCARE,		DONTCARE,	"control" },
14080Sstevel@tonic-gate 
14090Sstevel@tonic-gate { USB_CLASS_HID, USB_SUBCLS_HID_1, USB_PROTO_HID_KEYBOARD,	"keyboard" },
14100Sstevel@tonic-gate { USB_CLASS_HID, USB_SUBCLS_HID_1, USB_PROTO_HID_MOUSE,	"mouse" },
14110Sstevel@tonic-gate { USB_CLASS_HID,	DONTCARE,	DONTCARE,	"input" },
14120Sstevel@tonic-gate 
14130Sstevel@tonic-gate { USB_CLASS_HUB,	DONTCARE,	DONTCARE,	"hub" },
14140Sstevel@tonic-gate 
14150Sstevel@tonic-gate { USB_CLASS_PHYSICAL,	DONTCARE,	DONTCARE,	"physical" },
14160Sstevel@tonic-gate 
14170Sstevel@tonic-gate { USB_CLASS_PRINTER,	DONTCARE,	DONTCARE,	"printer" },
14180Sstevel@tonic-gate 
14190Sstevel@tonic-gate { USB_CLASS_MASS_STORAGE, DONTCARE,	DONTCARE,	"storage" },
14200Sstevel@tonic-gate 
14210Sstevel@tonic-gate { USB_CLASS_CDC_DATA,	DONTCARE,	DONTCARE,	"data" },
14220Sstevel@tonic-gate 
14230Sstevel@tonic-gate { USB_CLASS_SECURITY,	DONTCARE,	DONTCARE,	"security" },
14240Sstevel@tonic-gate 
14250Sstevel@tonic-gate { USB_CLASS_APP,	USB_SUBCLS_APP_FIRMWARE, DONTCARE, "firmware" },
14260Sstevel@tonic-gate { USB_CLASS_APP,	USB_SUBCLS_APP_IRDA,	DONTCARE, "IrDa" },
14270Sstevel@tonic-gate { USB_CLASS_APP,	USB_SUBCLS_APP_TEST,	DONTCARE, "test" },
14280Sstevel@tonic-gate 
14290Sstevel@tonic-gate { DONTCARE,		DONTCARE,	DONTCARE,	"interface" },
14300Sstevel@tonic-gate 
14310Sstevel@tonic-gate };
14320Sstevel@tonic-gate 
14330Sstevel@tonic-gate /* combined node table, refer to section 3.4.2.1 */
14340Sstevel@tonic-gate static node_name_entry_t combined_node_name_table[] = {
14350Sstevel@tonic-gate { USB_CLASS_AUDIO, USB_SUBCLS_AUD_CONTROL, DONTCARE,	"sound-control" },
14360Sstevel@tonic-gate { USB_CLASS_AUDIO, USB_SUBCLS_AUD_STREAMING, DONTCARE, "sound" },
14370Sstevel@tonic-gate { USB_CLASS_AUDIO, USB_SUBCLS_AUD_MIDI_STREAMING, DONTCARE, "midi" },
14380Sstevel@tonic-gate { USB_CLASS_AUDIO, DONTCARE,		DONTCARE,	"sound" },
14390Sstevel@tonic-gate 
14400Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_DIRECT_LINE,	DONTCARE, "line" },
14410Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_ABSTRCT_CTRL,	DONTCARE, "modem" },
14420Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_PHONE_CTRL, DONTCARE, "telephone" },
14430Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_MULTCNL_ISDN, DONTCARE, "isdn" },
14440Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_ISDN,		DONTCARE, "isdn" },
14450Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_ETHERNET,	DONTCARE, "ethernet" },
14460Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_ATM_NETWORK, DONTCARE, "atm-network" },
14470Sstevel@tonic-gate { USB_CLASS_COMM, DONTCARE,		DONTCARE,	"control" },
14480Sstevel@tonic-gate 
14490Sstevel@tonic-gate { USB_CLASS_HID, USB_SUBCLS_HID_1, USB_PROTO_HID_KEYBOARD, "keyboard" },
14500Sstevel@tonic-gate { USB_CLASS_HID, USB_SUBCLS_HID_1, USB_PROTO_HID_MOUSE,	"mouse" },
14510Sstevel@tonic-gate { USB_CLASS_HID,	DONTCARE,	DONTCARE,	"input" },
14520Sstevel@tonic-gate 
14530Sstevel@tonic-gate { USB_CLASS_PHYSICAL,	DONTCARE,	DONTCARE,	"physical" },
14540Sstevel@tonic-gate 
14550Sstevel@tonic-gate { USB_CLASS_PRINTER,	DONTCARE,	DONTCARE,	"printer" },
14560Sstevel@tonic-gate 
14570Sstevel@tonic-gate { USB_CLASS_MASS_STORAGE, DONTCARE,	DONTCARE,	"storage" },
14580Sstevel@tonic-gate 
14590Sstevel@tonic-gate { USB_CLASS_CDC_DATA,	DONTCARE,	DONTCARE,	"data" },
14600Sstevel@tonic-gate 
14610Sstevel@tonic-gate { USB_CLASS_SECURITY,	DONTCARE,	DONTCARE,	"security" },
14620Sstevel@tonic-gate 
14630Sstevel@tonic-gate { USB_CLASS_APP,	USB_SUBCLS_APP_FIRMWARE, DONTCARE, "firmware" },
14640Sstevel@tonic-gate { USB_CLASS_APP,	USB_SUBCLS_APP_IRDA,	DONTCARE, "IrDa" },
14650Sstevel@tonic-gate { USB_CLASS_APP,	USB_SUBCLS_APP_TEST,	DONTCARE, "test" },
14660Sstevel@tonic-gate 
14670Sstevel@tonic-gate { USB_CLASS_HUB,	DONTCARE,	DONTCARE,	"hub" },
14680Sstevel@tonic-gate { USB_CLASS_COMM,	DONTCARE,	DONTCARE,	"communications" },
14690Sstevel@tonic-gate { DONTCARE,		DONTCARE,	DONTCARE,	"device" },
14700Sstevel@tonic-gate };
14710Sstevel@tonic-gate 
14720Sstevel@tonic-gate static size_t device_node_name_table_size =
14730Sstevel@tonic-gate 	sizeof (device_node_name_table)/sizeof (struct node_name_entry);
14740Sstevel@tonic-gate static size_t if_node_name_table_size =
14750Sstevel@tonic-gate 	sizeof (if_node_name_table)/sizeof (struct node_name_entry);
14760Sstevel@tonic-gate static size_t combined_node_name_table_size =
14770Sstevel@tonic-gate 	sizeof (combined_node_name_table)/sizeof (struct node_name_entry);
14780Sstevel@tonic-gate 
14790Sstevel@tonic-gate 
14800Sstevel@tonic-gate static void
14810Sstevel@tonic-gate usba_set_node_name(dev_info_t *dip, uint8_t class, uint8_t subclass,
14820Sstevel@tonic-gate     uint8_t protocol, uint_t flag)
14830Sstevel@tonic-gate {
14840Sstevel@tonic-gate 	int i;
14850Sstevel@tonic-gate 	size_t size;
14860Sstevel@tonic-gate 	node_name_entry_t *node_name_table;
14870Sstevel@tonic-gate 
14880Sstevel@tonic-gate 	switch (flag) {
14890Sstevel@tonic-gate 	case FLAG_INTERFACE_NODE:
14900Sstevel@tonic-gate 		node_name_table = if_node_name_table;
14910Sstevel@tonic-gate 		size = if_node_name_table_size;
14920Sstevel@tonic-gate 		break;
14930Sstevel@tonic-gate 	case FLAG_DEVICE_NODE:
14940Sstevel@tonic-gate 		node_name_table = device_node_name_table;
14950Sstevel@tonic-gate 		size = device_node_name_table_size;
14960Sstevel@tonic-gate 		break;
14970Sstevel@tonic-gate 	case FLAG_COMBINED_NODE:
14980Sstevel@tonic-gate 		node_name_table = combined_node_name_table;
14990Sstevel@tonic-gate 		size = combined_node_name_table_size;
15000Sstevel@tonic-gate 		break;
15010Sstevel@tonic-gate 	default:
15020Sstevel@tonic-gate 
15030Sstevel@tonic-gate 		return;
15040Sstevel@tonic-gate 	}
15050Sstevel@tonic-gate 
15060Sstevel@tonic-gate 	for (i = 0; i < size; i++) {
15070Sstevel@tonic-gate 		int16_t c = node_name_table[i].class;
15080Sstevel@tonic-gate 		int16_t s = node_name_table[i].subclass;
15090Sstevel@tonic-gate 		int16_t p = node_name_table[i].protocol;
15100Sstevel@tonic-gate 
15110Sstevel@tonic-gate 		if (((c == DONTCARE) || (c == class)) &&
15120Sstevel@tonic-gate 		    ((s == DONTCARE) || (s == subclass)) &&
15130Sstevel@tonic-gate 		    ((p == DONTCARE) || (p == protocol))) {
15140Sstevel@tonic-gate 			char *name = node_name_table[i].name;
15150Sstevel@tonic-gate 			(void) ndi_devi_set_nodename(dip, name, 0);
15160Sstevel@tonic-gate 			break;
15170Sstevel@tonic-gate 		}
15180Sstevel@tonic-gate 	}
15190Sstevel@tonic-gate }
15200Sstevel@tonic-gate 
15210Sstevel@tonic-gate 
15220Sstevel@tonic-gate #ifdef DEBUG
15230Sstevel@tonic-gate /*
15240Sstevel@tonic-gate  * walk the children of the parent of this devi and compare the
15250Sstevel@tonic-gate  * name and  reg property of each child. If there is a match
15260Sstevel@tonic-gate  * return this node
15270Sstevel@tonic-gate  */
15280Sstevel@tonic-gate static dev_info_t *
15290Sstevel@tonic-gate usba_find_existing_node(dev_info_t *odip)
15300Sstevel@tonic-gate {
15310Sstevel@tonic-gate 	dev_info_t *ndip, *child, *pdip;
15320Sstevel@tonic-gate 	int	*odata, *ndata;
15330Sstevel@tonic-gate 	uint_t	n_odata, n_ndata;
15340Sstevel@tonic-gate 	int	circular;
15350Sstevel@tonic-gate 
15360Sstevel@tonic-gate 	pdip = ddi_get_parent(odip);
15370Sstevel@tonic-gate 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY,
15380Sstevel@tonic-gate 	    odip, DDI_PROP_DONTPASS, "reg",
15390Sstevel@tonic-gate 	    &odata, &n_odata) != DDI_SUCCESS) {
15400Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_HCDI, usba_log_handle,
15410Sstevel@tonic-gate 		    "usba_find_existing_node: "
15420Sstevel@tonic-gate 		    "%s: DDI_NOT_WELL_FORMED", ddi_driver_name(odip));
15430Sstevel@tonic-gate 
15440Sstevel@tonic-gate 		return (NULL);
15450Sstevel@tonic-gate 	}
15460Sstevel@tonic-gate 
15470Sstevel@tonic-gate 	ndi_devi_enter(pdip, &circular);
15480Sstevel@tonic-gate 	ndip = (dev_info_t *)(DEVI(pdip)->devi_child);
15490Sstevel@tonic-gate 	while ((child = ndip) != NULL) {
15500Sstevel@tonic-gate 
15510Sstevel@tonic-gate 		ndip = (dev_info_t *)(DEVI(child)->devi_sibling);
15520Sstevel@tonic-gate 
15530Sstevel@tonic-gate 		if (child == odip) {
15540Sstevel@tonic-gate 			continue;
15550Sstevel@tonic-gate 		}
15560Sstevel@tonic-gate 
15570Sstevel@tonic-gate 		if (strcmp(DEVI(child)->devi_node_name,
15580Sstevel@tonic-gate 		    DEVI(odip)->devi_node_name)) {
15590Sstevel@tonic-gate 			continue;
15600Sstevel@tonic-gate 		}
15610Sstevel@tonic-gate 
15620Sstevel@tonic-gate 		if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY,
15630Sstevel@tonic-gate 		    child, DDI_PROP_DONTPASS, "reg",
15640Sstevel@tonic-gate 		    &ndata, &n_ndata) != DDI_SUCCESS) {
15650Sstevel@tonic-gate 
15660Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_HCDI, usba_log_handle,
15670Sstevel@tonic-gate 			    "usba_find_existing_node: "
15680Sstevel@tonic-gate 			    "%s DDI_NOT_WELL_FORMED", ddi_driver_name(child));
15690Sstevel@tonic-gate 
15700Sstevel@tonic-gate 		} else if (n_ndata && n_odata && (bcmp(odata, ndata,
15710Sstevel@tonic-gate 		    max(n_odata, n_ndata) * sizeof (int)) == 0)) {
15720Sstevel@tonic-gate 
15730Sstevel@tonic-gate 			USB_DPRINTF_L3(DPRINT_MASK_HCDI, usba_log_handle,
15740Sstevel@tonic-gate 			    "usba_find_existing_node: found %s%d (%p)",
15750Sstevel@tonic-gate 			    ddi_driver_name(child),
15760Sstevel@tonic-gate 			    ddi_get_instance(child), (void *)child);
15770Sstevel@tonic-gate 
15780Sstevel@tonic-gate 			USB_DPRINTF_L3(DPRINT_MASK_HCDI, usba_log_handle,
15790Sstevel@tonic-gate 			    "usba_find_existing_node: "
15800Sstevel@tonic-gate 			    "reg: %x %x %x - %x %x %x",
15810Sstevel@tonic-gate 			    n_odata, odata[0], odata[1],
15820Sstevel@tonic-gate 			    n_ndata, ndata[0], ndata[1]);
15830Sstevel@tonic-gate 
15840Sstevel@tonic-gate 			ddi_prop_free(ndata);
15850Sstevel@tonic-gate 			break;
15860Sstevel@tonic-gate 
15870Sstevel@tonic-gate 		} else {
15880Sstevel@tonic-gate 			ddi_prop_free(ndata);
15890Sstevel@tonic-gate 		}
15900Sstevel@tonic-gate 	}
15910Sstevel@tonic-gate 
15920Sstevel@tonic-gate 	ndi_devi_exit(pdip, circular);
15930Sstevel@tonic-gate 
15940Sstevel@tonic-gate 	ddi_prop_free(odata);
15950Sstevel@tonic-gate 
15960Sstevel@tonic-gate 	return (child);
15970Sstevel@tonic-gate }
15980Sstevel@tonic-gate #endif
15990Sstevel@tonic-gate 
16000Sstevel@tonic-gate /* change all unprintable characters to spaces */
16010Sstevel@tonic-gate static void
16020Sstevel@tonic-gate usba_filter_string(char *instr, char *outstr)
16030Sstevel@tonic-gate {
16040Sstevel@tonic-gate 	while (*instr) {
16050Sstevel@tonic-gate 		if ((*instr >= ' ') && (*instr <= '~')) {
16060Sstevel@tonic-gate 			*outstr = *instr;
16070Sstevel@tonic-gate 		} else {
16080Sstevel@tonic-gate 			*outstr = ' ';
16090Sstevel@tonic-gate 		}
16100Sstevel@tonic-gate 		outstr++;
16110Sstevel@tonic-gate 		instr++;
16120Sstevel@tonic-gate 	}
16130Sstevel@tonic-gate 	*outstr = '\0';
16140Sstevel@tonic-gate }
16150Sstevel@tonic-gate 
16160Sstevel@tonic-gate 
16170Sstevel@tonic-gate /*
16180Sstevel@tonic-gate  * lookup ugen binding specified in property in
16190Sstevel@tonic-gate  * hcd.conf files
16200Sstevel@tonic-gate  */
16210Sstevel@tonic-gate int
16220Sstevel@tonic-gate usba_get_ugen_binding(dev_info_t *dip)
16230Sstevel@tonic-gate {
16240Sstevel@tonic-gate 	usba_device_t	*usba_device = usba_get_usba_device(dip);
16250Sstevel@tonic-gate 	usba_hcdi_t	*hcdi =
16260Sstevel@tonic-gate 			    usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
16270Sstevel@tonic-gate 
16280Sstevel@tonic-gate 	return (hcdi->hcdi_ugen_default_binding);
16290Sstevel@tonic-gate }
16300Sstevel@tonic-gate 
16310Sstevel@tonic-gate 
16320Sstevel@tonic-gate /*
16330Sstevel@tonic-gate  * driver binding support at device level
16340Sstevel@tonic-gate  */
16350Sstevel@tonic-gate dev_info_t *
16360Sstevel@tonic-gate usba_ready_device_node(dev_info_t *child_dip)
16370Sstevel@tonic-gate {
16380Sstevel@tonic-gate 	int		rval, i;
16390Sstevel@tonic-gate 	int		n = 0;
16400Sstevel@tonic-gate 	usba_device_t	*usba_device = usba_get_usba_device(child_dip);
16410Sstevel@tonic-gate 	usb_dev_descr_t	*usb_dev_descr;
16420Sstevel@tonic-gate 	uint_t		n_cfgs;	/* number of configs */
16430Sstevel@tonic-gate 	uint_t		n_ifs;	/* number of interfaces */
16440Sstevel@tonic-gate 	uint_t		port;
16450Sstevel@tonic-gate 	size_t		usb_config_length;
16460Sstevel@tonic-gate 	uchar_t 	*usb_config;
16470Sstevel@tonic-gate 	int		reg[1];
16480Sstevel@tonic-gate 	usb_addr_t	address = usb_get_addr(child_dip);
16490Sstevel@tonic-gate 	usb_if_descr_t	if_descr;
16500Sstevel@tonic-gate 	size_t		size;
16510Sstevel@tonic-gate 	int		combined_node = 0;
16520Sstevel@tonic-gate 	int		is_hub;
16530Sstevel@tonic-gate 	char		*devprop_str;
16540Sstevel@tonic-gate 	char		*force_bind = NULL;
16550Sstevel@tonic-gate 
16560Sstevel@tonic-gate 	usb_config = usb_get_raw_cfg_data(child_dip, &usb_config_length);
16570Sstevel@tonic-gate 
16580Sstevel@tonic-gate 	mutex_enter(&usba_device->usb_mutex);
16590Sstevel@tonic-gate 	mutex_enter(&usba_mutex);
16600Sstevel@tonic-gate 
16610Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
16620Sstevel@tonic-gate 	    "usba_ready_device_node: child=0x%p", (void *)child_dip);
16630Sstevel@tonic-gate 
16640Sstevel@tonic-gate 	port = usba_device->usb_port;
16650Sstevel@tonic-gate 	usb_dev_descr = usba_device->usb_dev_descr;
16660Sstevel@tonic-gate 	n_cfgs = usba_device->usb_n_cfgs;
16670Sstevel@tonic-gate 	n_ifs = usba_device->usb_n_ifs;
16680Sstevel@tonic-gate 
16690Sstevel@tonic-gate 
16700Sstevel@tonic-gate 	if (address != ROOT_HUB_ADDR) {
16710Sstevel@tonic-gate 		size = usb_parse_if_descr(
16720Sstevel@tonic-gate 				usb_config,
16730Sstevel@tonic-gate 				usb_config_length,
16740Sstevel@tonic-gate 				0,		/* interface index */
16750Sstevel@tonic-gate 				0,		/* alt interface index */
16760Sstevel@tonic-gate 				&if_descr,
16770Sstevel@tonic-gate 				USB_IF_DESCR_SIZE);
16780Sstevel@tonic-gate 
16790Sstevel@tonic-gate 		if (size != USB_IF_DESCR_SIZE) {
16800Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_USBA, usba_log_handle,
16810Sstevel@tonic-gate 			    "parsing interface: "
16820Sstevel@tonic-gate 			    "size (%lu) != USB_IF_DESCR_SIZE (%d)",
16830Sstevel@tonic-gate 			    size, USB_IF_DESCR_SIZE);
16840Sstevel@tonic-gate 
16850Sstevel@tonic-gate 			mutex_exit(&usba_mutex);
16860Sstevel@tonic-gate 			mutex_exit(&usba_device->usb_mutex);
16870Sstevel@tonic-gate 
16880Sstevel@tonic-gate 			return (child_dip);
16890Sstevel@tonic-gate 		}
16900Sstevel@tonic-gate 	} else {
16910Sstevel@tonic-gate 		/* fake an interface descriptor for the root hub */
16920Sstevel@tonic-gate 		bzero(&if_descr, sizeof (if_descr));
16930Sstevel@tonic-gate 
16940Sstevel@tonic-gate 		if_descr.bInterfaceClass = USB_CLASS_HUB;
16950Sstevel@tonic-gate 	}
16960Sstevel@tonic-gate 
16970Sstevel@tonic-gate 	reg[0] = port;
16980Sstevel@tonic-gate 
16990Sstevel@tonic-gate 	mutex_exit(&usba_mutex);
17000Sstevel@tonic-gate 	mutex_exit(&usba_device->usb_mutex);
17010Sstevel@tonic-gate 
17020Sstevel@tonic-gate 	rval = ndi_prop_update_int_array(
17030Sstevel@tonic-gate 		DDI_DEV_T_NONE, child_dip, "reg", reg, 1);
17040Sstevel@tonic-gate 
17050Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
17060Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_USBA, usba_log_handle,
17070Sstevel@tonic-gate 		    "usba_ready_device_node: property update failed");
17080Sstevel@tonic-gate 
17090Sstevel@tonic-gate 		return (child_dip);
17100Sstevel@tonic-gate 	}
17110Sstevel@tonic-gate 
17120Sstevel@tonic-gate 	combined_node = ((n_cfgs == 1) && (n_ifs == 1) &&
17130Sstevel@tonic-gate 	    ((usb_dev_descr->bDeviceClass == USB_CLASS_HUB) ||
17140Sstevel@tonic-gate 	    (usb_dev_descr->bDeviceClass == 0)));
17150Sstevel@tonic-gate 
17160Sstevel@tonic-gate 	is_hub = (if_descr.bInterfaceClass == USB_CLASS_HUB) ||
17170Sstevel@tonic-gate 		(usb_dev_descr->bDeviceClass == USB_CLASS_HUB);
17180Sstevel@tonic-gate 
17190Sstevel@tonic-gate 	/* set node name */
17200Sstevel@tonic-gate 	if (combined_node) {
17210Sstevel@tonic-gate 		usba_set_node_name(child_dip,
17220Sstevel@tonic-gate 		    if_descr.bInterfaceClass,
17230Sstevel@tonic-gate 		    if_descr.bInterfaceSubClass,
17240Sstevel@tonic-gate 		    if_descr.bInterfaceProtocol,
17250Sstevel@tonic-gate 		    FLAG_COMBINED_NODE);
17260Sstevel@tonic-gate 	} else {
17270Sstevel@tonic-gate 		usba_set_node_name(child_dip,
17280Sstevel@tonic-gate 		    usb_dev_descr->bDeviceClass,
17290Sstevel@tonic-gate 		    usb_dev_descr->bDeviceSubClass,
17300Sstevel@tonic-gate 		    usb_dev_descr->bDeviceProtocol,
17310Sstevel@tonic-gate 		    FLAG_DEVICE_NODE);
17320Sstevel@tonic-gate 	}
17330Sstevel@tonic-gate 
17340Sstevel@tonic-gate 	/*
17350Sstevel@tonic-gate 	 * check force binding rules
17360Sstevel@tonic-gate 	 */
17370Sstevel@tonic-gate 	if ((address != ROOT_HUB_ADDR) && usba_ddivs_usbc &&
17380Sstevel@tonic-gate 	    (address != usba_ddivs_usbc_xaddress) &&
17390Sstevel@tonic-gate 	    (!(usba_ddivs_usbc_xhubs && is_hub))) {
17400Sstevel@tonic-gate 		force_bind = "ddivs_usbc";
17410Sstevel@tonic-gate 		(void) ndi_devi_set_nodename(child_dip, "ddivs_usbc", 0);
17420Sstevel@tonic-gate 
17430Sstevel@tonic-gate 	} else if (usba_device->usb_preferred_driver) {
17440Sstevel@tonic-gate 		force_bind = usba_device->usb_preferred_driver;
17450Sstevel@tonic-gate 
17460Sstevel@tonic-gate 	} else if ((address != ROOT_HUB_ADDR) &&
17470Sstevel@tonic-gate 	    ((usba_ugen_force_binding == USBA_UGEN_DEVICE_BINDING) ||
17480Sstevel@tonic-gate 	    ((usba_ugen_force_binding == USBA_UGEN_INTERFACE_BINDING) &&
17490Sstevel@tonic-gate 	    combined_node)) && (!is_hub)) {
17500Sstevel@tonic-gate 		force_bind = "ugen";
17510Sstevel@tonic-gate 	}
17520Sstevel@tonic-gate 
17530Sstevel@tonic-gate #ifdef DEBUG
17540Sstevel@tonic-gate 	/*
17550Sstevel@tonic-gate 	 * check whether there is another dip with this name and address
17560Sstevel@tonic-gate 	 * If the dip contains usba_device, it is held by the previous
17570Sstevel@tonic-gate 	 * round of configuration.
17580Sstevel@tonic-gate 	 */
17590Sstevel@tonic-gate 	ASSERT(usba_find_existing_node(child_dip) == NULL);
17600Sstevel@tonic-gate #endif
17610Sstevel@tonic-gate 	mutex_enter(&usba_mutex);
17620Sstevel@tonic-gate 
17630Sstevel@tonic-gate 	if (force_bind) {
17640Sstevel@tonic-gate 		(void) ndi_devi_set_nodename(child_dip, force_bind, 0);
17650Sstevel@tonic-gate 		(void) strncpy(usba_name[n++], force_bind,
17660Sstevel@tonic-gate 						USBA_MAX_COMPAT_NAME_LEN);
17670Sstevel@tonic-gate 	}
17680Sstevel@tonic-gate 
17690Sstevel@tonic-gate 	/* create compatible names */
17700Sstevel@tonic-gate 	if (combined_node) {
17710Sstevel@tonic-gate 
17720Sstevel@tonic-gate 		/* 1. usbVID,PID.REV */
17730Sstevel@tonic-gate 		(void) sprintf(usba_name[n++],
17740Sstevel@tonic-gate 			"usb%x,%x.%x",
17750Sstevel@tonic-gate 			usb_dev_descr->idVendor,
17760Sstevel@tonic-gate 			usb_dev_descr->idProduct,
17770Sstevel@tonic-gate 			usb_dev_descr->bcdDevice);
17780Sstevel@tonic-gate 
17790Sstevel@tonic-gate 		/* 2. usbVID,PID */
17800Sstevel@tonic-gate 		(void) sprintf(usba_name[n++],
17810Sstevel@tonic-gate 			"usb%x,%x",
17820Sstevel@tonic-gate 			usb_dev_descr->idVendor,
17830Sstevel@tonic-gate 			usb_dev_descr->idProduct);
17840Sstevel@tonic-gate 
17850Sstevel@tonic-gate 		if (usb_dev_descr->bDeviceClass != 0) {
17860Sstevel@tonic-gate 			/* 3. usbVID,classDC.DSC.DPROTO */
17870Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
17880Sstevel@tonic-gate 				"usb%x,class%x.%x.%x",
17890Sstevel@tonic-gate 				usb_dev_descr->idVendor,
17900Sstevel@tonic-gate 				usb_dev_descr->bDeviceClass,
17910Sstevel@tonic-gate 				usb_dev_descr->bDeviceSubClass,
17920Sstevel@tonic-gate 				usb_dev_descr->bDeviceProtocol);
17930Sstevel@tonic-gate 
17940Sstevel@tonic-gate 			/* 4. usbVID,classDC.DSC */
17950Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
17960Sstevel@tonic-gate 				"usb%x,class%x.%x",
17970Sstevel@tonic-gate 				usb_dev_descr->idVendor,
17980Sstevel@tonic-gate 				usb_dev_descr->bDeviceClass,
17990Sstevel@tonic-gate 				usb_dev_descr->bDeviceSubClass);
18000Sstevel@tonic-gate 
18010Sstevel@tonic-gate 			/* 5. usbVID,classDC */
18020Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
18030Sstevel@tonic-gate 				"usb%x,class%x",
18040Sstevel@tonic-gate 				usb_dev_descr->idVendor,
18050Sstevel@tonic-gate 				usb_dev_descr->bDeviceClass);
18060Sstevel@tonic-gate 
18070Sstevel@tonic-gate 			/* 6. usb,classDC.DSC.DPROTO */
18080Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
18090Sstevel@tonic-gate 				"usb,class%x.%x.%x",
18100Sstevel@tonic-gate 				usb_dev_descr->bDeviceClass,
18110Sstevel@tonic-gate 				usb_dev_descr->bDeviceSubClass,
18120Sstevel@tonic-gate 				usb_dev_descr->bDeviceProtocol);
18130Sstevel@tonic-gate 
18140Sstevel@tonic-gate 			/* 7. usb,classDC.DSC */
18150Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
18160Sstevel@tonic-gate 				"usb,class%x.%x",
18170Sstevel@tonic-gate 				usb_dev_descr->bDeviceClass,
18180Sstevel@tonic-gate 				usb_dev_descr->bDeviceSubClass);
18190Sstevel@tonic-gate 
18200Sstevel@tonic-gate 			/* 8. usb,classDC */
18210Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
18220Sstevel@tonic-gate 				"usb,class%x",
18230Sstevel@tonic-gate 				usb_dev_descr->bDeviceClass);
18240Sstevel@tonic-gate 		}
18250Sstevel@tonic-gate 
18260Sstevel@tonic-gate 		if (if_descr.bInterfaceClass != 0) {
18270Sstevel@tonic-gate 			/* 9. usbifVID,classIC.ISC.IPROTO */
18280Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
18290Sstevel@tonic-gate 				"usbif%x,class%x.%x.%x",
18300Sstevel@tonic-gate 				usb_dev_descr->idVendor,
18310Sstevel@tonic-gate 				if_descr.bInterfaceClass,
18320Sstevel@tonic-gate 				if_descr.bInterfaceSubClass,
18330Sstevel@tonic-gate 				if_descr.bInterfaceProtocol);
18340Sstevel@tonic-gate 
18350Sstevel@tonic-gate 			/* 10. usbifVID,classIC.ISC */
18360Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
18370Sstevel@tonic-gate 				"usbif%x,class%x.%x",
18380Sstevel@tonic-gate 				usb_dev_descr->idVendor,
18390Sstevel@tonic-gate 				if_descr.bInterfaceClass,
18400Sstevel@tonic-gate 				if_descr.bInterfaceSubClass);
18410Sstevel@tonic-gate 
18420Sstevel@tonic-gate 			/* 11. usbifVID,classIC */
18430Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
18440Sstevel@tonic-gate 				"usbif%x,class%x",
18450Sstevel@tonic-gate 				usb_dev_descr->idVendor,
18460Sstevel@tonic-gate 				if_descr.bInterfaceClass);
18470Sstevel@tonic-gate 
18480Sstevel@tonic-gate 			/* 12. usbif,classIC.ISC.IPROTO */
18490Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
18500Sstevel@tonic-gate 				"usbif,class%x.%x.%x",
18510Sstevel@tonic-gate 				if_descr.bInterfaceClass,
18520Sstevel@tonic-gate 				if_descr.bInterfaceSubClass,
18530Sstevel@tonic-gate 				if_descr.bInterfaceProtocol);
18540Sstevel@tonic-gate 
18550Sstevel@tonic-gate 			/* 13. usbif,classIC.ISC */
18560Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
18570Sstevel@tonic-gate 				"usbif,class%x.%x",
18580Sstevel@tonic-gate 				if_descr.bInterfaceClass,
18590Sstevel@tonic-gate 				if_descr.bInterfaceSubClass);
18600Sstevel@tonic-gate 
18610Sstevel@tonic-gate 			/* 14. usbif,classIC */
18620Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
18630Sstevel@tonic-gate 				"usbif,class%x",
18640Sstevel@tonic-gate 				if_descr.bInterfaceClass);
18650Sstevel@tonic-gate 		}
18660Sstevel@tonic-gate 
18670Sstevel@tonic-gate 		/* 15. ugen or usb_mid */
18680Sstevel@tonic-gate 		if (usba_get_ugen_binding(child_dip) ==
18690Sstevel@tonic-gate 		    USBA_UGEN_DEVICE_BINDING) {
18700Sstevel@tonic-gate 			(void) sprintf(usba_name[n++], "ugen");
18710Sstevel@tonic-gate 		} else {
18720Sstevel@tonic-gate 			(void) sprintf(usba_name[n++], "usb,device");
18730Sstevel@tonic-gate 		}
18740Sstevel@tonic-gate 
18750Sstevel@tonic-gate 	} else {
18760Sstevel@tonic-gate 		if (n_cfgs > 1) {
18770Sstevel@tonic-gate 			/* 1. usbVID,PID.REV.configCN */
18780Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
18790Sstevel@tonic-gate 				"usb%x,%x.%x.config%x",
18800Sstevel@tonic-gate 				usb_dev_descr->idVendor,
18810Sstevel@tonic-gate 				usb_dev_descr->idProduct,
18820Sstevel@tonic-gate 				usb_dev_descr->bcdDevice,
18830Sstevel@tonic-gate 				usba_device->usb_cfg_value);
18840Sstevel@tonic-gate 		}
18850Sstevel@tonic-gate 
18860Sstevel@tonic-gate 		/* 2. usbVID,PID.REV */
18870Sstevel@tonic-gate 		(void) sprintf(usba_name[n++],
18880Sstevel@tonic-gate 			"usb%x,%x.%x",
18890Sstevel@tonic-gate 			usb_dev_descr->idVendor,
18900Sstevel@tonic-gate 			usb_dev_descr->idProduct,
18910Sstevel@tonic-gate 			usb_dev_descr->bcdDevice);
18920Sstevel@tonic-gate 
18930Sstevel@tonic-gate 		/* 3. usbVID,PID.configCN */
18940Sstevel@tonic-gate 		if (n_cfgs > 1) {
18950Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
18960Sstevel@tonic-gate 				"usb%x,%x.%x",
18970Sstevel@tonic-gate 				usb_dev_descr->idVendor,
18980Sstevel@tonic-gate 				usb_dev_descr->idProduct,
18990Sstevel@tonic-gate 				usba_device->usb_cfg_value);
19000Sstevel@tonic-gate 		}
19010Sstevel@tonic-gate 
19020Sstevel@tonic-gate 		/* 4. usbVID,PID */
19030Sstevel@tonic-gate 		(void) sprintf(usba_name[n++],
19040Sstevel@tonic-gate 			"usb%x,%x",
19050Sstevel@tonic-gate 			usb_dev_descr->idVendor,
19060Sstevel@tonic-gate 			usb_dev_descr->idProduct);
19070Sstevel@tonic-gate 
19080Sstevel@tonic-gate 		if (usb_dev_descr->bDeviceClass != 0) {
19090Sstevel@tonic-gate 			/* 5. usbVID,classDC.DSC.DPROTO */
19100Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
19110Sstevel@tonic-gate 				"usb%x,class%x.%x.%x",
19120Sstevel@tonic-gate 				usb_dev_descr->idVendor,
19130Sstevel@tonic-gate 				usb_dev_descr->bDeviceClass,
19140Sstevel@tonic-gate 				usb_dev_descr->bDeviceSubClass,
19150Sstevel@tonic-gate 				usb_dev_descr->bDeviceProtocol);
19160Sstevel@tonic-gate 
19170Sstevel@tonic-gate 			/* 6. usbVID,classDC.DSC */
19180Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
19190Sstevel@tonic-gate 				"usb%x.class%x.%x",
19200Sstevel@tonic-gate 				usb_dev_descr->idVendor,
19210Sstevel@tonic-gate 				usb_dev_descr->bDeviceClass,
19220Sstevel@tonic-gate 				usb_dev_descr->bDeviceSubClass);
19230Sstevel@tonic-gate 
19240Sstevel@tonic-gate 			/* 7. usbVID,classDC */
19250Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
19260Sstevel@tonic-gate 				"usb%x.class%x",
19270Sstevel@tonic-gate 				usb_dev_descr->idVendor,
19280Sstevel@tonic-gate 				usb_dev_descr->bDeviceClass);
19290Sstevel@tonic-gate 
19300Sstevel@tonic-gate 			/* 8. usb,classDC.DSC.DPROTO */
19310Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
19320Sstevel@tonic-gate 				"usb,class%x.%x.%x",
19330Sstevel@tonic-gate 				usb_dev_descr->bDeviceClass,
19340Sstevel@tonic-gate 				usb_dev_descr->bDeviceSubClass,
19350Sstevel@tonic-gate 				usb_dev_descr->bDeviceProtocol);
19360Sstevel@tonic-gate 
19370Sstevel@tonic-gate 			/* 9. usb,classDC.DSC */
19380Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
19390Sstevel@tonic-gate 				"usb,class%x.%x",
19400Sstevel@tonic-gate 				usb_dev_descr->bDeviceClass,
19410Sstevel@tonic-gate 				usb_dev_descr->bDeviceSubClass);
19420Sstevel@tonic-gate 
19430Sstevel@tonic-gate 			/* 10. usb,classDC */
19440Sstevel@tonic-gate 			(void) sprintf(usba_name[n++],
19450Sstevel@tonic-gate 				"usb,class%x",
19460Sstevel@tonic-gate 				usb_dev_descr->bDeviceClass);
19470Sstevel@tonic-gate 		}
19480Sstevel@tonic-gate 
19490Sstevel@tonic-gate 		if (usba_get_ugen_binding(child_dip) ==
19500Sstevel@tonic-gate 		    USBA_UGEN_DEVICE_BINDING) {
19510Sstevel@tonic-gate 			/* 11. ugen */
19520Sstevel@tonic-gate 			(void) sprintf(usba_name[n++], "ugen");
19530Sstevel@tonic-gate 		} else {
19540Sstevel@tonic-gate 			/* 11. usb,device */
19550Sstevel@tonic-gate 			(void) sprintf(usba_name[n++], "usb,device");
19560Sstevel@tonic-gate 		}
19570Sstevel@tonic-gate 	}
19580Sstevel@tonic-gate 
19590Sstevel@tonic-gate 	for (i = 0; i < n; i += 2) {
19600Sstevel@tonic-gate 		USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
19610Sstevel@tonic-gate 		    "compatible name:\t%s\t%s", usba_compatible[i],
19620Sstevel@tonic-gate 		    (((i+1) < n)? usba_compatible[i+1] : ""));
19630Sstevel@tonic-gate 	}
19640Sstevel@tonic-gate 	mutex_exit(&usba_mutex);
19650Sstevel@tonic-gate 
19660Sstevel@tonic-gate 	if (n) {
19670Sstevel@tonic-gate 		rval = ndi_prop_update_string_array(
19680Sstevel@tonic-gate 		    DDI_DEV_T_NONE, child_dip,
19690Sstevel@tonic-gate 		    "compatible", (char **)usba_compatible, n);
19700Sstevel@tonic-gate 
19710Sstevel@tonic-gate 		if (rval != DDI_PROP_SUCCESS) {
19720Sstevel@tonic-gate 
19730Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_USBA, usba_log_handle,
19740Sstevel@tonic-gate 			    "usba_ready_device_node: property update failed");
19750Sstevel@tonic-gate 
19760Sstevel@tonic-gate 			return (child_dip);
19770Sstevel@tonic-gate 		}
19780Sstevel@tonic-gate 	}
19790Sstevel@tonic-gate 
19800Sstevel@tonic-gate 	/* update the address property */
19810Sstevel@tonic-gate 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
19820Sstevel@tonic-gate 			"assigned-address", usba_device->usb_addr);
19830Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
19840Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_USBA, usba_log_handle,
19850Sstevel@tonic-gate 		    "usba_ready_device_node: address update failed");
19860Sstevel@tonic-gate 	}
19870Sstevel@tonic-gate 
19880Sstevel@tonic-gate 	/* update the address property */
19890Sstevel@tonic-gate 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
19900Sstevel@tonic-gate 			"assigned-address", usba_device->usb_addr);
19910Sstevel@tonic-gate 
19920Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
19930Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_USBA, usba_log_handle,
19940Sstevel@tonic-gate 		    "usba_ready_device_node: address update failed");
19950Sstevel@tonic-gate 	}
19960Sstevel@tonic-gate 
19970Sstevel@tonic-gate 	/* update the usb device properties (PSARC/2000/454) */
19980Sstevel@tonic-gate 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
19990Sstevel@tonic-gate 	    "usb-vendor-id", usb_dev_descr->idVendor);
20000Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
20010Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_USBA, usba_log_handle,
20020Sstevel@tonic-gate 		    "usba_ready_device_node: usb-vendor-id update failed");
20030Sstevel@tonic-gate 	}
20040Sstevel@tonic-gate 
20050Sstevel@tonic-gate 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
20060Sstevel@tonic-gate 	    "usb-product-id", usb_dev_descr->idProduct);
20070Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
20080Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_USBA, usba_log_handle,
20090Sstevel@tonic-gate 		    "usba_ready_device_node: usb-product-id update failed");
20100Sstevel@tonic-gate 	}
20110Sstevel@tonic-gate 
20120Sstevel@tonic-gate 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
20130Sstevel@tonic-gate 	    "usb-revision-id", usb_dev_descr->bcdDevice);
20140Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
20150Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_USBA, usba_log_handle,
20160Sstevel@tonic-gate 		    "usba_ready_device_node: usb-revision-id update failed");
20170Sstevel@tonic-gate 	}
20180Sstevel@tonic-gate 
20190Sstevel@tonic-gate 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
20200Sstevel@tonic-gate 	    "usb-num-configs", usb_dev_descr->bNumConfigurations);
20210Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
20220Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_USBA, usba_log_handle,
20230Sstevel@tonic-gate 		    "usba_ready_device_node: usb-num-configs update failed");
20240Sstevel@tonic-gate 	}
20250Sstevel@tonic-gate 
20260Sstevel@tonic-gate 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
20270Sstevel@tonic-gate 	    "usb-release", usb_dev_descr->bcdUSB);
20280Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
20290Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_USBA, usba_log_handle,
20300Sstevel@tonic-gate 		    "usba_ready_device_node: usb-release update failed");
20310Sstevel@tonic-gate 	}
20320Sstevel@tonic-gate 
20330Sstevel@tonic-gate 	devprop_str = kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP);
20340Sstevel@tonic-gate 
20350Sstevel@tonic-gate 	if (usba_device->usb_serialno_str) {
20360Sstevel@tonic-gate 		usba_filter_string(usba_device->usb_serialno_str, devprop_str);
20370Sstevel@tonic-gate 		rval = ndi_prop_update_string(DDI_DEV_T_NONE, child_dip,
20380Sstevel@tonic-gate 		    "usb-serialno", devprop_str);
20390Sstevel@tonic-gate 		if (rval != DDI_PROP_SUCCESS) {
20400Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_USBA, usba_log_handle,
20410Sstevel@tonic-gate 			    "usba_ready_device_node: "
20420Sstevel@tonic-gate 			    "usb-serialno update failed");
20430Sstevel@tonic-gate 		}
20440Sstevel@tonic-gate 	}
20450Sstevel@tonic-gate 
20460Sstevel@tonic-gate 	if (usba_device->usb_mfg_str) {
20470Sstevel@tonic-gate 		usba_filter_string(usba_device->usb_mfg_str, devprop_str);
20480Sstevel@tonic-gate 		rval = ndi_prop_update_string(DDI_DEV_T_NONE, child_dip,
20490Sstevel@tonic-gate 		    "usb-vendor-name", devprop_str);
20500Sstevel@tonic-gate 		if (rval != DDI_PROP_SUCCESS) {
20510Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_USBA, usba_log_handle,
20520Sstevel@tonic-gate 			    "usba_ready_device_node: "
20530Sstevel@tonic-gate 			    "usb-vendor-name update failed");
20540Sstevel@tonic-gate 		}
20550Sstevel@tonic-gate 	}
20560Sstevel@tonic-gate 
20570Sstevel@tonic-gate 	if (usba_device->usb_product_str) {
20580Sstevel@tonic-gate 		usba_filter_string(usba_device->usb_product_str, devprop_str);
20590Sstevel@tonic-gate 		rval = ndi_prop_update_string(DDI_DEV_T_NONE, child_dip,
20600Sstevel@tonic-gate 		    "usb-product-name", devprop_str);
20610Sstevel@tonic-gate 		if (rval != DDI_PROP_SUCCESS) {
20620Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_USBA, usba_log_handle,
20630Sstevel@tonic-gate 			    "usba_ready_device_node: "
20640Sstevel@tonic-gate 			    "usb-product-name update failed");
20650Sstevel@tonic-gate 		}
20660Sstevel@tonic-gate 	}
20670Sstevel@tonic-gate 
20680Sstevel@tonic-gate 	kmem_free(devprop_str, USB_MAXSTRINGLEN);
20690Sstevel@tonic-gate 
20700Sstevel@tonic-gate 	if (!combined_node) {
20710Sstevel@tonic-gate 		/* update the configuration property */
20720Sstevel@tonic-gate 		rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
20730Sstevel@tonic-gate 			"configuration#", usba_device->usb_cfg_value);
20740Sstevel@tonic-gate 		if (rval != DDI_PROP_SUCCESS) {
20750Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
20760Sstevel@tonic-gate 			    "usba_ready_device_node: "
20770Sstevel@tonic-gate 			    "config prop update failed");
20780Sstevel@tonic-gate 		}
20790Sstevel@tonic-gate 	}
20800Sstevel@tonic-gate 
20810Sstevel@tonic-gate 	if (usba_device->usb_port_status == USBA_LOW_SPEED_DEV) {
20820Sstevel@tonic-gate 		/* create boolean property */
20830Sstevel@tonic-gate 		rval = ndi_prop_create_boolean(DDI_DEV_T_NONE, child_dip,
20840Sstevel@tonic-gate 			"low-speed");
20850Sstevel@tonic-gate 		if (rval != DDI_PROP_SUCCESS) {
20860Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_USBA, usba_log_handle,
20870Sstevel@tonic-gate 			    "usba_ready_device_node: "
20880Sstevel@tonic-gate 			    "low speed prop update failed");
20890Sstevel@tonic-gate 		}
20900Sstevel@tonic-gate 	}
20910Sstevel@tonic-gate 
20920Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
20930Sstevel@tonic-gate 	    "%s%d at port %d: %s, dip=0x%p",
20940Sstevel@tonic-gate 	    ddi_node_name(ddi_get_parent(child_dip)),
20950Sstevel@tonic-gate 	    ddi_get_instance(ddi_get_parent(child_dip)),
20960Sstevel@tonic-gate 	    port, ddi_node_name(child_dip), child_dip);
20970Sstevel@tonic-gate 
20980Sstevel@tonic-gate 	usba_set_usba_device(child_dip, usba_device);
20990Sstevel@tonic-gate 
21000Sstevel@tonic-gate 	ASSERT(!mutex_owned(&(usba_get_usba_device(child_dip)->usb_mutex)));
21010Sstevel@tonic-gate 
21020Sstevel@tonic-gate 	return (child_dip);
21030Sstevel@tonic-gate }
21040Sstevel@tonic-gate 
21050Sstevel@tonic-gate 
21060Sstevel@tonic-gate /*
21070Sstevel@tonic-gate  * driver binding at interface level, the first arg will be the
21080Sstevel@tonic-gate  * the parent dip
21090Sstevel@tonic-gate  */
21100Sstevel@tonic-gate /*ARGSUSED*/
21110Sstevel@tonic-gate dev_info_t *
21120Sstevel@tonic-gate usba_ready_interface_node(dev_info_t *dip, uint_t intf)
21130Sstevel@tonic-gate {
21140Sstevel@tonic-gate 	dev_info_t		*child_dip = NULL;
21150Sstevel@tonic-gate 	usba_device_t		*child_ud = usba_get_usba_device(dip);
21160Sstevel@tonic-gate 	usb_dev_descr_t	*usb_dev_descr;
21170Sstevel@tonic-gate 	size_t			usb_cfg_length;
21180Sstevel@tonic-gate 	uchar_t 		*usb_cfg;
21190Sstevel@tonic-gate 	usb_if_descr_t	if_descr;
21200Sstevel@tonic-gate 	int			i, n, rval;
21210Sstevel@tonic-gate 	int			reg[2];
21220Sstevel@tonic-gate 	size_t			size;
21230Sstevel@tonic-gate 	usb_port_status_t	port_status;
21240Sstevel@tonic-gate 	char			*force_bind = NULL;
21250Sstevel@tonic-gate 
21260Sstevel@tonic-gate 	usb_cfg = usb_get_raw_cfg_data(dip, &usb_cfg_length);
21270Sstevel@tonic-gate 
21280Sstevel@tonic-gate 	mutex_enter(&child_ud->usb_mutex);
21290Sstevel@tonic-gate 
21300Sstevel@tonic-gate 	usb_dev_descr = child_ud->usb_dev_descr;
21310Sstevel@tonic-gate 
21320Sstevel@tonic-gate 	/*
21330Sstevel@tonic-gate 	 * for each interface, determine all compatible names
21340Sstevel@tonic-gate 	 */
21350Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
21360Sstevel@tonic-gate 	    "usba_ready_interface_node: "
21370Sstevel@tonic-gate 	    "port %d, interface = %d port status = %x",
21380Sstevel@tonic-gate 	    child_ud->usb_port, intf, child_ud->usb_port_status);
21390Sstevel@tonic-gate 
21400Sstevel@tonic-gate 	/* Parse the interface descriptor */
21410Sstevel@tonic-gate 	size = usb_parse_if_descr(
21420Sstevel@tonic-gate 			usb_cfg,
21430Sstevel@tonic-gate 			usb_cfg_length,
21440Sstevel@tonic-gate 			intf,		/* interface index */
21450Sstevel@tonic-gate 			0,		/* alt interface index */
21460Sstevel@tonic-gate 			&if_descr,
21470Sstevel@tonic-gate 			USB_IF_DESCR_SIZE);
21480Sstevel@tonic-gate 
21490Sstevel@tonic-gate 	if (size != USB_IF_DESCR_SIZE) {
21500Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_USBA, usba_log_handle,
21510Sstevel@tonic-gate 		    "parsing interface: size (%lu) != USB_IF_DESCR_SIZE (%d)",
21520Sstevel@tonic-gate 		    size, USB_IF_DESCR_SIZE);
21530Sstevel@tonic-gate 		mutex_exit(&child_ud->usb_mutex);
21540Sstevel@tonic-gate 
21550Sstevel@tonic-gate 		return (NULL);
21560Sstevel@tonic-gate 	}
21570Sstevel@tonic-gate 
21580Sstevel@tonic-gate 	port_status = child_ud->usb_port_status;
21590Sstevel@tonic-gate 
21600Sstevel@tonic-gate 	/* create reg property */
21610Sstevel@tonic-gate 	reg[0] = intf;
21620Sstevel@tonic-gate 	reg[1] = child_ud->usb_cfg_value;
21630Sstevel@tonic-gate 
21640Sstevel@tonic-gate 	mutex_exit(&child_ud->usb_mutex);
21650Sstevel@tonic-gate 
21660Sstevel@tonic-gate 	/* clone this dip */
21670Sstevel@tonic-gate 	rval =	usba_create_child_devi(dip,
21680Sstevel@tonic-gate 			"interface",
21690Sstevel@tonic-gate 			NULL,		/* usba_hcdi ops */
21700Sstevel@tonic-gate 			NULL,		/* root hub dip */
21710Sstevel@tonic-gate 			port_status,	/* port status */
21720Sstevel@tonic-gate 			child_ud,	/* share this usba_device */
21730Sstevel@tonic-gate 			&child_dip);
21740Sstevel@tonic-gate 
21750Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
21760Sstevel@tonic-gate 
21770Sstevel@tonic-gate 		goto fail;
21780Sstevel@tonic-gate 	}
21790Sstevel@tonic-gate 
21800Sstevel@tonic-gate 	rval = ndi_prop_update_int_array(
21810Sstevel@tonic-gate 		DDI_DEV_T_NONE, child_dip, "reg", reg, 2);
21820Sstevel@tonic-gate 
21830Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
21840Sstevel@tonic-gate 
21850Sstevel@tonic-gate 		goto fail;
21860Sstevel@tonic-gate 	}
21870Sstevel@tonic-gate 
21880Sstevel@tonic-gate 	usba_set_node_name(child_dip, if_descr.bInterfaceClass,
21890Sstevel@tonic-gate 	    if_descr.bInterfaceSubClass, if_descr.bInterfaceProtocol,
21900Sstevel@tonic-gate 	    FLAG_INTERFACE_NODE);
21910Sstevel@tonic-gate 
21920Sstevel@tonic-gate 	/* check force binding */
21930Sstevel@tonic-gate 	if (usba_ugen_force_binding == USBA_UGEN_INTERFACE_BINDING) {
21940Sstevel@tonic-gate 		force_bind = "ugen";
21950Sstevel@tonic-gate 	}
21960Sstevel@tonic-gate 
21970Sstevel@tonic-gate #ifdef DEBUG
21980Sstevel@tonic-gate 	/*
21990Sstevel@tonic-gate 	 * check whether there is another dip with this name and address
22000Sstevel@tonic-gate 	 */
22010Sstevel@tonic-gate 	ASSERT(usba_find_existing_node(child_dip) == NULL);
22020Sstevel@tonic-gate #endif
22030Sstevel@tonic-gate 
22040Sstevel@tonic-gate 	mutex_enter(&usba_mutex);
22050Sstevel@tonic-gate 	n = 0;
22060Sstevel@tonic-gate 
22070Sstevel@tonic-gate 	if (force_bind) {
22080Sstevel@tonic-gate 		(void) ndi_devi_set_nodename(child_dip, force_bind, 0);
22090Sstevel@tonic-gate 		(void) strncpy(usba_name[n++], force_bind,
22100Sstevel@tonic-gate 						USBA_MAX_COMPAT_NAME_LEN);
22110Sstevel@tonic-gate 	}
22120Sstevel@tonic-gate 
22130Sstevel@tonic-gate 	/* 1) usbifVID,PID.REV.configCN.IN */
22140Sstevel@tonic-gate 	(void) sprintf(usba_name[n++],
22150Sstevel@tonic-gate 			"usbif%x,%x.%x.config%x.%x",
22160Sstevel@tonic-gate 			usb_dev_descr->idVendor,
22170Sstevel@tonic-gate 			usb_dev_descr->idProduct,
22180Sstevel@tonic-gate 			usb_dev_descr->bcdDevice,
22190Sstevel@tonic-gate 			child_ud->usb_cfg_value,
22200Sstevel@tonic-gate 			intf);
22210Sstevel@tonic-gate 
22220Sstevel@tonic-gate 	/* 2) usbifVID,PID.configCN.IN */
22230Sstevel@tonic-gate 	(void) sprintf(usba_name[n++],
22240Sstevel@tonic-gate 			"usbif%x,%x.config%x.%x",
22250Sstevel@tonic-gate 			usb_dev_descr->idVendor,
22260Sstevel@tonic-gate 			usb_dev_descr->idProduct,
22270Sstevel@tonic-gate 			child_ud->usb_cfg_value,
22280Sstevel@tonic-gate 			intf);
22290Sstevel@tonic-gate 
22300Sstevel@tonic-gate 
22310Sstevel@tonic-gate 	if (if_descr.bInterfaceClass) {
22320Sstevel@tonic-gate 		/* 3) usbifVID,classIC.ISC.IPROTO */
22330Sstevel@tonic-gate 		(void) sprintf(usba_name[n++],
22340Sstevel@tonic-gate 			"usbif%x,class%x.%x.%x",
22350Sstevel@tonic-gate 			usb_dev_descr->idVendor,
22360Sstevel@tonic-gate 			if_descr.bInterfaceClass,
22370Sstevel@tonic-gate 			if_descr.bInterfaceSubClass,
22380Sstevel@tonic-gate 			if_descr.bInterfaceProtocol);
22390Sstevel@tonic-gate 
22400Sstevel@tonic-gate 		/* 4) usbifVID,classIC.ISC */
22410Sstevel@tonic-gate 		(void) sprintf(usba_name[n++],
22420Sstevel@tonic-gate 			"usbif%x,class%x.%x",
22430Sstevel@tonic-gate 			usb_dev_descr->idVendor,
22440Sstevel@tonic-gate 			if_descr.bInterfaceClass,
22450Sstevel@tonic-gate 			if_descr.bInterfaceSubClass);
22460Sstevel@tonic-gate 
22470Sstevel@tonic-gate 		/* 5) usbifVID,classIC */
22480Sstevel@tonic-gate 		(void) sprintf(usba_name[n++],
22490Sstevel@tonic-gate 			"usbif%x,class%x",
22500Sstevel@tonic-gate 			usb_dev_descr->idVendor,
22510Sstevel@tonic-gate 			if_descr.bInterfaceClass);
22520Sstevel@tonic-gate 
22530Sstevel@tonic-gate 		/* 6) usbif,classIC.ISC.IPROTO */
22540Sstevel@tonic-gate 		(void) sprintf(usba_name[n++],
22550Sstevel@tonic-gate 			"usbif,class%x.%x.%x",
22560Sstevel@tonic-gate 			if_descr.bInterfaceClass,
22570Sstevel@tonic-gate 			if_descr.bInterfaceSubClass,
22580Sstevel@tonic-gate 			if_descr.bInterfaceProtocol);
22590Sstevel@tonic-gate 
22600Sstevel@tonic-gate 		/* 7) usbif,classIC.ISC */
22610Sstevel@tonic-gate 		(void) sprintf(usba_name[n++],
22620Sstevel@tonic-gate 			"usbif,class%x.%x",
22630Sstevel@tonic-gate 			if_descr.bInterfaceClass,
22640Sstevel@tonic-gate 			if_descr.bInterfaceSubClass);
22650Sstevel@tonic-gate 
22660Sstevel@tonic-gate 		/* 8) usbif,classIC */
22670Sstevel@tonic-gate 		(void) sprintf(usba_name[n++],
22680Sstevel@tonic-gate 			"usbif,class%x",
22690Sstevel@tonic-gate 			if_descr.bInterfaceClass);
22700Sstevel@tonic-gate 	}
22710Sstevel@tonic-gate 
22720Sstevel@tonic-gate 	if (usba_get_ugen_binding(child_dip) ==
22730Sstevel@tonic-gate 	    USBA_UGEN_INTERFACE_BINDING) {
22740Sstevel@tonic-gate 		/* 9) ugen */
22750Sstevel@tonic-gate 		(void) sprintf(usba_name[n++], "ugen");
22760Sstevel@tonic-gate 	}
22770Sstevel@tonic-gate 
22780Sstevel@tonic-gate 	for (i = 0; i < n; i += 2) {
22790Sstevel@tonic-gate 		USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
22800Sstevel@tonic-gate 		    "compatible name:\t%s\t%s", usba_compatible[i],
22810Sstevel@tonic-gate 		    (((i+1) < n)? usba_compatible[i+1] : ""));
22820Sstevel@tonic-gate 	}
22830Sstevel@tonic-gate 	mutex_exit(&usba_mutex);
22840Sstevel@tonic-gate 
22850Sstevel@tonic-gate 	/* create compatible property */
22860Sstevel@tonic-gate 	if (n) {
22870Sstevel@tonic-gate 		rval = ndi_prop_update_string_array(
22880Sstevel@tonic-gate 		    DDI_DEV_T_NONE, child_dip,
22890Sstevel@tonic-gate 		    "compatible", (char **)usba_compatible,
22900Sstevel@tonic-gate 		    n);
22910Sstevel@tonic-gate 
22920Sstevel@tonic-gate 		if (rval != DDI_PROP_SUCCESS) {
22930Sstevel@tonic-gate 
22940Sstevel@tonic-gate 			goto fail;
22950Sstevel@tonic-gate 		}
22960Sstevel@tonic-gate 	}
22970Sstevel@tonic-gate 
22980Sstevel@tonic-gate 	/* update the address property */
22990Sstevel@tonic-gate 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
23000Sstevel@tonic-gate 			"assigned-address", child_ud->usb_addr);
23010Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
23020Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_USBA, usba_log_handle,
23030Sstevel@tonic-gate 		    "usba_ready_interface_node: address update failed");
23040Sstevel@tonic-gate 	}
23050Sstevel@tonic-gate 
23060Sstevel@tonic-gate 	/* create property with if number */
23070Sstevel@tonic-gate 	rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
23080Sstevel@tonic-gate 		"interface", intf);
23090Sstevel@tonic-gate 
23100Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS) {
23110Sstevel@tonic-gate 
23120Sstevel@tonic-gate 		goto fail;
23130Sstevel@tonic-gate 	}
23140Sstevel@tonic-gate 
23150Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
23160Sstevel@tonic-gate 	    "%s%d port %d: %s, dip = 0x%p",
23170Sstevel@tonic-gate 	    ddi_node_name(ddi_get_parent(dip)),
23180Sstevel@tonic-gate 	    ddi_get_instance(ddi_get_parent(dip)),
23190Sstevel@tonic-gate 	    child_ud->usb_port, ddi_node_name(child_dip), child_dip);
23200Sstevel@tonic-gate 
23210Sstevel@tonic-gate 	usba_set_usba_device(child_dip, child_ud);
23220Sstevel@tonic-gate 	ASSERT(!mutex_owned(&(usba_get_usba_device(child_dip)->usb_mutex)));
23230Sstevel@tonic-gate 
23240Sstevel@tonic-gate 	return (child_dip);
23250Sstevel@tonic-gate 
23260Sstevel@tonic-gate fail:
23270Sstevel@tonic-gate 	(void) usba_destroy_child_devi(child_dip, NDI_DEVI_REMOVE);
23280Sstevel@tonic-gate 
23290Sstevel@tonic-gate 	return (NULL);
23300Sstevel@tonic-gate }
23310Sstevel@tonic-gate 
23320Sstevel@tonic-gate 
23330Sstevel@tonic-gate /*
23340Sstevel@tonic-gate  * retrieve string descriptors for manufacturer, vendor and serial
23350Sstevel@tonic-gate  * number
23360Sstevel@tonic-gate  */
23370Sstevel@tonic-gate void
23380Sstevel@tonic-gate usba_get_dev_string_descrs(dev_info_t *dip, usba_device_t *ud)
23390Sstevel@tonic-gate {
23400Sstevel@tonic-gate 	char	*tmpbuf, *str;
23410Sstevel@tonic-gate 	int	l;
23420Sstevel@tonic-gate 	usb_dev_descr_t *usb_dev_descr = ud->usb_dev_descr;
23430Sstevel@tonic-gate 
23440Sstevel@tonic-gate 
23450Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
23460Sstevel@tonic-gate 	    "usba_get_usb_string_descr: m=%d, p=%d, s=%d",
23470Sstevel@tonic-gate 	    usb_dev_descr->iManufacturer,
23480Sstevel@tonic-gate 	    usb_dev_descr->iProduct,
23490Sstevel@tonic-gate 	    usb_dev_descr->iSerialNumber);
23500Sstevel@tonic-gate 
23510Sstevel@tonic-gate 	tmpbuf = kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP);
23520Sstevel@tonic-gate 
23530Sstevel@tonic-gate 	/* fetch manufacturer string */
23540Sstevel@tonic-gate 	if ((ud->usb_mfg_str == NULL) && usb_dev_descr->iManufacturer &&
23550Sstevel@tonic-gate 	    (usb_get_string_descr(dip, USB_LANG_ID,
23560Sstevel@tonic-gate 		usb_dev_descr->iManufacturer, tmpbuf, USB_MAXSTRINGLEN) ==
23570Sstevel@tonic-gate 		USB_SUCCESS)) {
23580Sstevel@tonic-gate 
23590Sstevel@tonic-gate 		l = strlen(tmpbuf);
23600Sstevel@tonic-gate 		if (l > 0) {
23610Sstevel@tonic-gate 			str = kmem_zalloc(l + 1, KM_SLEEP);
23620Sstevel@tonic-gate 			mutex_enter(&ud->usb_mutex);
23630Sstevel@tonic-gate 			ud->usb_mfg_str = str;
23640Sstevel@tonic-gate 			(void) strcpy(ud->usb_mfg_str, tmpbuf);
23650Sstevel@tonic-gate 			mutex_exit(&ud->usb_mutex);
23660Sstevel@tonic-gate 		}
23670Sstevel@tonic-gate 	}
23680Sstevel@tonic-gate 
23690Sstevel@tonic-gate 	/* fetch product string */
23700Sstevel@tonic-gate 	if ((ud->usb_product_str == NULL) && usb_dev_descr->iProduct &&
23710Sstevel@tonic-gate 	    (usb_get_string_descr(dip, USB_LANG_ID, usb_dev_descr->iProduct,
23720Sstevel@tonic-gate 	    tmpbuf, USB_MAXSTRINGLEN) ==
23730Sstevel@tonic-gate 		USB_SUCCESS)) {
23740Sstevel@tonic-gate 
23750Sstevel@tonic-gate 		l = strlen(tmpbuf);
23760Sstevel@tonic-gate 		if (l > 0) {
23770Sstevel@tonic-gate 			str = kmem_zalloc(l + 1, KM_SLEEP);
23780Sstevel@tonic-gate 			mutex_enter(&ud->usb_mutex);
23790Sstevel@tonic-gate 			ud->usb_product_str = str;
23800Sstevel@tonic-gate 			(void) strcpy(ud->usb_product_str, tmpbuf);
23810Sstevel@tonic-gate 			mutex_exit(&ud->usb_mutex);
23820Sstevel@tonic-gate 		}
23830Sstevel@tonic-gate 	}
23840Sstevel@tonic-gate 
23850Sstevel@tonic-gate 	/* fetch device serial number string */
23860Sstevel@tonic-gate 	if ((ud->usb_serialno_str == NULL) && usb_dev_descr->iSerialNumber &&
23870Sstevel@tonic-gate 	    (usb_get_string_descr(dip, USB_LANG_ID,
23880Sstevel@tonic-gate 		usb_dev_descr->iSerialNumber, tmpbuf, USB_MAXSTRINGLEN) ==
23890Sstevel@tonic-gate 		USB_SUCCESS)) {
23900Sstevel@tonic-gate 
23910Sstevel@tonic-gate 		l = strlen(tmpbuf);
23920Sstevel@tonic-gate 		if (l > 0) {
23930Sstevel@tonic-gate 			str = kmem_zalloc(l + 1, KM_SLEEP);
23940Sstevel@tonic-gate 			mutex_enter(&ud->usb_mutex);
23950Sstevel@tonic-gate 			ud->usb_serialno_str = str;
23960Sstevel@tonic-gate 			(void) strcpy(ud->usb_serialno_str, tmpbuf);
23970Sstevel@tonic-gate 			mutex_exit(&ud->usb_mutex);
23980Sstevel@tonic-gate 		}
23990Sstevel@tonic-gate 	}
24000Sstevel@tonic-gate 
24010Sstevel@tonic-gate 	kmem_free(tmpbuf, USB_MAXSTRINGLEN);
24020Sstevel@tonic-gate }
24030Sstevel@tonic-gate 
24040Sstevel@tonic-gate 
24050Sstevel@tonic-gate /*
24060Sstevel@tonic-gate  * usba_str_startcmp:
24070Sstevel@tonic-gate  *	Return the number of characters duplicated from the beginning of the
24080Sstevel@tonic-gate  *	string.  Return -1 if a complete duplicate.
24090Sstevel@tonic-gate  *
24100Sstevel@tonic-gate  * Arguments:
24110Sstevel@tonic-gate  *	Two strings to compare.
24120Sstevel@tonic-gate  */
24130Sstevel@tonic-gate static int usba_str_startcmp(char *first, char *second)
24140Sstevel@tonic-gate {
24150Sstevel@tonic-gate 	int num_same_chars = 0;
24160Sstevel@tonic-gate 	while (*first == *second++) {
24170Sstevel@tonic-gate 		if (*first++ == '\0') {
24180Sstevel@tonic-gate 			return (-1);
24190Sstevel@tonic-gate 		}
24200Sstevel@tonic-gate 		num_same_chars++;
24210Sstevel@tonic-gate 	}
24220Sstevel@tonic-gate 
24230Sstevel@tonic-gate 	return (num_same_chars);
24240Sstevel@tonic-gate }
24250Sstevel@tonic-gate 
24260Sstevel@tonic-gate 
24270Sstevel@tonic-gate /*
24280Sstevel@tonic-gate  * usba_get_mfg_prod_sn_str:
24290Sstevel@tonic-gate  *	Return a string containing mfg, product, serial number strings.
24300Sstevel@tonic-gate  *	Remove duplicates if some strings are the same.
24310Sstevel@tonic-gate  *
24320Sstevel@tonic-gate  * Arguments:
24330Sstevel@tonic-gate  *	dip	- pointer to dev info
24340Sstevel@tonic-gate  *	buffer	- Where string is returned
24350Sstevel@tonic-gate  *	buflen	- Length of buffer
24360Sstevel@tonic-gate  *
24370Sstevel@tonic-gate  * Returns:
24380Sstevel@tonic-gate  *	Same as second arg.
24390Sstevel@tonic-gate  */
24400Sstevel@tonic-gate char *
24410Sstevel@tonic-gate usba_get_mfg_prod_sn_str(
24420Sstevel@tonic-gate     dev_info_t	*dip,
24430Sstevel@tonic-gate     char	*buffer,
24440Sstevel@tonic-gate     int		buflen)
24450Sstevel@tonic-gate {
24460Sstevel@tonic-gate 	usba_device_t *usba_device = usba_get_usba_device(dip);
24470Sstevel@tonic-gate 	int return_len = 0;
24480Sstevel@tonic-gate 	int len = 0;
24490Sstevel@tonic-gate 	int duplen;
24500Sstevel@tonic-gate 
24510Sstevel@tonic-gate 	buffer[0] = '\0';
24520Sstevel@tonic-gate 	buffer[buflen-1] = '\0';
24530Sstevel@tonic-gate 
24540Sstevel@tonic-gate 	if ((usba_device->usb_mfg_str) &&
24550Sstevel@tonic-gate 	    ((len = strlen(usba_device->usb_mfg_str)) != 0)) {
24560Sstevel@tonic-gate 		(void) strncpy(buffer, usba_device->usb_mfg_str, buflen - 1);
24570Sstevel@tonic-gate 		return_len = min(buflen - 1, len);
24580Sstevel@tonic-gate 	}
24590Sstevel@tonic-gate 
24600Sstevel@tonic-gate 	/* Product string exists to append. */
24610Sstevel@tonic-gate 	if ((usba_device->usb_product_str) &&
24620Sstevel@tonic-gate 	    ((len = strlen(usba_device->usb_product_str)) != 0)) {
24630Sstevel@tonic-gate 
24640Sstevel@tonic-gate 		/* Append only parts of string that don't match mfg string. */
24650Sstevel@tonic-gate 		duplen = usba_str_startcmp(buffer,
24660Sstevel@tonic-gate 					usba_device->usb_product_str);
24670Sstevel@tonic-gate 
24680Sstevel@tonic-gate 		if (duplen != -1) {		/* Not a complete match. */
24690Sstevel@tonic-gate 			if (return_len > 0) {
24700Sstevel@tonic-gate 				buffer[return_len++] = ' ';
24710Sstevel@tonic-gate 			}
24720Sstevel@tonic-gate 
24730Sstevel@tonic-gate 			/* Skip over the dup part of the concat'ed string. */
24740Sstevel@tonic-gate 			len -= duplen;
24750Sstevel@tonic-gate 			(void) strncpy(&buffer[return_len],
24760Sstevel@tonic-gate 			    &usba_device->usb_product_str[duplen],
24770Sstevel@tonic-gate 			    buflen - return_len - 1);
24780Sstevel@tonic-gate 			return_len = min(buflen - 1, return_len + len);
24790Sstevel@tonic-gate 		}
24800Sstevel@tonic-gate 	}
24810Sstevel@tonic-gate 
24820Sstevel@tonic-gate 	if ((usba_device->usb_serialno_str) &&
24830Sstevel@tonic-gate 	    ((len = strlen(usba_device->usb_serialno_str)) != 0)) {
24840Sstevel@tonic-gate 		if (return_len > 0) {
24850Sstevel@tonic-gate 			buffer[return_len++] = ' ';
24860Sstevel@tonic-gate 		}
24870Sstevel@tonic-gate 		(void) strncpy(&buffer[return_len],
24880Sstevel@tonic-gate 				usba_device->usb_serialno_str,
24890Sstevel@tonic-gate 				buflen - return_len - 1);
24900Sstevel@tonic-gate 	}
24910Sstevel@tonic-gate 
24920Sstevel@tonic-gate 	return (buffer);
24930Sstevel@tonic-gate }
24940Sstevel@tonic-gate 
24950Sstevel@tonic-gate 
24960Sstevel@tonic-gate /*
24970Sstevel@tonic-gate  * USB enumeration statistic functions
24980Sstevel@tonic-gate  */
24990Sstevel@tonic-gate 
25000Sstevel@tonic-gate /*
25010Sstevel@tonic-gate  * Increments the hotplug statistics based on flags.
25020Sstevel@tonic-gate  */
25030Sstevel@tonic-gate void
25040Sstevel@tonic-gate usba_update_hotplug_stats(dev_info_t *dip, usb_flags_t flags)
25050Sstevel@tonic-gate {
25060Sstevel@tonic-gate 	usba_device_t	*usba_device = usba_get_usba_device(dip);
25070Sstevel@tonic-gate 	usba_hcdi_t	*hcdi =
25080Sstevel@tonic-gate 			    usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
25090Sstevel@tonic-gate 
25100Sstevel@tonic-gate 	mutex_enter(&hcdi->hcdi_mutex);
25110Sstevel@tonic-gate 	if (flags & USBA_TOTAL_HOTPLUG_SUCCESS) {
25120Sstevel@tonic-gate 		hcdi->hcdi_total_hotplug_success++;
25130Sstevel@tonic-gate 		HCDI_HOTPLUG_STATS_DATA(hcdi)->
25140Sstevel@tonic-gate 		    hcdi_hotplug_total_success.value.ui64++;
25150Sstevel@tonic-gate 	}
25160Sstevel@tonic-gate 	if (flags & USBA_HOTPLUG_SUCCESS) {
25170Sstevel@tonic-gate 		hcdi->hcdi_hotplug_success++;
25180Sstevel@tonic-gate 		HCDI_HOTPLUG_STATS_DATA(hcdi)->
25190Sstevel@tonic-gate 		    hcdi_hotplug_success.value.ui64++;
25200Sstevel@tonic-gate 	}
25210Sstevel@tonic-gate 	if (flags & USBA_TOTAL_HOTPLUG_FAILURE) {
25220Sstevel@tonic-gate 		hcdi->hcdi_total_hotplug_failure++;
25230Sstevel@tonic-gate 		HCDI_HOTPLUG_STATS_DATA(hcdi)->
25240Sstevel@tonic-gate 		    hcdi_hotplug_total_failure.value.ui64++;
25250Sstevel@tonic-gate 	}
25260Sstevel@tonic-gate 	if (flags & USBA_HOTPLUG_FAILURE) {
25270Sstevel@tonic-gate 		hcdi->hcdi_hotplug_failure++;
25280Sstevel@tonic-gate 		HCDI_HOTPLUG_STATS_DATA(hcdi)->
25290Sstevel@tonic-gate 		    hcdi_hotplug_failure.value.ui64++;
25300Sstevel@tonic-gate 	}
25310Sstevel@tonic-gate 	mutex_exit(&hcdi->hcdi_mutex);
25320Sstevel@tonic-gate }
25330Sstevel@tonic-gate 
25340Sstevel@tonic-gate 
25350Sstevel@tonic-gate /*
25360Sstevel@tonic-gate  * Retrieve the current enumeration statistics
25370Sstevel@tonic-gate  */
25380Sstevel@tonic-gate void
25390Sstevel@tonic-gate usba_get_hotplug_stats(dev_info_t *dip, ulong_t *total_success,
25400Sstevel@tonic-gate     ulong_t *success, ulong_t *total_failure, ulong_t *failure,
25410Sstevel@tonic-gate     uchar_t *device_count)
25420Sstevel@tonic-gate {
25430Sstevel@tonic-gate 	usba_device_t	*usba_device = usba_get_usba_device(dip);
25440Sstevel@tonic-gate 	usba_hcdi_t	*hcdi =
25450Sstevel@tonic-gate 			    usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
25460Sstevel@tonic-gate 
25470Sstevel@tonic-gate 	mutex_enter(&hcdi->hcdi_mutex);
25480Sstevel@tonic-gate 	*total_success = hcdi->hcdi_total_hotplug_success;
25490Sstevel@tonic-gate 	*success = hcdi->hcdi_hotplug_success;
25500Sstevel@tonic-gate 	*total_failure = hcdi->hcdi_total_hotplug_failure;
25510Sstevel@tonic-gate 	*failure = hcdi->hcdi_hotplug_failure;
25520Sstevel@tonic-gate 	*device_count = hcdi->hcdi_device_count;
25530Sstevel@tonic-gate 	mutex_exit(&hcdi->hcdi_mutex);
25540Sstevel@tonic-gate }
25550Sstevel@tonic-gate 
25560Sstevel@tonic-gate 
25570Sstevel@tonic-gate /*
25580Sstevel@tonic-gate  * Reset the resetable hotplug stats
25590Sstevel@tonic-gate  */
25600Sstevel@tonic-gate void
25610Sstevel@tonic-gate usba_reset_hotplug_stats(dev_info_t *dip)
25620Sstevel@tonic-gate {
25630Sstevel@tonic-gate 	usba_device_t	*usba_device = usba_get_usba_device(dip);
25640Sstevel@tonic-gate 	usba_hcdi_t	*hcdi =
25650Sstevel@tonic-gate 			    usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
25660Sstevel@tonic-gate 	hcdi_hotplug_stats_t *hsp;
25670Sstevel@tonic-gate 
25680Sstevel@tonic-gate 	mutex_enter(&hcdi->hcdi_mutex);
25690Sstevel@tonic-gate 	hcdi->hcdi_hotplug_success = 0;
25700Sstevel@tonic-gate 	hcdi->hcdi_hotplug_failure = 0;
25710Sstevel@tonic-gate 
25720Sstevel@tonic-gate 	hsp = HCDI_HOTPLUG_STATS_DATA(hcdi);
25730Sstevel@tonic-gate 	hsp->hcdi_hotplug_success.value.ui64 = 0;
25740Sstevel@tonic-gate 	hsp->hcdi_hotplug_failure.value.ui64 = 0;
25750Sstevel@tonic-gate 	mutex_exit(&hcdi->hcdi_mutex);
25760Sstevel@tonic-gate }
25770Sstevel@tonic-gate 
25780Sstevel@tonic-gate 
25790Sstevel@tonic-gate /*
25800Sstevel@tonic-gate  * usba_bind_driver():
25810Sstevel@tonic-gate  *	This function calls ndi_devi_bind_driver() which tries to
25820Sstevel@tonic-gate  *	bind a driver to the device.  If the driver binding fails
25830Sstevel@tonic-gate  *	we get an rval of NDI_UNBOUD and report an error to the
25840Sstevel@tonic-gate  *	syslog that the driver failed binding.
25850Sstevel@tonic-gate  *	If rval is something other than NDI_UNBOUND we report an
25860Sstevel@tonic-gate  *	error to the console.
25870Sstevel@tonic-gate  *
25880Sstevel@tonic-gate  *	This function returns USB_SUCCESS if no errors were
25890Sstevel@tonic-gate  *	encountered while binding.
25900Sstevel@tonic-gate  */
25910Sstevel@tonic-gate int
25920Sstevel@tonic-gate usba_bind_driver(dev_info_t *dip)
25930Sstevel@tonic-gate {
25940Sstevel@tonic-gate 	int	rval;
25950Sstevel@tonic-gate 	char	*name;
25960Sstevel@tonic-gate 	uint8_t if_num = usba_get_ifno(dip);
25970Sstevel@tonic-gate 
25980Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
25990Sstevel@tonic-gate 	    "usba_bind_driver: dip = 0x%p, if_num = 0x%x", dip, if_num);
26000Sstevel@tonic-gate 
26010Sstevel@tonic-gate 	name = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
26020Sstevel@tonic-gate 
26030Sstevel@tonic-gate 	/* bind device to the driver */
26040Sstevel@tonic-gate 	if ((rval = ndi_devi_bind_driver(dip, 0)) != NDI_SUCCESS) {
26050Sstevel@tonic-gate 		/* if we fail to bind report an error */
26060Sstevel@tonic-gate 		(void) usba_get_mfg_prod_sn_str(dip, name, MAXNAMELEN);
26070Sstevel@tonic-gate 		if (name[0] != '\0') {
26080Sstevel@tonic-gate 			if (!usb_owns_device(dip)) {
26090Sstevel@tonic-gate 				USB_DPRINTF_L1(DPRINT_MASK_USBA,
26100Sstevel@tonic-gate 				    usba_log_handle,
26110Sstevel@tonic-gate 				    "no driver found for "
26120Sstevel@tonic-gate 				    "interface %d (nodename: '%s') of %s",
26130Sstevel@tonic-gate 				    if_num, ddi_node_name(dip), name);
26140Sstevel@tonic-gate 			} else {
26150Sstevel@tonic-gate 				USB_DPRINTF_L1(DPRINT_MASK_USBA,
26160Sstevel@tonic-gate 				    usba_log_handle,
26170Sstevel@tonic-gate 				    "no driver found for device %s", name);
26180Sstevel@tonic-gate 			}
26190Sstevel@tonic-gate 		} else {
26200Sstevel@tonic-gate 			(void) ddi_pathname(dip, name);
26210Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_USBA,
26220Sstevel@tonic-gate 			    usba_log_handle,
26230Sstevel@tonic-gate 			    "no driver found for device %s", name);
26240Sstevel@tonic-gate 		}
26250Sstevel@tonic-gate 
26260Sstevel@tonic-gate 		kmem_free(name, MAXNAMELEN);
26270Sstevel@tonic-gate 
26280Sstevel@tonic-gate 		return (USB_FAILURE);
26290Sstevel@tonic-gate 	}
26300Sstevel@tonic-gate 	kmem_free(name, MAXNAMELEN);
26310Sstevel@tonic-gate 
26320Sstevel@tonic-gate 	return ((rval == NDI_SUCCESS) ? USB_SUCCESS : USB_FAILURE);
26330Sstevel@tonic-gate }
26340Sstevel@tonic-gate 
26350Sstevel@tonic-gate 
26360Sstevel@tonic-gate /*
26370Sstevel@tonic-gate  * usba_get_hc_dma_attr:
26380Sstevel@tonic-gate  *	function returning dma attributes of the HCD
26390Sstevel@tonic-gate  *
26400Sstevel@tonic-gate  * Arguments:
26410Sstevel@tonic-gate  *	dip	- pointer to devinfo of the client
26420Sstevel@tonic-gate  *
26430Sstevel@tonic-gate  * Return Values:
26440Sstevel@tonic-gate  *	hcdi_dma_attr
26450Sstevel@tonic-gate  */
26460Sstevel@tonic-gate ddi_dma_attr_t *
26470Sstevel@tonic-gate usba_get_hc_dma_attr(dev_info_t *dip)
26480Sstevel@tonic-gate {
26490Sstevel@tonic-gate 	usba_device_t *usba_device = usba_get_usba_device(dip);
26500Sstevel@tonic-gate 	usba_hcdi_t *hcdi = usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
26510Sstevel@tonic-gate 
26520Sstevel@tonic-gate 	return (hcdi->hcdi_dma_attr);
26530Sstevel@tonic-gate }
26540Sstevel@tonic-gate 
26550Sstevel@tonic-gate 
26560Sstevel@tonic-gate /*
26570Sstevel@tonic-gate  * usba_check_for_leaks:
26580Sstevel@tonic-gate  *	check usba_device structure for leaks
26590Sstevel@tonic-gate  *
26600Sstevel@tonic-gate  * Arguments:
26610Sstevel@tonic-gate  *	usba_device	- usba_device structure pointer
26620Sstevel@tonic-gate  */
26630Sstevel@tonic-gate void
26640Sstevel@tonic-gate usba_check_for_leaks(usba_device_t *usba_device)
26650Sstevel@tonic-gate {
26660Sstevel@tonic-gate 	int i, ph_open_cnt, req_wrp_leaks, iface;
26670Sstevel@tonic-gate 	int leaks = 0;
26680Sstevel@tonic-gate 
26690Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
26700Sstevel@tonic-gate 	    "usba_check_for_leaks: %s%d usba_device=0x%p",
26710Sstevel@tonic-gate 	    ddi_driver_name(usba_device->usb_dip),
26720Sstevel@tonic-gate 	    ddi_get_instance(usba_device->usb_dip), usba_device);
26730Sstevel@tonic-gate 
26740Sstevel@tonic-gate 	/*
26750Sstevel@tonic-gate 	 * default pipe is still open
26760Sstevel@tonic-gate 	 * all other pipes should be closed
26770Sstevel@tonic-gate 	 */
26780Sstevel@tonic-gate 	for (ph_open_cnt = 0, i = 1; i < USBA_N_ENDPOINTS; i++) {
26790Sstevel@tonic-gate 		usba_ph_impl_t *ph_impl =
26800Sstevel@tonic-gate 		    &usba_device->usb_ph_list[i];
26810Sstevel@tonic-gate 		if (ph_impl->usba_ph_data) {
26820Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_USBA,
26830Sstevel@tonic-gate 			    usba_log_handle,
26840Sstevel@tonic-gate 			    "%s%d: leaking pipehandle=0x%p (0x%p) ep_addr=0x%x",
26850Sstevel@tonic-gate 			    ddi_driver_name(ph_impl->usba_ph_data->p_dip),
26860Sstevel@tonic-gate 			    ddi_get_instance(ph_impl->usba_ph_data->p_dip),
26870Sstevel@tonic-gate 			    ph_impl,
26880Sstevel@tonic-gate 			    ph_impl->usba_ph_data,
26890Sstevel@tonic-gate 			    ph_impl->usba_ph_ep.bEndpointAddress);
26900Sstevel@tonic-gate 			ph_open_cnt++;
26910Sstevel@tonic-gate 			leaks++;
26920Sstevel@tonic-gate #ifndef DEBUG
26930Sstevel@tonic-gate 			usb_pipe_close(ph_impl->usba_ph_data->p_dip,
26940Sstevel@tonic-gate 			    (usb_pipe_handle_t)ph_impl, USB_FLAGS_SLEEP,
26950Sstevel@tonic-gate 			    NULL, NULL);
26960Sstevel@tonic-gate #endif
26970Sstevel@tonic-gate 		}
26980Sstevel@tonic-gate 	}
26990Sstevel@tonic-gate 	req_wrp_leaks =  usba_list_entry_leaks(&usba_device->
27000Sstevel@tonic-gate 	    usb_allocated, "request wrappers");
27010Sstevel@tonic-gate 
27020Sstevel@tonic-gate 	ASSERT(ph_open_cnt == 0);
27030Sstevel@tonic-gate 	ASSERT(req_wrp_leaks == 0);
27040Sstevel@tonic-gate 
27050Sstevel@tonic-gate 	if (req_wrp_leaks) {
27060Sstevel@tonic-gate 		usba_list_entry_t *entry;
27070Sstevel@tonic-gate 
27080Sstevel@tonic-gate 		while ((entry = usba_rm_first_from_list(
27090Sstevel@tonic-gate 		    &usba_device->usb_allocated)) != NULL) {
27100Sstevel@tonic-gate 			usba_req_wrapper_t *wrp;
27110Sstevel@tonic-gate 
27120Sstevel@tonic-gate 			mutex_enter(&entry->list_mutex);
27130Sstevel@tonic-gate 			wrp = (usba_req_wrapper_t *)entry->private;
27140Sstevel@tonic-gate 			mutex_exit(&entry->list_mutex);
27150Sstevel@tonic-gate 			leaks++;
27160Sstevel@tonic-gate 
27170Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_USBA,
27180Sstevel@tonic-gate 			    usba_log_handle,
27190Sstevel@tonic-gate 			    "%s%d: leaking request 0x%p",
27200Sstevel@tonic-gate 			    ddi_driver_name(wrp->wr_dip),
27210Sstevel@tonic-gate 			    ddi_get_instance(wrp->wr_dip),
27220Sstevel@tonic-gate 			    wrp->wr_req);
27230Sstevel@tonic-gate 
27240Sstevel@tonic-gate 			/*
27250Sstevel@tonic-gate 			 * put it back, usba_req_wrapper_free
27260Sstevel@tonic-gate 			 * expects it on the list
27270Sstevel@tonic-gate 			 */
27280Sstevel@tonic-gate 			usba_add_to_list(&usba_device->usb_allocated,
27290Sstevel@tonic-gate 			    &wrp->wr_allocated_list);
27300Sstevel@tonic-gate 
27310Sstevel@tonic-gate 			usba_req_wrapper_free(wrp);
27320Sstevel@tonic-gate 		}
27330Sstevel@tonic-gate 	}
27340Sstevel@tonic-gate 
27350Sstevel@tonic-gate 	mutex_enter(&usba_device->usb_mutex);
27360Sstevel@tonic-gate 	for (iface = 0; iface < usba_device->usb_n_ifs; iface++) {
27370Sstevel@tonic-gate 		USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
27380Sstevel@tonic-gate 		    "usba_check_for_leaks: if=%d client_flags=0x%x",
27390Sstevel@tonic-gate 		    iface, usba_device->usb_client_flags[iface]);
27400Sstevel@tonic-gate 
27410Sstevel@tonic-gate 		if (usba_device->usb_client_flags[iface] &
27420Sstevel@tonic-gate 		    USBA_CLIENT_FLAG_DEV_DATA) {
27430Sstevel@tonic-gate 			usb_client_dev_data_list_t *entry =
27440Sstevel@tonic-gate 			    usba_device->usb_client_dev_data_list.cddl_next;
27450Sstevel@tonic-gate 			usb_client_dev_data_list_t *next;
27460Sstevel@tonic-gate 			usb_client_dev_data_t *dev_data;
27470Sstevel@tonic-gate 
27480Sstevel@tonic-gate 			while (entry) {
27490Sstevel@tonic-gate 				dev_info_t *dip = entry->cddl_dip;
27500Sstevel@tonic-gate 				next = entry->cddl_next;
27510Sstevel@tonic-gate 				dev_data = entry->cddl_dev_data;
27520Sstevel@tonic-gate 
27530Sstevel@tonic-gate 
27540Sstevel@tonic-gate 				if (i_ddi_node_state(dip) < DS_ATTACHED) {
27550Sstevel@tonic-gate 					USB_DPRINTF_L1(DPRINT_MASK_USBA,
27560Sstevel@tonic-gate 					    usba_log_handle,
27570Sstevel@tonic-gate 					    "%s%d: leaking dev_data 0x%p",
27580Sstevel@tonic-gate 					    ddi_driver_name(dip),
27590Sstevel@tonic-gate 					    ddi_get_instance(dip),
27600Sstevel@tonic-gate 					    (void *)dev_data);
27610Sstevel@tonic-gate 
27620Sstevel@tonic-gate 					leaks++;
27630Sstevel@tonic-gate 
27640Sstevel@tonic-gate 					mutex_exit(&usba_device->usb_mutex);
27650Sstevel@tonic-gate 					usb_free_dev_data(dip, dev_data);
27660Sstevel@tonic-gate 					mutex_enter(&usba_device->usb_mutex);
27670Sstevel@tonic-gate 				}
27680Sstevel@tonic-gate 
27690Sstevel@tonic-gate 				entry = next;
27700Sstevel@tonic-gate 			}
27710Sstevel@tonic-gate 		}
27720Sstevel@tonic-gate 		if (usba_device->usb_client_flags[iface] &
27730Sstevel@tonic-gate 		    USBA_CLIENT_FLAG_ATTACH) {
27740Sstevel@tonic-gate 			dev_info_t *dip = usba_device->
27750Sstevel@tonic-gate 				usb_client_attach_list[iface].dip;
27760Sstevel@tonic-gate 
27770Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_USBA,
27780Sstevel@tonic-gate 			    usba_log_handle,
27790Sstevel@tonic-gate 			    "%s%d: did no usb_client_detach",
27800Sstevel@tonic-gate 			    ddi_driver_name(dip), ddi_get_instance(dip));
27810Sstevel@tonic-gate 			leaks++;
27820Sstevel@tonic-gate 
27830Sstevel@tonic-gate 			mutex_exit(&usba_device->usb_mutex);
27840Sstevel@tonic-gate 			usb_client_detach(dip, NULL);
27850Sstevel@tonic-gate 			mutex_enter(&usba_device->usb_mutex);
27860Sstevel@tonic-gate 
27870Sstevel@tonic-gate 			usba_device->
27880Sstevel@tonic-gate 			    usb_client_attach_list[iface].dip = NULL;
27890Sstevel@tonic-gate 
27900Sstevel@tonic-gate 			usba_device->usb_client_flags[iface] &=
27910Sstevel@tonic-gate 			    ~USBA_CLIENT_FLAG_ATTACH;
27920Sstevel@tonic-gate 
27930Sstevel@tonic-gate 		}
27940Sstevel@tonic-gate 		if (usba_device->usb_client_flags[iface] &
27950Sstevel@tonic-gate 		    USBA_CLIENT_FLAG_EV_CBS) {
27960Sstevel@tonic-gate 			dev_info_t *dip =
27970Sstevel@tonic-gate 			    usba_device->usb_client_ev_cb_list[iface].
27980Sstevel@tonic-gate 							dip;
27990Sstevel@tonic-gate 			usb_event_t *ev_data =
28000Sstevel@tonic-gate 			    usba_device->usb_client_ev_cb_list[iface].
28010Sstevel@tonic-gate 							ev_data;
28020Sstevel@tonic-gate 
28030Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_USBA,
28040Sstevel@tonic-gate 			    usba_log_handle,
28050Sstevel@tonic-gate 			    "%s%d: did no usb_unregister_event_cbs",
28060Sstevel@tonic-gate 			    ddi_driver_name(dip), ddi_get_instance(dip));
28070Sstevel@tonic-gate 			leaks++;
28080Sstevel@tonic-gate 
28090Sstevel@tonic-gate 			mutex_exit(&usba_device->usb_mutex);
28100Sstevel@tonic-gate 			usb_unregister_event_cbs(dip, ev_data);
28110Sstevel@tonic-gate 			mutex_enter(&usba_device->usb_mutex);
28120Sstevel@tonic-gate 
28130Sstevel@tonic-gate 			usba_device->usb_client_ev_cb_list[iface].
28140Sstevel@tonic-gate 					dip = NULL;
28150Sstevel@tonic-gate 			usba_device->usb_client_ev_cb_list[iface].
28160Sstevel@tonic-gate 					ev_data = NULL;
28170Sstevel@tonic-gate 			usba_device->usb_client_flags[iface] &=
28180Sstevel@tonic-gate 			    ~USBA_CLIENT_FLAG_EV_CBS;
28190Sstevel@tonic-gate 		}
28200Sstevel@tonic-gate 	}
28210Sstevel@tonic-gate 	mutex_exit(&usba_device->usb_mutex);
28220Sstevel@tonic-gate 
28230Sstevel@tonic-gate 	if (leaks) {
28240Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_USBA, usba_log_handle,
28250Sstevel@tonic-gate 		    "all %d leaks fixed", leaks);
28260Sstevel@tonic-gate 	}
28270Sstevel@tonic-gate }
2828