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