17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5cbab2b26Slg150142 * Common Development and Distribution License (the "License").
6cbab2b26Slg150142 * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
22de6f998eSrui wang - Sun Microsystems - Beijing China * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
24e2c88f0cSGarrett D'Amore *
25e2c88f0cSGarrett D'Amore * Copyright 2014 Garrett D'Amore <garrett@damore.org>
265c9564e1SJames Blachly * Copyright 2016 James S. Blachly, MD <james.blachly@gmail.com>
270d2006e4SRobert Mustacchi * Copyright 2019 Joyent, Inc.
283fe80ca4SDan Cross * Copyright 2023 Oxide Computer Company
297c478bd9Sstevel@tonic-gate */
307c478bd9Sstevel@tonic-gate
317c478bd9Sstevel@tonic-gate
327c478bd9Sstevel@tonic-gate /*
337c478bd9Sstevel@tonic-gate * USBA: Solaris USB Architecture support
347c478bd9Sstevel@tonic-gate */
357c478bd9Sstevel@tonic-gate #define USBA_FRAMEWORK
367c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usba_impl.h>
377c478bd9Sstevel@tonic-gate #include <sys/usb/usba/hcdi_impl.h>
387c478bd9Sstevel@tonic-gate #include <sys/usb/hubd/hub.h>
397c478bd9Sstevel@tonic-gate #include <sys/fs/dv_node.h>
407c478bd9Sstevel@tonic-gate
417c478bd9Sstevel@tonic-gate /*
427c478bd9Sstevel@tonic-gate * USBA private variables and tunables
437c478bd9Sstevel@tonic-gate */
447c478bd9Sstevel@tonic-gate static kmutex_t usba_mutex;
457c478bd9Sstevel@tonic-gate
46de6f998eSrui wang - Sun Microsystems - Beijing China /* mutex to protect usba_root_hubs */
47de6f998eSrui wang - Sun Microsystems - Beijing China static kmutex_t usba_hub_mutex;
48de6f998eSrui wang - Sun Microsystems - Beijing China
49de6f998eSrui wang - Sun Microsystems - Beijing China typedef struct usba_root_hub_ent {
50de6f998eSrui wang - Sun Microsystems - Beijing China dev_info_t *dip;
51de6f998eSrui wang - Sun Microsystems - Beijing China struct usba_root_hub_ent *next;
52de6f998eSrui wang - Sun Microsystems - Beijing China }usba_root_hub_ent_t;
53de6f998eSrui wang - Sun Microsystems - Beijing China
54de6f998eSrui wang - Sun Microsystems - Beijing China static usba_root_hub_ent_t *usba_root_hubs = NULL;
55de6f998eSrui wang - Sun Microsystems - Beijing China
567c478bd9Sstevel@tonic-gate /*
577c478bd9Sstevel@tonic-gate * ddivs forced binding:
587c478bd9Sstevel@tonic-gate *
597c478bd9Sstevel@tonic-gate * usbc usbc_xhubs usbc_xaddress node name
607c478bd9Sstevel@tonic-gate *
617c478bd9Sstevel@tonic-gate * 0 x x class name or "device"
627c478bd9Sstevel@tonic-gate *
637c478bd9Sstevel@tonic-gate * 1 0 0 ddivs_usbc
647c478bd9Sstevel@tonic-gate * 1 0 >1 ddivs_usbc except device
657c478bd9Sstevel@tonic-gate * at usbc_xaddress
667c478bd9Sstevel@tonic-gate * 1 1 0 ddivs_usbc except hubs
677c478bd9Sstevel@tonic-gate * 1 1 >1 ddivs_usbc except hubs and
687c478bd9Sstevel@tonic-gate * device at usbc_xaddress
697c478bd9Sstevel@tonic-gate */
707c478bd9Sstevel@tonic-gate uint_t usba_ddivs_usbc;
717c478bd9Sstevel@tonic-gate uint_t usba_ddivs_usbc_xhubs;
727c478bd9Sstevel@tonic-gate uint_t usba_ddivs_usbc_xaddress;
737c478bd9Sstevel@tonic-gate
747c478bd9Sstevel@tonic-gate uint_t usba_ugen_force_binding;
757c478bd9Sstevel@tonic-gate
767c478bd9Sstevel@tonic-gate /*
777c478bd9Sstevel@tonic-gate * compatible name handling
787c478bd9Sstevel@tonic-gate */
79a7df97baSStrony Zhang - Solaris China Team /*
80a7df97baSStrony Zhang - Solaris China Team * allowing for 15 compat names, plus one force bind name and
81a7df97baSStrony Zhang - Solaris China Team * one possible specified client driver name
82a7df97baSStrony Zhang - Solaris China Team */
83a7df97baSStrony Zhang - Solaris China Team #define USBA_MAX_COMPAT_NAMES 17
847c478bd9Sstevel@tonic-gate #define USBA_MAX_COMPAT_NAME_LEN 64
857c478bd9Sstevel@tonic-gate
867c478bd9Sstevel@tonic-gate /* double linked list for usba_devices */
877c478bd9Sstevel@tonic-gate usba_list_entry_t usba_device_list;
887c478bd9Sstevel@tonic-gate
897c478bd9Sstevel@tonic-gate _NOTE(MUTEX_PROTECTS_DATA(usba_mutex, usba_device_list))
907c478bd9Sstevel@tonic-gate
917c478bd9Sstevel@tonic-gate /*
927c478bd9Sstevel@tonic-gate * modload support
937c478bd9Sstevel@tonic-gate */
947c478bd9Sstevel@tonic-gate
95e8ed0869SJohn Beck static struct modlmisc modlmisc = {
967c478bd9Sstevel@tonic-gate &mod_miscops, /* Type of module */
97d73ae94eSgc161489 "USBA: USB Architecture 2.0 1.66"
987c478bd9Sstevel@tonic-gate };
997c478bd9Sstevel@tonic-gate
100e8ed0869SJohn Beck static struct modlinkage modlinkage = {
1017c478bd9Sstevel@tonic-gate MODREV_1, (void *)&modlmisc, NULL
1027c478bd9Sstevel@tonic-gate };
1037c478bd9Sstevel@tonic-gate
1047c478bd9Sstevel@tonic-gate
1057c478bd9Sstevel@tonic-gate static usb_log_handle_t usba_log_handle;
1064610e4a0Sfrits uint_t usba_errlevel = USB_LOG_L4;
1074610e4a0Sfrits uint_t usba_errmask = (uint_t)-1;
1087c478bd9Sstevel@tonic-gate
1097c478bd9Sstevel@tonic-gate extern usb_log_handle_t hubdi_log_handle;
1107c478bd9Sstevel@tonic-gate
1117c478bd9Sstevel@tonic-gate int
_init(void)1127c478bd9Sstevel@tonic-gate _init(void)
1137c478bd9Sstevel@tonic-gate {
1143c91d182Slg150142 int rval;
1157c478bd9Sstevel@tonic-gate
1167c478bd9Sstevel@tonic-gate /*
1177c478bd9Sstevel@tonic-gate * usbai providing log support needs to be init'ed first
1187c478bd9Sstevel@tonic-gate * and destroyed last
1197c478bd9Sstevel@tonic-gate */
1207c478bd9Sstevel@tonic-gate usba_usbai_initialization();
1217c478bd9Sstevel@tonic-gate usba_usba_initialization();
1227c478bd9Sstevel@tonic-gate usba_usbai_register_initialization();
1237c478bd9Sstevel@tonic-gate usba_hcdi_initialization();
1247c478bd9Sstevel@tonic-gate usba_hubdi_initialization();
1257c478bd9Sstevel@tonic-gate usba_devdb_initialization();
1267c478bd9Sstevel@tonic-gate
1277c478bd9Sstevel@tonic-gate if ((rval = mod_install(&modlinkage)) != 0) {
1287c478bd9Sstevel@tonic-gate usba_devdb_destroy();
1297c478bd9Sstevel@tonic-gate usba_hubdi_destroy();
1307c478bd9Sstevel@tonic-gate usba_hcdi_destroy();
1317c478bd9Sstevel@tonic-gate usba_usbai_register_destroy();
1327c478bd9Sstevel@tonic-gate usba_usba_destroy();
1337c478bd9Sstevel@tonic-gate usba_usbai_destroy();
1347c478bd9Sstevel@tonic-gate }
1357c478bd9Sstevel@tonic-gate
1367c478bd9Sstevel@tonic-gate return (rval);
1377c478bd9Sstevel@tonic-gate }
1387c478bd9Sstevel@tonic-gate
1397c478bd9Sstevel@tonic-gate int
_fini()1407c478bd9Sstevel@tonic-gate _fini()
1417c478bd9Sstevel@tonic-gate {
1427c478bd9Sstevel@tonic-gate int rval;
1437c478bd9Sstevel@tonic-gate
1447c478bd9Sstevel@tonic-gate if ((rval = mod_remove(&modlinkage)) == 0) {
1457c478bd9Sstevel@tonic-gate usba_devdb_destroy();
1467c478bd9Sstevel@tonic-gate usba_hubdi_destroy();
1477c478bd9Sstevel@tonic-gate usba_hcdi_destroy();
1487c478bd9Sstevel@tonic-gate usba_usbai_register_destroy();
1497c478bd9Sstevel@tonic-gate usba_usba_destroy();
1507c478bd9Sstevel@tonic-gate usba_usbai_destroy();
1517c478bd9Sstevel@tonic-gate }
1527c478bd9Sstevel@tonic-gate
1537c478bd9Sstevel@tonic-gate return (rval);
1547c478bd9Sstevel@tonic-gate }
1557c478bd9Sstevel@tonic-gate
1567c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)1577c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
1587c478bd9Sstevel@tonic-gate {
1597c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop));
1607c478bd9Sstevel@tonic-gate }
1617c478bd9Sstevel@tonic-gate
162d73ae94eSgc161489 boolean_t
usba_owns_ia(dev_info_t * dip)163d73ae94eSgc161489 usba_owns_ia(dev_info_t *dip)
164d73ae94eSgc161489 {
165d73ae94eSgc161489 int if_count = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
166d73ae94eSgc161489 "interface-count", 0);
167d73ae94eSgc161489
168d73ae94eSgc161489 return ((if_count) ? B_TRUE : B_FALSE);
169d73ae94eSgc161489 }
1707c478bd9Sstevel@tonic-gate
1717c478bd9Sstevel@tonic-gate /*
1727c478bd9Sstevel@tonic-gate * common bus ctl for hcd, usb_mid, and hubd
1737c478bd9Sstevel@tonic-gate */
1747c478bd9Sstevel@tonic-gate int
usba_bus_ctl(dev_info_t * dip,dev_info_t * rdip,ddi_ctl_enum_t op,void * arg,void * result)175d5ebc493SDan Cross usba_bus_ctl(
176d5ebc493SDan Cross dev_info_t *dip,
1777c478bd9Sstevel@tonic-gate dev_info_t *rdip,
1787c478bd9Sstevel@tonic-gate ddi_ctl_enum_t op,
1797c478bd9Sstevel@tonic-gate void *arg,
1807c478bd9Sstevel@tonic-gate void *result)
1817c478bd9Sstevel@tonic-gate {
1827c478bd9Sstevel@tonic-gate dev_info_t *child_dip = (dev_info_t *)arg;
1837c478bd9Sstevel@tonic-gate usba_device_t *usba_device;
1847c478bd9Sstevel@tonic-gate usba_hcdi_t *usba_hcdi;
1857c478bd9Sstevel@tonic-gate usba_hcdi_ops_t *usba_hcdi_ops;
1867c478bd9Sstevel@tonic-gate
1877c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, hubdi_log_handle,
1887c478bd9Sstevel@tonic-gate "usba_bus_ctl: %s%d %s%d op=%d", ddi_node_name(rdip),
1897c478bd9Sstevel@tonic-gate ddi_get_instance(rdip), ddi_node_name(dip),
1907c478bd9Sstevel@tonic-gate ddi_get_instance(dip), op);
1917c478bd9Sstevel@tonic-gate
1927c478bd9Sstevel@tonic-gate switch (op) {
1937c478bd9Sstevel@tonic-gate
1947c478bd9Sstevel@tonic-gate case DDI_CTLOPS_REPORTDEV:
1957c478bd9Sstevel@tonic-gate {
1967c478bd9Sstevel@tonic-gate char *name, compat_name[64], *speed;
1977c478bd9Sstevel@tonic-gate usba_device_t *hub_usba_device;
1987c478bd9Sstevel@tonic-gate dev_info_t *hubdip;
1997c478bd9Sstevel@tonic-gate
2007c478bd9Sstevel@tonic-gate usba_device = usba_get_usba_device(rdip);
2017c478bd9Sstevel@tonic-gate
2027c478bd9Sstevel@tonic-gate /* find the parent hub */
2037c478bd9Sstevel@tonic-gate hubdip = ddi_get_parent(rdip);
2047c478bd9Sstevel@tonic-gate while ((strcmp(ddi_driver_name(hubdip), "hubd") != 0) &&
2057c478bd9Sstevel@tonic-gate !(usba_is_root_hub(hubdip))) {
2067c478bd9Sstevel@tonic-gate hubdip = ddi_get_parent(hubdip);
2077c478bd9Sstevel@tonic-gate }
2087c478bd9Sstevel@tonic-gate
2097c478bd9Sstevel@tonic-gate hub_usba_device = usba_get_usba_device(hubdip);
2107c478bd9Sstevel@tonic-gate
2117c478bd9Sstevel@tonic-gate if (usba_device) {
2127c478bd9Sstevel@tonic-gate if (usb_owns_device(rdip)) {
2137c478bd9Sstevel@tonic-gate (void) snprintf(compat_name,
2147c478bd9Sstevel@tonic-gate sizeof (compat_name),
2157c478bd9Sstevel@tonic-gate "usb%x,%x",
2167c478bd9Sstevel@tonic-gate usba_device->usb_dev_descr->idVendor,
2177c478bd9Sstevel@tonic-gate usba_device->usb_dev_descr->idProduct);
218d73ae94eSgc161489 } else if (usba_owns_ia(rdip)) {
219d73ae94eSgc161489 (void) snprintf(compat_name,
220d73ae94eSgc161489 sizeof (compat_name),
221d73ae94eSgc161489 "usbia%x,%x.config%x.%x",
222d73ae94eSgc161489 usba_device->usb_dev_descr->idVendor,
223d73ae94eSgc161489 usba_device->usb_dev_descr->idProduct,
224d73ae94eSgc161489 usba_device->usb_cfg_value,
225d73ae94eSgc161489 usb_get_if_number(rdip));
2267c478bd9Sstevel@tonic-gate } else {
2277c478bd9Sstevel@tonic-gate (void) snprintf(compat_name,
2287c478bd9Sstevel@tonic-gate sizeof (compat_name),
2297c478bd9Sstevel@tonic-gate "usbif%x,%x.config%x.%x",
2307c478bd9Sstevel@tonic-gate usba_device->usb_dev_descr->idVendor,
2317c478bd9Sstevel@tonic-gate usba_device->usb_dev_descr->idProduct,
2327c478bd9Sstevel@tonic-gate usba_device->usb_cfg_value,
2337c478bd9Sstevel@tonic-gate usb_get_if_number(rdip));
2347c478bd9Sstevel@tonic-gate }
2357c478bd9Sstevel@tonic-gate switch (usba_device->usb_port_status) {
236993e3fafSRobert Mustacchi case USBA_SUPER_SPEED_DEV:
237993e3fafSRobert Mustacchi speed = "super speed (USB 3.x)";
238993e3fafSRobert Mustacchi break;
2397c478bd9Sstevel@tonic-gate case USBA_HIGH_SPEED_DEV:
2407c478bd9Sstevel@tonic-gate speed = "hi speed (USB 2.x)";
2417c478bd9Sstevel@tonic-gate break;
2427c478bd9Sstevel@tonic-gate case USBA_LOW_SPEED_DEV:
2437c478bd9Sstevel@tonic-gate speed = "low speed (USB 1.x)";
2447c478bd9Sstevel@tonic-gate break;
2457c478bd9Sstevel@tonic-gate case USBA_FULL_SPEED_DEV:
2467c478bd9Sstevel@tonic-gate default:
2477c478bd9Sstevel@tonic-gate speed = "full speed (USB 1.x)";
2487c478bd9Sstevel@tonic-gate break;
2497c478bd9Sstevel@tonic-gate }
2507c478bd9Sstevel@tonic-gate
2517c478bd9Sstevel@tonic-gate cmn_err(CE_CONT,
2527c478bd9Sstevel@tonic-gate "?USB %x.%x %s (%s) operating at %s on "
2537c478bd9Sstevel@tonic-gate "USB %x.%x %s hub: "
2547c478bd9Sstevel@tonic-gate "%s@%s, %s%d at bus address %d\n",
2557c478bd9Sstevel@tonic-gate (usba_device->usb_dev_descr->bcdUSB & 0xff00) >> 8,
2567c478bd9Sstevel@tonic-gate usba_device->usb_dev_descr->bcdUSB & 0xff,
257d73ae94eSgc161489 (usb_owns_device(rdip) ? "device" :
258d73ae94eSgc161489 ((usba_owns_ia(rdip) ? "interface-association" :
259d73ae94eSgc161489 "interface"))),
2607c478bd9Sstevel@tonic-gate compat_name, speed,
2617c478bd9Sstevel@tonic-gate (hub_usba_device->usb_dev_descr->bcdUSB &
2627c478bd9Sstevel@tonic-gate 0xff00) >> 8,
2637c478bd9Sstevel@tonic-gate hub_usba_device->usb_dev_descr->bcdUSB & 0xff,
2647c478bd9Sstevel@tonic-gate usba_is_root_hub(hubdip) ? "root" : "external",
2657c478bd9Sstevel@tonic-gate ddi_node_name(rdip), ddi_get_name_addr(rdip),
2667c478bd9Sstevel@tonic-gate ddi_driver_name(rdip),
2677c478bd9Sstevel@tonic-gate ddi_get_instance(rdip), usba_device->usb_addr);
2687c478bd9Sstevel@tonic-gate
2697c478bd9Sstevel@tonic-gate name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
2707c478bd9Sstevel@tonic-gate (void) usba_get_mfg_prod_sn_str(rdip, name, MAXNAMELEN);
2717c478bd9Sstevel@tonic-gate if (name[0] != '\0') {
2725c9564e1SJames Blachly cmn_err(CE_CONT, "?%s\n", name);
2737c478bd9Sstevel@tonic-gate }
2747c478bd9Sstevel@tonic-gate kmem_free(name, MAXNAMELEN);
2757c478bd9Sstevel@tonic-gate
2767c478bd9Sstevel@tonic-gate } else { /* harden USBA against this case; if it happens */
2777c478bd9Sstevel@tonic-gate
2787c478bd9Sstevel@tonic-gate cmn_err(CE_CONT,
2797c478bd9Sstevel@tonic-gate "?USB-device: %s@%s, %s%d\n",
2807c478bd9Sstevel@tonic-gate ddi_node_name(rdip), ddi_get_name_addr(rdip),
2817c478bd9Sstevel@tonic-gate ddi_driver_name(rdip), ddi_get_instance(rdip));
2827c478bd9Sstevel@tonic-gate }
2837c478bd9Sstevel@tonic-gate
2847c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
2857c478bd9Sstevel@tonic-gate }
2867c478bd9Sstevel@tonic-gate
2877c478bd9Sstevel@tonic-gate case DDI_CTLOPS_INITCHILD:
2887c478bd9Sstevel@tonic-gate {
2897c478bd9Sstevel@tonic-gate int usb_addr;
2907c478bd9Sstevel@tonic-gate uint_t n;
2917c478bd9Sstevel@tonic-gate char name[32];
2927c478bd9Sstevel@tonic-gate int *data;
2937c478bd9Sstevel@tonic-gate int rval;
2947c478bd9Sstevel@tonic-gate int len = sizeof (usb_addr);
2957c478bd9Sstevel@tonic-gate
2967c478bd9Sstevel@tonic-gate usba_hcdi = usba_hcdi_get_hcdi(dip);
2977c478bd9Sstevel@tonic-gate usba_hcdi_ops = usba_hcdi->hcdi_ops;
2987c478bd9Sstevel@tonic-gate ASSERT(usba_hcdi_ops != NULL);
2997c478bd9Sstevel@tonic-gate
3007c478bd9Sstevel@tonic-gate /*
3017c478bd9Sstevel@tonic-gate * as long as the dip exists, it should have
3027c478bd9Sstevel@tonic-gate * usba_device structure associated with it
3037c478bd9Sstevel@tonic-gate */
3047c478bd9Sstevel@tonic-gate usba_device = usba_get_usba_device(child_dip);
3057c478bd9Sstevel@tonic-gate if (usba_device == NULL) {
3067c478bd9Sstevel@tonic-gate
3077c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBA, hubdi_log_handle,
3087c478bd9Sstevel@tonic-gate "usba_bus_ctl: DDI_NOT_WELL_FORMED (%s (0x%p))",
3097c478bd9Sstevel@tonic-gate ddi_node_name(child_dip), (void *)child_dip);
3107c478bd9Sstevel@tonic-gate
3117c478bd9Sstevel@tonic-gate return (DDI_NOT_WELL_FORMED);
3127c478bd9Sstevel@tonic-gate }
3137c478bd9Sstevel@tonic-gate
3147c478bd9Sstevel@tonic-gate /* the dip should have an address and reg property */
3157c478bd9Sstevel@tonic-gate if (ddi_prop_op(DDI_DEV_T_NONE, child_dip, PROP_LEN_AND_VAL_BUF,
3167c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "assigned-address",
3177c478bd9Sstevel@tonic-gate (caddr_t)&usb_addr, &len) != DDI_SUCCESS) {
3187c478bd9Sstevel@tonic-gate
319d291d9f2Sfrits USB_DPRINTF_L2(DPRINT_MASK_USBA, hubdi_log_handle,
3207c478bd9Sstevel@tonic-gate "usba_bus_ctl:\n\t"
3217c478bd9Sstevel@tonic-gate "%s%d %s%d op=%d rdip = 0x%p dip = 0x%p",
3227c478bd9Sstevel@tonic-gate ddi_node_name(rdip), ddi_get_instance(rdip),
3237c478bd9Sstevel@tonic-gate ddi_node_name(dip), ddi_get_instance(dip), op,
324112116d8Sfb209375 (void *)rdip, (void *)dip);
3257c478bd9Sstevel@tonic-gate
326d291d9f2Sfrits USB_DPRINTF_L2(DPRINT_MASK_USBA, hubdi_log_handle,
3277c478bd9Sstevel@tonic-gate "usba_bus_ctl: DDI_NOT_WELL_FORMED (%s (0x%p))",
3287c478bd9Sstevel@tonic-gate ddi_node_name(child_dip), (void *)child_dip);
3297c478bd9Sstevel@tonic-gate
3307c478bd9Sstevel@tonic-gate return (DDI_NOT_WELL_FORMED);
3317c478bd9Sstevel@tonic-gate }
3327c478bd9Sstevel@tonic-gate
3337c478bd9Sstevel@tonic-gate if ((rval = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child_dip,
3347c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "reg",
3357c478bd9Sstevel@tonic-gate &data, &n)) != DDI_SUCCESS) {
3367c478bd9Sstevel@tonic-gate
337d291d9f2Sfrits USB_DPRINTF_L2(DPRINT_MASK_USBA, hubdi_log_handle,
3387c478bd9Sstevel@tonic-gate "usba_bus_ctl: %d, DDI_NOT_WELL_FORMED", rval);
3397c478bd9Sstevel@tonic-gate
3407c478bd9Sstevel@tonic-gate return (DDI_NOT_WELL_FORMED);
3417c478bd9Sstevel@tonic-gate }
3427c478bd9Sstevel@tonic-gate
3437c478bd9Sstevel@tonic-gate
3447c478bd9Sstevel@tonic-gate /*
3457c478bd9Sstevel@tonic-gate * if the configuration is 1, the unit address is
3467c478bd9Sstevel@tonic-gate * just the interface number
3477c478bd9Sstevel@tonic-gate */
3487c478bd9Sstevel@tonic-gate if ((n == 1) || ((n > 1) && (data[1] == 1))) {
3497c478bd9Sstevel@tonic-gate (void) sprintf(name, "%x", data[0]);
3507c478bd9Sstevel@tonic-gate } else {
3517c478bd9Sstevel@tonic-gate (void) sprintf(name, "%x,%x", data[0], data[1]);
3527c478bd9Sstevel@tonic-gate }
3537c478bd9Sstevel@tonic-gate
3547c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_USBA,
3557c478bd9Sstevel@tonic-gate hubdi_log_handle, "usba_bus_ctl: name = %s", name);
3567c478bd9Sstevel@tonic-gate
3577c478bd9Sstevel@tonic-gate ddi_prop_free(data);
3587c478bd9Sstevel@tonic-gate ddi_set_name_addr(child_dip, name);
3597c478bd9Sstevel@tonic-gate
3607c478bd9Sstevel@tonic-gate /*
3617c478bd9Sstevel@tonic-gate * increment the reference count for each child using this
3627c478bd9Sstevel@tonic-gate * usba_device structure
3637c478bd9Sstevel@tonic-gate */
3647c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex);
3657c478bd9Sstevel@tonic-gate usba_device->usb_ref_count++;
3667c478bd9Sstevel@tonic-gate
3677c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_USBA, hubdi_log_handle,
3687c478bd9Sstevel@tonic-gate "usba_bus_ctl: init usba_device = 0x%p ref_count = %d",
3697c478bd9Sstevel@tonic-gate (void *)usba_device, usba_device->usb_ref_count);
3707c478bd9Sstevel@tonic-gate
3717c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex);
3727c478bd9Sstevel@tonic-gate
3737c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
3747c478bd9Sstevel@tonic-gate }
3757c478bd9Sstevel@tonic-gate
3767c478bd9Sstevel@tonic-gate case DDI_CTLOPS_UNINITCHILD:
3777c478bd9Sstevel@tonic-gate {
3787c478bd9Sstevel@tonic-gate usba_device = usba_get_usba_device(child_dip);
3797c478bd9Sstevel@tonic-gate
3807c478bd9Sstevel@tonic-gate if (usba_device != NULL) {
3817c478bd9Sstevel@tonic-gate /*
3827c478bd9Sstevel@tonic-gate * decrement the reference count for each child
3837c478bd9Sstevel@tonic-gate * using this usba_device structure
3847c478bd9Sstevel@tonic-gate */
3857c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex);
3867c478bd9Sstevel@tonic-gate usba_device->usb_ref_count--;
3877c478bd9Sstevel@tonic-gate
3887c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_USBA, hubdi_log_handle,
3897c478bd9Sstevel@tonic-gate "usba_hcdi_bus_ctl: uninit usba_device=0x%p "
3907c478bd9Sstevel@tonic-gate "ref_count=%d",
391112116d8Sfb209375 (void *)usba_device, usba_device->usb_ref_count);
3927c478bd9Sstevel@tonic-gate
3937c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex);
3947c478bd9Sstevel@tonic-gate }
3957c478bd9Sstevel@tonic-gate ddi_set_name_addr(child_dip, NULL);
3967c478bd9Sstevel@tonic-gate
3977c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
3987c478bd9Sstevel@tonic-gate }
3997c478bd9Sstevel@tonic-gate
4007c478bd9Sstevel@tonic-gate case DDI_CTLOPS_IOMIN:
4017c478bd9Sstevel@tonic-gate /* Do nothing */
4027c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
4037c478bd9Sstevel@tonic-gate
4047c478bd9Sstevel@tonic-gate /*
4057c478bd9Sstevel@tonic-gate * These ops correspond to functions that "shouldn't" be called
4067c478bd9Sstevel@tonic-gate * by a USB client driver. So we whine when we're called.
4077c478bd9Sstevel@tonic-gate */
4087c478bd9Sstevel@tonic-gate case DDI_CTLOPS_DMAPMAPC:
4097c478bd9Sstevel@tonic-gate case DDI_CTLOPS_REPORTINT:
4107c478bd9Sstevel@tonic-gate case DDI_CTLOPS_REGSIZE:
4117c478bd9Sstevel@tonic-gate case DDI_CTLOPS_NREGS:
4127c478bd9Sstevel@tonic-gate case DDI_CTLOPS_SIDDEV:
4137c478bd9Sstevel@tonic-gate case DDI_CTLOPS_SLAVEONLY:
4147c478bd9Sstevel@tonic-gate case DDI_CTLOPS_AFFINITY:
4157c478bd9Sstevel@tonic-gate case DDI_CTLOPS_POKE:
4167c478bd9Sstevel@tonic-gate case DDI_CTLOPS_PEEK:
4177c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "%s%d: invalid op (%d) from %s%d",
4187c478bd9Sstevel@tonic-gate ddi_node_name(dip), ddi_get_instance(dip),
4197c478bd9Sstevel@tonic-gate op, ddi_node_name(rdip), ddi_get_instance(rdip));
4207c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
4217c478bd9Sstevel@tonic-gate
4227c478bd9Sstevel@tonic-gate /*
4237c478bd9Sstevel@tonic-gate * Everything else (e.g. PTOB/BTOP/BTOPR requests) we pass up
4247c478bd9Sstevel@tonic-gate */
4257c478bd9Sstevel@tonic-gate default:
4267c478bd9Sstevel@tonic-gate return (ddi_ctlops(dip, rdip, op, arg, result));
4277c478bd9Sstevel@tonic-gate }
4287c478bd9Sstevel@tonic-gate }
4297c478bd9Sstevel@tonic-gate
4307c478bd9Sstevel@tonic-gate
4317c478bd9Sstevel@tonic-gate /*
4327c478bd9Sstevel@tonic-gate * initialize and destroy USBA module
4337c478bd9Sstevel@tonic-gate */
4347c478bd9Sstevel@tonic-gate void
usba_usba_initialization()4357c478bd9Sstevel@tonic-gate usba_usba_initialization()
4367c478bd9Sstevel@tonic-gate {
4377c478bd9Sstevel@tonic-gate usba_log_handle = usb_alloc_log_hdl(NULL, "usba", &usba_errlevel,
4387c478bd9Sstevel@tonic-gate &usba_errmask, NULL, 0);
4397c478bd9Sstevel@tonic-gate
4407c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA,
4417c478bd9Sstevel@tonic-gate usba_log_handle, "usba_usba_initialization");
4427c478bd9Sstevel@tonic-gate
4437c478bd9Sstevel@tonic-gate mutex_init(&usba_mutex, NULL, MUTEX_DRIVER, NULL);
444de6f998eSrui wang - Sun Microsystems - Beijing China mutex_init(&usba_hub_mutex, NULL, MUTEX_DRIVER, NULL);
4457c478bd9Sstevel@tonic-gate usba_init_list(&usba_device_list, NULL, NULL);
4467c478bd9Sstevel@tonic-gate }
4477c478bd9Sstevel@tonic-gate
4487c478bd9Sstevel@tonic-gate
4497c478bd9Sstevel@tonic-gate void
usba_usba_destroy()4507c478bd9Sstevel@tonic-gate usba_usba_destroy()
4517c478bd9Sstevel@tonic-gate {
4527c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle, "usba_usba_destroy");
4537c478bd9Sstevel@tonic-gate
454de6f998eSrui wang - Sun Microsystems - Beijing China mutex_destroy(&usba_hub_mutex);
4557c478bd9Sstevel@tonic-gate mutex_destroy(&usba_mutex);
4567c478bd9Sstevel@tonic-gate usba_destroy_list(&usba_device_list);
4577c478bd9Sstevel@tonic-gate
4587c478bd9Sstevel@tonic-gate usb_free_log_hdl(usba_log_handle);
4597c478bd9Sstevel@tonic-gate }
4607c478bd9Sstevel@tonic-gate
4617c478bd9Sstevel@tonic-gate
4627c478bd9Sstevel@tonic-gate /*
4637c478bd9Sstevel@tonic-gate * usba_set_usb_address:
4647c478bd9Sstevel@tonic-gate * set usb address in usba_device structure
4657c478bd9Sstevel@tonic-gate */
4667c478bd9Sstevel@tonic-gate int
usba_set_usb_address(usba_device_t * usba_device)4677c478bd9Sstevel@tonic-gate usba_set_usb_address(usba_device_t *usba_device)
4687c478bd9Sstevel@tonic-gate {
4697c478bd9Sstevel@tonic-gate usb_addr_t address;
4707c478bd9Sstevel@tonic-gate uchar_t s = 8;
4717c478bd9Sstevel@tonic-gate usba_hcdi_t *hcdi;
4727c478bd9Sstevel@tonic-gate char *usb_address_in_use;
4737c478bd9Sstevel@tonic-gate
4747c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex);
4757c478bd9Sstevel@tonic-gate
4767c478bd9Sstevel@tonic-gate hcdi = usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
4777c478bd9Sstevel@tonic-gate
4787c478bd9Sstevel@tonic-gate mutex_enter(&hcdi->hcdi_mutex);
4797c478bd9Sstevel@tonic-gate usb_address_in_use = hcdi->hcdi_usb_address_in_use;
4807c478bd9Sstevel@tonic-gate
4817c478bd9Sstevel@tonic-gate for (address = ROOT_HUB_ADDR + 1;
4827c478bd9Sstevel@tonic-gate address <= USBA_MAX_ADDRESS; address++) {
4837c478bd9Sstevel@tonic-gate if (usb_address_in_use[address/s] & (1 << (address % s))) {
4847c478bd9Sstevel@tonic-gate continue;
4857c478bd9Sstevel@tonic-gate }
4867c478bd9Sstevel@tonic-gate usb_address_in_use[address/s] |= (1 << (address % s));
4877c478bd9Sstevel@tonic-gate hcdi->hcdi_device_count++;
4887c478bd9Sstevel@tonic-gate HCDI_HOTPLUG_STATS_DATA(hcdi)->hcdi_device_count.value.ui64++;
4897c478bd9Sstevel@tonic-gate mutex_exit(&hcdi->hcdi_mutex);
4907c478bd9Sstevel@tonic-gate
4917c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
4927c478bd9Sstevel@tonic-gate "usba_set_usb_address: %d", address);
4937c478bd9Sstevel@tonic-gate
4947c478bd9Sstevel@tonic-gate usba_device->usb_addr = address;
4957c478bd9Sstevel@tonic-gate
4967c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex);
4977c478bd9Sstevel@tonic-gate
4987c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
4997c478bd9Sstevel@tonic-gate }
5007c478bd9Sstevel@tonic-gate
5017c478bd9Sstevel@tonic-gate usba_device->usb_addr = 0;
5027c478bd9Sstevel@tonic-gate
503d291d9f2Sfrits USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
5047c478bd9Sstevel@tonic-gate "no usb address available");
5057c478bd9Sstevel@tonic-gate
5067c478bd9Sstevel@tonic-gate mutex_exit(&hcdi->hcdi_mutex);
5077c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex);
5087c478bd9Sstevel@tonic-gate
5097c478bd9Sstevel@tonic-gate return (USB_FAILURE);
5107c478bd9Sstevel@tonic-gate }
5117c478bd9Sstevel@tonic-gate
5127c478bd9Sstevel@tonic-gate
5137c478bd9Sstevel@tonic-gate /*
5147c478bd9Sstevel@tonic-gate * usba_unset_usb_address:
5157c478bd9Sstevel@tonic-gate * unset usb_address in usba_device structure
5167c478bd9Sstevel@tonic-gate */
5177c478bd9Sstevel@tonic-gate void
usba_unset_usb_address(usba_device_t * usba_device)5187c478bd9Sstevel@tonic-gate usba_unset_usb_address(usba_device_t *usba_device)
5197c478bd9Sstevel@tonic-gate {
5207c478bd9Sstevel@tonic-gate usb_addr_t address;
5217c478bd9Sstevel@tonic-gate usba_hcdi_t *hcdi;
5227c478bd9Sstevel@tonic-gate uchar_t s = 8;
5237c478bd9Sstevel@tonic-gate char *usb_address_in_use;
5247c478bd9Sstevel@tonic-gate
5257c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex);
5267c478bd9Sstevel@tonic-gate address = usba_device->usb_addr;
5277c478bd9Sstevel@tonic-gate hcdi = usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
5287c478bd9Sstevel@tonic-gate
5297c478bd9Sstevel@tonic-gate if (address > ROOT_HUB_ADDR) {
5307c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
5317c478bd9Sstevel@tonic-gate "usba_unset_usb_address: address=%d", address);
5327c478bd9Sstevel@tonic-gate
5337c478bd9Sstevel@tonic-gate mutex_enter(&hcdi->hcdi_mutex);
5347c478bd9Sstevel@tonic-gate usb_address_in_use = hcdi->hcdi_usb_address_in_use;
5357c478bd9Sstevel@tonic-gate
5367c478bd9Sstevel@tonic-gate ASSERT(usb_address_in_use[address/s] & (1 << (address % s)));
5377c478bd9Sstevel@tonic-gate
5387c478bd9Sstevel@tonic-gate usb_address_in_use[address/s] &= ~(1 << (address % s));
5397c478bd9Sstevel@tonic-gate
5407c478bd9Sstevel@tonic-gate hcdi->hcdi_device_count--;
5417c478bd9Sstevel@tonic-gate HCDI_HOTPLUG_STATS_DATA(hcdi)->hcdi_device_count.value.ui64--;
5427c478bd9Sstevel@tonic-gate
5437c478bd9Sstevel@tonic-gate mutex_exit(&hcdi->hcdi_mutex);
5447c478bd9Sstevel@tonic-gate
5457c478bd9Sstevel@tonic-gate usba_device->usb_addr = 0;
5467c478bd9Sstevel@tonic-gate }
5477c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex);
5487c478bd9Sstevel@tonic-gate }
5497c478bd9Sstevel@tonic-gate
5507c478bd9Sstevel@tonic-gate
5517c478bd9Sstevel@tonic-gate struct usba_evdata *
usba_get_evdata(dev_info_t * dip)5527c478bd9Sstevel@tonic-gate usba_get_evdata(dev_info_t *dip)
5537c478bd9Sstevel@tonic-gate {
5547c478bd9Sstevel@tonic-gate usba_evdata_t *evdata;
5557c478bd9Sstevel@tonic-gate usba_device_t *usba_device = usba_get_usba_device(dip);
5567c478bd9Sstevel@tonic-gate
5577c478bd9Sstevel@tonic-gate /* called when dip attaches */
5587c478bd9Sstevel@tonic-gate ASSERT(usba_device != NULL);
5597c478bd9Sstevel@tonic-gate
5607c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex);
5617c478bd9Sstevel@tonic-gate evdata = usba_device->usb_evdata;
5627c478bd9Sstevel@tonic-gate while (evdata) {
5637c478bd9Sstevel@tonic-gate if (evdata->ev_dip == dip) {
5647c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex);
5657c478bd9Sstevel@tonic-gate
5667c478bd9Sstevel@tonic-gate return (evdata);
5677c478bd9Sstevel@tonic-gate }
5687c478bd9Sstevel@tonic-gate evdata = evdata->ev_next;
5697c478bd9Sstevel@tonic-gate }
5707c478bd9Sstevel@tonic-gate
5717c478bd9Sstevel@tonic-gate evdata = kmem_zalloc(sizeof (usba_evdata_t), KM_SLEEP);
5727c478bd9Sstevel@tonic-gate evdata->ev_dip = dip;
5737c478bd9Sstevel@tonic-gate evdata->ev_next = usba_device->usb_evdata;
5747c478bd9Sstevel@tonic-gate usba_device->usb_evdata = evdata;
5757c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex);
5767c478bd9Sstevel@tonic-gate
5777c478bd9Sstevel@tonic-gate return (evdata);
5787c478bd9Sstevel@tonic-gate }
5797c478bd9Sstevel@tonic-gate
5807c478bd9Sstevel@tonic-gate
5817c478bd9Sstevel@tonic-gate /*
5827c478bd9Sstevel@tonic-gate * allocate a usb device structure and link it in the list
5837c478bd9Sstevel@tonic-gate */
5847c478bd9Sstevel@tonic-gate usba_device_t *
usba_alloc_usba_device(dev_info_t * root_hub_dip)5857c478bd9Sstevel@tonic-gate usba_alloc_usba_device(dev_info_t *root_hub_dip)
5867c478bd9Sstevel@tonic-gate {
5877c478bd9Sstevel@tonic-gate usba_device_t *usba_device;
5887c478bd9Sstevel@tonic-gate int ep_idx;
5897c478bd9Sstevel@tonic-gate ddi_iblock_cookie_t iblock_cookie =
5907c478bd9Sstevel@tonic-gate usba_hcdi_get_hcdi(root_hub_dip)->hcdi_iblock_cookie;
5917c478bd9Sstevel@tonic-gate
5927c478bd9Sstevel@tonic-gate /*
5937c478bd9Sstevel@tonic-gate * create a new usba_device structure
5947c478bd9Sstevel@tonic-gate */
5957c478bd9Sstevel@tonic-gate usba_device = kmem_zalloc(sizeof (usba_device_t), KM_SLEEP);
5967c478bd9Sstevel@tonic-gate
5977c478bd9Sstevel@tonic-gate /*
5987c478bd9Sstevel@tonic-gate * initialize usba_device
5997c478bd9Sstevel@tonic-gate */
6007c478bd9Sstevel@tonic-gate mutex_init(&usba_device->usb_mutex, NULL, MUTEX_DRIVER,
6017c478bd9Sstevel@tonic-gate iblock_cookie);
6027c478bd9Sstevel@tonic-gate
6037c478bd9Sstevel@tonic-gate usba_init_list(&usba_device->usb_device_list, (usb_opaque_t)usba_device,
6047c478bd9Sstevel@tonic-gate iblock_cookie);
6057c478bd9Sstevel@tonic-gate usba_init_list(&usba_device->usb_allocated, (usb_opaque_t)usba_device,
6067c478bd9Sstevel@tonic-gate iblock_cookie);
6077c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex);
6087c478bd9Sstevel@tonic-gate usba_device->usb_root_hub_dip = root_hub_dip;
6097c478bd9Sstevel@tonic-gate
6107c478bd9Sstevel@tonic-gate /*
6117c478bd9Sstevel@tonic-gate * add to list of usba_devices
6127c478bd9Sstevel@tonic-gate */
6137c478bd9Sstevel@tonic-gate usba_add_to_list(&usba_device_list, &usba_device->usb_device_list);
6147c478bd9Sstevel@tonic-gate
6157c478bd9Sstevel@tonic-gate /* init mutex in each usba_ph_impl structure */
6167c478bd9Sstevel@tonic-gate for (ep_idx = 0; ep_idx < USBA_N_ENDPOINTS; ep_idx++) {
6177c478bd9Sstevel@tonic-gate mutex_init(&usba_device->usb_ph_list[ep_idx].usba_ph_mutex,
6187c478bd9Sstevel@tonic-gate NULL, MUTEX_DRIVER, iblock_cookie);
6197c478bd9Sstevel@tonic-gate }
6207c478bd9Sstevel@tonic-gate
6217c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
6227c478bd9Sstevel@tonic-gate "allocated usba_device 0x%p", (void *)usba_device);
6237c478bd9Sstevel@tonic-gate
6247c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex);
6257c478bd9Sstevel@tonic-gate
6267c478bd9Sstevel@tonic-gate return (usba_device);
6277c478bd9Sstevel@tonic-gate }
6287c478bd9Sstevel@tonic-gate
6297c478bd9Sstevel@tonic-gate
6307c478bd9Sstevel@tonic-gate /* free NDI event data associated with usba_device */
6317c478bd9Sstevel@tonic-gate void
usba_free_evdata(usba_evdata_t * evdata)6327c478bd9Sstevel@tonic-gate usba_free_evdata(usba_evdata_t *evdata)
6337c478bd9Sstevel@tonic-gate {
6347c478bd9Sstevel@tonic-gate usba_evdata_t *next;
6357c478bd9Sstevel@tonic-gate
6367c478bd9Sstevel@tonic-gate while (evdata) {
6377c478bd9Sstevel@tonic-gate next = evdata->ev_next;
6387c478bd9Sstevel@tonic-gate kmem_free(evdata, sizeof (usba_evdata_t));
6397c478bd9Sstevel@tonic-gate evdata = next;
6407c478bd9Sstevel@tonic-gate }
6417c478bd9Sstevel@tonic-gate }
6427c478bd9Sstevel@tonic-gate
6437c478bd9Sstevel@tonic-gate
6447c478bd9Sstevel@tonic-gate /*
6457c478bd9Sstevel@tonic-gate * free usb device structure
6467c478bd9Sstevel@tonic-gate */
6477c478bd9Sstevel@tonic-gate void
usba_free_usba_device(usba_device_t * usba_device)6487c478bd9Sstevel@tonic-gate usba_free_usba_device(usba_device_t *usba_device)
6497c478bd9Sstevel@tonic-gate {
6507c478bd9Sstevel@tonic-gate int i, ep_idx;
6517c478bd9Sstevel@tonic-gate usb_pipe_handle_t def_ph;
6527c478bd9Sstevel@tonic-gate
6537c478bd9Sstevel@tonic-gate if (usba_device == NULL) {
6547c478bd9Sstevel@tonic-gate
6557c478bd9Sstevel@tonic-gate return;
6567c478bd9Sstevel@tonic-gate }
6577c478bd9Sstevel@tonic-gate
6587c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex);
6597c478bd9Sstevel@tonic-gate if (usba_device->usb_ref_count) {
6607c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex);
6617c478bd9Sstevel@tonic-gate
6627c478bd9Sstevel@tonic-gate return;
6637c478bd9Sstevel@tonic-gate }
6647c478bd9Sstevel@tonic-gate
6657c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
6667c478bd9Sstevel@tonic-gate "usba_free_usba_device 0x%p, address=0x%x, ref cnt=%d",
6677c478bd9Sstevel@tonic-gate (void *)usba_device, usba_device->usb_addr,
6687c478bd9Sstevel@tonic-gate usba_device->usb_ref_count);
6697c478bd9Sstevel@tonic-gate
6707c478bd9Sstevel@tonic-gate usba_free_evdata(usba_device->usb_evdata);
6717c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex);
6727c478bd9Sstevel@tonic-gate
6737c478bd9Sstevel@tonic-gate def_ph = usba_usbdev_to_dflt_pipe_handle(usba_device);
6747c478bd9Sstevel@tonic-gate if (def_ph != NULL) {
6757c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = usba_get_ph_data(def_ph);
6767c478bd9Sstevel@tonic-gate
6777c478bd9Sstevel@tonic-gate if (ph_data) {
6787c478bd9Sstevel@tonic-gate usb_pipe_close(ph_data->p_dip, def_ph,
6797c478bd9Sstevel@tonic-gate USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED,
6807c478bd9Sstevel@tonic-gate NULL, NULL);
6817c478bd9Sstevel@tonic-gate }
6827c478bd9Sstevel@tonic-gate }
6837c478bd9Sstevel@tonic-gate
684993e3fafSRobert Mustacchi /*
685993e3fafSRobert Mustacchi * Give the HCD a chance to clean up this child device before we finish
686993e3fafSRobert Mustacchi * tearing things down.
687993e3fafSRobert Mustacchi */
688993e3fafSRobert Mustacchi if (usba_device->usb_hcdi_ops->usba_hcdi_device_fini != NULL) {
689993e3fafSRobert Mustacchi usba_device->usb_hcdi_ops->usba_hcdi_device_fini(
690993e3fafSRobert Mustacchi usba_device, usba_device->usb_hcd_private);
691993e3fafSRobert Mustacchi usba_device->usb_hcd_private = NULL;
692993e3fafSRobert Mustacchi }
693993e3fafSRobert Mustacchi
6947c478bd9Sstevel@tonic-gate mutex_enter(&usba_mutex);
6957c478bd9Sstevel@tonic-gate
6967c478bd9Sstevel@tonic-gate /* destroy mutex in each usba_ph_impl structure */
6977c478bd9Sstevel@tonic-gate for (ep_idx = 0; ep_idx < USBA_N_ENDPOINTS; ep_idx++) {
6987c478bd9Sstevel@tonic-gate mutex_destroy(&usba_device->usb_ph_list[ep_idx].usba_ph_mutex);
6997c478bd9Sstevel@tonic-gate }
7007c478bd9Sstevel@tonic-gate
7017c478bd9Sstevel@tonic-gate (void) usba_rm_from_list(&usba_device_list,
7027c478bd9Sstevel@tonic-gate &usba_device->usb_device_list);
7037c478bd9Sstevel@tonic-gate
7047c478bd9Sstevel@tonic-gate mutex_exit(&usba_mutex);
7057c478bd9Sstevel@tonic-gate
7067c478bd9Sstevel@tonic-gate usba_destroy_list(&usba_device->usb_device_list);
7077c478bd9Sstevel@tonic-gate usba_destroy_list(&usba_device->usb_allocated);
7087c478bd9Sstevel@tonic-gate
7097c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
7107c478bd9Sstevel@tonic-gate "deallocating usba_device = 0x%p, address = 0x%x",
7117c478bd9Sstevel@tonic-gate (void *)usba_device, usba_device->usb_addr);
7127c478bd9Sstevel@tonic-gate
7137c478bd9Sstevel@tonic-gate /*
7147c478bd9Sstevel@tonic-gate * ohci allocates descriptors for root hub so we can't
7157c478bd9Sstevel@tonic-gate * deallocate these here
7167c478bd9Sstevel@tonic-gate */
7177c478bd9Sstevel@tonic-gate
7187c478bd9Sstevel@tonic-gate if (usba_device->usb_addr != ROOT_HUB_ADDR) {
7197c478bd9Sstevel@tonic-gate if (usba_device->usb_cfg_array) {
7207c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
7217c478bd9Sstevel@tonic-gate "deallocating usb_config_array: 0x%p",
722112116d8Sfb209375 (void *)usba_device->usb_cfg_array);
7237c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex);
7247c478bd9Sstevel@tonic-gate for (i = 0;
7257c478bd9Sstevel@tonic-gate i < usba_device->usb_dev_descr->bNumConfigurations;
7267c478bd9Sstevel@tonic-gate i++) {
7277c478bd9Sstevel@tonic-gate if (usba_device->usb_cfg_array[i]) {
7287c478bd9Sstevel@tonic-gate kmem_free(
7297c478bd9Sstevel@tonic-gate usba_device->usb_cfg_array[i],
7307c478bd9Sstevel@tonic-gate usba_device->usb_cfg_array_len[i]);
7317c478bd9Sstevel@tonic-gate }
7327c478bd9Sstevel@tonic-gate }
7337c478bd9Sstevel@tonic-gate
7347c478bd9Sstevel@tonic-gate /* free the array pointers */
7357c478bd9Sstevel@tonic-gate kmem_free(usba_device->usb_cfg_array,
7367c478bd9Sstevel@tonic-gate usba_device->usb_cfg_array_length);
7377c478bd9Sstevel@tonic-gate kmem_free(usba_device->usb_cfg_array_len,
7387c478bd9Sstevel@tonic-gate usba_device->usb_cfg_array_len_length);
7397c478bd9Sstevel@tonic-gate
7407c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex);
7417c478bd9Sstevel@tonic-gate }
7427c478bd9Sstevel@tonic-gate
7437c478bd9Sstevel@tonic-gate if (usba_device->usb_cfg_str_descr) {
7447c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
7457c478bd9Sstevel@tonic-gate "deallocating usb_cfg_str_descr: 0x%p",
746112116d8Sfb209375 (void *)usba_device->usb_cfg_str_descr);
7477c478bd9Sstevel@tonic-gate for (i = 0;
7487c478bd9Sstevel@tonic-gate i < usba_device->usb_dev_descr->bNumConfigurations;
7497c478bd9Sstevel@tonic-gate i++) {
7507c478bd9Sstevel@tonic-gate if (usba_device->usb_cfg_str_descr[i]) {
7517c478bd9Sstevel@tonic-gate kmem_free(
7527c478bd9Sstevel@tonic-gate usba_device->usb_cfg_str_descr[i],
7537c478bd9Sstevel@tonic-gate strlen(usba_device->
7547c478bd9Sstevel@tonic-gate usb_cfg_str_descr[i]) + 1);
7557c478bd9Sstevel@tonic-gate }
7567c478bd9Sstevel@tonic-gate }
7577c478bd9Sstevel@tonic-gate /* free the array pointers */
7587c478bd9Sstevel@tonic-gate kmem_free(usba_device->usb_cfg_str_descr,
7597c478bd9Sstevel@tonic-gate sizeof (uchar_t *) * usba_device->usb_n_cfgs);
7607c478bd9Sstevel@tonic-gate }
7617c478bd9Sstevel@tonic-gate
7627c478bd9Sstevel@tonic-gate if (usba_device->usb_dev_descr) {
7637c478bd9Sstevel@tonic-gate kmem_free(usba_device->usb_dev_descr,
7647c478bd9Sstevel@tonic-gate sizeof (usb_dev_descr_t));
7657c478bd9Sstevel@tonic-gate }
7667c478bd9Sstevel@tonic-gate
7677c478bd9Sstevel@tonic-gate if (usba_device->usb_mfg_str) {
7687c478bd9Sstevel@tonic-gate kmem_free(usba_device->usb_mfg_str,
7697c478bd9Sstevel@tonic-gate strlen(usba_device->usb_mfg_str) + 1);
7707c478bd9Sstevel@tonic-gate }
7717c478bd9Sstevel@tonic-gate
7727c478bd9Sstevel@tonic-gate if (usba_device->usb_product_str) {
7737c478bd9Sstevel@tonic-gate kmem_free(usba_device->usb_product_str,
7747c478bd9Sstevel@tonic-gate strlen(usba_device->usb_product_str) + 1);
7757c478bd9Sstevel@tonic-gate }
7767c478bd9Sstevel@tonic-gate
7777c478bd9Sstevel@tonic-gate if (usba_device->usb_serialno_str) {
7787c478bd9Sstevel@tonic-gate kmem_free(usba_device->usb_serialno_str,
7797c478bd9Sstevel@tonic-gate strlen(usba_device->usb_serialno_str) + 1);
7807c478bd9Sstevel@tonic-gate }
7817c478bd9Sstevel@tonic-gate
7820d2006e4SRobert Mustacchi usba_free_binary_object_store(usba_device);
7830d2006e4SRobert Mustacchi
7847c478bd9Sstevel@tonic-gate usba_unset_usb_address(usba_device);
7857c478bd9Sstevel@tonic-gate }
7867c478bd9Sstevel@tonic-gate
7877c478bd9Sstevel@tonic-gate #ifndef __lock_lint
7887c478bd9Sstevel@tonic-gate ASSERT(usba_device->usb_client_dev_data_list.cddl_next == NULL);
7897c478bd9Sstevel@tonic-gate #endif
7907c478bd9Sstevel@tonic-gate
7917c478bd9Sstevel@tonic-gate if (usba_device->usb_client_flags) {
7927c478bd9Sstevel@tonic-gate #ifndef __lock_lint
7937c478bd9Sstevel@tonic-gate int i;
7947c478bd9Sstevel@tonic-gate
7957c478bd9Sstevel@tonic-gate for (i = 0; i < usba_device->usb_n_ifs; i++) {
7967c478bd9Sstevel@tonic-gate ASSERT(usba_device->usb_client_flags[i] == 0);
7977c478bd9Sstevel@tonic-gate }
7987c478bd9Sstevel@tonic-gate #endif
7997c478bd9Sstevel@tonic-gate kmem_free(usba_device->usb_client_flags,
8007c478bd9Sstevel@tonic-gate usba_device->usb_n_ifs * USBA_CLIENT_FLAG_SIZE);
8017c478bd9Sstevel@tonic-gate }
8027c478bd9Sstevel@tonic-gate
8037c478bd9Sstevel@tonic-gate
8047c478bd9Sstevel@tonic-gate if (usba_device->usb_client_attach_list) {
8057c478bd9Sstevel@tonic-gate kmem_free(usba_device->usb_client_attach_list,
8067c478bd9Sstevel@tonic-gate usba_device->usb_n_ifs *
8077c478bd9Sstevel@tonic-gate sizeof (*usba_device->usb_client_attach_list));
8087c478bd9Sstevel@tonic-gate }
8097c478bd9Sstevel@tonic-gate if (usba_device->usb_client_ev_cb_list) {
8107c478bd9Sstevel@tonic-gate kmem_free(usba_device->usb_client_ev_cb_list,
8117c478bd9Sstevel@tonic-gate usba_device->usb_n_ifs *
8127c478bd9Sstevel@tonic-gate sizeof (*usba_device->usb_client_ev_cb_list));
8137c478bd9Sstevel@tonic-gate }
8147c478bd9Sstevel@tonic-gate
8157c478bd9Sstevel@tonic-gate /*
8167c478bd9Sstevel@tonic-gate * finally ready to destroy the structure
8177c478bd9Sstevel@tonic-gate */
8187c478bd9Sstevel@tonic-gate mutex_destroy(&usba_device->usb_mutex);
8197c478bd9Sstevel@tonic-gate
8207c478bd9Sstevel@tonic-gate kmem_free((caddr_t)usba_device, sizeof (usba_device_t));
8217c478bd9Sstevel@tonic-gate }
8227c478bd9Sstevel@tonic-gate
8237c478bd9Sstevel@tonic-gate
8247c478bd9Sstevel@tonic-gate /* clear the data toggle for all endpoints on this device */
8257c478bd9Sstevel@tonic-gate void
usba_clear_data_toggle(usba_device_t * usba_device)8267c478bd9Sstevel@tonic-gate usba_clear_data_toggle(usba_device_t *usba_device)
8277c478bd9Sstevel@tonic-gate {
8287c478bd9Sstevel@tonic-gate int i;
8297c478bd9Sstevel@tonic-gate
8307c478bd9Sstevel@tonic-gate if (usba_device != NULL) {
8317c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex);
8327c478bd9Sstevel@tonic-gate for (i = 0; i < USBA_N_ENDPOINTS; i++) {
8337c478bd9Sstevel@tonic-gate usba_device->usb_ph_list[i].usba_ph_flags &=
8347c478bd9Sstevel@tonic-gate ~USBA_PH_DATA_TOGGLE;
8357c478bd9Sstevel@tonic-gate }
8367c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex);
8377c478bd9Sstevel@tonic-gate }
8387c478bd9Sstevel@tonic-gate }
8397c478bd9Sstevel@tonic-gate
8407c478bd9Sstevel@tonic-gate
8417c478bd9Sstevel@tonic-gate /*
8427c478bd9Sstevel@tonic-gate * usba_create_child_devi():
8437c478bd9Sstevel@tonic-gate * create a child devinfo node, usba_device, attach properties.
8447c478bd9Sstevel@tonic-gate * the usba_device structure is shared between all interfaces
8457c478bd9Sstevel@tonic-gate */
8467c478bd9Sstevel@tonic-gate int
usba_create_child_devi(dev_info_t * dip,char * node_name,usba_hcdi_ops_t * usba_hcdi_ops,dev_info_t * usb_root_hub_dip,usb_port_status_t port_status,usba_device_t * usba_device,dev_info_t ** child_dip)8477c478bd9Sstevel@tonic-gate usba_create_child_devi(dev_info_t *dip,
8487c478bd9Sstevel@tonic-gate char *node_name,
8497c478bd9Sstevel@tonic-gate usba_hcdi_ops_t *usba_hcdi_ops,
8507c478bd9Sstevel@tonic-gate dev_info_t *usb_root_hub_dip,
8517c478bd9Sstevel@tonic-gate usb_port_status_t port_status,
8527c478bd9Sstevel@tonic-gate usba_device_t *usba_device,
8537c478bd9Sstevel@tonic-gate dev_info_t **child_dip)
8547c478bd9Sstevel@tonic-gate {
8557c478bd9Sstevel@tonic-gate int rval = USB_FAILURE;
8567c478bd9Sstevel@tonic-gate int usba_device_allocated = 0;
8577c478bd9Sstevel@tonic-gate usb_addr_t address;
8587c478bd9Sstevel@tonic-gate
8597c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
8607c478bd9Sstevel@tonic-gate "usba_create_child_devi: %s usba_device=0x%p "
8617c478bd9Sstevel@tonic-gate "port status=0x%x", node_name,
8627c478bd9Sstevel@tonic-gate (void *)usba_device, port_status);
8637c478bd9Sstevel@tonic-gate
864fa9e4066Sahrens ndi_devi_alloc_sleep(dip, node_name, (pnode_t)DEVI_SID_NODEID,
8657c478bd9Sstevel@tonic-gate child_dip);
8667c478bd9Sstevel@tonic-gate
8677c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
868112116d8Sfb209375 "child dip=0x%p", (void *)*child_dip);
8697c478bd9Sstevel@tonic-gate
8707c478bd9Sstevel@tonic-gate if (usba_device == NULL) {
8717c478bd9Sstevel@tonic-gate
8727c478bd9Sstevel@tonic-gate usba_device = usba_alloc_usba_device(usb_root_hub_dip);
8737c478bd9Sstevel@tonic-gate
8747c478bd9Sstevel@tonic-gate /* grab the mutex to keep warlock happy */
8757c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex);
8767c478bd9Sstevel@tonic-gate usba_device->usb_hcdi_ops = usba_hcdi_ops;
8777c478bd9Sstevel@tonic-gate usba_device->usb_port_status = port_status;
8787c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex);
8797c478bd9Sstevel@tonic-gate
8807c478bd9Sstevel@tonic-gate usba_device_allocated++;
8817c478bd9Sstevel@tonic-gate } else {
8827c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex);
8837c478bd9Sstevel@tonic-gate if (usba_hcdi_ops) {
8847c478bd9Sstevel@tonic-gate ASSERT(usba_device->usb_hcdi_ops == usba_hcdi_ops);
8857c478bd9Sstevel@tonic-gate }
8867c478bd9Sstevel@tonic-gate if (usb_root_hub_dip) {
8877c478bd9Sstevel@tonic-gate ASSERT(usba_device->usb_root_hub_dip ==
8887c478bd9Sstevel@tonic-gate usb_root_hub_dip);
8897c478bd9Sstevel@tonic-gate }
8907c478bd9Sstevel@tonic-gate
8917c478bd9Sstevel@tonic-gate usba_device->usb_port_status = port_status;
8927c478bd9Sstevel@tonic-gate
8937c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex);
8947c478bd9Sstevel@tonic-gate }
8957c478bd9Sstevel@tonic-gate
8967c478bd9Sstevel@tonic-gate if (usba_device->usb_addr == 0) {
8977c478bd9Sstevel@tonic-gate if (usba_set_usb_address(usba_device) == USB_FAILURE) {
8987c478bd9Sstevel@tonic-gate address = 0;
8997c478bd9Sstevel@tonic-gate
9007c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
9017c478bd9Sstevel@tonic-gate "cannot set usb address for dip=0x%p",
902112116d8Sfb209375 (void *)*child_dip);
9037c478bd9Sstevel@tonic-gate
9047c478bd9Sstevel@tonic-gate goto fail;
9057c478bd9Sstevel@tonic-gate }
9067c478bd9Sstevel@tonic-gate }
9077c478bd9Sstevel@tonic-gate address = usba_device->usb_addr;
9087c478bd9Sstevel@tonic-gate
9097c478bd9Sstevel@tonic-gate /* attach properties */
9107c478bd9Sstevel@tonic-gate rval = ndi_prop_update_int(DDI_DEV_T_NONE, *child_dip,
9117c478bd9Sstevel@tonic-gate "assigned-address", address);
9127c478bd9Sstevel@tonic-gate if (rval != DDI_PROP_SUCCESS) {
9137c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
9147c478bd9Sstevel@tonic-gate "cannot set usb address property for dip=0x%p",
915112116d8Sfb209375 (void *)*child_dip);
9167c478bd9Sstevel@tonic-gate rval = USB_FAILURE;
9177c478bd9Sstevel@tonic-gate
9187c478bd9Sstevel@tonic-gate goto fail;
9197c478bd9Sstevel@tonic-gate }
9207c478bd9Sstevel@tonic-gate
9217c478bd9Sstevel@tonic-gate /*
9227c478bd9Sstevel@tonic-gate * store the usba_device point in the dip
9237c478bd9Sstevel@tonic-gate */
9247c478bd9Sstevel@tonic-gate usba_set_usba_device(*child_dip, usba_device);
9257c478bd9Sstevel@tonic-gate
9267c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
9277c478bd9Sstevel@tonic-gate "usba_create_child_devi: devi=0x%p (%s) ud=0x%p",
928112116d8Sfb209375 (void *)*child_dip, ddi_driver_name(*child_dip),
929112116d8Sfb209375 (void *)usba_device);
9307c478bd9Sstevel@tonic-gate
9317c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
9327c478bd9Sstevel@tonic-gate
9337c478bd9Sstevel@tonic-gate fail:
9347c478bd9Sstevel@tonic-gate if (*child_dip) {
9357c478bd9Sstevel@tonic-gate int rval = usba_destroy_child_devi(*child_dip, NDI_DEVI_REMOVE);
9367c478bd9Sstevel@tonic-gate ASSERT(rval == USB_SUCCESS);
9377c478bd9Sstevel@tonic-gate *child_dip = NULL;
9387c478bd9Sstevel@tonic-gate }
9397c478bd9Sstevel@tonic-gate
9407c478bd9Sstevel@tonic-gate if (usba_device_allocated) {
9417c478bd9Sstevel@tonic-gate usba_free_usba_device(usba_device);
9427c478bd9Sstevel@tonic-gate } else if (address && usba_device) {
9437c478bd9Sstevel@tonic-gate usba_unset_usb_address(usba_device);
9447c478bd9Sstevel@tonic-gate }
9457c478bd9Sstevel@tonic-gate
946d291d9f2Sfrits USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
9477c478bd9Sstevel@tonic-gate "usba_create_child_devi failed: rval=%d", rval);
9487c478bd9Sstevel@tonic-gate
9497c478bd9Sstevel@tonic-gate return (rval);
9507c478bd9Sstevel@tonic-gate }
9517c478bd9Sstevel@tonic-gate
9527c478bd9Sstevel@tonic-gate
9537c478bd9Sstevel@tonic-gate int
usba_destroy_child_devi(dev_info_t * dip,uint_t flag)9547c478bd9Sstevel@tonic-gate usba_destroy_child_devi(dev_info_t *dip, uint_t flag)
9557c478bd9Sstevel@tonic-gate {
9567c478bd9Sstevel@tonic-gate usba_device_t *usba_device;
9577c478bd9Sstevel@tonic-gate int rval = NDI_SUCCESS;
9587c478bd9Sstevel@tonic-gate
9597c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
9607c478bd9Sstevel@tonic-gate "usba_destroy_child_devi: %s%d (0x%p)",
961112116d8Sfb209375 ddi_driver_name(dip), ddi_get_instance(dip), (void *)dip);
9627c478bd9Sstevel@tonic-gate
9637c478bd9Sstevel@tonic-gate usba_device = usba_get_usba_device(dip);
9647c478bd9Sstevel@tonic-gate
9657c478bd9Sstevel@tonic-gate /*
9667c478bd9Sstevel@tonic-gate * if the child hasn't been bound yet, we can just
9677c478bd9Sstevel@tonic-gate * free the dip
9687c478bd9Sstevel@tonic-gate */
9697c478bd9Sstevel@tonic-gate if (i_ddi_node_state(dip) < DS_INITIALIZED) {
9707c478bd9Sstevel@tonic-gate /*
9717c478bd9Sstevel@tonic-gate * do not call ndi_devi_free() since it might
9727c478bd9Sstevel@tonic-gate * deadlock
9737c478bd9Sstevel@tonic-gate */
9747c478bd9Sstevel@tonic-gate rval = ddi_remove_child(dip, 0);
9757c478bd9Sstevel@tonic-gate
9767c478bd9Sstevel@tonic-gate } else {
9777c478bd9Sstevel@tonic-gate char *devnm = kmem_alloc(MAXNAMELEN + 1, KM_SLEEP);
9787c478bd9Sstevel@tonic-gate dev_info_t *pdip = ddi_get_parent(dip);
9797c478bd9Sstevel@tonic-gate
9807c478bd9Sstevel@tonic-gate (void) ddi_deviname(dip, devnm);
9817c478bd9Sstevel@tonic-gate
9827c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
9837c478bd9Sstevel@tonic-gate "usba_destroy_child_devi:\n\t"
984112116d8Sfb209375 "offlining dip 0x%p usba_device=0x%p (%s)", (void *)dip,
9857c478bd9Sstevel@tonic-gate (void *)usba_device, devnm);
9867c478bd9Sstevel@tonic-gate
9877c478bd9Sstevel@tonic-gate (void) devfs_clean(pdip, NULL, DV_CLEAN_FORCE);
9887c478bd9Sstevel@tonic-gate rval = ndi_devi_unconfig_one(pdip, devnm + 1, NULL,
9897c478bd9Sstevel@tonic-gate flag | NDI_UNCONFIG | NDI_DEVI_OFFLINE);
9907c478bd9Sstevel@tonic-gate if (rval != NDI_SUCCESS) {
9917c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
9927c478bd9Sstevel@tonic-gate " ndi_devi_unconfig_one %s%d failed (%d)",
9937c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip),
9947c478bd9Sstevel@tonic-gate rval);
9957c478bd9Sstevel@tonic-gate }
9967c478bd9Sstevel@tonic-gate kmem_free(devnm, MAXNAMELEN + 1);
9977c478bd9Sstevel@tonic-gate }
9987c478bd9Sstevel@tonic-gate
9997c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
10007c478bd9Sstevel@tonic-gate "usba_destroy_child_devi: rval=%d", rval);
10017c478bd9Sstevel@tonic-gate
10027c478bd9Sstevel@tonic-gate return (rval == NDI_SUCCESS ? USB_SUCCESS : USB_FAILURE);
10037c478bd9Sstevel@tonic-gate }
10047c478bd9Sstevel@tonic-gate
10057c478bd9Sstevel@tonic-gate
10067c478bd9Sstevel@tonic-gate /*
10077c478bd9Sstevel@tonic-gate * list management
10087c478bd9Sstevel@tonic-gate */
10097c478bd9Sstevel@tonic-gate void
usba_init_list(usba_list_entry_t * element,usb_opaque_t private,ddi_iblock_cookie_t iblock_cookie)10107c478bd9Sstevel@tonic-gate usba_init_list(usba_list_entry_t *element, usb_opaque_t private,
10117c478bd9Sstevel@tonic-gate ddi_iblock_cookie_t iblock_cookie)
10127c478bd9Sstevel@tonic-gate {
10137c478bd9Sstevel@tonic-gate mutex_init(&element->list_mutex, NULL, MUTEX_DRIVER,
10147c478bd9Sstevel@tonic-gate iblock_cookie);
10157c478bd9Sstevel@tonic-gate mutex_enter(&element->list_mutex);
10167c478bd9Sstevel@tonic-gate element->private = private;
10177c478bd9Sstevel@tonic-gate mutex_exit(&element->list_mutex);
10187c478bd9Sstevel@tonic-gate }
10197c478bd9Sstevel@tonic-gate
10207c478bd9Sstevel@tonic-gate
10217c478bd9Sstevel@tonic-gate void
usba_destroy_list(usba_list_entry_t * head)10227c478bd9Sstevel@tonic-gate usba_destroy_list(usba_list_entry_t *head)
10237c478bd9Sstevel@tonic-gate {
10247c478bd9Sstevel@tonic-gate mutex_enter(&head->list_mutex);
10257c478bd9Sstevel@tonic-gate ASSERT(head->next == NULL);
10267c478bd9Sstevel@tonic-gate ASSERT(head->prev == NULL);
10277c478bd9Sstevel@tonic-gate mutex_exit(&head->list_mutex);
10287c478bd9Sstevel@tonic-gate
10297c478bd9Sstevel@tonic-gate mutex_destroy(&head->list_mutex);
10307c478bd9Sstevel@tonic-gate }
10317c478bd9Sstevel@tonic-gate
10327c478bd9Sstevel@tonic-gate
10337c478bd9Sstevel@tonic-gate void
usba_add_to_list(usba_list_entry_t * head,usba_list_entry_t * element)10347c478bd9Sstevel@tonic-gate usba_add_to_list(usba_list_entry_t *head, usba_list_entry_t *element)
10357c478bd9Sstevel@tonic-gate {
10367c478bd9Sstevel@tonic-gate usba_list_entry_t *next;
10377c478bd9Sstevel@tonic-gate int remaining;
10387c478bd9Sstevel@tonic-gate
10397c478bd9Sstevel@tonic-gate mutex_enter(&head->list_mutex);
10407c478bd9Sstevel@tonic-gate mutex_enter(&element->list_mutex);
10417c478bd9Sstevel@tonic-gate
10427c478bd9Sstevel@tonic-gate remaining = head->count;
10437c478bd9Sstevel@tonic-gate
10447c478bd9Sstevel@tonic-gate /* check if it is not in another list */
10457c478bd9Sstevel@tonic-gate ASSERT(element->next == NULL);
10467c478bd9Sstevel@tonic-gate ASSERT(element->prev == NULL);
10477c478bd9Sstevel@tonic-gate
10487c478bd9Sstevel@tonic-gate #ifdef DEBUG
10497c478bd9Sstevel@tonic-gate /*
10507c478bd9Sstevel@tonic-gate * only verify the list when not in interrupt context, we
10517c478bd9Sstevel@tonic-gate * have to trust the HCD
10527c478bd9Sstevel@tonic-gate */
10537c478bd9Sstevel@tonic-gate if (!servicing_interrupt()) {
10547c478bd9Sstevel@tonic-gate
10557c478bd9Sstevel@tonic-gate /* check if not already in this list */
10567c478bd9Sstevel@tonic-gate for (next = head->next; (next != NULL);
10577c478bd9Sstevel@tonic-gate next = next->next) {
10587c478bd9Sstevel@tonic-gate if (next == element) {
10597c478bd9Sstevel@tonic-gate USB_DPRINTF_L0(DPRINT_MASK_USBA,
10607c478bd9Sstevel@tonic-gate usba_log_handle,
10617c478bd9Sstevel@tonic-gate "Attempt to corrupt USB list at 0x%p",
10627c478bd9Sstevel@tonic-gate (void *)head);
10637c478bd9Sstevel@tonic-gate ASSERT(next == element);
10647c478bd9Sstevel@tonic-gate
10657c478bd9Sstevel@tonic-gate goto done;
10667c478bd9Sstevel@tonic-gate }
10677c478bd9Sstevel@tonic-gate remaining--;
10687c478bd9Sstevel@tonic-gate
10697c478bd9Sstevel@tonic-gate /*
10707c478bd9Sstevel@tonic-gate * Detect incorrect circ links or found
10717c478bd9Sstevel@tonic-gate * unexpected elements.
10727c478bd9Sstevel@tonic-gate */
10737c478bd9Sstevel@tonic-gate if ((next->next && (remaining == 0)) ||
10747c478bd9Sstevel@tonic-gate ((next->next == NULL) && remaining)) {
10757c478bd9Sstevel@tonic-gate panic("Corrupted USB list at 0x%p",
10767c478bd9Sstevel@tonic-gate (void *)head);
10777c478bd9Sstevel@tonic-gate /*NOTREACHED*/
10787c478bd9Sstevel@tonic-gate }
10797c478bd9Sstevel@tonic-gate }
10807c478bd9Sstevel@tonic-gate }
10817c478bd9Sstevel@tonic-gate #endif
10827c478bd9Sstevel@tonic-gate
10837c478bd9Sstevel@tonic-gate if (head->next == NULL) {
10847c478bd9Sstevel@tonic-gate head->prev = head->next = element;
10857c478bd9Sstevel@tonic-gate } else {
10867c478bd9Sstevel@tonic-gate /* add to tail */
10877c478bd9Sstevel@tonic-gate head->prev->next = element;
10887c478bd9Sstevel@tonic-gate element->prev = head->prev;
10897c478bd9Sstevel@tonic-gate head->prev = element;
10907c478bd9Sstevel@tonic-gate }
10917c478bd9Sstevel@tonic-gate
10927c478bd9Sstevel@tonic-gate head->count++;
10937c478bd9Sstevel@tonic-gate
10947c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
10957c478bd9Sstevel@tonic-gate "usba_add_to_list: head=0x%p element=0x%p count=%d",
1096112116d8Sfb209375 (void *)head, (void *)element, head->count);
10977c478bd9Sstevel@tonic-gate
1098*e2eb5315SToomas Soome #ifdef DEBUG
10997c478bd9Sstevel@tonic-gate done:
1100*e2eb5315SToomas Soome #endif
11017c478bd9Sstevel@tonic-gate mutex_exit(&head->list_mutex);
11027c478bd9Sstevel@tonic-gate mutex_exit(&element->list_mutex);
11037c478bd9Sstevel@tonic-gate }
11047c478bd9Sstevel@tonic-gate
11057c478bd9Sstevel@tonic-gate
11067c478bd9Sstevel@tonic-gate int
usba_rm_from_list(usba_list_entry_t * head,usba_list_entry_t * element)11077c478bd9Sstevel@tonic-gate usba_rm_from_list(usba_list_entry_t *head, usba_list_entry_t *element)
11087c478bd9Sstevel@tonic-gate {
11097c478bd9Sstevel@tonic-gate usba_list_entry_t *e;
11107c478bd9Sstevel@tonic-gate int found = 0;
11117c478bd9Sstevel@tonic-gate int remaining;
11127c478bd9Sstevel@tonic-gate
11137c478bd9Sstevel@tonic-gate /* find the element in the list first */
11147c478bd9Sstevel@tonic-gate mutex_enter(&head->list_mutex);
11157c478bd9Sstevel@tonic-gate
11167c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
11177c478bd9Sstevel@tonic-gate "usba_rm_from_list: head=0x%p element=0x%p count=%d",
1118112116d8Sfb209375 (void *)head, (void *)element, head->count);
11197c478bd9Sstevel@tonic-gate
11207c478bd9Sstevel@tonic-gate remaining = head->count;
11217c478bd9Sstevel@tonic-gate e = head->next;
11227c478bd9Sstevel@tonic-gate
11237c478bd9Sstevel@tonic-gate while (e) {
11247c478bd9Sstevel@tonic-gate if (e == element) {
11257c478bd9Sstevel@tonic-gate found++;
11267c478bd9Sstevel@tonic-gate break;
11277c478bd9Sstevel@tonic-gate }
11287c478bd9Sstevel@tonic-gate e = e->next;
11297c478bd9Sstevel@tonic-gate
11307c478bd9Sstevel@tonic-gate remaining--;
11317c478bd9Sstevel@tonic-gate
11327c478bd9Sstevel@tonic-gate /* Detect incorrect circ links or found unexpected elements. */
11337c478bd9Sstevel@tonic-gate if ((e && (remaining == 0)) ||
11347c478bd9Sstevel@tonic-gate ((e == NULL) && (remaining))) {
11357c478bd9Sstevel@tonic-gate panic("Corrupted USB list at 0x%p", (void *)head);
11367c478bd9Sstevel@tonic-gate /*NOTREACHED*/
11377c478bd9Sstevel@tonic-gate }
11387c478bd9Sstevel@tonic-gate }
11397c478bd9Sstevel@tonic-gate
11407c478bd9Sstevel@tonic-gate if (!found) {
11417c478bd9Sstevel@tonic-gate mutex_exit(&head->list_mutex);
11427c478bd9Sstevel@tonic-gate
11437c478bd9Sstevel@tonic-gate return (USB_FAILURE);
11447c478bd9Sstevel@tonic-gate }
11457c478bd9Sstevel@tonic-gate
11467c478bd9Sstevel@tonic-gate /* now remove the element */
11477c478bd9Sstevel@tonic-gate mutex_enter(&element->list_mutex);
11487c478bd9Sstevel@tonic-gate
11497c478bd9Sstevel@tonic-gate if (element->next) {
11507c478bd9Sstevel@tonic-gate element->next->prev = element->prev;
11517c478bd9Sstevel@tonic-gate }
11527c478bd9Sstevel@tonic-gate if (element->prev) {
11537c478bd9Sstevel@tonic-gate element->prev->next = element->next;
11547c478bd9Sstevel@tonic-gate }
11557c478bd9Sstevel@tonic-gate if (head->next == element) {
11567c478bd9Sstevel@tonic-gate head->next = element->next;
11577c478bd9Sstevel@tonic-gate }
11587c478bd9Sstevel@tonic-gate if (head->prev == element) {
11597c478bd9Sstevel@tonic-gate head->prev = element->prev;
11607c478bd9Sstevel@tonic-gate }
11617c478bd9Sstevel@tonic-gate
11627c478bd9Sstevel@tonic-gate element->prev = element->next = NULL;
11637c478bd9Sstevel@tonic-gate if (head->next == NULL) {
11647c478bd9Sstevel@tonic-gate ASSERT(head->prev == NULL);
11657c478bd9Sstevel@tonic-gate } else {
11667c478bd9Sstevel@tonic-gate ASSERT(head->next->prev == NULL);
11677c478bd9Sstevel@tonic-gate }
11687c478bd9Sstevel@tonic-gate if (head->prev == NULL) {
11697c478bd9Sstevel@tonic-gate ASSERT(head->next == NULL);
11707c478bd9Sstevel@tonic-gate } else {
11717c478bd9Sstevel@tonic-gate ASSERT(head->prev->next == NULL);
11727c478bd9Sstevel@tonic-gate }
11737c478bd9Sstevel@tonic-gate
11747c478bd9Sstevel@tonic-gate head->count--;
11757c478bd9Sstevel@tonic-gate
11767c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
11777c478bd9Sstevel@tonic-gate "usba_rm_from_list success: head=0x%p element=0x%p cnt=%d",
1178112116d8Sfb209375 (void *)head, (void *)element, head->count);
11797c478bd9Sstevel@tonic-gate
11807c478bd9Sstevel@tonic-gate mutex_exit(&element->list_mutex);
11817c478bd9Sstevel@tonic-gate mutex_exit(&head->list_mutex);
11827c478bd9Sstevel@tonic-gate
11837c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
11847c478bd9Sstevel@tonic-gate }
11857c478bd9Sstevel@tonic-gate
11867c478bd9Sstevel@tonic-gate
11877c478bd9Sstevel@tonic-gate usba_list_entry_t *
usba_rm_first_from_list(usba_list_entry_t * head)11887c478bd9Sstevel@tonic-gate usba_rm_first_from_list(usba_list_entry_t *head)
11897c478bd9Sstevel@tonic-gate {
11907c478bd9Sstevel@tonic-gate usba_list_entry_t *element = NULL;
11917c478bd9Sstevel@tonic-gate
11927c478bd9Sstevel@tonic-gate if (head) {
11937c478bd9Sstevel@tonic-gate mutex_enter(&head->list_mutex);
11947c478bd9Sstevel@tonic-gate element = head->next;
11957c478bd9Sstevel@tonic-gate if (element) {
11967c478bd9Sstevel@tonic-gate /* now remove the element */
11977c478bd9Sstevel@tonic-gate mutex_enter(&element->list_mutex);
11987c478bd9Sstevel@tonic-gate head->next = element->next;
11997c478bd9Sstevel@tonic-gate if (head->next) {
12007c478bd9Sstevel@tonic-gate head->next->prev = NULL;
12017c478bd9Sstevel@tonic-gate }
12027c478bd9Sstevel@tonic-gate if (head->prev == element) {
12037c478bd9Sstevel@tonic-gate head->prev = element->next;
12047c478bd9Sstevel@tonic-gate }
12057c478bd9Sstevel@tonic-gate element->prev = element->next = NULL;
12067c478bd9Sstevel@tonic-gate mutex_exit(&element->list_mutex);
12077c478bd9Sstevel@tonic-gate head->count--;
12087c478bd9Sstevel@tonic-gate }
12097c478bd9Sstevel@tonic-gate if (head->next == NULL) {
12107c478bd9Sstevel@tonic-gate ASSERT(head->prev == NULL);
12117c478bd9Sstevel@tonic-gate } else {
12127c478bd9Sstevel@tonic-gate ASSERT(head->next->prev == NULL);
12137c478bd9Sstevel@tonic-gate }
12147c478bd9Sstevel@tonic-gate if (head->prev == NULL) {
12157c478bd9Sstevel@tonic-gate ASSERT(head->next == NULL);
12167c478bd9Sstevel@tonic-gate } else {
12177c478bd9Sstevel@tonic-gate ASSERT(head->prev->next == NULL);
12187c478bd9Sstevel@tonic-gate }
12197c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
12207c478bd9Sstevel@tonic-gate "usba_rm_first_from_list: head=0x%p el=0x%p cnt=%d",
1221112116d8Sfb209375 (void *)head, (void *)element, head->count);
12227c478bd9Sstevel@tonic-gate
12237c478bd9Sstevel@tonic-gate mutex_exit(&head->list_mutex);
12247c478bd9Sstevel@tonic-gate }
12257c478bd9Sstevel@tonic-gate
12267c478bd9Sstevel@tonic-gate return (element);
12277c478bd9Sstevel@tonic-gate }
12287c478bd9Sstevel@tonic-gate
12297c478bd9Sstevel@tonic-gate
12307c478bd9Sstevel@tonic-gate usb_opaque_t
usba_rm_first_pvt_from_list(usba_list_entry_t * head)12317c478bd9Sstevel@tonic-gate usba_rm_first_pvt_from_list(usba_list_entry_t *head)
12327c478bd9Sstevel@tonic-gate {
12337c478bd9Sstevel@tonic-gate usba_list_entry_t *element = usba_rm_first_from_list(head);
12347c478bd9Sstevel@tonic-gate usb_opaque_t private = NULL;
12357c478bd9Sstevel@tonic-gate
12367c478bd9Sstevel@tonic-gate if (element) {
12377c478bd9Sstevel@tonic-gate mutex_enter(&element->list_mutex);
12387c478bd9Sstevel@tonic-gate private = element->private;
12397c478bd9Sstevel@tonic-gate mutex_exit(&element->list_mutex);
12407c478bd9Sstevel@tonic-gate }
12417c478bd9Sstevel@tonic-gate
12427c478bd9Sstevel@tonic-gate return (private);
12437c478bd9Sstevel@tonic-gate }
12447c478bd9Sstevel@tonic-gate
12457c478bd9Sstevel@tonic-gate
12467c478bd9Sstevel@tonic-gate /*
12477c478bd9Sstevel@tonic-gate * move list to new list and zero original list
12487c478bd9Sstevel@tonic-gate */
12497c478bd9Sstevel@tonic-gate void
usba_move_list(usba_list_entry_t * head,usba_list_entry_t * new,ddi_iblock_cookie_t iblock_cookie)12507c478bd9Sstevel@tonic-gate usba_move_list(usba_list_entry_t *head, usba_list_entry_t *new,
12517c478bd9Sstevel@tonic-gate ddi_iblock_cookie_t iblock_cookie)
12527c478bd9Sstevel@tonic-gate {
12537c478bd9Sstevel@tonic-gate usba_init_list(new, NULL, iblock_cookie);
12547c478bd9Sstevel@tonic-gate mutex_enter(&head->list_mutex);
12557c478bd9Sstevel@tonic-gate mutex_enter(&new->list_mutex);
12567c478bd9Sstevel@tonic-gate
12577c478bd9Sstevel@tonic-gate new->next = head->next;
12587c478bd9Sstevel@tonic-gate new->prev = head->prev;
12597c478bd9Sstevel@tonic-gate new->count = head->count;
12607c478bd9Sstevel@tonic-gate new->private = head->private;
12617c478bd9Sstevel@tonic-gate
12627c478bd9Sstevel@tonic-gate head->next = NULL;
12637c478bd9Sstevel@tonic-gate head->prev = NULL;
12647c478bd9Sstevel@tonic-gate head->count = 0;
12657c478bd9Sstevel@tonic-gate head->private = NULL;
12667c478bd9Sstevel@tonic-gate mutex_exit(&head->list_mutex);
12677c478bd9Sstevel@tonic-gate mutex_exit(&new->list_mutex);
12687c478bd9Sstevel@tonic-gate }
12697c478bd9Sstevel@tonic-gate
12707c478bd9Sstevel@tonic-gate
12717c478bd9Sstevel@tonic-gate int
usba_check_in_list(usba_list_entry_t * head,usba_list_entry_t * element)12727c478bd9Sstevel@tonic-gate usba_check_in_list(usba_list_entry_t *head, usba_list_entry_t *element)
12737c478bd9Sstevel@tonic-gate {
12747c478bd9Sstevel@tonic-gate int rval = USB_FAILURE;
12757c478bd9Sstevel@tonic-gate int remaining;
12767c478bd9Sstevel@tonic-gate usba_list_entry_t *next;
12777c478bd9Sstevel@tonic-gate
12787c478bd9Sstevel@tonic-gate mutex_enter(&head->list_mutex);
12797c478bd9Sstevel@tonic-gate remaining = head->count;
12807c478bd9Sstevel@tonic-gate
12817c478bd9Sstevel@tonic-gate mutex_enter(&element->list_mutex);
12827c478bd9Sstevel@tonic-gate for (next = head->next; next != NULL; next = next->next) {
12837c478bd9Sstevel@tonic-gate if (next == element) {
12847c478bd9Sstevel@tonic-gate rval = USB_SUCCESS;
12857c478bd9Sstevel@tonic-gate break;
12867c478bd9Sstevel@tonic-gate }
12877c478bd9Sstevel@tonic-gate remaining--;
12887c478bd9Sstevel@tonic-gate
12897c478bd9Sstevel@tonic-gate /* Detect incorrect circ links or found unexpected elements. */
12907c478bd9Sstevel@tonic-gate if ((next->next && (remaining == 0)) ||
12917c478bd9Sstevel@tonic-gate ((next->next == NULL) && remaining)) {
12927c478bd9Sstevel@tonic-gate panic("Corrupted USB list at 0x%p", (void *)head);
12937c478bd9Sstevel@tonic-gate /*NOTREACHED*/
12947c478bd9Sstevel@tonic-gate }
12957c478bd9Sstevel@tonic-gate }
12967c478bd9Sstevel@tonic-gate mutex_exit(&element->list_mutex);
12977c478bd9Sstevel@tonic-gate mutex_exit(&head->list_mutex);
12987c478bd9Sstevel@tonic-gate
12997c478bd9Sstevel@tonic-gate return (rval);
13007c478bd9Sstevel@tonic-gate }
13017c478bd9Sstevel@tonic-gate
13027c478bd9Sstevel@tonic-gate
13037c478bd9Sstevel@tonic-gate int
usba_list_entry_leaks(usba_list_entry_t * head,char * what)13047c478bd9Sstevel@tonic-gate usba_list_entry_leaks(usba_list_entry_t *head, char *what)
13057c478bd9Sstevel@tonic-gate {
13067c478bd9Sstevel@tonic-gate int count = 0;
13077c478bd9Sstevel@tonic-gate int remaining;
13087c478bd9Sstevel@tonic-gate usba_list_entry_t *next;
13097c478bd9Sstevel@tonic-gate
13107c478bd9Sstevel@tonic-gate mutex_enter(&head->list_mutex);
13117c478bd9Sstevel@tonic-gate remaining = head->count;
13127c478bd9Sstevel@tonic-gate for (next = head->next; next != NULL; next = next->next) {
13137c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_HCDI, usba_log_handle,
1314112116d8Sfb209375 "leaking %s 0x%p", what, (void *)next->private);
13157c478bd9Sstevel@tonic-gate count++;
13167c478bd9Sstevel@tonic-gate
13177c478bd9Sstevel@tonic-gate remaining--;
13187c478bd9Sstevel@tonic-gate
13197c478bd9Sstevel@tonic-gate /* Detect incorrect circ links or found unexpected elements. */
13207c478bd9Sstevel@tonic-gate if ((next->next && (remaining == 0)) ||
13217c478bd9Sstevel@tonic-gate ((next->next == NULL) && remaining)) {
13227c478bd9Sstevel@tonic-gate panic("Corrupted USB list at 0x%p", (void *)head);
13237c478bd9Sstevel@tonic-gate /*NOTREACHED*/
13247c478bd9Sstevel@tonic-gate }
13257c478bd9Sstevel@tonic-gate }
13267c478bd9Sstevel@tonic-gate ASSERT(count == head->count);
13277c478bd9Sstevel@tonic-gate mutex_exit(&head->list_mutex);
13287c478bd9Sstevel@tonic-gate
13297c478bd9Sstevel@tonic-gate if (count) {
13307c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_HCDI, usba_log_handle,
13317c478bd9Sstevel@tonic-gate "usba_list_entry_count: leaking %d", count);
13327c478bd9Sstevel@tonic-gate }
13337c478bd9Sstevel@tonic-gate
13347c478bd9Sstevel@tonic-gate return (count);
13357c478bd9Sstevel@tonic-gate }
13367c478bd9Sstevel@tonic-gate
13377c478bd9Sstevel@tonic-gate
13387c478bd9Sstevel@tonic-gate int
usba_list_entry_count(usba_list_entry_t * head)13397c478bd9Sstevel@tonic-gate usba_list_entry_count(usba_list_entry_t *head)
13407c478bd9Sstevel@tonic-gate {
13417c478bd9Sstevel@tonic-gate int count;
13427c478bd9Sstevel@tonic-gate
13437c478bd9Sstevel@tonic-gate mutex_enter(&head->list_mutex);
13447c478bd9Sstevel@tonic-gate count = head->count;
13457c478bd9Sstevel@tonic-gate mutex_exit(&head->list_mutex);
13467c478bd9Sstevel@tonic-gate
13477c478bd9Sstevel@tonic-gate return (count);
13487c478bd9Sstevel@tonic-gate }
13497c478bd9Sstevel@tonic-gate
1350de6f998eSrui wang - Sun Microsystems - Beijing China /* add a new root hub to the usba_root_hubs list */
1351de6f998eSrui wang - Sun Microsystems - Beijing China
1352de6f998eSrui wang - Sun Microsystems - Beijing China void
usba_add_root_hub(dev_info_t * dip)1353de6f998eSrui wang - Sun Microsystems - Beijing China usba_add_root_hub(dev_info_t *dip)
1354de6f998eSrui wang - Sun Microsystems - Beijing China {
1355de6f998eSrui wang - Sun Microsystems - Beijing China usba_root_hub_ent_t *hub;
1356de6f998eSrui wang - Sun Microsystems - Beijing China
1357de6f998eSrui wang - Sun Microsystems - Beijing China hub = (usba_root_hub_ent_t *)
1358de6f998eSrui wang - Sun Microsystems - Beijing China kmem_zalloc(sizeof (usba_root_hub_ent_t), KM_SLEEP);
1359de6f998eSrui wang - Sun Microsystems - Beijing China
1360de6f998eSrui wang - Sun Microsystems - Beijing China mutex_enter(&usba_hub_mutex);
1361de6f998eSrui wang - Sun Microsystems - Beijing China hub->dip = dip;
1362de6f998eSrui wang - Sun Microsystems - Beijing China hub->next = usba_root_hubs;
1363de6f998eSrui wang - Sun Microsystems - Beijing China usba_root_hubs = hub;
1364de6f998eSrui wang - Sun Microsystems - Beijing China mutex_exit(&usba_hub_mutex);
1365de6f998eSrui wang - Sun Microsystems - Beijing China }
1366de6f998eSrui wang - Sun Microsystems - Beijing China
1367de6f998eSrui wang - Sun Microsystems - Beijing China /* remove a root hub from the usba_root_hubs list */
1368de6f998eSrui wang - Sun Microsystems - Beijing China
1369de6f998eSrui wang - Sun Microsystems - Beijing China void
usba_rem_root_hub(dev_info_t * dip)1370de6f998eSrui wang - Sun Microsystems - Beijing China usba_rem_root_hub(dev_info_t *dip)
1371de6f998eSrui wang - Sun Microsystems - Beijing China {
1372de6f998eSrui wang - Sun Microsystems - Beijing China usba_root_hub_ent_t **hubp, *hub;
1373de6f998eSrui wang - Sun Microsystems - Beijing China
1374de6f998eSrui wang - Sun Microsystems - Beijing China mutex_enter(&usba_hub_mutex);
1375de6f998eSrui wang - Sun Microsystems - Beijing China hubp = &usba_root_hubs;
1376de6f998eSrui wang - Sun Microsystems - Beijing China while (*hubp) {
1377de6f998eSrui wang - Sun Microsystems - Beijing China if ((*hubp)->dip == dip) {
1378de6f998eSrui wang - Sun Microsystems - Beijing China hub = *hubp;
1379de6f998eSrui wang - Sun Microsystems - Beijing China *hubp = hub->next;
1380de6f998eSrui wang - Sun Microsystems - Beijing China kmem_free(hub, sizeof (struct usba_root_hub_ent));
1381de6f998eSrui wang - Sun Microsystems - Beijing China mutex_exit(&usba_hub_mutex);
1382de6f998eSrui wang - Sun Microsystems - Beijing China
1383de6f998eSrui wang - Sun Microsystems - Beijing China return;
1384de6f998eSrui wang - Sun Microsystems - Beijing China }
1385de6f998eSrui wang - Sun Microsystems - Beijing China hubp = &(*hubp)->next;
1386de6f998eSrui wang - Sun Microsystems - Beijing China }
1387de6f998eSrui wang - Sun Microsystems - Beijing China mutex_exit(&usba_hub_mutex);
1388de6f998eSrui wang - Sun Microsystems - Beijing China }
13897c478bd9Sstevel@tonic-gate
13907c478bd9Sstevel@tonic-gate /*
1391de6f998eSrui wang - Sun Microsystems - Beijing China * check whether this dip is the root hub. Any root hub known by
1392de6f998eSrui wang - Sun Microsystems - Beijing China * usba is recorded in the linked list pointed to by usba_root_hubs
13937c478bd9Sstevel@tonic-gate */
13947c478bd9Sstevel@tonic-gate int
usba_is_root_hub(dev_info_t * dip)13957c478bd9Sstevel@tonic-gate usba_is_root_hub(dev_info_t *dip)
13967c478bd9Sstevel@tonic-gate {
1397de6f998eSrui wang - Sun Microsystems - Beijing China usba_root_hub_ent_t *hub;
1398de6f998eSrui wang - Sun Microsystems - Beijing China
1399de6f998eSrui wang - Sun Microsystems - Beijing China mutex_enter(&usba_hub_mutex);
1400de6f998eSrui wang - Sun Microsystems - Beijing China hub = usba_root_hubs;
1401de6f998eSrui wang - Sun Microsystems - Beijing China while (hub) {
1402de6f998eSrui wang - Sun Microsystems - Beijing China if (hub->dip == dip) {
1403de6f998eSrui wang - Sun Microsystems - Beijing China mutex_exit(&usba_hub_mutex);
1404de6f998eSrui wang - Sun Microsystems - Beijing China
1405de6f998eSrui wang - Sun Microsystems - Beijing China return (1);
14067c478bd9Sstevel@tonic-gate }
1407de6f998eSrui wang - Sun Microsystems - Beijing China hub = hub->next;
1408de6f998eSrui wang - Sun Microsystems - Beijing China }
1409de6f998eSrui wang - Sun Microsystems - Beijing China mutex_exit(&usba_hub_mutex);
1410de6f998eSrui wang - Sun Microsystems - Beijing China
14117c478bd9Sstevel@tonic-gate return (0);
14127c478bd9Sstevel@tonic-gate }
14137c478bd9Sstevel@tonic-gate
1414ff0e937bSRaymond Chen /*
14157c478bd9Sstevel@tonic-gate * get and store usba_device pointer in the devi
14167c478bd9Sstevel@tonic-gate */
14177c478bd9Sstevel@tonic-gate usba_device_t *
usba_get_usba_device(dev_info_t * dip)14187c478bd9Sstevel@tonic-gate usba_get_usba_device(dev_info_t *dip)
14197c478bd9Sstevel@tonic-gate {
14207c478bd9Sstevel@tonic-gate /*
14217c478bd9Sstevel@tonic-gate * we cannot use parent_data in the usb node because its
14227c478bd9Sstevel@tonic-gate * bus parent (eg. PCI nexus driver) uses this data
14237c478bd9Sstevel@tonic-gate *
14247c478bd9Sstevel@tonic-gate * we cannot use driver data in the other usb nodes since
14257c478bd9Sstevel@tonic-gate * usb drivers may need to use this
14267c478bd9Sstevel@tonic-gate */
14277c478bd9Sstevel@tonic-gate if (usba_is_root_hub(dip)) {
14287c478bd9Sstevel@tonic-gate usba_hcdi_t *hcdi = usba_hcdi_get_hcdi(dip);
14297c478bd9Sstevel@tonic-gate
14307c478bd9Sstevel@tonic-gate return (hcdi->hcdi_usba_device);
14317c478bd9Sstevel@tonic-gate } else {
14327c478bd9Sstevel@tonic-gate
14337c478bd9Sstevel@tonic-gate return (ddi_get_parent_data(dip));
14347c478bd9Sstevel@tonic-gate }
14357c478bd9Sstevel@tonic-gate }
14367c478bd9Sstevel@tonic-gate
14377c478bd9Sstevel@tonic-gate
14387c478bd9Sstevel@tonic-gate /*
14397c478bd9Sstevel@tonic-gate * Retrieve the usba_device pointer from the dev without checking for
14407c478bd9Sstevel@tonic-gate * the root hub first. This function is only used in polled mode.
14417c478bd9Sstevel@tonic-gate */
14427c478bd9Sstevel@tonic-gate usba_device_t *
usba_polled_get_usba_device(dev_info_t * dip)14437c478bd9Sstevel@tonic-gate usba_polled_get_usba_device(dev_info_t *dip)
14447c478bd9Sstevel@tonic-gate {
14457c478bd9Sstevel@tonic-gate /*
14467c478bd9Sstevel@tonic-gate * Don't call usba_is_root_hub() to find out if this is
14477c478bd9Sstevel@tonic-gate * the root hub usba_is_root_hub() calls into the DDI
14487c478bd9Sstevel@tonic-gate * where there are locking issues. The dip sent in during
14497c478bd9Sstevel@tonic-gate * polled mode will never be the root hub, so just get
14507c478bd9Sstevel@tonic-gate * the usba_device pointer from the dip.
14517c478bd9Sstevel@tonic-gate */
14527c478bd9Sstevel@tonic-gate return (ddi_get_parent_data(dip));
14537c478bd9Sstevel@tonic-gate }
14547c478bd9Sstevel@tonic-gate
14557c478bd9Sstevel@tonic-gate
14567c478bd9Sstevel@tonic-gate void
usba_set_usba_device(dev_info_t * dip,usba_device_t * usba_device)14577c478bd9Sstevel@tonic-gate usba_set_usba_device(dev_info_t *dip, usba_device_t *usba_device)
14587c478bd9Sstevel@tonic-gate {
14597c478bd9Sstevel@tonic-gate if (usba_is_root_hub(dip)) {
14607c478bd9Sstevel@tonic-gate usba_hcdi_t *hcdi = usba_hcdi_get_hcdi(dip);
14617c478bd9Sstevel@tonic-gate /* no locking is needed here */
14627c478bd9Sstevel@tonic-gate _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(hcdi->hcdi_usba_device))
14637c478bd9Sstevel@tonic-gate hcdi->hcdi_usba_device = usba_device;
14647c478bd9Sstevel@tonic-gate _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(hcdi->hcdi_usba_device))
14657c478bd9Sstevel@tonic-gate } else {
14667c478bd9Sstevel@tonic-gate ddi_set_parent_data(dip, usba_device);
14677c478bd9Sstevel@tonic-gate }
14687c478bd9Sstevel@tonic-gate }
14697c478bd9Sstevel@tonic-gate
14707c478bd9Sstevel@tonic-gate
14717c478bd9Sstevel@tonic-gate /*
14727c478bd9Sstevel@tonic-gate * usba_set_node_name() according to class, subclass, and protocol
14737c478bd9Sstevel@tonic-gate * following the 1275 USB binding tables.
14747c478bd9Sstevel@tonic-gate */
14757c478bd9Sstevel@tonic-gate
14767c478bd9Sstevel@tonic-gate /* device node table, refer to section 3.2.2.1 of 1275 binding */
14777c478bd9Sstevel@tonic-gate static node_name_entry_t device_node_name_table[] = {
14787c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, DONTCARE, DONTCARE, "communications" },
14797c478bd9Sstevel@tonic-gate { USB_CLASS_HUB, DONTCARE, DONTCARE, "hub" },
1480d73ae94eSgc161489 { USB_CLASS_DIAG, DONTCARE, DONTCARE, "diagnostics" },
1481d73ae94eSgc161489 { USB_CLASS_MISC, DONTCARE, DONTCARE, "miscellaneous" },
14827c478bd9Sstevel@tonic-gate { DONTCARE, DONTCARE, DONTCARE, "device" }
14837c478bd9Sstevel@tonic-gate };
14847c478bd9Sstevel@tonic-gate
1485d73ae94eSgc161489 /* interface-association node table */
1486d73ae94eSgc161489 static node_name_entry_t ia_node_name_table[] = {
1487d73ae94eSgc161489 { USB_CLASS_AUDIO, DONTCARE, DONTCARE, "audio" },
1488d73ae94eSgc161489 { USB_CLASS_VIDEO, DONTCARE, DONTCARE, "video" },
1489d73ae94eSgc161489 { USB_CLASS_WIRELESS, USB_SUBCLS_WUSB_2, USB_PROTO_WUSB_DWA,
1490d73ae94eSgc161489 "device-wire-adaptor" },
1491d73ae94eSgc161489 { USB_CLASS_WIRELESS, DONTCARE, DONTCARE, "wireless-controller" },
1492d73ae94eSgc161489 { DONTCARE, DONTCARE, DONTCARE, "interface-association" }
1493d73ae94eSgc161489 };
1494d73ae94eSgc161489
14957c478bd9Sstevel@tonic-gate /* interface node table, refer to section 3.3.2.1 */
14967c478bd9Sstevel@tonic-gate static node_name_entry_t if_node_name_table[] = {
14977c478bd9Sstevel@tonic-gate { USB_CLASS_AUDIO, USB_SUBCLS_AUD_CONTROL, DONTCARE, "sound-control" },
14987c478bd9Sstevel@tonic-gate { USB_CLASS_AUDIO, USB_SUBCLS_AUD_STREAMING, DONTCARE, "sound" },
14997c478bd9Sstevel@tonic-gate { USB_CLASS_AUDIO, USB_SUBCLS_AUD_MIDI_STREAMING, DONTCARE, "midi" },
15007c478bd9Sstevel@tonic-gate { USB_CLASS_AUDIO, DONTCARE, DONTCARE, "sound" },
15017c478bd9Sstevel@tonic-gate
15027c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_DIRECT_LINE, DONTCARE, "line" },
15037c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_ABSTRCT_CTRL, DONTCARE, "modem" },
15047c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_PHONE_CTRL, DONTCARE, "telephone" },
15057c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_MULTCNL_ISDN, DONTCARE, "isdn" },
15067c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_ISDN, DONTCARE, "isdn" },
15077c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_ETHERNET, DONTCARE, "ethernet" },
15087c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_ATM_NETWORK, DONTCARE, "atm-network" },
1509d73ae94eSgc161489 { USB_CLASS_COMM, DONTCARE, DONTCARE, "communications" },
15107c478bd9Sstevel@tonic-gate
15117c478bd9Sstevel@tonic-gate { USB_CLASS_HID, USB_SUBCLS_HID_1, USB_PROTO_HID_KEYBOARD, "keyboard" },
15127c478bd9Sstevel@tonic-gate { USB_CLASS_HID, USB_SUBCLS_HID_1, USB_PROTO_HID_MOUSE, "mouse" },
15137c478bd9Sstevel@tonic-gate { USB_CLASS_HID, DONTCARE, DONTCARE, "input" },
15147c478bd9Sstevel@tonic-gate
15157c478bd9Sstevel@tonic-gate { USB_CLASS_HUB, DONTCARE, DONTCARE, "hub" },
15167c478bd9Sstevel@tonic-gate
15177c478bd9Sstevel@tonic-gate { USB_CLASS_PHYSICAL, DONTCARE, DONTCARE, "physical" },
15187c478bd9Sstevel@tonic-gate
1519d73ae94eSgc161489 { USB_CLASS_IMAGE, DONTCARE, DONTCARE, "image" },
1520d73ae94eSgc161489
15217c478bd9Sstevel@tonic-gate { USB_CLASS_PRINTER, DONTCARE, DONTCARE, "printer" },
15227c478bd9Sstevel@tonic-gate
15237c478bd9Sstevel@tonic-gate { USB_CLASS_MASS_STORAGE, DONTCARE, DONTCARE, "storage" },
15247c478bd9Sstevel@tonic-gate
15257c478bd9Sstevel@tonic-gate { USB_CLASS_CDC_DATA, DONTCARE, DONTCARE, "data" },
15267c478bd9Sstevel@tonic-gate
15277c478bd9Sstevel@tonic-gate { USB_CLASS_SECURITY, DONTCARE, DONTCARE, "security" },
15287c478bd9Sstevel@tonic-gate
1529d73ae94eSgc161489 { USB_CLASS_VIDEO, USB_SUBCLS_VIDEO_CONTROL, DONTCARE, "video-control" },
1530d73ae94eSgc161489 { USB_CLASS_VIDEO, USB_SUBCLS_VIDEO_STREAM, DONTCARE, "video-stream" },
1531d73ae94eSgc161489 { USB_CLASS_VIDEO, DONTCARE, DONTCARE, "video" },
1532d73ae94eSgc161489
15337c478bd9Sstevel@tonic-gate { USB_CLASS_APP, USB_SUBCLS_APP_FIRMWARE, DONTCARE, "firmware" },
15347c478bd9Sstevel@tonic-gate { USB_CLASS_APP, USB_SUBCLS_APP_IRDA, DONTCARE, "IrDa" },
15357c478bd9Sstevel@tonic-gate { USB_CLASS_APP, USB_SUBCLS_APP_TEST, DONTCARE, "test" },
15367c478bd9Sstevel@tonic-gate
1537ff0e937bSRaymond Chen { USB_CLASS_MISC, USB_SUBCLS_CBAF, USB_PROTO_CBAF, "wusb_ca"},
1538ff0e937bSRaymond Chen { USB_CLASS_WIRELESS, USB_SUBCLS_WUSB_1, USB_PROTO_WUSB_RC, "hwa-radio" },
1539ff0e937bSRaymond Chen { USB_CLASS_WIRELESS, USB_SUBCLS_WUSB_2, USB_PROTO_WUSB_HWA, "hwa-host" },
1540ff0e937bSRaymond Chen { USB_CLASS_WIRELESS, USB_SUBCLS_WUSB_2, USB_PROTO_WUSB_DWA, "dwa-control" },
1541ff0e937bSRaymond Chen { USB_CLASS_WIRELESS, USB_SUBCLS_WUSB_2, USB_PROTO_WUSB_DWA_ISO, "dwa-isoc" },
1542ff0e937bSRaymond Chen { USB_CLASS_WIRELESS, DONTCARE, DONTCARE, "wireless" },
1543ff0e937bSRaymond Chen
15447c478bd9Sstevel@tonic-gate { DONTCARE, DONTCARE, DONTCARE, "interface" },
15457c478bd9Sstevel@tonic-gate
15467c478bd9Sstevel@tonic-gate };
15477c478bd9Sstevel@tonic-gate
15487c478bd9Sstevel@tonic-gate /* combined node table, refer to section 3.4.2.1 */
15497c478bd9Sstevel@tonic-gate static node_name_entry_t combined_node_name_table[] = {
15507c478bd9Sstevel@tonic-gate { USB_CLASS_AUDIO, USB_SUBCLS_AUD_CONTROL, DONTCARE, "sound-control" },
15517c478bd9Sstevel@tonic-gate { USB_CLASS_AUDIO, USB_SUBCLS_AUD_STREAMING, DONTCARE, "sound" },
15527c478bd9Sstevel@tonic-gate { USB_CLASS_AUDIO, USB_SUBCLS_AUD_MIDI_STREAMING, DONTCARE, "midi" },
15537c478bd9Sstevel@tonic-gate { USB_CLASS_AUDIO, DONTCARE, DONTCARE, "sound" },
15547c478bd9Sstevel@tonic-gate
15557c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_DIRECT_LINE, DONTCARE, "line" },
15567c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_ABSTRCT_CTRL, DONTCARE, "modem" },
15577c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_PHONE_CTRL, DONTCARE, "telephone" },
15587c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_MULTCNL_ISDN, DONTCARE, "isdn" },
15597c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_ISDN, DONTCARE, "isdn" },
15607c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_ETHERNET, DONTCARE, "ethernet" },
15617c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, USB_SUBCLS_CDCC_ATM_NETWORK, DONTCARE, "atm-network" },
1562d73ae94eSgc161489 { USB_CLASS_COMM, DONTCARE, DONTCARE, "communications" },
15637c478bd9Sstevel@tonic-gate
15647c478bd9Sstevel@tonic-gate { USB_CLASS_HID, USB_SUBCLS_HID_1, USB_PROTO_HID_KEYBOARD, "keyboard" },
15657c478bd9Sstevel@tonic-gate { USB_CLASS_HID, USB_SUBCLS_HID_1, USB_PROTO_HID_MOUSE, "mouse" },
15667c478bd9Sstevel@tonic-gate { USB_CLASS_HID, DONTCARE, DONTCARE, "input" },
15677c478bd9Sstevel@tonic-gate
15687c478bd9Sstevel@tonic-gate { USB_CLASS_PHYSICAL, DONTCARE, DONTCARE, "physical" },
15697c478bd9Sstevel@tonic-gate
1570d73ae94eSgc161489 { USB_CLASS_IMAGE, DONTCARE, DONTCARE, "image" },
1571d73ae94eSgc161489
15727c478bd9Sstevel@tonic-gate { USB_CLASS_PRINTER, DONTCARE, DONTCARE, "printer" },
15737c478bd9Sstevel@tonic-gate
1574d73ae94eSgc161489 { USB_CLASS_MASS_STORAGE, USB_SUBCLS_MS_RBC_T10, DONTCARE, "storage" },
1575d73ae94eSgc161489 { USB_CLASS_MASS_STORAGE, USB_SUBCLS_MS_SFF8020I, DONTCARE, "cdrom" },
1576d73ae94eSgc161489 { USB_CLASS_MASS_STORAGE, USB_SUBCLS_MS_QIC_157, DONTCARE, "tape" },
1577d73ae94eSgc161489 { USB_CLASS_MASS_STORAGE, USB_SUBCLS_MS_UFI, DONTCARE, "floppy" },
1578d73ae94eSgc161489 { USB_CLASS_MASS_STORAGE, USB_SUBCLS_MS_SFF8070I, DONTCARE, "storage" },
1579d73ae94eSgc161489 { USB_CLASS_MASS_STORAGE, USB_SUBCLS_MS_SCSI, DONTCARE, "storage" },
15807c478bd9Sstevel@tonic-gate { USB_CLASS_MASS_STORAGE, DONTCARE, DONTCARE, "storage" },
15817c478bd9Sstevel@tonic-gate
15827c478bd9Sstevel@tonic-gate { USB_CLASS_CDC_DATA, DONTCARE, DONTCARE, "data" },
15837c478bd9Sstevel@tonic-gate
15847c478bd9Sstevel@tonic-gate { USB_CLASS_SECURITY, DONTCARE, DONTCARE, "security" },
15857c478bd9Sstevel@tonic-gate
1586d73ae94eSgc161489 { USB_CLASS_VIDEO, USB_SUBCLS_VIDEO_CONTROL, DONTCARE, "video-control" },
1587d73ae94eSgc161489 { USB_CLASS_VIDEO, USB_SUBCLS_VIDEO_STREAM, DONTCARE, "video-stream" },
1588d73ae94eSgc161489 { USB_CLASS_VIDEO, DONTCARE, DONTCARE, "video" },
1589d73ae94eSgc161489
15907c478bd9Sstevel@tonic-gate { USB_CLASS_APP, USB_SUBCLS_APP_FIRMWARE, DONTCARE, "firmware" },
15917c478bd9Sstevel@tonic-gate { USB_CLASS_APP, USB_SUBCLS_APP_IRDA, DONTCARE, "IrDa" },
15927c478bd9Sstevel@tonic-gate { USB_CLASS_APP, USB_SUBCLS_APP_TEST, DONTCARE, "test" },
15937c478bd9Sstevel@tonic-gate
15947c478bd9Sstevel@tonic-gate { USB_CLASS_COMM, DONTCARE, DONTCARE, "communications" },
1595d73ae94eSgc161489 { USB_CLASS_HUB, DONTCARE, DONTCARE, "hub" },
1596d73ae94eSgc161489 { USB_CLASS_DIAG, DONTCARE, DONTCARE, "diagnostics" },
1597d73ae94eSgc161489 { USB_CLASS_MISC, DONTCARE, DONTCARE, "miscellaneous" },
1598d73ae94eSgc161489 { DONTCARE, DONTCARE, DONTCARE, "device" }
15997c478bd9Sstevel@tonic-gate };
16007c478bd9Sstevel@tonic-gate
16017c478bd9Sstevel@tonic-gate static size_t device_node_name_table_size =
16027c478bd9Sstevel@tonic-gate sizeof (device_node_name_table)/sizeof (struct node_name_entry);
1603d73ae94eSgc161489 static size_t ia_node_name_table_size =
1604d73ae94eSgc161489 sizeof (ia_node_name_table)/sizeof (struct node_name_entry);
16057c478bd9Sstevel@tonic-gate static size_t if_node_name_table_size =
16067c478bd9Sstevel@tonic-gate sizeof (if_node_name_table)/sizeof (struct node_name_entry);
16077c478bd9Sstevel@tonic-gate static size_t combined_node_name_table_size =
16087c478bd9Sstevel@tonic-gate sizeof (combined_node_name_table)/sizeof (struct node_name_entry);
16097c478bd9Sstevel@tonic-gate
16107c478bd9Sstevel@tonic-gate
16117c478bd9Sstevel@tonic-gate static void
usba_set_node_name(dev_info_t * dip,uint8_t class,uint8_t subclass,uint8_t protocol,uint_t flag)16127c478bd9Sstevel@tonic-gate usba_set_node_name(dev_info_t *dip, uint8_t class, uint8_t subclass,
16137c478bd9Sstevel@tonic-gate uint8_t protocol, uint_t flag)
16147c478bd9Sstevel@tonic-gate {
16157c478bd9Sstevel@tonic-gate int i;
16167c478bd9Sstevel@tonic-gate size_t size;
16177c478bd9Sstevel@tonic-gate node_name_entry_t *node_name_table;
16187c478bd9Sstevel@tonic-gate
16197c478bd9Sstevel@tonic-gate switch (flag) {
1620d73ae94eSgc161489 /* interface share node names with interface-association */
1621d73ae94eSgc161489 case FLAG_INTERFACE_ASSOCIATION_NODE:
1622d73ae94eSgc161489 node_name_table = ia_node_name_table;
1623d73ae94eSgc161489 size = ia_node_name_table_size;
1624d73ae94eSgc161489 break;
16257c478bd9Sstevel@tonic-gate case FLAG_INTERFACE_NODE:
16267c478bd9Sstevel@tonic-gate node_name_table = if_node_name_table;
16277c478bd9Sstevel@tonic-gate size = if_node_name_table_size;
16287c478bd9Sstevel@tonic-gate break;
16297c478bd9Sstevel@tonic-gate case FLAG_DEVICE_NODE:
16307c478bd9Sstevel@tonic-gate node_name_table = device_node_name_table;
16317c478bd9Sstevel@tonic-gate size = device_node_name_table_size;
16327c478bd9Sstevel@tonic-gate break;
16337c478bd9Sstevel@tonic-gate case FLAG_COMBINED_NODE:
16347c478bd9Sstevel@tonic-gate node_name_table = combined_node_name_table;
16357c478bd9Sstevel@tonic-gate size = combined_node_name_table_size;
16367c478bd9Sstevel@tonic-gate break;
16377c478bd9Sstevel@tonic-gate default:
16387c478bd9Sstevel@tonic-gate
16397c478bd9Sstevel@tonic-gate return;
16407c478bd9Sstevel@tonic-gate }
16417c478bd9Sstevel@tonic-gate
16427c478bd9Sstevel@tonic-gate for (i = 0; i < size; i++) {
16437c478bd9Sstevel@tonic-gate int16_t c = node_name_table[i].class;
16447c478bd9Sstevel@tonic-gate int16_t s = node_name_table[i].subclass;
16457c478bd9Sstevel@tonic-gate int16_t p = node_name_table[i].protocol;
16467c478bd9Sstevel@tonic-gate
16477c478bd9Sstevel@tonic-gate if (((c == DONTCARE) || (c == class)) &&
16487c478bd9Sstevel@tonic-gate ((s == DONTCARE) || (s == subclass)) &&
16497c478bd9Sstevel@tonic-gate ((p == DONTCARE) || (p == protocol))) {
16507c478bd9Sstevel@tonic-gate char *name = node_name_table[i].name;
1651d73ae94eSgc161489
16527c478bd9Sstevel@tonic-gate (void) ndi_devi_set_nodename(dip, name, 0);
16537c478bd9Sstevel@tonic-gate break;
16547c478bd9Sstevel@tonic-gate }
16557c478bd9Sstevel@tonic-gate }
16567c478bd9Sstevel@tonic-gate }
16577c478bd9Sstevel@tonic-gate
16587c478bd9Sstevel@tonic-gate
16597c478bd9Sstevel@tonic-gate #ifdef DEBUG
16607c478bd9Sstevel@tonic-gate /*
16617c478bd9Sstevel@tonic-gate * walk the children of the parent of this devi and compare the
16627c478bd9Sstevel@tonic-gate * name and reg property of each child. If there is a match
16637c478bd9Sstevel@tonic-gate * return this node
16647c478bd9Sstevel@tonic-gate */
16657c478bd9Sstevel@tonic-gate static dev_info_t *
usba_find_existing_node(dev_info_t * odip)16667c478bd9Sstevel@tonic-gate usba_find_existing_node(dev_info_t *odip)
16677c478bd9Sstevel@tonic-gate {
16687c478bd9Sstevel@tonic-gate dev_info_t *ndip, *child, *pdip;
16697c478bd9Sstevel@tonic-gate int *odata, *ndata;
16707c478bd9Sstevel@tonic-gate uint_t n_odata, n_ndata;
16717c478bd9Sstevel@tonic-gate
16727c478bd9Sstevel@tonic-gate pdip = ddi_get_parent(odip);
16737c478bd9Sstevel@tonic-gate if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY,
16747c478bd9Sstevel@tonic-gate odip, DDI_PROP_DONTPASS, "reg",
16757c478bd9Sstevel@tonic-gate &odata, &n_odata) != DDI_SUCCESS) {
1676d291d9f2Sfrits USB_DPRINTF_L2(DPRINT_MASK_HCDI, usba_log_handle,
16777c478bd9Sstevel@tonic-gate "usba_find_existing_node: "
16787c478bd9Sstevel@tonic-gate "%s: DDI_NOT_WELL_FORMED", ddi_driver_name(odip));
16797c478bd9Sstevel@tonic-gate
16807c478bd9Sstevel@tonic-gate return (NULL);
16817c478bd9Sstevel@tonic-gate }
16827c478bd9Sstevel@tonic-gate
16833fe80ca4SDan Cross ndi_devi_enter(pdip);
16847c478bd9Sstevel@tonic-gate ndip = (dev_info_t *)(DEVI(pdip)->devi_child);
16857c478bd9Sstevel@tonic-gate while ((child = ndip) != NULL) {
16867c478bd9Sstevel@tonic-gate
16877c478bd9Sstevel@tonic-gate ndip = (dev_info_t *)(DEVI(child)->devi_sibling);
16887c478bd9Sstevel@tonic-gate
16897c478bd9Sstevel@tonic-gate if (child == odip) {
16907c478bd9Sstevel@tonic-gate continue;
16917c478bd9Sstevel@tonic-gate }
16927c478bd9Sstevel@tonic-gate
16937c478bd9Sstevel@tonic-gate if (strcmp(DEVI(child)->devi_node_name,
16947c478bd9Sstevel@tonic-gate DEVI(odip)->devi_node_name)) {
16957c478bd9Sstevel@tonic-gate continue;
16967c478bd9Sstevel@tonic-gate }
16977c478bd9Sstevel@tonic-gate
16987c478bd9Sstevel@tonic-gate if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY,
16997c478bd9Sstevel@tonic-gate child, DDI_PROP_DONTPASS, "reg",
17007c478bd9Sstevel@tonic-gate &ndata, &n_ndata) != DDI_SUCCESS) {
17017c478bd9Sstevel@tonic-gate
1702d291d9f2Sfrits USB_DPRINTF_L2(DPRINT_MASK_HCDI, usba_log_handle,
17037c478bd9Sstevel@tonic-gate "usba_find_existing_node: "
17047c478bd9Sstevel@tonic-gate "%s DDI_NOT_WELL_FORMED", ddi_driver_name(child));
17057c478bd9Sstevel@tonic-gate
17067c478bd9Sstevel@tonic-gate } else if (n_ndata && n_odata && (bcmp(odata, ndata,
17077c478bd9Sstevel@tonic-gate max(n_odata, n_ndata) * sizeof (int)) == 0)) {
17087c478bd9Sstevel@tonic-gate
17097c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_HCDI, usba_log_handle,
17107c478bd9Sstevel@tonic-gate "usba_find_existing_node: found %s%d (%p)",
17117c478bd9Sstevel@tonic-gate ddi_driver_name(child),
17127c478bd9Sstevel@tonic-gate ddi_get_instance(child), (void *)child);
17137c478bd9Sstevel@tonic-gate
17147c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_HCDI, usba_log_handle,
17157c478bd9Sstevel@tonic-gate "usba_find_existing_node: "
17167c478bd9Sstevel@tonic-gate "reg: %x %x %x - %x %x %x",
17177c478bd9Sstevel@tonic-gate n_odata, odata[0], odata[1],
17187c478bd9Sstevel@tonic-gate n_ndata, ndata[0], ndata[1]);
17197c478bd9Sstevel@tonic-gate
17207c478bd9Sstevel@tonic-gate ddi_prop_free(ndata);
17217c478bd9Sstevel@tonic-gate break;
17227c478bd9Sstevel@tonic-gate
17237c478bd9Sstevel@tonic-gate } else {
17247c478bd9Sstevel@tonic-gate ddi_prop_free(ndata);
17257c478bd9Sstevel@tonic-gate }
17267c478bd9Sstevel@tonic-gate }
17277c478bd9Sstevel@tonic-gate
17283fe80ca4SDan Cross ndi_devi_exit(pdip);
17297c478bd9Sstevel@tonic-gate
17307c478bd9Sstevel@tonic-gate ddi_prop_free(odata);
17317c478bd9Sstevel@tonic-gate
17327c478bd9Sstevel@tonic-gate return (child);
17337c478bd9Sstevel@tonic-gate }
17347c478bd9Sstevel@tonic-gate #endif
17357c478bd9Sstevel@tonic-gate
17367c478bd9Sstevel@tonic-gate /* change all unprintable characters to spaces */
17377c478bd9Sstevel@tonic-gate static void
usba_filter_string(char * instr,char * outstr)17387c478bd9Sstevel@tonic-gate usba_filter_string(char *instr, char *outstr)
17397c478bd9Sstevel@tonic-gate {
17407c478bd9Sstevel@tonic-gate while (*instr) {
17417c478bd9Sstevel@tonic-gate if ((*instr >= ' ') && (*instr <= '~')) {
17427c478bd9Sstevel@tonic-gate *outstr = *instr;
17437c478bd9Sstevel@tonic-gate } else {
17447c478bd9Sstevel@tonic-gate *outstr = ' ';
17457c478bd9Sstevel@tonic-gate }
17467c478bd9Sstevel@tonic-gate outstr++;
17477c478bd9Sstevel@tonic-gate instr++;
17487c478bd9Sstevel@tonic-gate }
17497c478bd9Sstevel@tonic-gate *outstr = '\0';
17507c478bd9Sstevel@tonic-gate }
17517c478bd9Sstevel@tonic-gate
17527c478bd9Sstevel@tonic-gate
17537c478bd9Sstevel@tonic-gate /*
17547c478bd9Sstevel@tonic-gate * lookup ugen binding specified in property in
17557c478bd9Sstevel@tonic-gate * hcd.conf files
17567c478bd9Sstevel@tonic-gate */
17577c478bd9Sstevel@tonic-gate int
usba_get_ugen_binding(dev_info_t * dip)17587c478bd9Sstevel@tonic-gate usba_get_ugen_binding(dev_info_t *dip)
17597c478bd9Sstevel@tonic-gate {
17607c478bd9Sstevel@tonic-gate usba_device_t *usba_device = usba_get_usba_device(dip);
17617c478bd9Sstevel@tonic-gate usba_hcdi_t *hcdi =
17627c478bd9Sstevel@tonic-gate usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
17637c478bd9Sstevel@tonic-gate
17647c478bd9Sstevel@tonic-gate return (hcdi->hcdi_ugen_default_binding);
17657c478bd9Sstevel@tonic-gate }
17667c478bd9Sstevel@tonic-gate
17677c478bd9Sstevel@tonic-gate
17687c478bd9Sstevel@tonic-gate /*
17697c478bd9Sstevel@tonic-gate * driver binding support at device level
17707c478bd9Sstevel@tonic-gate */
17717c478bd9Sstevel@tonic-gate dev_info_t *
usba_ready_device_node(dev_info_t * child_dip)17727c478bd9Sstevel@tonic-gate usba_ready_device_node(dev_info_t *child_dip)
17737c478bd9Sstevel@tonic-gate {
17747c478bd9Sstevel@tonic-gate int rval, i;
17757c478bd9Sstevel@tonic-gate int n = 0;
17767c478bd9Sstevel@tonic-gate usba_device_t *usba_device = usba_get_usba_device(child_dip);
17777c478bd9Sstevel@tonic-gate usb_dev_descr_t *usb_dev_descr;
17787c478bd9Sstevel@tonic-gate uint_t n_cfgs; /* number of configs */
17797c478bd9Sstevel@tonic-gate uint_t n_ifs; /* number of interfaces */
1780a7df97baSStrony Zhang - Solaris China Team uint_t port, bus_num;
17817c478bd9Sstevel@tonic-gate size_t usb_config_length;
17827c478bd9Sstevel@tonic-gate uchar_t *usb_config;
17837c478bd9Sstevel@tonic-gate int reg[1];
17847c478bd9Sstevel@tonic-gate usb_addr_t address = usb_get_addr(child_dip);
17857c478bd9Sstevel@tonic-gate usb_if_descr_t if_descr;
17867c478bd9Sstevel@tonic-gate size_t size;
17877c478bd9Sstevel@tonic-gate int combined_node = 0;
17887c478bd9Sstevel@tonic-gate int is_hub;
17897c478bd9Sstevel@tonic-gate char *devprop_str;
17907c478bd9Sstevel@tonic-gate char *force_bind = NULL;
17913c91d182Slg150142 char *usba_name_buf = NULL;
17923c91d182Slg150142 char *usba_name[USBA_MAX_COMPAT_NAMES];
17937c478bd9Sstevel@tonic-gate
17947c478bd9Sstevel@tonic-gate usb_config = usb_get_raw_cfg_data(child_dip, &usb_config_length);
17957c478bd9Sstevel@tonic-gate
17967c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex);
17977c478bd9Sstevel@tonic-gate mutex_enter(&usba_mutex);
17987c478bd9Sstevel@tonic-gate
17997c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
18007c478bd9Sstevel@tonic-gate "usba_ready_device_node: child=0x%p", (void *)child_dip);
18017c478bd9Sstevel@tonic-gate
18027c478bd9Sstevel@tonic-gate port = usba_device->usb_port;
18037c478bd9Sstevel@tonic-gate usb_dev_descr = usba_device->usb_dev_descr;
18047c478bd9Sstevel@tonic-gate n_cfgs = usba_device->usb_n_cfgs;
18057c478bd9Sstevel@tonic-gate n_ifs = usba_device->usb_n_ifs;
1806a7df97baSStrony Zhang - Solaris China Team bus_num = usba_device->usb_addr;
18077c478bd9Sstevel@tonic-gate
18087c478bd9Sstevel@tonic-gate if (address != ROOT_HUB_ADDR) {
18097c478bd9Sstevel@tonic-gate size = usb_parse_if_descr(
18107c478bd9Sstevel@tonic-gate usb_config,
18117c478bd9Sstevel@tonic-gate usb_config_length,
18127c478bd9Sstevel@tonic-gate 0, /* interface index */
18137c478bd9Sstevel@tonic-gate 0, /* alt interface index */
18147c478bd9Sstevel@tonic-gate &if_descr,
18157c478bd9Sstevel@tonic-gate USB_IF_DESCR_SIZE);
18167c478bd9Sstevel@tonic-gate
18177c478bd9Sstevel@tonic-gate if (size != USB_IF_DESCR_SIZE) {
1818d291d9f2Sfrits USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
18197c478bd9Sstevel@tonic-gate "parsing interface: "
18207c478bd9Sstevel@tonic-gate "size (%lu) != USB_IF_DESCR_SIZE (%d)",
18217c478bd9Sstevel@tonic-gate size, USB_IF_DESCR_SIZE);
18227c478bd9Sstevel@tonic-gate
18237c478bd9Sstevel@tonic-gate mutex_exit(&usba_mutex);
18247c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex);
18257c478bd9Sstevel@tonic-gate
18267c478bd9Sstevel@tonic-gate return (child_dip);
18277c478bd9Sstevel@tonic-gate }
18287c478bd9Sstevel@tonic-gate } else {
18297c478bd9Sstevel@tonic-gate /* fake an interface descriptor for the root hub */
18307c478bd9Sstevel@tonic-gate bzero(&if_descr, sizeof (if_descr));
18317c478bd9Sstevel@tonic-gate
18327c478bd9Sstevel@tonic-gate if_descr.bInterfaceClass = USB_CLASS_HUB;
18337c478bd9Sstevel@tonic-gate }
18347c478bd9Sstevel@tonic-gate
18357c478bd9Sstevel@tonic-gate reg[0] = port;
18367c478bd9Sstevel@tonic-gate
18377c478bd9Sstevel@tonic-gate mutex_exit(&usba_mutex);
18387c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex);
18397c478bd9Sstevel@tonic-gate
18407c478bd9Sstevel@tonic-gate rval = ndi_prop_update_int_array(
18417c478bd9Sstevel@tonic-gate DDI_DEV_T_NONE, child_dip, "reg", reg, 1);
18427c478bd9Sstevel@tonic-gate
18437c478bd9Sstevel@tonic-gate if (rval != DDI_PROP_SUCCESS) {
1844d291d9f2Sfrits USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
18457c478bd9Sstevel@tonic-gate "usba_ready_device_node: property update failed");
18467c478bd9Sstevel@tonic-gate
18477c478bd9Sstevel@tonic-gate return (child_dip);
18487c478bd9Sstevel@tonic-gate }
18497c478bd9Sstevel@tonic-gate
18507c478bd9Sstevel@tonic-gate combined_node = ((n_cfgs == 1) && (n_ifs == 1) &&
18517c478bd9Sstevel@tonic-gate ((usb_dev_descr->bDeviceClass == USB_CLASS_HUB) ||
18527c478bd9Sstevel@tonic-gate (usb_dev_descr->bDeviceClass == 0)));
18537c478bd9Sstevel@tonic-gate
18547c478bd9Sstevel@tonic-gate is_hub = (if_descr.bInterfaceClass == USB_CLASS_HUB) ||
18557c478bd9Sstevel@tonic-gate (usb_dev_descr->bDeviceClass == USB_CLASS_HUB);
18567c478bd9Sstevel@tonic-gate
18577c478bd9Sstevel@tonic-gate /* set node name */
18587c478bd9Sstevel@tonic-gate if (combined_node) {
18597c478bd9Sstevel@tonic-gate usba_set_node_name(child_dip,
18607c478bd9Sstevel@tonic-gate if_descr.bInterfaceClass,
18617c478bd9Sstevel@tonic-gate if_descr.bInterfaceSubClass,
18627c478bd9Sstevel@tonic-gate if_descr.bInterfaceProtocol,
18637c478bd9Sstevel@tonic-gate FLAG_COMBINED_NODE);
18647c478bd9Sstevel@tonic-gate } else {
18657c478bd9Sstevel@tonic-gate usba_set_node_name(child_dip,
18667c478bd9Sstevel@tonic-gate usb_dev_descr->bDeviceClass,
18677c478bd9Sstevel@tonic-gate usb_dev_descr->bDeviceSubClass,
18687c478bd9Sstevel@tonic-gate usb_dev_descr->bDeviceProtocol,
18697c478bd9Sstevel@tonic-gate FLAG_DEVICE_NODE);
18707c478bd9Sstevel@tonic-gate }
18717c478bd9Sstevel@tonic-gate
18727c478bd9Sstevel@tonic-gate /*
18737c478bd9Sstevel@tonic-gate * check force binding rules
18747c478bd9Sstevel@tonic-gate */
18757c478bd9Sstevel@tonic-gate if ((address != ROOT_HUB_ADDR) && usba_ddivs_usbc &&
18767c478bd9Sstevel@tonic-gate (address != usba_ddivs_usbc_xaddress) &&
18777c478bd9Sstevel@tonic-gate (!(usba_ddivs_usbc_xhubs && is_hub))) {
18787c478bd9Sstevel@tonic-gate force_bind = "ddivs_usbc";
18797c478bd9Sstevel@tonic-gate (void) ndi_devi_set_nodename(child_dip, "ddivs_usbc", 0);
18807c478bd9Sstevel@tonic-gate
18817c478bd9Sstevel@tonic-gate } else if (usba_device->usb_preferred_driver) {
18827c478bd9Sstevel@tonic-gate force_bind = usba_device->usb_preferred_driver;
18837c478bd9Sstevel@tonic-gate
18847c478bd9Sstevel@tonic-gate } else if ((address != ROOT_HUB_ADDR) &&
18857c478bd9Sstevel@tonic-gate ((usba_ugen_force_binding == USBA_UGEN_DEVICE_BINDING) ||
18867c478bd9Sstevel@tonic-gate ((usba_ugen_force_binding == USBA_UGEN_INTERFACE_BINDING) &&
18877c478bd9Sstevel@tonic-gate combined_node)) && (!is_hub)) {
18887c478bd9Sstevel@tonic-gate force_bind = "ugen";
18897c478bd9Sstevel@tonic-gate }
18907c478bd9Sstevel@tonic-gate
18917c478bd9Sstevel@tonic-gate #ifdef DEBUG
18927c478bd9Sstevel@tonic-gate /*
18937c478bd9Sstevel@tonic-gate * check whether there is another dip with this name and address
18947c478bd9Sstevel@tonic-gate * If the dip contains usba_device, it is held by the previous
18957c478bd9Sstevel@tonic-gate * round of configuration.
18967c478bd9Sstevel@tonic-gate */
18977c478bd9Sstevel@tonic-gate ASSERT(usba_find_existing_node(child_dip) == NULL);
18987c478bd9Sstevel@tonic-gate #endif
18993c91d182Slg150142
19003c91d182Slg150142 usba_name_buf = kmem_zalloc(USBA_MAX_COMPAT_NAMES *
19013c91d182Slg150142 USBA_MAX_COMPAT_NAME_LEN, KM_SLEEP);
19023c91d182Slg150142
19033c91d182Slg150142 for (i = 0; i < USBA_MAX_COMPAT_NAMES; i++) {
19043c91d182Slg150142 usba_name[i] = usba_name_buf + (i * USBA_MAX_COMPAT_NAME_LEN);
19053c91d182Slg150142 }
19067c478bd9Sstevel@tonic-gate
19077c478bd9Sstevel@tonic-gate if (force_bind) {
19087c478bd9Sstevel@tonic-gate (void) ndi_devi_set_nodename(child_dip, force_bind, 0);
19097c478bd9Sstevel@tonic-gate (void) strncpy(usba_name[n++], force_bind,
19107c478bd9Sstevel@tonic-gate USBA_MAX_COMPAT_NAME_LEN);
19117c478bd9Sstevel@tonic-gate }
19127c478bd9Sstevel@tonic-gate
1913a7df97baSStrony Zhang - Solaris China Team /*
1914a7df97baSStrony Zhang - Solaris China Team * If the callback function of specified driver is registered,
1915a7df97baSStrony Zhang - Solaris China Team * it will be called here to check whether to take over the device.
1916a7df97baSStrony Zhang - Solaris China Team */
1917a7df97baSStrony Zhang - Solaris China Team if (usb_cap.usba_dev_driver_cb != NULL) {
1918a7df97baSStrony Zhang - Solaris China Team char *dev_drv = NULL;
1919a7df97baSStrony Zhang - Solaris China Team usb_dev_str_t dev_str;
1920a7df97baSStrony Zhang - Solaris China Team char *pathname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1921a7df97baSStrony Zhang - Solaris China Team
1922a7df97baSStrony Zhang - Solaris China Team dev_str.usb_mfg = usba_device->usb_mfg_str;
1923a7df97baSStrony Zhang - Solaris China Team dev_str.usb_product = usba_device->usb_product_str;
1924a7df97baSStrony Zhang - Solaris China Team dev_str.usb_serialno = usba_device->usb_serialno_str;
1925a7df97baSStrony Zhang - Solaris China Team
1926a7df97baSStrony Zhang - Solaris China Team (void) ddi_pathname(child_dip, pathname);
1927a7df97baSStrony Zhang - Solaris China Team
1928a7df97baSStrony Zhang - Solaris China Team if ((usb_cap.usba_dev_driver_cb(usb_dev_descr, &dev_str,
1929a7df97baSStrony Zhang - Solaris China Team pathname, bus_num, port, &dev_drv, NULL) == USB_SUCCESS) &&
1930a7df97baSStrony Zhang - Solaris China Team (dev_drv != NULL)) {
1931a7df97baSStrony Zhang - Solaris China Team USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
1932a7df97baSStrony Zhang - Solaris China Team "usba_ready_device_node: dev_driver=%s, port =%d,"
1933a7df97baSStrony Zhang - Solaris China Team "bus =%d, path=%s\n\t",
1934a7df97baSStrony Zhang - Solaris China Team dev_drv, port, bus_num, pathname);
1935a7df97baSStrony Zhang - Solaris China Team
1936a7df97baSStrony Zhang - Solaris China Team (void) strncpy(usba_name[n++], dev_drv,
1937a7df97baSStrony Zhang - Solaris China Team USBA_MAX_COMPAT_NAME_LEN);
1938a7df97baSStrony Zhang - Solaris China Team }
1939a7df97baSStrony Zhang - Solaris China Team kmem_free(pathname, MAXPATHLEN);
1940a7df97baSStrony Zhang - Solaris China Team }
1941a7df97baSStrony Zhang - Solaris China Team
19427c478bd9Sstevel@tonic-gate /* create compatible names */
19437c478bd9Sstevel@tonic-gate if (combined_node) {
19447c478bd9Sstevel@tonic-gate
19457c478bd9Sstevel@tonic-gate /* 1. usbVID,PID.REV */
19467c478bd9Sstevel@tonic-gate (void) sprintf(usba_name[n++],
19477c478bd9Sstevel@tonic-gate "usb%x,%x.%x",
19487c478bd9Sstevel@tonic-gate usb_dev_descr->idVendor,
19497c478bd9Sstevel@tonic-gate usb_dev_descr->idProduct,
19507c478bd9Sstevel@tonic-gate usb_dev_descr->bcdDevice);
19517c478bd9Sstevel@tonic-gate
19527c478bd9Sstevel@tonic-gate /* 2. usbVID,PID */
19537c478bd9Sstevel@tonic-gate (void) sprintf(usba_name[n++],
19547c478bd9Sstevel@tonic-gate "usb%x,%x",
19557c478bd9Sstevel@tonic-gate usb_dev_descr->idVendor,
19567c478bd9Sstevel@tonic-gate usb_dev_descr->idProduct);
19577c478bd9Sstevel@tonic-gate
19587c478bd9Sstevel@tonic-gate if (usb_dev_descr->bDeviceClass != 0) {
19597c478bd9Sstevel@tonic-gate /* 3. usbVID,classDC.DSC.DPROTO */
19607c478bd9Sstevel@tonic-gate (void) sprintf(usba_name[n++],
19617c478bd9Sstevel@tonic-gate "usb%x,class%x.%x.%x",
19627c478bd9Sstevel@tonic-gate usb_dev_descr->idVendor,
19637c478bd9Sstevel@tonic-gate usb_dev_descr->bDeviceClass,
19647c478bd9Sstevel@tonic-gate usb_dev_descr->bDeviceSubClass,
19657c478bd9Sstevel@tonic-gate usb_dev_descr->bDeviceProtocol);
19667c478bd9Sstevel@tonic-gate
19677c478bd9Sstevel@tonic-gate /* 4. usbVID,classDC.DSC */
19687c478bd9Sstevel@tonic-gate (void) sprintf(usba_name[n++],
19697c478bd9Sstevel@tonic-gate "usb%x,class%x.%x",
19707c478bd9Sstevel@tonic-gate usb_dev_descr->idVendor,
19717c478bd9Sstevel@tonic-gate usb_dev_descr->bDeviceClass,
19727c478bd9Sstevel@tonic-gate usb_dev_descr->bDeviceSubClass);
19737c478bd9Sstevel@tonic-gate
19747c478bd9Sstevel@tonic-gate /* 5. usbVID,classDC */
19757c478bd9Sstevel@tonic-gate (void) sprintf(usba_name[n++],
19767c478bd9Sstevel@tonic-gate "usb%x,class%x",
19777c478bd9Sstevel@tonic-gate usb_dev_descr->idVendor,
19787c478bd9Sstevel@tonic-gate usb_dev_descr->bDeviceClass);
19797c478bd9Sstevel@tonic-gate
19807c478bd9Sstevel@tonic-gate /* 6. usb,classDC.DSC.DPROTO */
19817c478bd9Sstevel@tonic-gate (void) sprintf(usba_name[n++],
19827c478bd9Sstevel@tonic-gate "usb,class%x.%x.%x",
19837c478bd9Sstevel@tonic-gate usb_dev_descr->bDeviceClass,
19847c478bd9Sstevel@tonic-gate usb_dev_descr->bDeviceSubClass,
19857c478bd9Sstevel@tonic-gate usb_dev_descr->bDeviceProtocol);
19867c478bd9Sstevel@tonic-gate
19877c478bd9Sstevel@tonic-gate /* 7. usb,classDC.DSC */
19887c478bd9Sstevel@tonic-gate (void) sprintf(usba_name[n++],
19897c478bd9Sstevel@tonic-gate "usb,class%x.%x",
19907c478bd9Sstevel@tonic-gate usb_dev_descr->bDeviceClass,
19917c478bd9Sstevel@tonic-gate usb_dev_descr->bDeviceSubClass);
19927c478bd9Sstevel@tonic-gate
19937c478bd9Sstevel@tonic-gate /* 8. usb,classDC */
19947c478bd9Sstevel@tonic-gate (void) sprintf(usba_name[n++],
19957c478bd9Sstevel@tonic-gate "usb,class%x",
19967c478bd9Sstevel@tonic-gate usb_dev_descr->bDeviceClass);
19977c478bd9Sstevel@tonic-gate }
19987c478bd9Sstevel@tonic-gate
19997c478bd9Sstevel@tonic-gate if (if_descr.bInterfaceClass != 0) {
20007c478bd9Sstevel@tonic-gate /* 9. usbifVID,classIC.ISC.IPROTO */
20017c478bd9Sstevel@tonic-gate (void) sprintf(usba_name[n++],
20027c478bd9Sstevel@tonic-gate "usbif%x,class%x.%x.%x",
20037c478bd9Sstevel@tonic-gate usb_dev_descr->idVendor,
20047c478bd9Sstevel@tonic-gate if_descr.bInterfaceClass,
20057c478bd9Sstevel@tonic-gate if_descr.bInterfaceSubClass,
20067c478bd9Sstevel@tonic-gate if_descr.bInterfaceProtocol);
20077c478bd9Sstevel@tonic-gate
20087c478bd9Sstevel@tonic-gate /* 10. usbifVID,classIC.ISC */
20097c478bd9Sstevel@tonic-gate (void) sprintf(usba_name[n++],
20107c478bd9Sstevel@tonic-gate "usbif%x,class%x.%x",
20117c478bd9Sstevel@tonic-gate usb_dev_descr->idVendor,
20127c478bd9Sstevel@tonic-gate if_descr.bInterfaceClass,
20137c478bd9Sstevel@tonic-gate if_descr.bInterfaceSubClass);
20147c478bd9Sstevel@tonic-gate
20157c478bd9Sstevel@tonic-gate /* 11. usbifVID,classIC */
20167c478bd9Sstevel@tonic-gate (void) sprintf(usba_name[n++],
20177c478bd9Sstevel@tonic-gate "usbif%x,class%x",
20187c478bd9Sstevel@tonic-gate usb_dev_descr->idVendor,
20197c478bd9Sstevel@tonic-gate if_descr.bInterfaceClass);
20207c478bd9Sstevel@tonic-gate
20217c478bd9Sstevel@tonic-gate /* 12. usbif,classIC.ISC.IPROTO */
20227c478bd9Sstevel@tonic-gate (void) sprintf(usba_name[n++],
20237c478bd9Sstevel@tonic-gate "usbif,class%x.%x.%x",
20247c478bd9Sstevel@tonic-gate if_descr.bInterfaceClass,
20257c478bd9Sstevel@tonic-gate if_descr.bInterfaceSubClass,
20267c478bd9Sstevel@tonic-gate if_descr.bInterfaceProtocol);
20277c478bd9Sstevel@tonic-gate
20287c478bd9Sstevel@tonic-gate /* 13. usbif,classIC.ISC */
20297c478bd9Sstevel@tonic-gate (void) sprintf(usba_name[n++],
20307c478bd9Sstevel@tonic-gate "usbif,class%x.%x",
20317c478bd9Sstevel@tonic-gate if_descr.bInterfaceClass,
20327c478bd9Sstevel@tonic-gate if_descr.bInterfaceSubClass);
20337c478bd9Sstevel@tonic-gate
20347c478bd9Sstevel@tonic-gate /* 14. usbif,classIC */
20357c478bd9Sstevel@tonic-gate (void) sprintf(usba_name[n++],
20367c478bd9Sstevel@tonic-gate "usbif,class%x",
20377c478bd9Sstevel@tonic-gate if_descr.bInterfaceClass);
20387c478bd9Sstevel@tonic-gate }
20397c478bd9Sstevel@tonic-gate
20407c478bd9Sstevel@tonic-gate /* 15. ugen or usb_mid */
20417c478bd9Sstevel@tonic-gate if (usba_get_ugen_binding(child_dip) ==
20427c478bd9Sstevel@tonic-gate USBA_UGEN_DEVICE_BINDING) {
20437c478bd9Sstevel@tonic-gate (void) sprintf(usba_name[n++], "ugen");
20447c478bd9Sstevel@tonic-gate } else {
20457c478bd9Sstevel@tonic-gate (void) sprintf(usba_name[n++], "usb,device");
20467c478bd9Sstevel@tonic-gate }
20477c478bd9Sstevel@tonic-gate
20487c478bd9Sstevel@tonic-gate } else {
20497c478bd9Sstevel@tonic-gate if (n_cfgs > 1) {
20507c478bd9Sstevel@tonic-gate /* 1. usbVID,PID.REV.configCN */
20517c478bd9Sstevel@tonic-gate (void) sprintf(usba_name[n++],
20527c478bd9Sstevel@tonic-gate "usb%x,%x.%x.config%x",
20537c478bd9Sstevel@tonic-gate usb_dev_descr->idVendor,
20547c478bd9Sstevel@tonic-gate usb_dev_descr->idProduct,
20557c478bd9Sstevel@tonic-gate usb_dev_descr->bcdDevice,
20567c478bd9Sstevel@tonic-gate usba_device->usb_cfg_value);
20577c478bd9Sstevel@tonic-gate }
20587c478bd9Sstevel@tonic-gate
20597c478bd9Sstevel@tonic-gate /* 2. usbVID,PID.REV */
20607c478bd9Sstevel@tonic-gate (void) sprintf(usba_name[n++],
20617c478bd9Sstevel@tonic-gate "usb%x,%x.%x",
20627c478bd9Sstevel@tonic-gate usb_dev_descr->idVendor,
20637c478bd9Sstevel@tonic-gate usb_dev_descr->idProduct,
20647c478bd9Sstevel@tonic-gate usb_dev_descr->bcdDevice);
20657c478bd9Sstevel@tonic-gate
20667c478bd9Sstevel@tonic-gate /* 3. usbVID,PID.configCN */
20677c478bd9Sstevel@tonic-gate if (n_cfgs > 1) {
20687c478bd9Sstevel@tonic-gate (void) sprintf(usba_name[n++],
20697c478bd9Sstevel@tonic-gate "usb%x,%x.%x",
20707c478bd9Sstevel@tonic-gate usb_dev_descr->idVendor,
20717c478bd9Sstevel@tonic-gate usb_dev_descr->idProduct,
20727c478bd9Sstevel@tonic-gate usba_device->usb_cfg_value);
20737c478bd9Sstevel@tonic-gate }
20747c478bd9Sstevel@tonic-gate
20757c478bd9Sstevel@tonic-gate /* 4. usbVID,PID */
20767c478bd9Sstevel@tonic-gate (void) sprintf(usba_name[n++],
20777c478bd9Sstevel@tonic-gate "usb%x,%x",
20787c478bd9Sstevel@tonic-gate usb_dev_descr->idVendor,
20797c478bd9Sstevel@tonic-gate usb_dev_descr->idProduct);
20807c478bd9Sstevel@tonic-gate
20817c478bd9Sstevel@tonic-gate if (usb_dev_descr->bDeviceClass != 0) {
20827c478bd9Sstevel@tonic-gate /* 5. usbVID,classDC.DSC.DPROTO */
20837c478bd9Sstevel@tonic-gate (void) sprintf(usba_name[n++],
20847c478bd9Sstevel@tonic-gate "usb%x,class%x.%x.%x",
20857c478bd9Sstevel@tonic-gate usb_dev_descr->idVendor,
20867c478bd9Sstevel@tonic-gate usb_dev_descr->bDeviceClass,
20877c478bd9Sstevel@tonic-gate usb_dev_descr->bDeviceSubClass,
20887c478bd9Sstevel@tonic-gate usb_dev_descr->bDeviceProtocol);
20897c478bd9Sstevel@tonic-gate
20907c478bd9Sstevel@tonic-gate /* 6. usbVID,classDC.DSC */
20917c478bd9Sstevel@tonic-gate (void) sprintf(usba_name[n++],
20927c478bd9Sstevel@tonic-gate "usb%x.class%x.%x",
20937c478bd9Sstevel@tonic-gate usb_dev_descr->idVendor,
20947c478bd9Sstevel@tonic-gate usb_dev_descr->bDeviceClass,
20957c478bd9Sstevel@tonic-gate usb_dev_descr->bDeviceSubClass);
20967c478bd9Sstevel@tonic-gate
20977c478bd9Sstevel@tonic-gate /* 7. usbVID,classDC */
20987c478bd9Sstevel@tonic-gate (void) sprintf(usba_name[n++],
20997c478bd9Sstevel@tonic-gate "usb%x.class%x",
21007c478bd9Sstevel@tonic-gate usb_dev_descr->idVendor,
21017c478bd9Sstevel@tonic-gate usb_dev_descr->bDeviceClass);
21027c478bd9Sstevel@tonic-gate
21037c478bd9Sstevel@tonic-gate /* 8. usb,classDC.DSC.DPROTO */
21047c478bd9Sstevel@tonic-gate (void) sprintf(usba_name[n++],
21057c478bd9Sstevel@tonic-gate "usb,class%x.%x.%x",
21067c478bd9Sstevel@tonic-gate usb_dev_descr->bDeviceClass,
21077c478bd9Sstevel@tonic-gate usb_dev_descr->bDeviceSubClass,
21087c478bd9Sstevel@tonic-gate usb_dev_descr->bDeviceProtocol);
21097c478bd9Sstevel@tonic-gate
21107c478bd9Sstevel@tonic-gate /* 9. usb,classDC.DSC */
21117c478bd9Sstevel@tonic-gate (void) sprintf(usba_name[n++],
21127c478bd9Sstevel@tonic-gate "usb,class%x.%x",
21137c478bd9Sstevel@tonic-gate usb_dev_descr->bDeviceClass,
21147c478bd9Sstevel@tonic-gate usb_dev_descr->bDeviceSubClass);
21157c478bd9Sstevel@tonic-gate
21167c478bd9Sstevel@tonic-gate /* 10. usb,classDC */
21177c478bd9Sstevel@tonic-gate (void) sprintf(usba_name[n++],
21187c478bd9Sstevel@tonic-gate "usb,class%x",
21197c478bd9Sstevel@tonic-gate usb_dev_descr->bDeviceClass);
21207c478bd9Sstevel@tonic-gate }
21217c478bd9Sstevel@tonic-gate
21227c478bd9Sstevel@tonic-gate if (usba_get_ugen_binding(child_dip) ==
21237c478bd9Sstevel@tonic-gate USBA_UGEN_DEVICE_BINDING) {
21247c478bd9Sstevel@tonic-gate /* 11. ugen */
21257c478bd9Sstevel@tonic-gate (void) sprintf(usba_name[n++], "ugen");
21267c478bd9Sstevel@tonic-gate } else {
21277c478bd9Sstevel@tonic-gate /* 11. usb,device */
21287c478bd9Sstevel@tonic-gate (void) sprintf(usba_name[n++], "usb,device");
21297c478bd9Sstevel@tonic-gate }
21307c478bd9Sstevel@tonic-gate }
21317c478bd9Sstevel@tonic-gate
21327c478bd9Sstevel@tonic-gate for (i = 0; i < n; i += 2) {
21337c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
21343c91d182Slg150142 "compatible name:\t%s\t%s", usba_name[i],
21353c91d182Slg150142 (((i+1) < n)? usba_name[i+1] : ""));
21367c478bd9Sstevel@tonic-gate }
21377c478bd9Sstevel@tonic-gate
21383c91d182Slg150142 rval = ndi_prop_update_string_array(DDI_DEV_T_NONE, child_dip,
21393c91d182Slg150142 "compatible", (char **)usba_name, n);
21403c91d182Slg150142
21413c91d182Slg150142 kmem_free(usba_name_buf, USBA_MAX_COMPAT_NAMES *
21423c91d182Slg150142 USBA_MAX_COMPAT_NAME_LEN);
21437c478bd9Sstevel@tonic-gate
21447c478bd9Sstevel@tonic-gate if (rval != DDI_PROP_SUCCESS) {
21457c478bd9Sstevel@tonic-gate
2146d291d9f2Sfrits USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
21477c478bd9Sstevel@tonic-gate "usba_ready_device_node: property update failed");
21487c478bd9Sstevel@tonic-gate
21497c478bd9Sstevel@tonic-gate return (child_dip);
21507c478bd9Sstevel@tonic-gate }
21517c478bd9Sstevel@tonic-gate
21527c478bd9Sstevel@tonic-gate /* update the address property */
21537c478bd9Sstevel@tonic-gate rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
21547c478bd9Sstevel@tonic-gate "assigned-address", usba_device->usb_addr);
21557c478bd9Sstevel@tonic-gate if (rval != DDI_PROP_SUCCESS) {
2156d291d9f2Sfrits USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
21577c478bd9Sstevel@tonic-gate "usba_ready_device_node: address update failed");
21587c478bd9Sstevel@tonic-gate }
21597c478bd9Sstevel@tonic-gate
21607c478bd9Sstevel@tonic-gate /* update the usb device properties (PSARC/2000/454) */
21617c478bd9Sstevel@tonic-gate rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
21627c478bd9Sstevel@tonic-gate "usb-vendor-id", usb_dev_descr->idVendor);
21637c478bd9Sstevel@tonic-gate if (rval != DDI_PROP_SUCCESS) {
2164d291d9f2Sfrits USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
21657c478bd9Sstevel@tonic-gate "usba_ready_device_node: usb-vendor-id update failed");
21667c478bd9Sstevel@tonic-gate }
21677c478bd9Sstevel@tonic-gate
21687c478bd9Sstevel@tonic-gate rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
21697c478bd9Sstevel@tonic-gate "usb-product-id", usb_dev_descr->idProduct);
21707c478bd9Sstevel@tonic-gate if (rval != DDI_PROP_SUCCESS) {
2171d291d9f2Sfrits USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
21727c478bd9Sstevel@tonic-gate "usba_ready_device_node: usb-product-id update failed");
21737c478bd9Sstevel@tonic-gate }
21747c478bd9Sstevel@tonic-gate
21757c478bd9Sstevel@tonic-gate rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
21767c478bd9Sstevel@tonic-gate "usb-revision-id", usb_dev_descr->bcdDevice);
21777c478bd9Sstevel@tonic-gate if (rval != DDI_PROP_SUCCESS) {
2178d291d9f2Sfrits USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
21797c478bd9Sstevel@tonic-gate "usba_ready_device_node: usb-revision-id update failed");
21807c478bd9Sstevel@tonic-gate }
21817c478bd9Sstevel@tonic-gate
21827c478bd9Sstevel@tonic-gate rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
21837c478bd9Sstevel@tonic-gate "usb-num-configs", usb_dev_descr->bNumConfigurations);
21847c478bd9Sstevel@tonic-gate if (rval != DDI_PROP_SUCCESS) {
2185d291d9f2Sfrits USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
21867c478bd9Sstevel@tonic-gate "usba_ready_device_node: usb-num-configs update failed");
21877c478bd9Sstevel@tonic-gate }
21887c478bd9Sstevel@tonic-gate
21897c478bd9Sstevel@tonic-gate rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
21907c478bd9Sstevel@tonic-gate "usb-release", usb_dev_descr->bcdUSB);
21917c478bd9Sstevel@tonic-gate if (rval != DDI_PROP_SUCCESS) {
2192d291d9f2Sfrits USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
21937c478bd9Sstevel@tonic-gate "usba_ready_device_node: usb-release update failed");
21947c478bd9Sstevel@tonic-gate }
21957c478bd9Sstevel@tonic-gate
2196112cd14aSqz150045 rval = ndi_prop_update_byte_array(DDI_DEV_T_NONE, child_dip,
2197112cd14aSqz150045 "usb-dev-descriptor", (uchar_t *)usb_dev_descr,
2198112cd14aSqz150045 sizeof (usb_dev_descr_t));
2199112cd14aSqz150045 if (rval != DDI_PROP_SUCCESS) {
2200112cd14aSqz150045 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2201112cd14aSqz150045 "usba_ready_device_node: usb-descriptor update failed");
2202112cd14aSqz150045 }
2203112cd14aSqz150045
2204112cd14aSqz150045 rval = ndi_prop_update_byte_array(DDI_DEV_T_NONE, child_dip,
2205112cd14aSqz150045 "usb-raw-cfg-descriptors", usb_config, usb_config_length);
2206112cd14aSqz150045 if (rval != DDI_PROP_SUCCESS) {
2207112cd14aSqz150045 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2208112cd14aSqz150045 "usba_ready_device_node: usb-raw-cfg-descriptors update "
2209112cd14aSqz150045 "failed");
2210112cd14aSqz150045 }
2211112cd14aSqz150045
22127c478bd9Sstevel@tonic-gate devprop_str = kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP);
22137c478bd9Sstevel@tonic-gate
22147c478bd9Sstevel@tonic-gate if (usba_device->usb_serialno_str) {
22157c478bd9Sstevel@tonic-gate usba_filter_string(usba_device->usb_serialno_str, devprop_str);
22167c478bd9Sstevel@tonic-gate rval = ndi_prop_update_string(DDI_DEV_T_NONE, child_dip,
22177c478bd9Sstevel@tonic-gate "usb-serialno", devprop_str);
22187c478bd9Sstevel@tonic-gate if (rval != DDI_PROP_SUCCESS) {
2219d291d9f2Sfrits USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
22207c478bd9Sstevel@tonic-gate "usba_ready_device_node: "
22217c478bd9Sstevel@tonic-gate "usb-serialno update failed");
22227c478bd9Sstevel@tonic-gate }
22237c478bd9Sstevel@tonic-gate }
22247c478bd9Sstevel@tonic-gate
22257c478bd9Sstevel@tonic-gate if (usba_device->usb_mfg_str) {
22267c478bd9Sstevel@tonic-gate usba_filter_string(usba_device->usb_mfg_str, devprop_str);
22277c478bd9Sstevel@tonic-gate rval = ndi_prop_update_string(DDI_DEV_T_NONE, child_dip,
22287c478bd9Sstevel@tonic-gate "usb-vendor-name", devprop_str);
22297c478bd9Sstevel@tonic-gate if (rval != DDI_PROP_SUCCESS) {
2230d291d9f2Sfrits USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
22317c478bd9Sstevel@tonic-gate "usba_ready_device_node: "
22327c478bd9Sstevel@tonic-gate "usb-vendor-name update failed");
22337c478bd9Sstevel@tonic-gate }
22347c478bd9Sstevel@tonic-gate }
22357c478bd9Sstevel@tonic-gate
22367c478bd9Sstevel@tonic-gate if (usba_device->usb_product_str) {
22377c478bd9Sstevel@tonic-gate usba_filter_string(usba_device->usb_product_str, devprop_str);
22387c478bd9Sstevel@tonic-gate rval = ndi_prop_update_string(DDI_DEV_T_NONE, child_dip,
22397c478bd9Sstevel@tonic-gate "usb-product-name", devprop_str);
22407c478bd9Sstevel@tonic-gate if (rval != DDI_PROP_SUCCESS) {
2241d291d9f2Sfrits USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
22427c478bd9Sstevel@tonic-gate "usba_ready_device_node: "
22437c478bd9Sstevel@tonic-gate "usb-product-name update failed");
22447c478bd9Sstevel@tonic-gate }
22457c478bd9Sstevel@tonic-gate }
22467c478bd9Sstevel@tonic-gate
22477c478bd9Sstevel@tonic-gate kmem_free(devprop_str, USB_MAXSTRINGLEN);
22487c478bd9Sstevel@tonic-gate
22497c478bd9Sstevel@tonic-gate if (!combined_node) {
22507c478bd9Sstevel@tonic-gate /* update the configuration property */
22517c478bd9Sstevel@tonic-gate rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
22527c478bd9Sstevel@tonic-gate "configuration#", usba_device->usb_cfg_value);
22537c478bd9Sstevel@tonic-gate if (rval != DDI_PROP_SUCCESS) {
22547c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
22557c478bd9Sstevel@tonic-gate "usba_ready_device_node: "
22567c478bd9Sstevel@tonic-gate "config prop update failed");
22577c478bd9Sstevel@tonic-gate }
22587c478bd9Sstevel@tonic-gate }
22597c478bd9Sstevel@tonic-gate
22607c478bd9Sstevel@tonic-gate if (usba_device->usb_port_status == USBA_LOW_SPEED_DEV) {
22617c478bd9Sstevel@tonic-gate /* create boolean property */
22627c478bd9Sstevel@tonic-gate rval = ndi_prop_create_boolean(DDI_DEV_T_NONE, child_dip,
22637c478bd9Sstevel@tonic-gate "low-speed");
22647c478bd9Sstevel@tonic-gate if (rval != DDI_PROP_SUCCESS) {
2265d291d9f2Sfrits USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
22667c478bd9Sstevel@tonic-gate "usba_ready_device_node: "
22677c478bd9Sstevel@tonic-gate "low speed prop update failed");
22687c478bd9Sstevel@tonic-gate }
22697c478bd9Sstevel@tonic-gate }
22707c478bd9Sstevel@tonic-gate
22710d2006e4SRobert Mustacchi if (usba_device->usb_port_status == USBA_FULL_SPEED_DEV) {
22720d2006e4SRobert Mustacchi /* create boolean property */
22730d2006e4SRobert Mustacchi rval = ndi_prop_create_boolean(DDI_DEV_T_NONE, child_dip,
22740d2006e4SRobert Mustacchi "full-speed");
22750d2006e4SRobert Mustacchi if (rval != DDI_PROP_SUCCESS) {
22760d2006e4SRobert Mustacchi USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
22770d2006e4SRobert Mustacchi "usba_ready_device_node: "
22780d2006e4SRobert Mustacchi "full speed prop update failed");
22790d2006e4SRobert Mustacchi }
22800d2006e4SRobert Mustacchi }
22810d2006e4SRobert Mustacchi
2282112cd14aSqz150045 if (usba_device->usb_port_status == USBA_HIGH_SPEED_DEV) {
2283112cd14aSqz150045 /* create boolean property */
2284112cd14aSqz150045 rval = ndi_prop_create_boolean(DDI_DEV_T_NONE, child_dip,
2285112cd14aSqz150045 "high-speed");
2286112cd14aSqz150045 if (rval != DDI_PROP_SUCCESS) {
2287112cd14aSqz150045 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2288112cd14aSqz150045 "usba_ready_device_node: "
2289112cd14aSqz150045 "high speed prop update failed");
2290112cd14aSqz150045 }
2291112cd14aSqz150045 }
2292112cd14aSqz150045
2293993e3fafSRobert Mustacchi if (usba_device->usb_port_status == USBA_SUPER_SPEED_DEV) {
2294993e3fafSRobert Mustacchi rval = ndi_prop_create_boolean(DDI_DEV_T_NONE, child_dip,
2295993e3fafSRobert Mustacchi "super-speed");
2296993e3fafSRobert Mustacchi if (rval != DDI_PROP_SUCCESS) {
2297993e3fafSRobert Mustacchi USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2298993e3fafSRobert Mustacchi "usba_ready_device_node: "
2299993e3fafSRobert Mustacchi "super speed prop update failed");
2300993e3fafSRobert Mustacchi }
2301993e3fafSRobert Mustacchi }
2302993e3fafSRobert Mustacchi
23030d2006e4SRobert Mustacchi usba_add_binary_object_store_props(child_dip, usba_device);
23040d2006e4SRobert Mustacchi
23057c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
23067c478bd9Sstevel@tonic-gate "%s%d at port %d: %s, dip=0x%p",
23077c478bd9Sstevel@tonic-gate ddi_node_name(ddi_get_parent(child_dip)),
23087c478bd9Sstevel@tonic-gate ddi_get_instance(ddi_get_parent(child_dip)),
2309112116d8Sfb209375 port, ddi_node_name(child_dip), (void *)child_dip);
23107c478bd9Sstevel@tonic-gate
23117c478bd9Sstevel@tonic-gate usba_set_usba_device(child_dip, usba_device);
23127c478bd9Sstevel@tonic-gate
23137c478bd9Sstevel@tonic-gate ASSERT(!mutex_owned(&(usba_get_usba_device(child_dip)->usb_mutex)));
23147c478bd9Sstevel@tonic-gate
23157c478bd9Sstevel@tonic-gate return (child_dip);
23167c478bd9Sstevel@tonic-gate }
23177c478bd9Sstevel@tonic-gate
23187c478bd9Sstevel@tonic-gate
23197c478bd9Sstevel@tonic-gate /*
2320d73ae94eSgc161489 * driver binding at interface association level. the first arg is the parent
2321d73ae94eSgc161489 * dip. if_count returns amount of interfaces which are associated within
2322d73ae94eSgc161489 * this interface-association that starts from first_if.
2323d73ae94eSgc161489 */
2324d73ae94eSgc161489 /*ARGSUSED*/
2325d73ae94eSgc161489 dev_info_t *
usba_ready_interface_association_node(dev_info_t * dip,uint_t first_if,uint_t * if_count)2326d5ebc493SDan Cross usba_ready_interface_association_node(
2327d5ebc493SDan Cross dev_info_t *dip,
2328d73ae94eSgc161489 uint_t first_if,
2329d73ae94eSgc161489 uint_t *if_count)
2330d73ae94eSgc161489 {
2331d73ae94eSgc161489 dev_info_t *child_dip = NULL;
2332d73ae94eSgc161489 usba_device_t *child_ud = usba_get_usba_device(dip);
2333d73ae94eSgc161489 usb_dev_descr_t *usb_dev_descr;
2334d73ae94eSgc161489 size_t usb_cfg_length;
2335d73ae94eSgc161489 uchar_t *usb_cfg;
2336d73ae94eSgc161489 usb_ia_descr_t ia_descr;
2337d73ae94eSgc161489 int i, n, rval;
2338d73ae94eSgc161489 int reg[2];
2339d73ae94eSgc161489 size_t size;
2340d73ae94eSgc161489 usb_port_status_t port_status;
2341d73ae94eSgc161489 char *force_bind = NULL;
23423c91d182Slg150142 char *usba_name_buf = NULL;
23433c91d182Slg150142 char *usba_name[USBA_MAX_COMPAT_NAMES];
2344d73ae94eSgc161489
2345d73ae94eSgc161489 usb_cfg = usb_get_raw_cfg_data(dip, &usb_cfg_length);
2346d73ae94eSgc161489
2347d73ae94eSgc161489 mutex_enter(&child_ud->usb_mutex);
2348d73ae94eSgc161489
2349d73ae94eSgc161489 usb_dev_descr = child_ud->usb_dev_descr;
2350d73ae94eSgc161489
2351d73ae94eSgc161489 /*
2352d73ae94eSgc161489 * for each interface association, determine all compatible names
2353d73ae94eSgc161489 */
2354d73ae94eSgc161489 USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
2355d73ae94eSgc161489 "usba_ready_ia_node: "
2356d73ae94eSgc161489 "port %d, interface = %d, port_status = %x",
2357d73ae94eSgc161489 child_ud->usb_port, first_if, child_ud->usb_port_status);
2358d73ae94eSgc161489
2359d73ae94eSgc161489 /* Parse the interface descriptor */
2360d73ae94eSgc161489 size = usb_parse_ia_descr(
2361d73ae94eSgc161489 usb_cfg,
2362d73ae94eSgc161489 usb_cfg_length,
2363d73ae94eSgc161489 first_if, /* interface index */
2364d73ae94eSgc161489 &ia_descr,
2365d73ae94eSgc161489 USB_IA_DESCR_SIZE);
2366d73ae94eSgc161489
2367d73ae94eSgc161489 *if_count = 1;
2368d73ae94eSgc161489 if (size != USB_IA_DESCR_SIZE) {
2369d73ae94eSgc161489 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2370d73ae94eSgc161489 "parsing ia: size (%lu) != USB_IA_DESCR_SIZE (%d)",
2371d73ae94eSgc161489 size, USB_IA_DESCR_SIZE);
2372d73ae94eSgc161489 mutex_exit(&child_ud->usb_mutex);
2373d73ae94eSgc161489
2374d73ae94eSgc161489 return (NULL);
2375d73ae94eSgc161489 }
2376d73ae94eSgc161489
2377d73ae94eSgc161489 port_status = child_ud->usb_port_status;
2378d73ae94eSgc161489
2379d73ae94eSgc161489 /* create reg property */
2380d73ae94eSgc161489 reg[0] = first_if;
2381d73ae94eSgc161489 reg[1] = child_ud->usb_cfg_value;
2382d73ae94eSgc161489
2383d73ae94eSgc161489 mutex_exit(&child_ud->usb_mutex);
2384d73ae94eSgc161489
2385d73ae94eSgc161489 /* clone this dip */
2386d73ae94eSgc161489 rval = usba_create_child_devi(dip,
2387d73ae94eSgc161489 "interface-association",
2388d73ae94eSgc161489 NULL, /* usba_hcdi ops */
2389d73ae94eSgc161489 NULL, /* root hub dip */
2390d73ae94eSgc161489 port_status, /* port status */
2391d73ae94eSgc161489 child_ud, /* share this usba_device */
2392d73ae94eSgc161489 &child_dip);
2393d73ae94eSgc161489
2394d73ae94eSgc161489 if (rval != USB_SUCCESS) {
2395d73ae94eSgc161489
2396d73ae94eSgc161489 goto fail;
2397d73ae94eSgc161489 }
2398d73ae94eSgc161489
2399d73ae94eSgc161489 rval = ndi_prop_update_int_array(
2400d73ae94eSgc161489 DDI_DEV_T_NONE, child_dip, "reg", reg, 2);
2401d73ae94eSgc161489
2402d73ae94eSgc161489 if (rval != DDI_PROP_SUCCESS) {
2403d73ae94eSgc161489
2404d73ae94eSgc161489 goto fail;
2405d73ae94eSgc161489 }
2406d73ae94eSgc161489
2407d73ae94eSgc161489 usba_set_node_name(child_dip, ia_descr.bFunctionClass,
2408d73ae94eSgc161489 ia_descr.bFunctionSubClass, ia_descr.bFunctionProtocol,
2409d73ae94eSgc161489 FLAG_INTERFACE_ASSOCIATION_NODE);
2410d73ae94eSgc161489
2411d73ae94eSgc161489 /* check force binding */
2412d73ae94eSgc161489 if (usba_ugen_force_binding ==
2413d73ae94eSgc161489 USBA_UGEN_INTERFACE_ASSOCIATION_BINDING) {
2414d73ae94eSgc161489 force_bind = "ugen";
2415d73ae94eSgc161489 }
2416d73ae94eSgc161489
2417d73ae94eSgc161489 /*
2418d73ae94eSgc161489 * check whether there is another dip with this name and address
2419d73ae94eSgc161489 */
2420d73ae94eSgc161489 ASSERT(usba_find_existing_node(child_dip) == NULL);
2421d73ae94eSgc161489
24223c91d182Slg150142 usba_name_buf = kmem_zalloc(USBA_MAX_COMPAT_NAMES *
24233c91d182Slg150142 USBA_MAX_COMPAT_NAME_LEN, KM_SLEEP);
24243c91d182Slg150142
24253c91d182Slg150142 for (i = 0; i < USBA_MAX_COMPAT_NAMES; i++) {
24263c91d182Slg150142 usba_name[i] = usba_name_buf + (i * USBA_MAX_COMPAT_NAME_LEN);
24273c91d182Slg150142 }
24283c91d182Slg150142
2429d73ae94eSgc161489 n = 0;
2430d73ae94eSgc161489
2431d73ae94eSgc161489 if (force_bind) {
2432d73ae94eSgc161489 (void) ndi_devi_set_nodename(child_dip, force_bind, 0);
2433d73ae94eSgc161489 (void) strncpy(usba_name[n++], force_bind,
2434d73ae94eSgc161489 USBA_MAX_COMPAT_NAME_LEN);
2435d73ae94eSgc161489 }
2436d73ae94eSgc161489
2437d73ae94eSgc161489 /* 1) usbiaVID,PID.REV.configCN.FN */
2438d73ae94eSgc161489 (void) sprintf(usba_name[n++],
2439d73ae94eSgc161489 "usbia%x,%x.%x.config%x.%x",
2440d73ae94eSgc161489 usb_dev_descr->idVendor,
2441d73ae94eSgc161489 usb_dev_descr->idProduct,
2442d73ae94eSgc161489 usb_dev_descr->bcdDevice,
2443d73ae94eSgc161489 child_ud->usb_cfg_value,
2444d73ae94eSgc161489 first_if);
2445d73ae94eSgc161489
2446d73ae94eSgc161489 /* 2) usbiaVID,PID.configCN.FN */
2447d73ae94eSgc161489 (void) sprintf(usba_name[n++],
2448d73ae94eSgc161489 "usbia%x,%x.config%x.%x",
2449d73ae94eSgc161489 usb_dev_descr->idVendor,
2450d73ae94eSgc161489 usb_dev_descr->idProduct,
2451d73ae94eSgc161489 child_ud->usb_cfg_value,
2452d73ae94eSgc161489 first_if);
2453d73ae94eSgc161489
2454d73ae94eSgc161489
2455d73ae94eSgc161489 if (ia_descr.bFunctionClass) {
2456d73ae94eSgc161489 /* 3) usbiaVID,classFC.FSC.FPROTO */
2457d73ae94eSgc161489 (void) sprintf(usba_name[n++],
2458d73ae94eSgc161489 "usbia%x,class%x.%x.%x",
2459d73ae94eSgc161489 usb_dev_descr->idVendor,
2460d73ae94eSgc161489 ia_descr.bFunctionClass,
2461d73ae94eSgc161489 ia_descr.bFunctionSubClass,
2462d73ae94eSgc161489 ia_descr.bFunctionProtocol);
2463d73ae94eSgc161489
2464d73ae94eSgc161489 /* 4) usbiaVID,classFC.FSC */
2465d73ae94eSgc161489 (void) sprintf(usba_name[n++],
2466d73ae94eSgc161489 "usbia%x,class%x.%x",
2467d73ae94eSgc161489 usb_dev_descr->idVendor,
2468d73ae94eSgc161489 ia_descr.bFunctionClass,
2469d73ae94eSgc161489 ia_descr.bFunctionSubClass);
2470d73ae94eSgc161489
2471d73ae94eSgc161489 /* 5) usbiaVID,classFC */
2472d73ae94eSgc161489 (void) sprintf(usba_name[n++],
2473d73ae94eSgc161489 "usbia%x,class%x",
2474d73ae94eSgc161489 usb_dev_descr->idVendor,
2475d73ae94eSgc161489 ia_descr.bFunctionClass);
2476d73ae94eSgc161489
2477d73ae94eSgc161489 /* 6) usbia,classFC.FSC.FPROTO */
2478d73ae94eSgc161489 (void) sprintf(usba_name[n++],
2479d73ae94eSgc161489 "usbia,class%x.%x.%x",
2480d73ae94eSgc161489 ia_descr.bFunctionClass,
2481d73ae94eSgc161489 ia_descr.bFunctionSubClass,
2482d73ae94eSgc161489 ia_descr.bFunctionProtocol);
2483d73ae94eSgc161489
2484d73ae94eSgc161489 /* 7) usbia,classFC.FSC */
2485d73ae94eSgc161489 (void) sprintf(usba_name[n++],
2486d73ae94eSgc161489 "usbia,class%x.%x",
2487d73ae94eSgc161489 ia_descr.bFunctionClass,
2488d73ae94eSgc161489 ia_descr.bFunctionSubClass);
2489d73ae94eSgc161489
2490d73ae94eSgc161489 /* 8) usbia,classFC */
2491d73ae94eSgc161489 (void) sprintf(usba_name[n++],
2492d73ae94eSgc161489 "usbia,class%x",
2493d73ae94eSgc161489 ia_descr.bFunctionClass);
2494d73ae94eSgc161489 }
2495d73ae94eSgc161489
2496d73ae94eSgc161489 if (usba_get_ugen_binding(child_dip) ==
2497d73ae94eSgc161489 USBA_UGEN_INTERFACE_ASSOCIATION_BINDING) {
2498d73ae94eSgc161489 /* 9) ugen */
2499d73ae94eSgc161489 (void) sprintf(usba_name[n++], "ugen");
2500d73ae94eSgc161489 } else {
2501d73ae94eSgc161489
2502d73ae94eSgc161489 (void) sprintf(usba_name[n++], "usb,ia");
2503d73ae94eSgc161489 }
2504d73ae94eSgc161489
2505d73ae94eSgc161489 for (i = 0; i < n; i += 2) {
2506d73ae94eSgc161489 USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
25073c91d182Slg150142 "compatible name:\t%s\t%s", usba_name[i],
25083c91d182Slg150142 (((i+1) < n)? usba_name[i+1] : ""));
2509d73ae94eSgc161489 }
2510d73ae94eSgc161489
2511d73ae94eSgc161489 /* create compatible property */
25123c91d182Slg150142 rval = ndi_prop_update_string_array(DDI_DEV_T_NONE, child_dip,
25133c91d182Slg150142 "compatible", (char **)usba_name, n);
25143c91d182Slg150142
25153c91d182Slg150142 kmem_free(usba_name_buf, USBA_MAX_COMPAT_NAMES *
25163c91d182Slg150142 USBA_MAX_COMPAT_NAME_LEN);
2517d73ae94eSgc161489
2518d73ae94eSgc161489 if (rval != DDI_PROP_SUCCESS) {
2519d73ae94eSgc161489
2520d73ae94eSgc161489 goto fail;
2521d73ae94eSgc161489 }
2522d73ae94eSgc161489
2523d73ae94eSgc161489 /* update the address property */
2524d73ae94eSgc161489 rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2525d73ae94eSgc161489 "assigned-address", child_ud->usb_addr);
2526d73ae94eSgc161489 if (rval != DDI_PROP_SUCCESS) {
2527d73ae94eSgc161489 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2528d73ae94eSgc161489 "usba_ready_interface_node: address update failed");
2529d73ae94eSgc161489 }
2530d73ae94eSgc161489
2531d73ae94eSgc161489 /* create property with first interface number */
2532d73ae94eSgc161489 rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2533d73ae94eSgc161489 "interface", ia_descr.bFirstInterface);
2534d73ae94eSgc161489
2535d73ae94eSgc161489 if (rval != DDI_PROP_SUCCESS) {
2536d73ae94eSgc161489
2537d73ae94eSgc161489 goto fail;
2538d73ae94eSgc161489 }
2539d73ae94eSgc161489
2540d73ae94eSgc161489 /* create property with the count of interfaces in this ia */
2541d73ae94eSgc161489 rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
2542d73ae94eSgc161489 "interface-count", ia_descr.bInterfaceCount);
2543d73ae94eSgc161489
2544d73ae94eSgc161489 if (rval != DDI_PROP_SUCCESS) {
2545d73ae94eSgc161489
2546d73ae94eSgc161489 goto fail;
2547d73ae94eSgc161489 }
2548d73ae94eSgc161489
2549d73ae94eSgc161489 USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
2550d73ae94eSgc161489 "%s%d port %d: %s, dip = 0x%p",
2551d73ae94eSgc161489 ddi_node_name(ddi_get_parent(dip)),
2552d73ae94eSgc161489 ddi_get_instance(ddi_get_parent(dip)),
2553112116d8Sfb209375 child_ud->usb_port, ddi_node_name(child_dip), (void *)child_dip);
2554d73ae94eSgc161489
2555d73ae94eSgc161489 *if_count = ia_descr.bInterfaceCount;
2556d73ae94eSgc161489 usba_set_usba_device(child_dip, child_ud);
2557d73ae94eSgc161489 ASSERT(!mutex_owned(&(usba_get_usba_device(child_dip)->usb_mutex)));
2558d73ae94eSgc161489
2559d73ae94eSgc161489 return (child_dip);
2560d73ae94eSgc161489
2561d73ae94eSgc161489 fail:
2562d73ae94eSgc161489 (void) usba_destroy_child_devi(child_dip, NDI_DEVI_REMOVE);
2563d73ae94eSgc161489
2564d73ae94eSgc161489 return (NULL);
2565d73ae94eSgc161489 }
2566d73ae94eSgc161489
2567d73ae94eSgc161489
2568d73ae94eSgc161489 /*
25697c478bd9Sstevel@tonic-gate * driver binding at interface level, the first arg will be the
25707c478bd9Sstevel@tonic-gate * the parent dip
25717c478bd9Sstevel@tonic-gate */
25727c478bd9Sstevel@tonic-gate /*ARGSUSED*/
25737c478bd9Sstevel@tonic-gate dev_info_t *
usba_ready_interface_node(dev_info_t * dip,uint_t intf)25747c478bd9Sstevel@tonic-gate usba_ready_interface_node(dev_info_t *dip, uint_t intf)
25757c478bd9Sstevel@tonic-gate {
25767c478bd9Sstevel@tonic-gate dev_info_t *child_dip = NULL;
25777c478bd9Sstevel@tonic-gate usba_device_t *child_ud = usba_get_usba_device(dip);
25787c478bd9Sstevel@tonic-gate usb_dev_descr_t *usb_dev_descr;
25797c478bd9Sstevel@tonic-gate size_t usb_cfg_length;
25807c478bd9Sstevel@tonic-gate uchar_t *usb_cfg;
25817c478bd9Sstevel@tonic-gate usb_if_descr_t if_descr;
25827c478bd9Sstevel@tonic-gate int i, n, rval;
25837c478bd9Sstevel@tonic-gate int reg[2];
25847c478bd9Sstevel@tonic-gate size_t size;
25857c478bd9Sstevel@tonic-gate usb_port_status_t port_status;
25867c478bd9Sstevel@tonic-gate char *force_bind = NULL;
25873c91d182Slg150142 char *usba_name_buf = NULL;
25883c91d182Slg150142 char *usba_name[USBA_MAX_COMPAT_NAMES];
25897c478bd9Sstevel@tonic-gate
25907c478bd9Sstevel@tonic-gate usb_cfg = usb_get_raw_cfg_data(dip, &usb_cfg_length);
25917c478bd9Sstevel@tonic-gate
25927c478bd9Sstevel@tonic-gate mutex_enter(&child_ud->usb_mutex);
25937c478bd9Sstevel@tonic-gate
25947c478bd9Sstevel@tonic-gate usb_dev_descr = child_ud->usb_dev_descr;
25957c478bd9Sstevel@tonic-gate
25967c478bd9Sstevel@tonic-gate /*
25977c478bd9Sstevel@tonic-gate * for each interface, determine all compatible names
25987c478bd9Sstevel@tonic-gate */
25997c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
26007c478bd9Sstevel@tonic-gate "usba_ready_interface_node: "
26017c478bd9Sstevel@tonic-gate "port %d, interface = %d port status = %x",
26027c478bd9Sstevel@tonic-gate child_ud->usb_port, intf, child_ud->usb_port_status);
26037c478bd9Sstevel@tonic-gate
26047c478bd9Sstevel@tonic-gate /* Parse the interface descriptor */
26057c478bd9Sstevel@tonic-gate size = usb_parse_if_descr(
26067c478bd9Sstevel@tonic-gate usb_cfg,
26077c478bd9Sstevel@tonic-gate usb_cfg_length,
26087c478bd9Sstevel@tonic-gate intf, /* interface index */
26097c478bd9Sstevel@tonic-gate 0, /* alt interface index */
26107c478bd9Sstevel@tonic-gate &if_descr,
26117c478bd9Sstevel@tonic-gate USB_IF_DESCR_SIZE);
26127c478bd9Sstevel@tonic-gate
26137c478bd9Sstevel@tonic-gate if (size != USB_IF_DESCR_SIZE) {
2614d291d9f2Sfrits USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
26157c478bd9Sstevel@tonic-gate "parsing interface: size (%lu) != USB_IF_DESCR_SIZE (%d)",
26167c478bd9Sstevel@tonic-gate size, USB_IF_DESCR_SIZE);
26177c478bd9Sstevel@tonic-gate mutex_exit(&child_ud->usb_mutex);
26187c478bd9Sstevel@tonic-gate
26197c478bd9Sstevel@tonic-gate return (NULL);
26207c478bd9Sstevel@tonic-gate }
26217c478bd9Sstevel@tonic-gate
26227c478bd9Sstevel@tonic-gate port_status = child_ud->usb_port_status;
26237c478bd9Sstevel@tonic-gate
26247c478bd9Sstevel@tonic-gate /* create reg property */
26257c478bd9Sstevel@tonic-gate reg[0] = intf;
26267c478bd9Sstevel@tonic-gate reg[1] = child_ud->usb_cfg_value;
26277c478bd9Sstevel@tonic-gate
26287c478bd9Sstevel@tonic-gate mutex_exit(&child_ud->usb_mutex);
26297c478bd9Sstevel@tonic-gate
26307c478bd9Sstevel@tonic-gate /* clone this dip */
26317c478bd9Sstevel@tonic-gate rval = usba_create_child_devi(dip,
26327c478bd9Sstevel@tonic-gate "interface",
26337c478bd9Sstevel@tonic-gate NULL, /* usba_hcdi ops */
26347c478bd9Sstevel@tonic-gate NULL, /* root hub dip */
26357c478bd9Sstevel@tonic-gate port_status, /* port status */
26367c478bd9Sstevel@tonic-gate child_ud, /* share this usba_device */
26377c478bd9Sstevel@tonic-gate &child_dip);
26387c478bd9Sstevel@tonic-gate
26397c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) {
26407c478bd9Sstevel@tonic-gate
26417c478bd9Sstevel@tonic-gate goto fail;
26427c478bd9Sstevel@tonic-gate }
26437c478bd9Sstevel@tonic-gate
26447c478bd9Sstevel@tonic-gate rval = ndi_prop_update_int_array(
26457c478bd9Sstevel@tonic-gate DDI_DEV_T_NONE, child_dip, "reg", reg, 2);
26467c478bd9Sstevel@tonic-gate
26477c478bd9Sstevel@tonic-gate if (rval != DDI_PROP_SUCCESS) {
26487c478bd9Sstevel@tonic-gate
26497c478bd9Sstevel@tonic-gate goto fail;
26507c478bd9Sstevel@tonic-gate }
26517c478bd9Sstevel@tonic-gate
26527c478bd9Sstevel@tonic-gate usba_set_node_name(child_dip, if_descr.bInterfaceClass,
26537c478bd9Sstevel@tonic-gate if_descr.bInterfaceSubClass, if_descr.bInterfaceProtocol,
26547c478bd9Sstevel@tonic-gate FLAG_INTERFACE_NODE);
26557c478bd9Sstevel@tonic-gate
26567c478bd9Sstevel@tonic-gate /* check force binding */
26577c478bd9Sstevel@tonic-gate if (usba_ugen_force_binding == USBA_UGEN_INTERFACE_BINDING) {
26587c478bd9Sstevel@tonic-gate force_bind = "ugen";
26597c478bd9Sstevel@tonic-gate }
26607c478bd9Sstevel@tonic-gate
26617c478bd9Sstevel@tonic-gate /*
26627c478bd9Sstevel@tonic-gate * check whether there is another dip with this name and address
26637c478bd9Sstevel@tonic-gate */
26647c478bd9Sstevel@tonic-gate ASSERT(usba_find_existing_node(child_dip) == NULL);
26657c478bd9Sstevel@tonic-gate
26663c91d182Slg150142 usba_name_buf = kmem_zalloc(USBA_MAX_COMPAT_NAMES *
26673c91d182Slg150142 USBA_MAX_COMPAT_NAME_LEN, KM_SLEEP);
26683c91d182Slg150142
26693c91d182Slg150142 for (i = 0; i < USBA_MAX_COMPAT_NAMES; i++) {
26703c91d182Slg150142 usba_name[i] = usba_name_buf + (i * USBA_MAX_COMPAT_NAME_LEN);
26713c91d182Slg150142 }
26723c91d182Slg150142
26737c478bd9Sstevel@tonic-gate n = 0;
26747c478bd9Sstevel@tonic-gate
26757c478bd9Sstevel@tonic-gate if (force_bind) {
26767c478bd9Sstevel@tonic-gate (void) ndi_devi_set_nodename(child_dip, force_bind, 0);
26777c478bd9Sstevel@tonic-gate (void) strncpy(usba_name[n++], force_bind,
26787c478bd9Sstevel@tonic-gate USBA_MAX_COMPAT_NAME_LEN);
26797c478bd9Sstevel@tonic-gate }
26807c478bd9Sstevel@tonic-gate
26817c478bd9Sstevel@tonic-gate /* 1) usbifVID,PID.REV.configCN.IN */
26827c478bd9Sstevel@tonic-gate (void) sprintf(usba_name[n++],
26837c478bd9Sstevel@tonic-gate "usbif%x,%x.%x.config%x.%x",
26847c478bd9Sstevel@tonic-gate usb_dev_descr->idVendor,
26857c478bd9Sstevel@tonic-gate usb_dev_descr->idProduct,
26867c478bd9Sstevel@tonic-gate usb_dev_descr->bcdDevice,
26877c478bd9Sstevel@tonic-gate child_ud->usb_cfg_value,
26887c478bd9Sstevel@tonic-gate intf);
26897c478bd9Sstevel@tonic-gate
26907c478bd9Sstevel@tonic-gate /* 2) usbifVID,PID.configCN.IN */
26917c478bd9Sstevel@tonic-gate (void) sprintf(usba_name[n++],
26927c478bd9Sstevel@tonic-gate "usbif%x,%x.config%x.%x",
26937c478bd9Sstevel@tonic-gate usb_dev_descr->idVendor,
26947c478bd9Sstevel@tonic-gate usb_dev_descr->idProduct,
26957c478bd9Sstevel@tonic-gate child_ud->usb_cfg_value,
26967c478bd9Sstevel@tonic-gate intf);
26977c478bd9Sstevel@tonic-gate
26987c478bd9Sstevel@tonic-gate
26997c478bd9Sstevel@tonic-gate if (if_descr.bInterfaceClass) {
27007c478bd9Sstevel@tonic-gate /* 3) usbifVID,classIC.ISC.IPROTO */
27017c478bd9Sstevel@tonic-gate (void) sprintf(usba_name[n++],
27027c478bd9Sstevel@tonic-gate "usbif%x,class%x.%x.%x",
27037c478bd9Sstevel@tonic-gate usb_dev_descr->idVendor,
27047c478bd9Sstevel@tonic-gate if_descr.bInterfaceClass,
27057c478bd9Sstevel@tonic-gate if_descr.bInterfaceSubClass,
27067c478bd9Sstevel@tonic-gate if_descr.bInterfaceProtocol);
27077c478bd9Sstevel@tonic-gate
27087c478bd9Sstevel@tonic-gate /* 4) usbifVID,classIC.ISC */
27097c478bd9Sstevel@tonic-gate (void) sprintf(usba_name[n++],
27107c478bd9Sstevel@tonic-gate "usbif%x,class%x.%x",
27117c478bd9Sstevel@tonic-gate usb_dev_descr->idVendor,
27127c478bd9Sstevel@tonic-gate if_descr.bInterfaceClass,
27137c478bd9Sstevel@tonic-gate if_descr.bInterfaceSubClass);
27147c478bd9Sstevel@tonic-gate
27157c478bd9Sstevel@tonic-gate /* 5) usbifVID,classIC */
27167c478bd9Sstevel@tonic-gate (void) sprintf(usba_name[n++],
27177c478bd9Sstevel@tonic-gate "usbif%x,class%x",
27187c478bd9Sstevel@tonic-gate usb_dev_descr->idVendor,
27197c478bd9Sstevel@tonic-gate if_descr.bInterfaceClass);
27207c478bd9Sstevel@tonic-gate
27217c478bd9Sstevel@tonic-gate /* 6) usbif,classIC.ISC.IPROTO */
27227c478bd9Sstevel@tonic-gate (void) sprintf(usba_name[n++],
27237c478bd9Sstevel@tonic-gate "usbif,class%x.%x.%x",
27247c478bd9Sstevel@tonic-gate if_descr.bInterfaceClass,
27257c478bd9Sstevel@tonic-gate if_descr.bInterfaceSubClass,
27267c478bd9Sstevel@tonic-gate if_descr.bInterfaceProtocol);
27277c478bd9Sstevel@tonic-gate
27287c478bd9Sstevel@tonic-gate /* 7) usbif,classIC.ISC */
27297c478bd9Sstevel@tonic-gate (void) sprintf(usba_name[n++],
27307c478bd9Sstevel@tonic-gate "usbif,class%x.%x",
27317c478bd9Sstevel@tonic-gate if_descr.bInterfaceClass,
27327c478bd9Sstevel@tonic-gate if_descr.bInterfaceSubClass);
27337c478bd9Sstevel@tonic-gate
27347c478bd9Sstevel@tonic-gate /* 8) usbif,classIC */
27357c478bd9Sstevel@tonic-gate (void) sprintf(usba_name[n++],
27367c478bd9Sstevel@tonic-gate "usbif,class%x",
27377c478bd9Sstevel@tonic-gate if_descr.bInterfaceClass);
27387c478bd9Sstevel@tonic-gate }
27397c478bd9Sstevel@tonic-gate
27407c478bd9Sstevel@tonic-gate if (usba_get_ugen_binding(child_dip) ==
27417c478bd9Sstevel@tonic-gate USBA_UGEN_INTERFACE_BINDING) {
27427c478bd9Sstevel@tonic-gate /* 9) ugen */
27437c478bd9Sstevel@tonic-gate (void) sprintf(usba_name[n++], "ugen");
27447c478bd9Sstevel@tonic-gate }
27457c478bd9Sstevel@tonic-gate
27467c478bd9Sstevel@tonic-gate for (i = 0; i < n; i += 2) {
27477c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
27483c91d182Slg150142 "compatible name:\t%s\t%s", usba_name[i],
27493c91d182Slg150142 (((i+1) < n)? usba_name[i+1] : ""));
27507c478bd9Sstevel@tonic-gate }
27517c478bd9Sstevel@tonic-gate
27527c478bd9Sstevel@tonic-gate /* create compatible property */
27533c91d182Slg150142 rval = ndi_prop_update_string_array(DDI_DEV_T_NONE, child_dip,
27543c91d182Slg150142 "compatible", (char **)usba_name, n);
27553c91d182Slg150142
27563c91d182Slg150142 kmem_free(usba_name_buf, USBA_MAX_COMPAT_NAMES *
27573c91d182Slg150142 USBA_MAX_COMPAT_NAME_LEN);
27587c478bd9Sstevel@tonic-gate
27597c478bd9Sstevel@tonic-gate if (rval != DDI_PROP_SUCCESS) {
27607c478bd9Sstevel@tonic-gate
27617c478bd9Sstevel@tonic-gate goto fail;
27627c478bd9Sstevel@tonic-gate }
27637c478bd9Sstevel@tonic-gate
27647c478bd9Sstevel@tonic-gate /* update the address property */
27657c478bd9Sstevel@tonic-gate rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
27667c478bd9Sstevel@tonic-gate "assigned-address", child_ud->usb_addr);
27677c478bd9Sstevel@tonic-gate if (rval != DDI_PROP_SUCCESS) {
2768d291d9f2Sfrits USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
27697c478bd9Sstevel@tonic-gate "usba_ready_interface_node: address update failed");
27707c478bd9Sstevel@tonic-gate }
27717c478bd9Sstevel@tonic-gate
27727c478bd9Sstevel@tonic-gate /* create property with if number */
27737c478bd9Sstevel@tonic-gate rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
27747c478bd9Sstevel@tonic-gate "interface", intf);
27757c478bd9Sstevel@tonic-gate
27767c478bd9Sstevel@tonic-gate if (rval != DDI_PROP_SUCCESS) {
27777c478bd9Sstevel@tonic-gate
27787c478bd9Sstevel@tonic-gate goto fail;
27797c478bd9Sstevel@tonic-gate }
27807c478bd9Sstevel@tonic-gate
27817c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
27827c478bd9Sstevel@tonic-gate "%s%d port %d: %s, dip = 0x%p",
27837c478bd9Sstevel@tonic-gate ddi_node_name(ddi_get_parent(dip)),
27847c478bd9Sstevel@tonic-gate ddi_get_instance(ddi_get_parent(dip)),
2785112116d8Sfb209375 child_ud->usb_port, ddi_node_name(child_dip), (void *)child_dip);
27867c478bd9Sstevel@tonic-gate
27877c478bd9Sstevel@tonic-gate usba_set_usba_device(child_dip, child_ud);
27887c478bd9Sstevel@tonic-gate ASSERT(!mutex_owned(&(usba_get_usba_device(child_dip)->usb_mutex)));
27897c478bd9Sstevel@tonic-gate
27907c478bd9Sstevel@tonic-gate return (child_dip);
27917c478bd9Sstevel@tonic-gate
27927c478bd9Sstevel@tonic-gate fail:
27937c478bd9Sstevel@tonic-gate (void) usba_destroy_child_devi(child_dip, NDI_DEVI_REMOVE);
27947c478bd9Sstevel@tonic-gate
27957c478bd9Sstevel@tonic-gate return (NULL);
27967c478bd9Sstevel@tonic-gate }
27977c478bd9Sstevel@tonic-gate
27987c478bd9Sstevel@tonic-gate
27997c478bd9Sstevel@tonic-gate /*
28007c478bd9Sstevel@tonic-gate * retrieve string descriptors for manufacturer, vendor and serial
28017c478bd9Sstevel@tonic-gate * number
28027c478bd9Sstevel@tonic-gate */
28037c478bd9Sstevel@tonic-gate void
usba_get_dev_string_descrs(dev_info_t * dip,usba_device_t * ud)28047c478bd9Sstevel@tonic-gate usba_get_dev_string_descrs(dev_info_t *dip, usba_device_t *ud)
28057c478bd9Sstevel@tonic-gate {
28067c478bd9Sstevel@tonic-gate char *tmpbuf, *str;
28077c478bd9Sstevel@tonic-gate int l;
28087c478bd9Sstevel@tonic-gate usb_dev_descr_t *usb_dev_descr = ud->usb_dev_descr;
28097c478bd9Sstevel@tonic-gate
28107c478bd9Sstevel@tonic-gate
28117c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
28127c478bd9Sstevel@tonic-gate "usba_get_usb_string_descr: m=%d, p=%d, s=%d",
28137c478bd9Sstevel@tonic-gate usb_dev_descr->iManufacturer,
28147c478bd9Sstevel@tonic-gate usb_dev_descr->iProduct,
28157c478bd9Sstevel@tonic-gate usb_dev_descr->iSerialNumber);
28167c478bd9Sstevel@tonic-gate
28177c478bd9Sstevel@tonic-gate tmpbuf = kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP);
28187c478bd9Sstevel@tonic-gate
28197c478bd9Sstevel@tonic-gate /* fetch manufacturer string */
28207c478bd9Sstevel@tonic-gate if ((ud->usb_mfg_str == NULL) && usb_dev_descr->iManufacturer &&
28217c478bd9Sstevel@tonic-gate (usb_get_string_descr(dip, USB_LANG_ID,
28227c478bd9Sstevel@tonic-gate usb_dev_descr->iManufacturer, tmpbuf, USB_MAXSTRINGLEN) ==
28237c478bd9Sstevel@tonic-gate USB_SUCCESS)) {
28247c478bd9Sstevel@tonic-gate
28257c478bd9Sstevel@tonic-gate l = strlen(tmpbuf);
28267c478bd9Sstevel@tonic-gate if (l > 0) {
28277c478bd9Sstevel@tonic-gate str = kmem_zalloc(l + 1, KM_SLEEP);
28287c478bd9Sstevel@tonic-gate mutex_enter(&ud->usb_mutex);
28297c478bd9Sstevel@tonic-gate ud->usb_mfg_str = str;
28307c478bd9Sstevel@tonic-gate (void) strcpy(ud->usb_mfg_str, tmpbuf);
28317c478bd9Sstevel@tonic-gate mutex_exit(&ud->usb_mutex);
28327c478bd9Sstevel@tonic-gate }
28337c478bd9Sstevel@tonic-gate }
28347c478bd9Sstevel@tonic-gate
28357c478bd9Sstevel@tonic-gate /* fetch product string */
28367c478bd9Sstevel@tonic-gate if ((ud->usb_product_str == NULL) && usb_dev_descr->iProduct &&
28377c478bd9Sstevel@tonic-gate (usb_get_string_descr(dip, USB_LANG_ID, usb_dev_descr->iProduct,
28387c478bd9Sstevel@tonic-gate tmpbuf, USB_MAXSTRINGLEN) ==
28397c478bd9Sstevel@tonic-gate USB_SUCCESS)) {
28407c478bd9Sstevel@tonic-gate
28417c478bd9Sstevel@tonic-gate l = strlen(tmpbuf);
28427c478bd9Sstevel@tonic-gate if (l > 0) {
28437c478bd9Sstevel@tonic-gate str = kmem_zalloc(l + 1, KM_SLEEP);
28447c478bd9Sstevel@tonic-gate mutex_enter(&ud->usb_mutex);
28457c478bd9Sstevel@tonic-gate ud->usb_product_str = str;
28467c478bd9Sstevel@tonic-gate (void) strcpy(ud->usb_product_str, tmpbuf);
28477c478bd9Sstevel@tonic-gate mutex_exit(&ud->usb_mutex);
28487c478bd9Sstevel@tonic-gate }
28497c478bd9Sstevel@tonic-gate }
28507c478bd9Sstevel@tonic-gate
28517c478bd9Sstevel@tonic-gate /* fetch device serial number string */
28527c478bd9Sstevel@tonic-gate if ((ud->usb_serialno_str == NULL) && usb_dev_descr->iSerialNumber &&
28537c478bd9Sstevel@tonic-gate (usb_get_string_descr(dip, USB_LANG_ID,
28547c478bd9Sstevel@tonic-gate usb_dev_descr->iSerialNumber, tmpbuf, USB_MAXSTRINGLEN) ==
28557c478bd9Sstevel@tonic-gate USB_SUCCESS)) {
28567c478bd9Sstevel@tonic-gate
28577c478bd9Sstevel@tonic-gate l = strlen(tmpbuf);
28587c478bd9Sstevel@tonic-gate if (l > 0) {
28597c478bd9Sstevel@tonic-gate str = kmem_zalloc(l + 1, KM_SLEEP);
28607c478bd9Sstevel@tonic-gate mutex_enter(&ud->usb_mutex);
28617c478bd9Sstevel@tonic-gate ud->usb_serialno_str = str;
28627c478bd9Sstevel@tonic-gate (void) strcpy(ud->usb_serialno_str, tmpbuf);
28637c478bd9Sstevel@tonic-gate mutex_exit(&ud->usb_mutex);
28647c478bd9Sstevel@tonic-gate }
28657c478bd9Sstevel@tonic-gate }
28667c478bd9Sstevel@tonic-gate
28677c478bd9Sstevel@tonic-gate kmem_free(tmpbuf, USB_MAXSTRINGLEN);
28687c478bd9Sstevel@tonic-gate }
28697c478bd9Sstevel@tonic-gate
28707c478bd9Sstevel@tonic-gate
28717c478bd9Sstevel@tonic-gate /*
28727c478bd9Sstevel@tonic-gate * usba_get_mfg_prod_sn_str:
28737c478bd9Sstevel@tonic-gate * Return a string containing mfg, product, serial number strings.
28747c478bd9Sstevel@tonic-gate * Remove duplicates if some strings are the same.
28757c478bd9Sstevel@tonic-gate *
28767c478bd9Sstevel@tonic-gate * Arguments:
28777c478bd9Sstevel@tonic-gate * dip - pointer to dev info
28787c478bd9Sstevel@tonic-gate * buffer - Where string is returned
28797c478bd9Sstevel@tonic-gate * buflen - Length of buffer
28807c478bd9Sstevel@tonic-gate *
28817c478bd9Sstevel@tonic-gate * Returns:
28827c478bd9Sstevel@tonic-gate * Same as second arg.
28837c478bd9Sstevel@tonic-gate */
28847c478bd9Sstevel@tonic-gate char *
usba_get_mfg_prod_sn_str(dev_info_t * dip,char * buffer,int buflen)28857c478bd9Sstevel@tonic-gate usba_get_mfg_prod_sn_str(
28867c478bd9Sstevel@tonic-gate dev_info_t *dip,
28877c478bd9Sstevel@tonic-gate char *buffer,
28887c478bd9Sstevel@tonic-gate int buflen)
28897c478bd9Sstevel@tonic-gate {
28907c478bd9Sstevel@tonic-gate usba_device_t *usba_device = usba_get_usba_device(dip);
28917c478bd9Sstevel@tonic-gate int return_len = 0;
28927c478bd9Sstevel@tonic-gate int len = 0;
28937c478bd9Sstevel@tonic-gate
28947c478bd9Sstevel@tonic-gate buffer[0] = '\0';
28957c478bd9Sstevel@tonic-gate buffer[buflen-1] = '\0';
28967c478bd9Sstevel@tonic-gate
28975c9564e1SJames Blachly /* Manufacturer string exists. */
28987c478bd9Sstevel@tonic-gate if ((usba_device->usb_mfg_str) &&
28997c478bd9Sstevel@tonic-gate ((len = strlen(usba_device->usb_mfg_str)) != 0)) {
29007c478bd9Sstevel@tonic-gate (void) strncpy(buffer, usba_device->usb_mfg_str, buflen - 1);
29017c478bd9Sstevel@tonic-gate return_len = min(buflen - 1, len);
29027c478bd9Sstevel@tonic-gate }
29037c478bd9Sstevel@tonic-gate
29047c478bd9Sstevel@tonic-gate /* Product string exists to append. */
29057c478bd9Sstevel@tonic-gate if ((usba_device->usb_product_str) &&
29067c478bd9Sstevel@tonic-gate ((len = strlen(usba_device->usb_product_str)) != 0)) {
29077c478bd9Sstevel@tonic-gate if (return_len > 0) {
29087c478bd9Sstevel@tonic-gate buffer[return_len++] = ' ';
29097c478bd9Sstevel@tonic-gate }
29107c478bd9Sstevel@tonic-gate (void) strncpy(&buffer[return_len],
29115c9564e1SJames Blachly usba_device->usb_product_str, buflen - return_len - 1);
29127c478bd9Sstevel@tonic-gate return_len = min(buflen - 1, return_len + len);
29137c478bd9Sstevel@tonic-gate }
29147c478bd9Sstevel@tonic-gate
29155c9564e1SJames Blachly /* Serial number string exists to append. */
29167c478bd9Sstevel@tonic-gate if ((usba_device->usb_serialno_str) &&
29177c478bd9Sstevel@tonic-gate ((len = strlen(usba_device->usb_serialno_str)) != 0)) {
29187c478bd9Sstevel@tonic-gate if (return_len > 0) {
29197c478bd9Sstevel@tonic-gate buffer[return_len++] = ' ';
29207c478bd9Sstevel@tonic-gate }
29217c478bd9Sstevel@tonic-gate (void) strncpy(&buffer[return_len],
29227c478bd9Sstevel@tonic-gate usba_device->usb_serialno_str,
29237c478bd9Sstevel@tonic-gate buflen - return_len - 1);
29247c478bd9Sstevel@tonic-gate }
29257c478bd9Sstevel@tonic-gate
29267c478bd9Sstevel@tonic-gate return (buffer);
29277c478bd9Sstevel@tonic-gate }
29287c478bd9Sstevel@tonic-gate
29297c478bd9Sstevel@tonic-gate /*
29307c478bd9Sstevel@tonic-gate * USB enumeration statistic functions
29317c478bd9Sstevel@tonic-gate */
29327c478bd9Sstevel@tonic-gate
29337c478bd9Sstevel@tonic-gate /*
29347c478bd9Sstevel@tonic-gate * Increments the hotplug statistics based on flags.
29357c478bd9Sstevel@tonic-gate */
29367c478bd9Sstevel@tonic-gate void
usba_update_hotplug_stats(dev_info_t * dip,usb_flags_t flags)29377c478bd9Sstevel@tonic-gate usba_update_hotplug_stats(dev_info_t *dip, usb_flags_t flags)
29387c478bd9Sstevel@tonic-gate {
29397c478bd9Sstevel@tonic-gate usba_device_t *usba_device = usba_get_usba_device(dip);
29407c478bd9Sstevel@tonic-gate usba_hcdi_t *hcdi =
29417c478bd9Sstevel@tonic-gate usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
29427c478bd9Sstevel@tonic-gate
29437c478bd9Sstevel@tonic-gate mutex_enter(&hcdi->hcdi_mutex);
29447c478bd9Sstevel@tonic-gate if (flags & USBA_TOTAL_HOTPLUG_SUCCESS) {
29457c478bd9Sstevel@tonic-gate hcdi->hcdi_total_hotplug_success++;
29467c478bd9Sstevel@tonic-gate HCDI_HOTPLUG_STATS_DATA(hcdi)->
29477c478bd9Sstevel@tonic-gate hcdi_hotplug_total_success.value.ui64++;
29487c478bd9Sstevel@tonic-gate }
29497c478bd9Sstevel@tonic-gate if (flags & USBA_HOTPLUG_SUCCESS) {
29507c478bd9Sstevel@tonic-gate hcdi->hcdi_hotplug_success++;
29517c478bd9Sstevel@tonic-gate HCDI_HOTPLUG_STATS_DATA(hcdi)->
29527c478bd9Sstevel@tonic-gate hcdi_hotplug_success.value.ui64++;
29537c478bd9Sstevel@tonic-gate }
29547c478bd9Sstevel@tonic-gate if (flags & USBA_TOTAL_HOTPLUG_FAILURE) {
29557c478bd9Sstevel@tonic-gate hcdi->hcdi_total_hotplug_failure++;
29567c478bd9Sstevel@tonic-gate HCDI_HOTPLUG_STATS_DATA(hcdi)->
29577c478bd9Sstevel@tonic-gate hcdi_hotplug_total_failure.value.ui64++;
29587c478bd9Sstevel@tonic-gate }
29597c478bd9Sstevel@tonic-gate if (flags & USBA_HOTPLUG_FAILURE) {
29607c478bd9Sstevel@tonic-gate hcdi->hcdi_hotplug_failure++;
29617c478bd9Sstevel@tonic-gate HCDI_HOTPLUG_STATS_DATA(hcdi)->
29627c478bd9Sstevel@tonic-gate hcdi_hotplug_failure.value.ui64++;
29637c478bd9Sstevel@tonic-gate }
29647c478bd9Sstevel@tonic-gate mutex_exit(&hcdi->hcdi_mutex);
29657c478bd9Sstevel@tonic-gate }
29667c478bd9Sstevel@tonic-gate
29677c478bd9Sstevel@tonic-gate
29687c478bd9Sstevel@tonic-gate /*
29697c478bd9Sstevel@tonic-gate * Retrieve the current enumeration statistics
29707c478bd9Sstevel@tonic-gate */
29717c478bd9Sstevel@tonic-gate void
usba_get_hotplug_stats(dev_info_t * dip,ulong_t * total_success,ulong_t * success,ulong_t * total_failure,ulong_t * failure,uchar_t * device_count)29727c478bd9Sstevel@tonic-gate usba_get_hotplug_stats(dev_info_t *dip, ulong_t *total_success,
29737c478bd9Sstevel@tonic-gate ulong_t *success, ulong_t *total_failure, ulong_t *failure,
29747c478bd9Sstevel@tonic-gate uchar_t *device_count)
29757c478bd9Sstevel@tonic-gate {
29767c478bd9Sstevel@tonic-gate usba_device_t *usba_device = usba_get_usba_device(dip);
29777c478bd9Sstevel@tonic-gate usba_hcdi_t *hcdi =
29787c478bd9Sstevel@tonic-gate usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
29797c478bd9Sstevel@tonic-gate
29807c478bd9Sstevel@tonic-gate mutex_enter(&hcdi->hcdi_mutex);
29817c478bd9Sstevel@tonic-gate *total_success = hcdi->hcdi_total_hotplug_success;
29827c478bd9Sstevel@tonic-gate *success = hcdi->hcdi_hotplug_success;
29837c478bd9Sstevel@tonic-gate *total_failure = hcdi->hcdi_total_hotplug_failure;
29847c478bd9Sstevel@tonic-gate *failure = hcdi->hcdi_hotplug_failure;
29857c478bd9Sstevel@tonic-gate *device_count = hcdi->hcdi_device_count;
29867c478bd9Sstevel@tonic-gate mutex_exit(&hcdi->hcdi_mutex);
29877c478bd9Sstevel@tonic-gate }
29887c478bd9Sstevel@tonic-gate
29897c478bd9Sstevel@tonic-gate
29907c478bd9Sstevel@tonic-gate /*
29917c478bd9Sstevel@tonic-gate * Reset the resetable hotplug stats
29927c478bd9Sstevel@tonic-gate */
29937c478bd9Sstevel@tonic-gate void
usba_reset_hotplug_stats(dev_info_t * dip)29947c478bd9Sstevel@tonic-gate usba_reset_hotplug_stats(dev_info_t *dip)
29957c478bd9Sstevel@tonic-gate {
29967c478bd9Sstevel@tonic-gate usba_device_t *usba_device = usba_get_usba_device(dip);
29977c478bd9Sstevel@tonic-gate usba_hcdi_t *hcdi =
29987c478bd9Sstevel@tonic-gate usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
29997c478bd9Sstevel@tonic-gate hcdi_hotplug_stats_t *hsp;
30007c478bd9Sstevel@tonic-gate
30017c478bd9Sstevel@tonic-gate mutex_enter(&hcdi->hcdi_mutex);
30027c478bd9Sstevel@tonic-gate hcdi->hcdi_hotplug_success = 0;
30037c478bd9Sstevel@tonic-gate hcdi->hcdi_hotplug_failure = 0;
30047c478bd9Sstevel@tonic-gate
30057c478bd9Sstevel@tonic-gate hsp = HCDI_HOTPLUG_STATS_DATA(hcdi);
30067c478bd9Sstevel@tonic-gate hsp->hcdi_hotplug_success.value.ui64 = 0;
30077c478bd9Sstevel@tonic-gate hsp->hcdi_hotplug_failure.value.ui64 = 0;
30087c478bd9Sstevel@tonic-gate mutex_exit(&hcdi->hcdi_mutex);
30097c478bd9Sstevel@tonic-gate }
30107c478bd9Sstevel@tonic-gate
30117c478bd9Sstevel@tonic-gate
30127c478bd9Sstevel@tonic-gate /*
30137c478bd9Sstevel@tonic-gate * usba_bind_driver():
30147c478bd9Sstevel@tonic-gate * This function calls ndi_devi_bind_driver() which tries to
30157c478bd9Sstevel@tonic-gate * bind a driver to the device. If the driver binding fails
30167c478bd9Sstevel@tonic-gate * we get an rval of NDI_UNBOUD and report an error to the
30177c478bd9Sstevel@tonic-gate * syslog that the driver failed binding.
30187c478bd9Sstevel@tonic-gate * If rval is something other than NDI_UNBOUND we report an
30197c478bd9Sstevel@tonic-gate * error to the console.
30207c478bd9Sstevel@tonic-gate *
30217c478bd9Sstevel@tonic-gate * This function returns USB_SUCCESS if no errors were
30227c478bd9Sstevel@tonic-gate * encountered while binding.
30237c478bd9Sstevel@tonic-gate */
30247c478bd9Sstevel@tonic-gate int
usba_bind_driver(dev_info_t * dip)30257c478bd9Sstevel@tonic-gate usba_bind_driver(dev_info_t *dip)
30267c478bd9Sstevel@tonic-gate {
30277c478bd9Sstevel@tonic-gate int rval;
30287c478bd9Sstevel@tonic-gate char *name;
30297c478bd9Sstevel@tonic-gate uint8_t if_num = usba_get_ifno(dip);
30307c478bd9Sstevel@tonic-gate
30317c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
3032112116d8Sfb209375 "usba_bind_driver: dip = 0x%p, if_num = 0x%x", (void *)dip, if_num);
30337c478bd9Sstevel@tonic-gate
30347c478bd9Sstevel@tonic-gate name = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
30357c478bd9Sstevel@tonic-gate
30367c478bd9Sstevel@tonic-gate /* bind device to the driver */
30377c478bd9Sstevel@tonic-gate if ((rval = ndi_devi_bind_driver(dip, 0)) != NDI_SUCCESS) {
30387c478bd9Sstevel@tonic-gate /* if we fail to bind report an error */
30397c478bd9Sstevel@tonic-gate (void) usba_get_mfg_prod_sn_str(dip, name, MAXNAMELEN);
30407c478bd9Sstevel@tonic-gate if (name[0] != '\0') {
30417c478bd9Sstevel@tonic-gate if (!usb_owns_device(dip)) {
30427c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(DPRINT_MASK_USBA,
30437c478bd9Sstevel@tonic-gate usba_log_handle,
30447c478bd9Sstevel@tonic-gate "no driver found for "
30457c478bd9Sstevel@tonic-gate "interface %d (nodename: '%s') of %s",
30467c478bd9Sstevel@tonic-gate if_num, ddi_node_name(dip), name);
30477c478bd9Sstevel@tonic-gate } else {
30487c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(DPRINT_MASK_USBA,
30497c478bd9Sstevel@tonic-gate usba_log_handle,
30507c478bd9Sstevel@tonic-gate "no driver found for device %s", name);
30517c478bd9Sstevel@tonic-gate }
30527c478bd9Sstevel@tonic-gate } else {
30537c478bd9Sstevel@tonic-gate (void) ddi_pathname(dip, name);
30547c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(DPRINT_MASK_USBA,
30557c478bd9Sstevel@tonic-gate usba_log_handle,
30567c478bd9Sstevel@tonic-gate "no driver found for device %s", name);
30577c478bd9Sstevel@tonic-gate }
30587c478bd9Sstevel@tonic-gate
30597c478bd9Sstevel@tonic-gate kmem_free(name, MAXNAMELEN);
30607c478bd9Sstevel@tonic-gate
30617c478bd9Sstevel@tonic-gate return (USB_FAILURE);
30627c478bd9Sstevel@tonic-gate }
30637c478bd9Sstevel@tonic-gate kmem_free(name, MAXNAMELEN);
30647c478bd9Sstevel@tonic-gate
30657c478bd9Sstevel@tonic-gate return ((rval == NDI_SUCCESS) ? USB_SUCCESS : USB_FAILURE);
30667c478bd9Sstevel@tonic-gate }
30677c478bd9Sstevel@tonic-gate
30687c478bd9Sstevel@tonic-gate
30697c478bd9Sstevel@tonic-gate /*
30707c478bd9Sstevel@tonic-gate * usba_get_hc_dma_attr:
30717c478bd9Sstevel@tonic-gate * function returning dma attributes of the HCD
30727c478bd9Sstevel@tonic-gate *
30737c478bd9Sstevel@tonic-gate * Arguments:
30747c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the client
30757c478bd9Sstevel@tonic-gate *
30767c478bd9Sstevel@tonic-gate * Return Values:
30777c478bd9Sstevel@tonic-gate * hcdi_dma_attr
30787c478bd9Sstevel@tonic-gate */
30797c478bd9Sstevel@tonic-gate ddi_dma_attr_t *
usba_get_hc_dma_attr(dev_info_t * dip)30807c478bd9Sstevel@tonic-gate usba_get_hc_dma_attr(dev_info_t *dip)
30817c478bd9Sstevel@tonic-gate {
30827c478bd9Sstevel@tonic-gate usba_device_t *usba_device = usba_get_usba_device(dip);
30837c478bd9Sstevel@tonic-gate usba_hcdi_t *hcdi = usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip);
30847c478bd9Sstevel@tonic-gate
30857c478bd9Sstevel@tonic-gate return (hcdi->hcdi_dma_attr);
30867c478bd9Sstevel@tonic-gate }
30877c478bd9Sstevel@tonic-gate
30887c478bd9Sstevel@tonic-gate
30897c478bd9Sstevel@tonic-gate /*
30907c478bd9Sstevel@tonic-gate * usba_check_for_leaks:
30917c478bd9Sstevel@tonic-gate * check usba_device structure for leaks
30927c478bd9Sstevel@tonic-gate *
30937c478bd9Sstevel@tonic-gate * Arguments:
30947c478bd9Sstevel@tonic-gate * usba_device - usba_device structure pointer
30957c478bd9Sstevel@tonic-gate */
30967c478bd9Sstevel@tonic-gate void
usba_check_for_leaks(usba_device_t * usba_device)30977c478bd9Sstevel@tonic-gate usba_check_for_leaks(usba_device_t *usba_device)
30987c478bd9Sstevel@tonic-gate {
30997c478bd9Sstevel@tonic-gate int i, ph_open_cnt, req_wrp_leaks, iface;
31007c478bd9Sstevel@tonic-gate int leaks = 0;
31017c478bd9Sstevel@tonic-gate
31027c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usba_log_handle,
31037c478bd9Sstevel@tonic-gate "usba_check_for_leaks: %s%d usba_device=0x%p",
31047c478bd9Sstevel@tonic-gate ddi_driver_name(usba_device->usb_dip),
3105112116d8Sfb209375 ddi_get_instance(usba_device->usb_dip), (void *)usba_device);
31067c478bd9Sstevel@tonic-gate
31077c478bd9Sstevel@tonic-gate /*
31087c478bd9Sstevel@tonic-gate * default pipe is still open
31097c478bd9Sstevel@tonic-gate * all other pipes should be closed
31107c478bd9Sstevel@tonic-gate */
31117c478bd9Sstevel@tonic-gate for (ph_open_cnt = 0, i = 1; i < USBA_N_ENDPOINTS; i++) {
31127c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl =
31137c478bd9Sstevel@tonic-gate &usba_device->usb_ph_list[i];
31147c478bd9Sstevel@tonic-gate if (ph_impl->usba_ph_data) {
3115d291d9f2Sfrits USB_DPRINTF_L2(DPRINT_MASK_USBA,
31167c478bd9Sstevel@tonic-gate usba_log_handle,
31177c478bd9Sstevel@tonic-gate "%s%d: leaking pipehandle=0x%p (0x%p) ep_addr=0x%x",
31187c478bd9Sstevel@tonic-gate ddi_driver_name(ph_impl->usba_ph_data->p_dip),
31197c478bd9Sstevel@tonic-gate ddi_get_instance(ph_impl->usba_ph_data->p_dip),
3120112116d8Sfb209375 (void *)ph_impl,
3121112116d8Sfb209375 (void *)ph_impl->usba_ph_data,
31227c478bd9Sstevel@tonic-gate ph_impl->usba_ph_ep.bEndpointAddress);
31237c478bd9Sstevel@tonic-gate ph_open_cnt++;
31247c478bd9Sstevel@tonic-gate leaks++;
31257c478bd9Sstevel@tonic-gate #ifndef DEBUG
31267c478bd9Sstevel@tonic-gate usb_pipe_close(ph_impl->usba_ph_data->p_dip,
31277c478bd9Sstevel@tonic-gate (usb_pipe_handle_t)ph_impl, USB_FLAGS_SLEEP,
31287c478bd9Sstevel@tonic-gate NULL, NULL);
31297c478bd9Sstevel@tonic-gate #endif
31307c478bd9Sstevel@tonic-gate }
31317c478bd9Sstevel@tonic-gate }
31327c478bd9Sstevel@tonic-gate req_wrp_leaks = usba_list_entry_leaks(&usba_device->
31337c478bd9Sstevel@tonic-gate usb_allocated, "request wrappers");
31347c478bd9Sstevel@tonic-gate
31357c478bd9Sstevel@tonic-gate ASSERT(ph_open_cnt == 0);
31367c478bd9Sstevel@tonic-gate ASSERT(req_wrp_leaks == 0);
31377c478bd9Sstevel@tonic-gate
31387c478bd9Sstevel@tonic-gate if (req_wrp_leaks) {
31397c478bd9Sstevel@tonic-gate usba_list_entry_t *entry;
31407c478bd9Sstevel@tonic-gate
31417c478bd9Sstevel@tonic-gate while ((entry = usba_rm_first_from_list(
31427c478bd9Sstevel@tonic-gate &usba_device->usb_allocated)) != NULL) {
31437c478bd9Sstevel@tonic-gate usba_req_wrapper_t *wrp;
31447c478bd9Sstevel@tonic-gate
31457c478bd9Sstevel@tonic-gate mutex_enter(&entry->list_mutex);
31467c478bd9Sstevel@tonic-gate wrp = (usba_req_wrapper_t *)entry->private;
31477c478bd9Sstevel@tonic-gate mutex_exit(&entry->list_mutex);
31487c478bd9Sstevel@tonic-gate leaks++;
31497c478bd9Sstevel@tonic-gate
3150d291d9f2Sfrits USB_DPRINTF_L2(DPRINT_MASK_USBA,
31517c478bd9Sstevel@tonic-gate usba_log_handle,
31527c478bd9Sstevel@tonic-gate "%s%d: leaking request 0x%p",
31537c478bd9Sstevel@tonic-gate ddi_driver_name(wrp->wr_dip),
31547c478bd9Sstevel@tonic-gate ddi_get_instance(wrp->wr_dip),
3155112116d8Sfb209375 (void *)wrp->wr_req);
31567c478bd9Sstevel@tonic-gate
31577c478bd9Sstevel@tonic-gate /*
31587c478bd9Sstevel@tonic-gate * put it back, usba_req_wrapper_free
31597c478bd9Sstevel@tonic-gate * expects it on the list
31607c478bd9Sstevel@tonic-gate */
31617c478bd9Sstevel@tonic-gate usba_add_to_list(&usba_device->usb_allocated,
31627c478bd9Sstevel@tonic-gate &wrp->wr_allocated_list);
31637c478bd9Sstevel@tonic-gate
31647c478bd9Sstevel@tonic-gate usba_req_wrapper_free(wrp);
31657c478bd9Sstevel@tonic-gate }
31667c478bd9Sstevel@tonic-gate }
31677c478bd9Sstevel@tonic-gate
31687c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex);
31697c478bd9Sstevel@tonic-gate for (iface = 0; iface < usba_device->usb_n_ifs; iface++) {
31707c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
31717c478bd9Sstevel@tonic-gate "usba_check_for_leaks: if=%d client_flags=0x%x",
31727c478bd9Sstevel@tonic-gate iface, usba_device->usb_client_flags[iface]);
31737c478bd9Sstevel@tonic-gate
31747c478bd9Sstevel@tonic-gate if (usba_device->usb_client_flags[iface] &
31757c478bd9Sstevel@tonic-gate USBA_CLIENT_FLAG_DEV_DATA) {
31767c478bd9Sstevel@tonic-gate usb_client_dev_data_list_t *entry =
31777c478bd9Sstevel@tonic-gate usba_device->usb_client_dev_data_list.cddl_next;
31787c478bd9Sstevel@tonic-gate usb_client_dev_data_list_t *next;
31797c478bd9Sstevel@tonic-gate usb_client_dev_data_t *dev_data;
31807c478bd9Sstevel@tonic-gate
31817c478bd9Sstevel@tonic-gate while (entry) {
31827c478bd9Sstevel@tonic-gate dev_info_t *dip = entry->cddl_dip;
31837c478bd9Sstevel@tonic-gate next = entry->cddl_next;
31847c478bd9Sstevel@tonic-gate dev_data = entry->cddl_dev_data;
31857c478bd9Sstevel@tonic-gate
31867c478bd9Sstevel@tonic-gate
3187737d277aScth if (!i_ddi_devi_attached(dip)) {
3188d291d9f2Sfrits USB_DPRINTF_L2(DPRINT_MASK_USBA,
31897c478bd9Sstevel@tonic-gate usba_log_handle,
31907c478bd9Sstevel@tonic-gate "%s%d: leaking dev_data 0x%p",
31917c478bd9Sstevel@tonic-gate ddi_driver_name(dip),
31927c478bd9Sstevel@tonic-gate ddi_get_instance(dip),
31937c478bd9Sstevel@tonic-gate (void *)dev_data);
31947c478bd9Sstevel@tonic-gate
31957c478bd9Sstevel@tonic-gate leaks++;
31967c478bd9Sstevel@tonic-gate
31977c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex);
31987c478bd9Sstevel@tonic-gate usb_free_dev_data(dip, dev_data);
31997c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex);
32007c478bd9Sstevel@tonic-gate }
32017c478bd9Sstevel@tonic-gate
32027c478bd9Sstevel@tonic-gate entry = next;
32037c478bd9Sstevel@tonic-gate }
32047c478bd9Sstevel@tonic-gate }
32057c478bd9Sstevel@tonic-gate if (usba_device->usb_client_flags[iface] &
32067c478bd9Sstevel@tonic-gate USBA_CLIENT_FLAG_ATTACH) {
32077c478bd9Sstevel@tonic-gate dev_info_t *dip = usba_device->
32087c478bd9Sstevel@tonic-gate usb_client_attach_list[iface].dip;
32097c478bd9Sstevel@tonic-gate
3210d291d9f2Sfrits USB_DPRINTF_L2(DPRINT_MASK_USBA,
32117c478bd9Sstevel@tonic-gate usba_log_handle,
32127c478bd9Sstevel@tonic-gate "%s%d: did no usb_client_detach",
32137c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip));
32147c478bd9Sstevel@tonic-gate leaks++;
32157c478bd9Sstevel@tonic-gate
32167c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex);
32177c478bd9Sstevel@tonic-gate usb_client_detach(dip, NULL);
32187c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex);
32197c478bd9Sstevel@tonic-gate
32207c478bd9Sstevel@tonic-gate usba_device->
32217c478bd9Sstevel@tonic-gate usb_client_attach_list[iface].dip = NULL;
32227c478bd9Sstevel@tonic-gate
32237c478bd9Sstevel@tonic-gate usba_device->usb_client_flags[iface] &=
32247c478bd9Sstevel@tonic-gate ~USBA_CLIENT_FLAG_ATTACH;
32257c478bd9Sstevel@tonic-gate
32267c478bd9Sstevel@tonic-gate }
32277c478bd9Sstevel@tonic-gate if (usba_device->usb_client_flags[iface] &
32287c478bd9Sstevel@tonic-gate USBA_CLIENT_FLAG_EV_CBS) {
32297c478bd9Sstevel@tonic-gate dev_info_t *dip =
32307c478bd9Sstevel@tonic-gate usba_device->usb_client_ev_cb_list[iface].
32317c478bd9Sstevel@tonic-gate dip;
32327c478bd9Sstevel@tonic-gate usb_event_t *ev_data =
32337c478bd9Sstevel@tonic-gate usba_device->usb_client_ev_cb_list[iface].
32347c478bd9Sstevel@tonic-gate ev_data;
32357c478bd9Sstevel@tonic-gate
3236d291d9f2Sfrits USB_DPRINTF_L2(DPRINT_MASK_USBA,
32377c478bd9Sstevel@tonic-gate usba_log_handle,
32387c478bd9Sstevel@tonic-gate "%s%d: did no usb_unregister_event_cbs",
32397c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip));
32407c478bd9Sstevel@tonic-gate leaks++;
32417c478bd9Sstevel@tonic-gate
32427c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex);
32437c478bd9Sstevel@tonic-gate usb_unregister_event_cbs(dip, ev_data);
32447c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex);
32457c478bd9Sstevel@tonic-gate
32467c478bd9Sstevel@tonic-gate usba_device->usb_client_ev_cb_list[iface].
32477c478bd9Sstevel@tonic-gate dip = NULL;
32487c478bd9Sstevel@tonic-gate usba_device->usb_client_ev_cb_list[iface].
32497c478bd9Sstevel@tonic-gate ev_data = NULL;
32507c478bd9Sstevel@tonic-gate usba_device->usb_client_flags[iface] &=
32517c478bd9Sstevel@tonic-gate ~USBA_CLIENT_FLAG_EV_CBS;
32527c478bd9Sstevel@tonic-gate }
32537c478bd9Sstevel@tonic-gate }
32547c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex);
32557c478bd9Sstevel@tonic-gate
32567c478bd9Sstevel@tonic-gate if (leaks) {
3257d291d9f2Sfrits USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
32587c478bd9Sstevel@tonic-gate "all %d leaks fixed", leaks);
32597c478bd9Sstevel@tonic-gate }
32607c478bd9Sstevel@tonic-gate }
3261