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 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 23*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 24*7c478bd9Sstevel@tonic-gate */ 25*7c478bd9Sstevel@tonic-gate 26*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 27*7c478bd9Sstevel@tonic-gate 28*7c478bd9Sstevel@tonic-gate /* 29*7c478bd9Sstevel@tonic-gate * usb multi interface and common class driver 30*7c478bd9Sstevel@tonic-gate * 31*7c478bd9Sstevel@tonic-gate * this driver attempts to attach each interface to a driver 32*7c478bd9Sstevel@tonic-gate * and may eventually handle common class features such as 33*7c478bd9Sstevel@tonic-gate * shared endpoints 34*7c478bd9Sstevel@tonic-gate */ 35*7c478bd9Sstevel@tonic-gate 36*7c478bd9Sstevel@tonic-gate #if defined(lint) && !defined(DEBUG) 37*7c478bd9Sstevel@tonic-gate #define DEBUG 1 38*7c478bd9Sstevel@tonic-gate #endif 39*7c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usbai_version.h> 40*7c478bd9Sstevel@tonic-gate #include <sys/usb/usba.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usba_types.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usba_impl.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usba_ugen.h> 44*7c478bd9Sstevel@tonic-gate #include <sys/usb/usb_mid/usb_midvar.h> 45*7c478bd9Sstevel@tonic-gate 46*7c478bd9Sstevel@tonic-gate void usba_free_evdata(usba_evdata_t *); 47*7c478bd9Sstevel@tonic-gate 48*7c478bd9Sstevel@tonic-gate /* Debugging support */ 49*7c478bd9Sstevel@tonic-gate static uint_t usb_mid_errlevel = USB_LOG_L4; 50*7c478bd9Sstevel@tonic-gate static uint_t usb_mid_errmask = (uint_t)DPRINT_MASK_ALL; 51*7c478bd9Sstevel@tonic-gate static uint_t usb_mid_instance_debug = (uint_t)-1; 52*7c478bd9Sstevel@tonic-gate static uint_t usb_mid_bus_config_debug = 0; 53*7c478bd9Sstevel@tonic-gate 54*7c478bd9Sstevel@tonic-gate _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_mid_errlevel)) 55*7c478bd9Sstevel@tonic-gate _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_mid_errmask)) 56*7c478bd9Sstevel@tonic-gate _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_mid_instance_debug)) 57*7c478bd9Sstevel@tonic-gate 58*7c478bd9Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unique", msgb)) 59*7c478bd9Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unique", dev_info)) 60*7c478bd9Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unique", usb_pipe_policy)) 61*7c478bd9Sstevel@tonic-gate 62*7c478bd9Sstevel@tonic-gate /* 63*7c478bd9Sstevel@tonic-gate * Hotplug support 64*7c478bd9Sstevel@tonic-gate * Leaf ops (hotplug controls for client devices) 65*7c478bd9Sstevel@tonic-gate */ 66*7c478bd9Sstevel@tonic-gate static int usb_mid_open(dev_t *, int, int, cred_t *); 67*7c478bd9Sstevel@tonic-gate static int usb_mid_close(dev_t, int, int, cred_t *); 68*7c478bd9Sstevel@tonic-gate static int usb_mid_read(dev_t, struct uio *, cred_t *); 69*7c478bd9Sstevel@tonic-gate static int usb_mid_write(dev_t, struct uio *, cred_t *); 70*7c478bd9Sstevel@tonic-gate static int usb_mid_poll(dev_t, short, int, short *, 71*7c478bd9Sstevel@tonic-gate struct pollhead **); 72*7c478bd9Sstevel@tonic-gate 73*7c478bd9Sstevel@tonic-gate static struct cb_ops usb_mid_cb_ops = { 74*7c478bd9Sstevel@tonic-gate usb_mid_open, 75*7c478bd9Sstevel@tonic-gate usb_mid_close, 76*7c478bd9Sstevel@tonic-gate nodev, /* strategy */ 77*7c478bd9Sstevel@tonic-gate nodev, /* print */ 78*7c478bd9Sstevel@tonic-gate nodev, /* dump */ 79*7c478bd9Sstevel@tonic-gate usb_mid_read, /* read */ 80*7c478bd9Sstevel@tonic-gate usb_mid_write, /* write */ 81*7c478bd9Sstevel@tonic-gate nodev, 82*7c478bd9Sstevel@tonic-gate nodev, /* devmap */ 83*7c478bd9Sstevel@tonic-gate nodev, /* mmap */ 84*7c478bd9Sstevel@tonic-gate nodev, /* segmap */ 85*7c478bd9Sstevel@tonic-gate usb_mid_poll, /* poll */ 86*7c478bd9Sstevel@tonic-gate ddi_prop_op, /* prop_op */ 87*7c478bd9Sstevel@tonic-gate NULL, 88*7c478bd9Sstevel@tonic-gate D_MP 89*7c478bd9Sstevel@tonic-gate }; 90*7c478bd9Sstevel@tonic-gate 91*7c478bd9Sstevel@tonic-gate static int usb_mid_busop_get_eventcookie(dev_info_t *dip, 92*7c478bd9Sstevel@tonic-gate dev_info_t *rdip, 93*7c478bd9Sstevel@tonic-gate char *eventname, 94*7c478bd9Sstevel@tonic-gate ddi_eventcookie_t *cookie); 95*7c478bd9Sstevel@tonic-gate static int usb_mid_busop_add_eventcall(dev_info_t *dip, 96*7c478bd9Sstevel@tonic-gate dev_info_t *rdip, 97*7c478bd9Sstevel@tonic-gate ddi_eventcookie_t cookie, 98*7c478bd9Sstevel@tonic-gate void (*callback)(dev_info_t *dip, 99*7c478bd9Sstevel@tonic-gate ddi_eventcookie_t cookie, void *arg, 100*7c478bd9Sstevel@tonic-gate void *bus_impldata), 101*7c478bd9Sstevel@tonic-gate void *arg, ddi_callback_id_t *cb_id); 102*7c478bd9Sstevel@tonic-gate static int usb_mid_busop_remove_eventcall(dev_info_t *dip, 103*7c478bd9Sstevel@tonic-gate ddi_callback_id_t cb_id); 104*7c478bd9Sstevel@tonic-gate static int usb_mid_busop_post_event(dev_info_t *dip, 105*7c478bd9Sstevel@tonic-gate dev_info_t *rdip, 106*7c478bd9Sstevel@tonic-gate ddi_eventcookie_t cookie, 107*7c478bd9Sstevel@tonic-gate void *bus_impldata); 108*7c478bd9Sstevel@tonic-gate static int usb_mid_bus_config(dev_info_t *dip, 109*7c478bd9Sstevel@tonic-gate uint_t flag, 110*7c478bd9Sstevel@tonic-gate ddi_bus_config_op_t op, 111*7c478bd9Sstevel@tonic-gate void *arg, 112*7c478bd9Sstevel@tonic-gate dev_info_t **child); 113*7c478bd9Sstevel@tonic-gate static int usb_mid_bus_unconfig(dev_info_t *dip, 114*7c478bd9Sstevel@tonic-gate uint_t flag, 115*7c478bd9Sstevel@tonic-gate ddi_bus_config_op_t op, 116*7c478bd9Sstevel@tonic-gate void *arg); 117*7c478bd9Sstevel@tonic-gate 118*7c478bd9Sstevel@tonic-gate 119*7c478bd9Sstevel@tonic-gate /* 120*7c478bd9Sstevel@tonic-gate * autoconfiguration data and routines. 121*7c478bd9Sstevel@tonic-gate */ 122*7c478bd9Sstevel@tonic-gate static int usb_mid_info(dev_info_t *, ddi_info_cmd_t, 123*7c478bd9Sstevel@tonic-gate void *, void **); 124*7c478bd9Sstevel@tonic-gate static int usb_mid_attach(dev_info_t *, ddi_attach_cmd_t); 125*7c478bd9Sstevel@tonic-gate static int usb_mid_detach(dev_info_t *, ddi_detach_cmd_t); 126*7c478bd9Sstevel@tonic-gate 127*7c478bd9Sstevel@tonic-gate /* other routines */ 128*7c478bd9Sstevel@tonic-gate static void usb_mid_create_pm_components(dev_info_t *, usb_mid_t *); 129*7c478bd9Sstevel@tonic-gate static int usb_mid_bus_ctl(dev_info_t *, dev_info_t *, 130*7c478bd9Sstevel@tonic-gate ddi_ctl_enum_t, void *, void *); 131*7c478bd9Sstevel@tonic-gate static int usb_mid_power(dev_info_t *, int, int); 132*7c478bd9Sstevel@tonic-gate static int usb_mid_restore_device_state(dev_info_t *, usb_mid_t *); 133*7c478bd9Sstevel@tonic-gate static usb_mid_t *usb_mid_obtain_state(dev_info_t *); 134*7c478bd9Sstevel@tonic-gate 135*7c478bd9Sstevel@tonic-gate /* 136*7c478bd9Sstevel@tonic-gate * Busops vector 137*7c478bd9Sstevel@tonic-gate */ 138*7c478bd9Sstevel@tonic-gate static struct bus_ops usb_mid_busops = { 139*7c478bd9Sstevel@tonic-gate BUSO_REV, 140*7c478bd9Sstevel@tonic-gate nullbusmap, /* bus_map */ 141*7c478bd9Sstevel@tonic-gate NULL, /* bus_get_intrspec */ 142*7c478bd9Sstevel@tonic-gate NULL, /* bus_add_intrspec */ 143*7c478bd9Sstevel@tonic-gate NULL, /* bus_remove_intrspec */ 144*7c478bd9Sstevel@tonic-gate NULL, /* XXXX bus_map_fault */ 145*7c478bd9Sstevel@tonic-gate ddi_dma_map, /* bus_dma_map */ 146*7c478bd9Sstevel@tonic-gate ddi_dma_allochdl, 147*7c478bd9Sstevel@tonic-gate ddi_dma_freehdl, 148*7c478bd9Sstevel@tonic-gate ddi_dma_bindhdl, 149*7c478bd9Sstevel@tonic-gate ddi_dma_unbindhdl, 150*7c478bd9Sstevel@tonic-gate ddi_dma_flush, 151*7c478bd9Sstevel@tonic-gate ddi_dma_win, 152*7c478bd9Sstevel@tonic-gate ddi_dma_mctl, /* bus_dma_ctl */ 153*7c478bd9Sstevel@tonic-gate usb_mid_bus_ctl, /* bus_ctl */ 154*7c478bd9Sstevel@tonic-gate ddi_bus_prop_op, /* bus_prop_op */ 155*7c478bd9Sstevel@tonic-gate usb_mid_busop_get_eventcookie, 156*7c478bd9Sstevel@tonic-gate usb_mid_busop_add_eventcall, 157*7c478bd9Sstevel@tonic-gate usb_mid_busop_remove_eventcall, 158*7c478bd9Sstevel@tonic-gate usb_mid_busop_post_event, /* bus_post_event */ 159*7c478bd9Sstevel@tonic-gate NULL, /* bus_intr_ctl */ 160*7c478bd9Sstevel@tonic-gate usb_mid_bus_config, /* bus_config */ 161*7c478bd9Sstevel@tonic-gate usb_mid_bus_unconfig, /* bus_unconfig */ 162*7c478bd9Sstevel@tonic-gate NULL, /* bus_fm_init */ 163*7c478bd9Sstevel@tonic-gate NULL, /* bus_fm_fini */ 164*7c478bd9Sstevel@tonic-gate NULL, /* bus_fm_access_enter */ 165*7c478bd9Sstevel@tonic-gate NULL, /* bus_fm_access_exit */ 166*7c478bd9Sstevel@tonic-gate NULL /* bus_power */ 167*7c478bd9Sstevel@tonic-gate }; 168*7c478bd9Sstevel@tonic-gate 169*7c478bd9Sstevel@tonic-gate 170*7c478bd9Sstevel@tonic-gate static struct dev_ops usb_mid_ops = { 171*7c478bd9Sstevel@tonic-gate DEVO_REV, /* devo_rev, */ 172*7c478bd9Sstevel@tonic-gate 0, /* refcnt */ 173*7c478bd9Sstevel@tonic-gate usb_mid_info, /* info */ 174*7c478bd9Sstevel@tonic-gate nulldev, /* identify */ 175*7c478bd9Sstevel@tonic-gate nulldev, /* probe */ 176*7c478bd9Sstevel@tonic-gate usb_mid_attach, /* attach */ 177*7c478bd9Sstevel@tonic-gate usb_mid_detach, /* detach */ 178*7c478bd9Sstevel@tonic-gate nodev, /* reset */ 179*7c478bd9Sstevel@tonic-gate &usb_mid_cb_ops, /* driver operations */ 180*7c478bd9Sstevel@tonic-gate &usb_mid_busops, /* bus operations */ 181*7c478bd9Sstevel@tonic-gate usb_mid_power /* power */ 182*7c478bd9Sstevel@tonic-gate }; 183*7c478bd9Sstevel@tonic-gate 184*7c478bd9Sstevel@tonic-gate static struct modldrv modldrv = { 185*7c478bd9Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a driver */ 186*7c478bd9Sstevel@tonic-gate "USB Multi Interface Driver %I%", /* Name of the module. */ 187*7c478bd9Sstevel@tonic-gate &usb_mid_ops, /* driver ops */ 188*7c478bd9Sstevel@tonic-gate }; 189*7c478bd9Sstevel@tonic-gate 190*7c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 191*7c478bd9Sstevel@tonic-gate MODREV_1, (void *)&modldrv, NULL 192*7c478bd9Sstevel@tonic-gate }; 193*7c478bd9Sstevel@tonic-gate 194*7c478bd9Sstevel@tonic-gate #define USB_MID_INITIAL_SOFT_SPACE 4 195*7c478bd9Sstevel@tonic-gate static void *usb_mid_statep; 196*7c478bd9Sstevel@tonic-gate 197*7c478bd9Sstevel@tonic-gate 198*7c478bd9Sstevel@tonic-gate /* 199*7c478bd9Sstevel@tonic-gate * prototypes 200*7c478bd9Sstevel@tonic-gate */ 201*7c478bd9Sstevel@tonic-gate static void usb_mid_create_children(usb_mid_t *usb_mid); 202*7c478bd9Sstevel@tonic-gate static int usb_mid_cleanup(dev_info_t *dip, usb_mid_t *usb_mid); 203*7c478bd9Sstevel@tonic-gate static void usb_mid_register_events(usb_mid_t *usb_mid); 204*7c478bd9Sstevel@tonic-gate static void usb_mid_unregister_events(usb_mid_t *usb_mid); 205*7c478bd9Sstevel@tonic-gate 206*7c478bd9Sstevel@tonic-gate /* usbai private */ 207*7c478bd9Sstevel@tonic-gate char *usba_get_mfg_prod_sn_str(dev_info_t *dip, 208*7c478bd9Sstevel@tonic-gate char *buffer, int buflen); 209*7c478bd9Sstevel@tonic-gate 210*7c478bd9Sstevel@tonic-gate /* 211*7c478bd9Sstevel@tonic-gate * event definition 212*7c478bd9Sstevel@tonic-gate */ 213*7c478bd9Sstevel@tonic-gate static ndi_event_definition_t usb_mid_ndi_event_defs[] = { 214*7c478bd9Sstevel@tonic-gate {USBA_EVENT_TAG_HOT_REMOVAL, DDI_DEVI_REMOVE_EVENT, EPL_KERNEL, 215*7c478bd9Sstevel@tonic-gate NDI_EVENT_POST_TO_ALL}, 216*7c478bd9Sstevel@tonic-gate {USBA_EVENT_TAG_HOT_INSERTION, DDI_DEVI_INSERT_EVENT, EPL_KERNEL, 217*7c478bd9Sstevel@tonic-gate NDI_EVENT_POST_TO_ALL}, 218*7c478bd9Sstevel@tonic-gate {USBA_EVENT_TAG_POST_RESUME, USBA_POST_RESUME_EVENT, EPL_KERNEL, 219*7c478bd9Sstevel@tonic-gate NDI_EVENT_POST_TO_ALL}, 220*7c478bd9Sstevel@tonic-gate {USBA_EVENT_TAG_PRE_SUSPEND, USBA_PRE_SUSPEND_EVENT, EPL_KERNEL, 221*7c478bd9Sstevel@tonic-gate NDI_EVENT_POST_TO_ALL} 222*7c478bd9Sstevel@tonic-gate }; 223*7c478bd9Sstevel@tonic-gate 224*7c478bd9Sstevel@tonic-gate #define USB_MID_N_NDI_EVENTS \ 225*7c478bd9Sstevel@tonic-gate (sizeof (usb_mid_ndi_event_defs) / sizeof (ndi_event_definition_t)) 226*7c478bd9Sstevel@tonic-gate 227*7c478bd9Sstevel@tonic-gate static ndi_event_set_t usb_mid_ndi_events = { 228*7c478bd9Sstevel@tonic-gate NDI_EVENTS_REV1, USB_MID_N_NDI_EVENTS, usb_mid_ndi_event_defs}; 229*7c478bd9Sstevel@tonic-gate 230*7c478bd9Sstevel@tonic-gate 231*7c478bd9Sstevel@tonic-gate /* 232*7c478bd9Sstevel@tonic-gate * standard driver entry points 233*7c478bd9Sstevel@tonic-gate */ 234*7c478bd9Sstevel@tonic-gate int 235*7c478bd9Sstevel@tonic-gate _init(void) 236*7c478bd9Sstevel@tonic-gate { 237*7c478bd9Sstevel@tonic-gate int rval; 238*7c478bd9Sstevel@tonic-gate 239*7c478bd9Sstevel@tonic-gate rval = ddi_soft_state_init(&usb_mid_statep, sizeof (struct usb_mid), 240*7c478bd9Sstevel@tonic-gate USB_MID_INITIAL_SOFT_SPACE); 241*7c478bd9Sstevel@tonic-gate if (rval != 0) { 242*7c478bd9Sstevel@tonic-gate return (rval); 243*7c478bd9Sstevel@tonic-gate } 244*7c478bd9Sstevel@tonic-gate 245*7c478bd9Sstevel@tonic-gate if ((rval = mod_install(&modlinkage)) != 0) { 246*7c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&usb_mid_statep); 247*7c478bd9Sstevel@tonic-gate return (rval); 248*7c478bd9Sstevel@tonic-gate } 249*7c478bd9Sstevel@tonic-gate 250*7c478bd9Sstevel@tonic-gate return (rval); 251*7c478bd9Sstevel@tonic-gate } 252*7c478bd9Sstevel@tonic-gate 253*7c478bd9Sstevel@tonic-gate 254*7c478bd9Sstevel@tonic-gate int 255*7c478bd9Sstevel@tonic-gate _fini(void) 256*7c478bd9Sstevel@tonic-gate { 257*7c478bd9Sstevel@tonic-gate int rval; 258*7c478bd9Sstevel@tonic-gate 259*7c478bd9Sstevel@tonic-gate rval = mod_remove(&modlinkage); 260*7c478bd9Sstevel@tonic-gate 261*7c478bd9Sstevel@tonic-gate if (rval) { 262*7c478bd9Sstevel@tonic-gate return (rval); 263*7c478bd9Sstevel@tonic-gate } 264*7c478bd9Sstevel@tonic-gate 265*7c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&usb_mid_statep); 266*7c478bd9Sstevel@tonic-gate 267*7c478bd9Sstevel@tonic-gate return (rval); 268*7c478bd9Sstevel@tonic-gate } 269*7c478bd9Sstevel@tonic-gate 270*7c478bd9Sstevel@tonic-gate 271*7c478bd9Sstevel@tonic-gate int 272*7c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 273*7c478bd9Sstevel@tonic-gate { 274*7c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 275*7c478bd9Sstevel@tonic-gate } 276*7c478bd9Sstevel@tonic-gate 277*7c478bd9Sstevel@tonic-gate 278*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 279*7c478bd9Sstevel@tonic-gate static int 280*7c478bd9Sstevel@tonic-gate usb_mid_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 281*7c478bd9Sstevel@tonic-gate { 282*7c478bd9Sstevel@tonic-gate usb_mid_t *usb_mid; 283*7c478bd9Sstevel@tonic-gate int instance = 284*7c478bd9Sstevel@tonic-gate USB_MID_MINOR_TO_INSTANCE(getminor((dev_t)arg)); 285*7c478bd9Sstevel@tonic-gate int error = DDI_FAILURE; 286*7c478bd9Sstevel@tonic-gate 287*7c478bd9Sstevel@tonic-gate switch (infocmd) { 288*7c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 289*7c478bd9Sstevel@tonic-gate if ((usb_mid = ddi_get_soft_state(usb_mid_statep, 290*7c478bd9Sstevel@tonic-gate instance)) != NULL) { 291*7c478bd9Sstevel@tonic-gate *result = (void *)usb_mid->mi_dip; 292*7c478bd9Sstevel@tonic-gate if (*result != NULL) { 293*7c478bd9Sstevel@tonic-gate error = DDI_SUCCESS; 294*7c478bd9Sstevel@tonic-gate } 295*7c478bd9Sstevel@tonic-gate } else { 296*7c478bd9Sstevel@tonic-gate *result = NULL; 297*7c478bd9Sstevel@tonic-gate } 298*7c478bd9Sstevel@tonic-gate break; 299*7c478bd9Sstevel@tonic-gate 300*7c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 301*7c478bd9Sstevel@tonic-gate *result = (void *)(intptr_t)instance; 302*7c478bd9Sstevel@tonic-gate error = DDI_SUCCESS; 303*7c478bd9Sstevel@tonic-gate break; 304*7c478bd9Sstevel@tonic-gate default: 305*7c478bd9Sstevel@tonic-gate break; 306*7c478bd9Sstevel@tonic-gate } 307*7c478bd9Sstevel@tonic-gate 308*7c478bd9Sstevel@tonic-gate return (error); 309*7c478bd9Sstevel@tonic-gate } 310*7c478bd9Sstevel@tonic-gate 311*7c478bd9Sstevel@tonic-gate 312*7c478bd9Sstevel@tonic-gate /* 313*7c478bd9Sstevel@tonic-gate * child post attach/detach notification 314*7c478bd9Sstevel@tonic-gate */ 315*7c478bd9Sstevel@tonic-gate static void 316*7c478bd9Sstevel@tonic-gate usb_mid_post_attach(usb_mid_t *usb_mid, uint8_t ifno, struct attachspec *as) 317*7c478bd9Sstevel@tonic-gate { 318*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_PM, usb_mid->mi_log_handle, 319*7c478bd9Sstevel@tonic-gate "usb_mid_post_attach: ifno = %d result = %d", ifno, as->result); 320*7c478bd9Sstevel@tonic-gate 321*7c478bd9Sstevel@tonic-gate /* if child successfully attached, set power */ 322*7c478bd9Sstevel@tonic-gate if (as->result == DDI_SUCCESS) { 323*7c478bd9Sstevel@tonic-gate /* 324*7c478bd9Sstevel@tonic-gate * Check if the child created wants to be power managed. 325*7c478bd9Sstevel@tonic-gate * If yes, the childs power level gets automatically tracked 326*7c478bd9Sstevel@tonic-gate * by DDI_CTLOPS_POWER busctl. 327*7c478bd9Sstevel@tonic-gate * If no, we set power of the new child by default 328*7c478bd9Sstevel@tonic-gate * to USB_DEV_OS_FULL_PWR. Because we should never suspend. 329*7c478bd9Sstevel@tonic-gate */ 330*7c478bd9Sstevel@tonic-gate mutex_enter(&usb_mid->mi_mutex); 331*7c478bd9Sstevel@tonic-gate usb_mid->mi_attach_count++; 332*7c478bd9Sstevel@tonic-gate mutex_exit(&usb_mid->mi_mutex); 333*7c478bd9Sstevel@tonic-gate } 334*7c478bd9Sstevel@tonic-gate } 335*7c478bd9Sstevel@tonic-gate 336*7c478bd9Sstevel@tonic-gate 337*7c478bd9Sstevel@tonic-gate static void 338*7c478bd9Sstevel@tonic-gate usb_mid_post_detach(usb_mid_t *usb_mid, uint8_t ifno, struct detachspec *ds) 339*7c478bd9Sstevel@tonic-gate { 340*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_PM, usb_mid->mi_log_handle, 341*7c478bd9Sstevel@tonic-gate "usb_mid_post_detach: ifno = %d result = %d", ifno, ds->result); 342*7c478bd9Sstevel@tonic-gate 343*7c478bd9Sstevel@tonic-gate /* 344*7c478bd9Sstevel@tonic-gate * if the device is successfully detached, 345*7c478bd9Sstevel@tonic-gate * mark component as idle 346*7c478bd9Sstevel@tonic-gate */ 347*7c478bd9Sstevel@tonic-gate if (ds->result == DDI_SUCCESS) { 348*7c478bd9Sstevel@tonic-gate usba_device_t *usba_device = 349*7c478bd9Sstevel@tonic-gate usba_get_usba_device(usb_mid->mi_dip); 350*7c478bd9Sstevel@tonic-gate 351*7c478bd9Sstevel@tonic-gate mutex_enter(&usb_mid->mi_mutex); 352*7c478bd9Sstevel@tonic-gate 353*7c478bd9Sstevel@tonic-gate /* check for leaks except when where is a ugen open */ 354*7c478bd9Sstevel@tonic-gate if ((ds->cmd == DDI_DETACH) && 355*7c478bd9Sstevel@tonic-gate (--usb_mid->mi_attach_count == 0) && usba_device && 356*7c478bd9Sstevel@tonic-gate (usb_mid->mi_ugen_open_count == 0)) { 357*7c478bd9Sstevel@tonic-gate usba_check_for_leaks(usba_device); 358*7c478bd9Sstevel@tonic-gate } 359*7c478bd9Sstevel@tonic-gate mutex_exit(&usb_mid->mi_mutex); 360*7c478bd9Sstevel@tonic-gate } 361*7c478bd9Sstevel@tonic-gate } 362*7c478bd9Sstevel@tonic-gate 363*7c478bd9Sstevel@tonic-gate 364*7c478bd9Sstevel@tonic-gate /* 365*7c478bd9Sstevel@tonic-gate * bus ctl support. we handle notifications here and the 366*7c478bd9Sstevel@tonic-gate * rest goes up to root hub/hcd 367*7c478bd9Sstevel@tonic-gate */ 368*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 369*7c478bd9Sstevel@tonic-gate static int 370*7c478bd9Sstevel@tonic-gate usb_mid_bus_ctl(dev_info_t *dip, 371*7c478bd9Sstevel@tonic-gate dev_info_t *rdip, 372*7c478bd9Sstevel@tonic-gate ddi_ctl_enum_t op, 373*7c478bd9Sstevel@tonic-gate void *arg, 374*7c478bd9Sstevel@tonic-gate void *result) 375*7c478bd9Sstevel@tonic-gate { 376*7c478bd9Sstevel@tonic-gate usba_device_t *hub_usba_device = usba_get_usba_device(rdip); 377*7c478bd9Sstevel@tonic-gate dev_info_t *root_hub_dip = hub_usba_device->usb_root_hub_dip; 378*7c478bd9Sstevel@tonic-gate usb_mid_t *usb_mid; 379*7c478bd9Sstevel@tonic-gate struct attachspec *as; 380*7c478bd9Sstevel@tonic-gate struct detachspec *ds; 381*7c478bd9Sstevel@tonic-gate 382*7c478bd9Sstevel@tonic-gate usb_mid = usb_mid_obtain_state(dip); 383*7c478bd9Sstevel@tonic-gate 384*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_PM, usb_mid->mi_log_handle, 385*7c478bd9Sstevel@tonic-gate "usb_mid_bus_ctl:\n\t" 386*7c478bd9Sstevel@tonic-gate "dip = 0x%p, rdip = 0x%p, op = 0x%x, arg = 0x%p", 387*7c478bd9Sstevel@tonic-gate dip, rdip, op, arg); 388*7c478bd9Sstevel@tonic-gate 389*7c478bd9Sstevel@tonic-gate switch (op) { 390*7c478bd9Sstevel@tonic-gate case DDI_CTLOPS_ATTACH: 391*7c478bd9Sstevel@tonic-gate as = (struct attachspec *)arg; 392*7c478bd9Sstevel@tonic-gate 393*7c478bd9Sstevel@tonic-gate switch (as->when) { 394*7c478bd9Sstevel@tonic-gate case DDI_PRE : 395*7c478bd9Sstevel@tonic-gate /* nothing to do basically */ 396*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_PM, usb_mid->mi_log_handle, 397*7c478bd9Sstevel@tonic-gate "DDI_PRE DDI_CTLOPS_ATTACH"); 398*7c478bd9Sstevel@tonic-gate break; 399*7c478bd9Sstevel@tonic-gate case DDI_POST : 400*7c478bd9Sstevel@tonic-gate usb_mid_post_attach(usb_mid, usba_get_ifno(rdip), 401*7c478bd9Sstevel@tonic-gate (struct attachspec *)arg); 402*7c478bd9Sstevel@tonic-gate break; 403*7c478bd9Sstevel@tonic-gate } 404*7c478bd9Sstevel@tonic-gate 405*7c478bd9Sstevel@tonic-gate break; 406*7c478bd9Sstevel@tonic-gate case DDI_CTLOPS_DETACH: 407*7c478bd9Sstevel@tonic-gate ds = (struct detachspec *)arg; 408*7c478bd9Sstevel@tonic-gate 409*7c478bd9Sstevel@tonic-gate switch (ds->when) { 410*7c478bd9Sstevel@tonic-gate case DDI_PRE : 411*7c478bd9Sstevel@tonic-gate /* nothing to do basically */ 412*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_PM, usb_mid->mi_log_handle, 413*7c478bd9Sstevel@tonic-gate "DDI_PRE DDI_CTLOPS_DETACH"); 414*7c478bd9Sstevel@tonic-gate break; 415*7c478bd9Sstevel@tonic-gate case DDI_POST : 416*7c478bd9Sstevel@tonic-gate usb_mid_post_detach(usb_mid, usba_get_ifno(rdip), 417*7c478bd9Sstevel@tonic-gate (struct detachspec *)arg); 418*7c478bd9Sstevel@tonic-gate break; 419*7c478bd9Sstevel@tonic-gate } 420*7c478bd9Sstevel@tonic-gate 421*7c478bd9Sstevel@tonic-gate break; 422*7c478bd9Sstevel@tonic-gate default: 423*7c478bd9Sstevel@tonic-gate /* pass to root hub to handle */ 424*7c478bd9Sstevel@tonic-gate return (usba_bus_ctl(root_hub_dip, rdip, op, arg, result)); 425*7c478bd9Sstevel@tonic-gate } 426*7c478bd9Sstevel@tonic-gate 427*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 428*7c478bd9Sstevel@tonic-gate } 429*7c478bd9Sstevel@tonic-gate 430*7c478bd9Sstevel@tonic-gate 431*7c478bd9Sstevel@tonic-gate /* 432*7c478bd9Sstevel@tonic-gate * bus enumeration entry points 433*7c478bd9Sstevel@tonic-gate */ 434*7c478bd9Sstevel@tonic-gate static int 435*7c478bd9Sstevel@tonic-gate usb_mid_bus_config(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op, 436*7c478bd9Sstevel@tonic-gate void *arg, dev_info_t **child) 437*7c478bd9Sstevel@tonic-gate { 438*7c478bd9Sstevel@tonic-gate int rval, circ; 439*7c478bd9Sstevel@tonic-gate usb_mid_t *usb_mid = usb_mid_obtain_state(dip); 440*7c478bd9Sstevel@tonic-gate 441*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_ALL, usb_mid->mi_log_handle, 442*7c478bd9Sstevel@tonic-gate "usb_mid_bus_config: op=%d", op); 443*7c478bd9Sstevel@tonic-gate 444*7c478bd9Sstevel@tonic-gate if (usb_mid_bus_config_debug) { 445*7c478bd9Sstevel@tonic-gate flag |= NDI_DEVI_DEBUG; 446*7c478bd9Sstevel@tonic-gate } 447*7c478bd9Sstevel@tonic-gate 448*7c478bd9Sstevel@tonic-gate ndi_devi_enter(dip, &circ); 449*7c478bd9Sstevel@tonic-gate 450*7c478bd9Sstevel@tonic-gate /* enumerate each interface below us */ 451*7c478bd9Sstevel@tonic-gate mutex_enter(&usb_mid->mi_mutex); 452*7c478bd9Sstevel@tonic-gate usb_mid_create_children(usb_mid); 453*7c478bd9Sstevel@tonic-gate mutex_exit(&usb_mid->mi_mutex); 454*7c478bd9Sstevel@tonic-gate 455*7c478bd9Sstevel@tonic-gate rval = ndi_busop_bus_config(dip, flag, op, arg, child, 0); 456*7c478bd9Sstevel@tonic-gate ndi_devi_exit(dip, circ); 457*7c478bd9Sstevel@tonic-gate 458*7c478bd9Sstevel@tonic-gate return (rval); 459*7c478bd9Sstevel@tonic-gate } 460*7c478bd9Sstevel@tonic-gate 461*7c478bd9Sstevel@tonic-gate 462*7c478bd9Sstevel@tonic-gate static int 463*7c478bd9Sstevel@tonic-gate usb_mid_bus_unconfig(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op, 464*7c478bd9Sstevel@tonic-gate void *arg) 465*7c478bd9Sstevel@tonic-gate { 466*7c478bd9Sstevel@tonic-gate usb_mid_t *usb_mid = usb_mid_obtain_state(dip); 467*7c478bd9Sstevel@tonic-gate 468*7c478bd9Sstevel@tonic-gate dev_info_t *cdip, *mdip; 469*7c478bd9Sstevel@tonic-gate int interface, circular_count; 470*7c478bd9Sstevel@tonic-gate int rval = NDI_SUCCESS; 471*7c478bd9Sstevel@tonic-gate 472*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_ALL, usb_mid->mi_log_handle, 473*7c478bd9Sstevel@tonic-gate "usb_mid_bus_unconfig: op=%d", op); 474*7c478bd9Sstevel@tonic-gate 475*7c478bd9Sstevel@tonic-gate if (usb_mid_bus_config_debug) { 476*7c478bd9Sstevel@tonic-gate flag |= NDI_DEVI_DEBUG; 477*7c478bd9Sstevel@tonic-gate } 478*7c478bd9Sstevel@tonic-gate 479*7c478bd9Sstevel@tonic-gate /* 480*7c478bd9Sstevel@tonic-gate * first offline and if offlining successful, then 481*7c478bd9Sstevel@tonic-gate * remove children 482*7c478bd9Sstevel@tonic-gate */ 483*7c478bd9Sstevel@tonic-gate if (op == BUS_UNCONFIG_ALL) { 484*7c478bd9Sstevel@tonic-gate flag &= ~(NDI_DEVI_REMOVE | NDI_UNCONFIG); 485*7c478bd9Sstevel@tonic-gate } 486*7c478bd9Sstevel@tonic-gate 487*7c478bd9Sstevel@tonic-gate ndi_devi_enter(dip, &circular_count); 488*7c478bd9Sstevel@tonic-gate rval = ndi_busop_bus_unconfig(dip, flag, op, arg); 489*7c478bd9Sstevel@tonic-gate 490*7c478bd9Sstevel@tonic-gate if (op == BUS_UNCONFIG_ALL && rval == NDI_SUCCESS && 491*7c478bd9Sstevel@tonic-gate (flag & NDI_AUTODETACH) == 0) { 492*7c478bd9Sstevel@tonic-gate flag |= NDI_DEVI_REMOVE; 493*7c478bd9Sstevel@tonic-gate rval = ndi_busop_bus_unconfig(dip, flag, op, arg); 494*7c478bd9Sstevel@tonic-gate } 495*7c478bd9Sstevel@tonic-gate 496*7c478bd9Sstevel@tonic-gate /* update children's list */ 497*7c478bd9Sstevel@tonic-gate mutex_enter(&usb_mid->mi_mutex); 498*7c478bd9Sstevel@tonic-gate for (interface = 0; usb_mid->mi_children_dips && 499*7c478bd9Sstevel@tonic-gate (interface < usb_mid->mi_n_ifs); interface++) { 500*7c478bd9Sstevel@tonic-gate mdip = usb_mid->mi_children_dips[interface]; 501*7c478bd9Sstevel@tonic-gate 502*7c478bd9Sstevel@tonic-gate /* now search if this dip still exists */ 503*7c478bd9Sstevel@tonic-gate for (cdip = ddi_get_child(dip); cdip && (cdip != mdip); 504*7c478bd9Sstevel@tonic-gate cdip = ddi_get_next_sibling(cdip)); 505*7c478bd9Sstevel@tonic-gate 506*7c478bd9Sstevel@tonic-gate if (cdip != mdip) { 507*7c478bd9Sstevel@tonic-gate /* we lost the dip on this interface */ 508*7c478bd9Sstevel@tonic-gate usb_mid->mi_children_dips[interface] = NULL; 509*7c478bd9Sstevel@tonic-gate } else if (cdip) { 510*7c478bd9Sstevel@tonic-gate /* 511*7c478bd9Sstevel@tonic-gate * keep in DS_INITALIZED to prevent parent 512*7c478bd9Sstevel@tonic-gate * from detaching 513*7c478bd9Sstevel@tonic-gate */ 514*7c478bd9Sstevel@tonic-gate (void) ddi_initchild(ddi_get_parent(cdip), cdip); 515*7c478bd9Sstevel@tonic-gate } 516*7c478bd9Sstevel@tonic-gate } 517*7c478bd9Sstevel@tonic-gate mutex_exit(&usb_mid->mi_mutex); 518*7c478bd9Sstevel@tonic-gate 519*7c478bd9Sstevel@tonic-gate ndi_devi_exit(dip, circular_count); 520*7c478bd9Sstevel@tonic-gate 521*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_ALL, usb_mid->mi_log_handle, 522*7c478bd9Sstevel@tonic-gate "usb_mid_bus_config: rval=%d", rval); 523*7c478bd9Sstevel@tonic-gate 524*7c478bd9Sstevel@tonic-gate return (rval); 525*7c478bd9Sstevel@tonic-gate } 526*7c478bd9Sstevel@tonic-gate 527*7c478bd9Sstevel@tonic-gate /* 528*7c478bd9Sstevel@tonic-gate * functions to handle power transition for OS levels 0 -> 3 529*7c478bd9Sstevel@tonic-gate */ 530*7c478bd9Sstevel@tonic-gate static int 531*7c478bd9Sstevel@tonic-gate usb_mid_pwrlvl0(usb_mid_t *usb_mid) 532*7c478bd9Sstevel@tonic-gate { 533*7c478bd9Sstevel@tonic-gate int rval; 534*7c478bd9Sstevel@tonic-gate 535*7c478bd9Sstevel@tonic-gate switch (usb_mid->mi_dev_state) { 536*7c478bd9Sstevel@tonic-gate case USB_DEV_ONLINE: 537*7c478bd9Sstevel@tonic-gate /* Issue USB D3 command to the device here */ 538*7c478bd9Sstevel@tonic-gate rval = usb_set_device_pwrlvl3(usb_mid->mi_dip); 539*7c478bd9Sstevel@tonic-gate ASSERT(rval == USB_SUCCESS); 540*7c478bd9Sstevel@tonic-gate 541*7c478bd9Sstevel@tonic-gate usb_mid->mi_dev_state = USB_DEV_PWRED_DOWN; 542*7c478bd9Sstevel@tonic-gate usb_mid->mi_pm->mip_current_power = 543*7c478bd9Sstevel@tonic-gate USB_DEV_OS_PWR_OFF; 544*7c478bd9Sstevel@tonic-gate /* FALLTHRU */ 545*7c478bd9Sstevel@tonic-gate case USB_DEV_DISCONNECTED: 546*7c478bd9Sstevel@tonic-gate case USB_DEV_SUSPENDED: 547*7c478bd9Sstevel@tonic-gate /* allow a disconnected/cpr'ed device to go to low pwr */ 548*7c478bd9Sstevel@tonic-gate 549*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 550*7c478bd9Sstevel@tonic-gate case USB_DEV_PWRED_DOWN: 551*7c478bd9Sstevel@tonic-gate default: 552*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 553*7c478bd9Sstevel@tonic-gate } 554*7c478bd9Sstevel@tonic-gate } 555*7c478bd9Sstevel@tonic-gate 556*7c478bd9Sstevel@tonic-gate 557*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 558*7c478bd9Sstevel@tonic-gate static int 559*7c478bd9Sstevel@tonic-gate usb_mid_pwrlvl1(usb_mid_t *usb_mid) 560*7c478bd9Sstevel@tonic-gate { 561*7c478bd9Sstevel@tonic-gate int rval; 562*7c478bd9Sstevel@tonic-gate 563*7c478bd9Sstevel@tonic-gate /* Issue USB D2 command to the device here */ 564*7c478bd9Sstevel@tonic-gate rval = usb_set_device_pwrlvl2(usb_mid->mi_dip); 565*7c478bd9Sstevel@tonic-gate ASSERT(rval == USB_SUCCESS); 566*7c478bd9Sstevel@tonic-gate 567*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 568*7c478bd9Sstevel@tonic-gate } 569*7c478bd9Sstevel@tonic-gate 570*7c478bd9Sstevel@tonic-gate 571*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 572*7c478bd9Sstevel@tonic-gate static int 573*7c478bd9Sstevel@tonic-gate usb_mid_pwrlvl2(usb_mid_t *usb_mid) 574*7c478bd9Sstevel@tonic-gate { 575*7c478bd9Sstevel@tonic-gate int rval; 576*7c478bd9Sstevel@tonic-gate 577*7c478bd9Sstevel@tonic-gate /* Issue USB D1 command to the device here */ 578*7c478bd9Sstevel@tonic-gate rval = usb_set_device_pwrlvl1(usb_mid->mi_dip); 579*7c478bd9Sstevel@tonic-gate ASSERT(rval == USB_SUCCESS); 580*7c478bd9Sstevel@tonic-gate 581*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 582*7c478bd9Sstevel@tonic-gate } 583*7c478bd9Sstevel@tonic-gate 584*7c478bd9Sstevel@tonic-gate 585*7c478bd9Sstevel@tonic-gate static int 586*7c478bd9Sstevel@tonic-gate usb_mid_pwrlvl3(usb_mid_t *usb_mid) 587*7c478bd9Sstevel@tonic-gate { 588*7c478bd9Sstevel@tonic-gate int rval; 589*7c478bd9Sstevel@tonic-gate 590*7c478bd9Sstevel@tonic-gate switch (usb_mid->mi_dev_state) { 591*7c478bd9Sstevel@tonic-gate case USB_DEV_PWRED_DOWN: 592*7c478bd9Sstevel@tonic-gate /* Issue USB D0 command to the device here */ 593*7c478bd9Sstevel@tonic-gate rval = usb_set_device_pwrlvl0(usb_mid->mi_dip); 594*7c478bd9Sstevel@tonic-gate ASSERT(rval == USB_SUCCESS); 595*7c478bd9Sstevel@tonic-gate 596*7c478bd9Sstevel@tonic-gate usb_mid->mi_dev_state = USB_DEV_ONLINE; 597*7c478bd9Sstevel@tonic-gate usb_mid->mi_pm->mip_current_power = USB_DEV_OS_FULL_PWR; 598*7c478bd9Sstevel@tonic-gate 599*7c478bd9Sstevel@tonic-gate /* FALLTHRU */ 600*7c478bd9Sstevel@tonic-gate case USB_DEV_ONLINE: 601*7c478bd9Sstevel@tonic-gate /* we are already in full power */ 602*7c478bd9Sstevel@tonic-gate 603*7c478bd9Sstevel@tonic-gate /* FALLTHRU */ 604*7c478bd9Sstevel@tonic-gate case USB_DEV_DISCONNECTED: 605*7c478bd9Sstevel@tonic-gate case USB_DEV_SUSPENDED: 606*7c478bd9Sstevel@tonic-gate /* allow a disconnected/cpr'ed device to go to low power */ 607*7c478bd9Sstevel@tonic-gate 608*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 609*7c478bd9Sstevel@tonic-gate default: 610*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_PM, usb_mid->mi_log_handle, 611*7c478bd9Sstevel@tonic-gate "usb_mid_pwrlvl3: Illegal state (%s)", 612*7c478bd9Sstevel@tonic-gate usb_str_dev_state(usb_mid->mi_dev_state)); 613*7c478bd9Sstevel@tonic-gate 614*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 615*7c478bd9Sstevel@tonic-gate } 616*7c478bd9Sstevel@tonic-gate } 617*7c478bd9Sstevel@tonic-gate 618*7c478bd9Sstevel@tonic-gate 619*7c478bd9Sstevel@tonic-gate /* power entry point */ 620*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 621*7c478bd9Sstevel@tonic-gate static int 622*7c478bd9Sstevel@tonic-gate usb_mid_power(dev_info_t *dip, int comp, int level) 623*7c478bd9Sstevel@tonic-gate { 624*7c478bd9Sstevel@tonic-gate usb_mid_t *usb_mid; 625*7c478bd9Sstevel@tonic-gate usb_mid_power_t *midpm; 626*7c478bd9Sstevel@tonic-gate int rval = DDI_FAILURE; 627*7c478bd9Sstevel@tonic-gate 628*7c478bd9Sstevel@tonic-gate usb_mid = usb_mid_obtain_state(dip); 629*7c478bd9Sstevel@tonic-gate 630*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_PM, usb_mid->mi_log_handle, 631*7c478bd9Sstevel@tonic-gate "usb_mid_power: Begin: usb_mid = %p, level = %d", usb_mid, level); 632*7c478bd9Sstevel@tonic-gate 633*7c478bd9Sstevel@tonic-gate mutex_enter(&usb_mid->mi_mutex); 634*7c478bd9Sstevel@tonic-gate midpm = usb_mid->mi_pm; 635*7c478bd9Sstevel@tonic-gate 636*7c478bd9Sstevel@tonic-gate /* check if we are transitioning to a legal power level */ 637*7c478bd9Sstevel@tonic-gate if (USB_DEV_PWRSTATE_OK(midpm->mip_pwr_states, level)) { 638*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_PM, usb_mid->mi_log_handle, 639*7c478bd9Sstevel@tonic-gate "usb_mid_power: illegal power level = %d " 640*7c478bd9Sstevel@tonic-gate "mip_pwr_states = %x", level, midpm->mip_pwr_states); 641*7c478bd9Sstevel@tonic-gate 642*7c478bd9Sstevel@tonic-gate mutex_exit(&usb_mid->mi_mutex); 643*7c478bd9Sstevel@tonic-gate 644*7c478bd9Sstevel@tonic-gate return (rval); 645*7c478bd9Sstevel@tonic-gate } 646*7c478bd9Sstevel@tonic-gate 647*7c478bd9Sstevel@tonic-gate switch (level) { 648*7c478bd9Sstevel@tonic-gate case USB_DEV_OS_PWR_OFF: 649*7c478bd9Sstevel@tonic-gate rval = usb_mid_pwrlvl0(usb_mid); 650*7c478bd9Sstevel@tonic-gate break; 651*7c478bd9Sstevel@tonic-gate case USB_DEV_OS_PWR_1: 652*7c478bd9Sstevel@tonic-gate rval = usb_mid_pwrlvl1(usb_mid); 653*7c478bd9Sstevel@tonic-gate break; 654*7c478bd9Sstevel@tonic-gate case USB_DEV_OS_PWR_2: 655*7c478bd9Sstevel@tonic-gate rval = usb_mid_pwrlvl2(usb_mid); 656*7c478bd9Sstevel@tonic-gate break; 657*7c478bd9Sstevel@tonic-gate case USB_DEV_OS_FULL_PWR: 658*7c478bd9Sstevel@tonic-gate rval = usb_mid_pwrlvl3(usb_mid); 659*7c478bd9Sstevel@tonic-gate break; 660*7c478bd9Sstevel@tonic-gate } 661*7c478bd9Sstevel@tonic-gate 662*7c478bd9Sstevel@tonic-gate mutex_exit(&usb_mid->mi_mutex); 663*7c478bd9Sstevel@tonic-gate 664*7c478bd9Sstevel@tonic-gate return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE); 665*7c478bd9Sstevel@tonic-gate } 666*7c478bd9Sstevel@tonic-gate 667*7c478bd9Sstevel@tonic-gate 668*7c478bd9Sstevel@tonic-gate /* 669*7c478bd9Sstevel@tonic-gate * attach/resume entry point 670*7c478bd9Sstevel@tonic-gate */ 671*7c478bd9Sstevel@tonic-gate static int 672*7c478bd9Sstevel@tonic-gate usb_mid_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 673*7c478bd9Sstevel@tonic-gate { 674*7c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 675*7c478bd9Sstevel@tonic-gate usb_mid_t *usb_mid = NULL; 676*7c478bd9Sstevel@tonic-gate uint_t n_ifs; 677*7c478bd9Sstevel@tonic-gate size_t size; 678*7c478bd9Sstevel@tonic-gate 679*7c478bd9Sstevel@tonic-gate switch (cmd) { 680*7c478bd9Sstevel@tonic-gate case DDI_ATTACH: 681*7c478bd9Sstevel@tonic-gate 682*7c478bd9Sstevel@tonic-gate break; 683*7c478bd9Sstevel@tonic-gate case DDI_RESUME: 684*7c478bd9Sstevel@tonic-gate usb_mid = (usb_mid_t *)ddi_get_soft_state(usb_mid_statep, 685*7c478bd9Sstevel@tonic-gate instance); 686*7c478bd9Sstevel@tonic-gate (void) usb_mid_restore_device_state(dip, usb_mid); 687*7c478bd9Sstevel@tonic-gate 688*7c478bd9Sstevel@tonic-gate if (usb_mid->mi_ugen_hdl) { 689*7c478bd9Sstevel@tonic-gate (void) usb_ugen_attach(usb_mid->mi_ugen_hdl, 690*7c478bd9Sstevel@tonic-gate DDI_RESUME); 691*7c478bd9Sstevel@tonic-gate } 692*7c478bd9Sstevel@tonic-gate 693*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 694*7c478bd9Sstevel@tonic-gate default: 695*7c478bd9Sstevel@tonic-gate 696*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 697*7c478bd9Sstevel@tonic-gate } 698*7c478bd9Sstevel@tonic-gate 699*7c478bd9Sstevel@tonic-gate /* 700*7c478bd9Sstevel@tonic-gate * Attach: 701*7c478bd9Sstevel@tonic-gate * 702*7c478bd9Sstevel@tonic-gate * Allocate soft state and initialize 703*7c478bd9Sstevel@tonic-gate */ 704*7c478bd9Sstevel@tonic-gate if (ddi_soft_state_zalloc(usb_mid_statep, instance) != DDI_SUCCESS) { 705*7c478bd9Sstevel@tonic-gate goto fail; 706*7c478bd9Sstevel@tonic-gate } 707*7c478bd9Sstevel@tonic-gate 708*7c478bd9Sstevel@tonic-gate usb_mid = ddi_get_soft_state(usb_mid_statep, instance); 709*7c478bd9Sstevel@tonic-gate if (usb_mid == NULL) { 710*7c478bd9Sstevel@tonic-gate 711*7c478bd9Sstevel@tonic-gate goto fail; 712*7c478bd9Sstevel@tonic-gate } 713*7c478bd9Sstevel@tonic-gate 714*7c478bd9Sstevel@tonic-gate /* allocate handle for logging of messages */ 715*7c478bd9Sstevel@tonic-gate usb_mid->mi_log_handle = usb_alloc_log_hdl(dip, "mid", 716*7c478bd9Sstevel@tonic-gate &usb_mid_errlevel, 717*7c478bd9Sstevel@tonic-gate &usb_mid_errmask, &usb_mid_instance_debug, 718*7c478bd9Sstevel@tonic-gate 0); 719*7c478bd9Sstevel@tonic-gate 720*7c478bd9Sstevel@tonic-gate usb_mid->mi_usba_device = usba_get_usba_device(dip); 721*7c478bd9Sstevel@tonic-gate usb_mid->mi_dip = dip; 722*7c478bd9Sstevel@tonic-gate usb_mid->mi_instance = instance; 723*7c478bd9Sstevel@tonic-gate usb_mid->mi_n_ifs = usb_mid->mi_usba_device->usb_n_ifs; 724*7c478bd9Sstevel@tonic-gate 725*7c478bd9Sstevel@tonic-gate /* attach client driver to USBA */ 726*7c478bd9Sstevel@tonic-gate if (usb_client_attach(dip, USBDRV_VERSION, 0) != USB_SUCCESS) { 727*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_mid->mi_log_handle, 728*7c478bd9Sstevel@tonic-gate "usb_client_attach failed"); 729*7c478bd9Sstevel@tonic-gate goto fail; 730*7c478bd9Sstevel@tonic-gate } 731*7c478bd9Sstevel@tonic-gate if (usb_get_dev_data(dip, &usb_mid->mi_dev_data, USB_PARSE_LVL_NONE, 732*7c478bd9Sstevel@tonic-gate 0) != USB_SUCCESS) { 733*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_mid->mi_log_handle, 734*7c478bd9Sstevel@tonic-gate "usb_get_dev_data failed"); 735*7c478bd9Sstevel@tonic-gate goto fail; 736*7c478bd9Sstevel@tonic-gate } 737*7c478bd9Sstevel@tonic-gate 738*7c478bd9Sstevel@tonic-gate mutex_init(&usb_mid->mi_mutex, NULL, MUTEX_DRIVER, 739*7c478bd9Sstevel@tonic-gate usb_mid->mi_dev_data->dev_iblock_cookie); 740*7c478bd9Sstevel@tonic-gate 741*7c478bd9Sstevel@tonic-gate usb_free_dev_data(dip, usb_mid->mi_dev_data); 742*7c478bd9Sstevel@tonic-gate usb_mid->mi_dev_data = NULL; 743*7c478bd9Sstevel@tonic-gate 744*7c478bd9Sstevel@tonic-gate usb_mid->mi_init_state |= USB_MID_LOCK_INIT; 745*7c478bd9Sstevel@tonic-gate 746*7c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(dip, "usb_mid", S_IFCHR, 747*7c478bd9Sstevel@tonic-gate instance << USB_MID_MINOR_INSTANCE_SHIFT, 748*7c478bd9Sstevel@tonic-gate DDI_NT_NEXUS, 0) != DDI_SUCCESS) { 749*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(DPRINT_MASK_ATTA, usb_mid->mi_log_handle, 750*7c478bd9Sstevel@tonic-gate "cannot create devctl minor node"); 751*7c478bd9Sstevel@tonic-gate goto fail; 752*7c478bd9Sstevel@tonic-gate } 753*7c478bd9Sstevel@tonic-gate 754*7c478bd9Sstevel@tonic-gate usb_mid->mi_init_state |= USB_MID_MINOR_NODE_CREATED; 755*7c478bd9Sstevel@tonic-gate 756*7c478bd9Sstevel@tonic-gate /* 757*7c478bd9Sstevel@tonic-gate * allocate array for keeping track of child dips 758*7c478bd9Sstevel@tonic-gate */ 759*7c478bd9Sstevel@tonic-gate n_ifs = usb_mid->mi_n_ifs; 760*7c478bd9Sstevel@tonic-gate usb_mid->mi_cd_list_length = size = (sizeof (dev_info_t *)) * n_ifs; 761*7c478bd9Sstevel@tonic-gate 762*7c478bd9Sstevel@tonic-gate usb_mid->mi_children_dips = kmem_zalloc(size, KM_SLEEP); 763*7c478bd9Sstevel@tonic-gate usb_mid->mi_child_events = kmem_zalloc(sizeof (uint8_t) * n_ifs, 764*7c478bd9Sstevel@tonic-gate KM_SLEEP); 765*7c478bd9Sstevel@tonic-gate /* 766*7c478bd9Sstevel@tonic-gate * Event handling: definition and registration 767*7c478bd9Sstevel@tonic-gate * get event handle for events that we have defined 768*7c478bd9Sstevel@tonic-gate */ 769*7c478bd9Sstevel@tonic-gate (void) ndi_event_alloc_hdl(dip, 0, &usb_mid->mi_ndi_event_hdl, 770*7c478bd9Sstevel@tonic-gate NDI_SLEEP); 771*7c478bd9Sstevel@tonic-gate 772*7c478bd9Sstevel@tonic-gate /* bind event set to the handle */ 773*7c478bd9Sstevel@tonic-gate if (ndi_event_bind_set(usb_mid->mi_ndi_event_hdl, &usb_mid_ndi_events, 774*7c478bd9Sstevel@tonic-gate NDI_SLEEP)) { 775*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_mid->mi_log_handle, 776*7c478bd9Sstevel@tonic-gate "usb_mid_attach: binding event set failed"); 777*7c478bd9Sstevel@tonic-gate 778*7c478bd9Sstevel@tonic-gate goto fail; 779*7c478bd9Sstevel@tonic-gate } 780*7c478bd9Sstevel@tonic-gate 781*7c478bd9Sstevel@tonic-gate usb_mid->mi_dev_state = USB_DEV_ONLINE; 782*7c478bd9Sstevel@tonic-gate 783*7c478bd9Sstevel@tonic-gate /* 784*7c478bd9Sstevel@tonic-gate * now create components to power manage this device 785*7c478bd9Sstevel@tonic-gate * before attaching children 786*7c478bd9Sstevel@tonic-gate */ 787*7c478bd9Sstevel@tonic-gate usb_mid_create_pm_components(dip, usb_mid); 788*7c478bd9Sstevel@tonic-gate 789*7c478bd9Sstevel@tonic-gate /* event registration for events from our parent */ 790*7c478bd9Sstevel@tonic-gate usb_mid_register_events(usb_mid); 791*7c478bd9Sstevel@tonic-gate 792*7c478bd9Sstevel@tonic-gate usb_mid->mi_init_state |= USB_MID_EVENTS_REGISTERED; 793*7c478bd9Sstevel@tonic-gate 794*7c478bd9Sstevel@tonic-gate ddi_report_dev(dip); 795*7c478bd9Sstevel@tonic-gate 796*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 797*7c478bd9Sstevel@tonic-gate 798*7c478bd9Sstevel@tonic-gate fail: 799*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(DPRINT_MASK_ATTA, NULL, "usb_mid%d cannot attach", 800*7c478bd9Sstevel@tonic-gate instance); 801*7c478bd9Sstevel@tonic-gate 802*7c478bd9Sstevel@tonic-gate if (usb_mid) { 803*7c478bd9Sstevel@tonic-gate (void) usb_mid_cleanup(dip, usb_mid); 804*7c478bd9Sstevel@tonic-gate } 805*7c478bd9Sstevel@tonic-gate 806*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 807*7c478bd9Sstevel@tonic-gate } 808*7c478bd9Sstevel@tonic-gate 809*7c478bd9Sstevel@tonic-gate 810*7c478bd9Sstevel@tonic-gate /* detach or suspend this instance */ 811*7c478bd9Sstevel@tonic-gate static int 812*7c478bd9Sstevel@tonic-gate usb_mid_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 813*7c478bd9Sstevel@tonic-gate { 814*7c478bd9Sstevel@tonic-gate usb_mid_t *usb_mid = usb_mid_obtain_state(dip); 815*7c478bd9Sstevel@tonic-gate 816*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_mid->mi_log_handle, 817*7c478bd9Sstevel@tonic-gate "usb_mid_detach: cmd = 0x%x", cmd); 818*7c478bd9Sstevel@tonic-gate 819*7c478bd9Sstevel@tonic-gate switch (cmd) { 820*7c478bd9Sstevel@tonic-gate case DDI_DETACH: 821*7c478bd9Sstevel@tonic-gate 822*7c478bd9Sstevel@tonic-gate return (usb_mid_cleanup(dip, usb_mid)); 823*7c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 824*7c478bd9Sstevel@tonic-gate /* nothing to do */ 825*7c478bd9Sstevel@tonic-gate mutex_enter(&usb_mid->mi_mutex); 826*7c478bd9Sstevel@tonic-gate usb_mid->mi_dev_state = USB_DEV_SUSPENDED; 827*7c478bd9Sstevel@tonic-gate mutex_exit(&usb_mid->mi_mutex); 828*7c478bd9Sstevel@tonic-gate 829*7c478bd9Sstevel@tonic-gate if (usb_mid->mi_ugen_hdl) { 830*7c478bd9Sstevel@tonic-gate int rval = usb_ugen_detach(usb_mid->mi_ugen_hdl, 831*7c478bd9Sstevel@tonic-gate DDI_SUSPEND); 832*7c478bd9Sstevel@tonic-gate return (rval == USB_SUCCESS ? DDI_SUCCESS : 833*7c478bd9Sstevel@tonic-gate DDI_FAILURE); 834*7c478bd9Sstevel@tonic-gate } 835*7c478bd9Sstevel@tonic-gate 836*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 837*7c478bd9Sstevel@tonic-gate default: 838*7c478bd9Sstevel@tonic-gate 839*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 840*7c478bd9Sstevel@tonic-gate } 841*7c478bd9Sstevel@tonic-gate 842*7c478bd9Sstevel@tonic-gate _NOTE(NOT_REACHED) 843*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 844*7c478bd9Sstevel@tonic-gate } 845*7c478bd9Sstevel@tonic-gate 846*7c478bd9Sstevel@tonic-gate 847*7c478bd9Sstevel@tonic-gate /* 848*7c478bd9Sstevel@tonic-gate * usb_mid_cleanup: 849*7c478bd9Sstevel@tonic-gate * cleanup usb_mid and deallocate. this function is called for 850*7c478bd9Sstevel@tonic-gate * handling attach failures and detaching including dynamic 851*7c478bd9Sstevel@tonic-gate * reconfiguration 852*7c478bd9Sstevel@tonic-gate */ 853*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 854*7c478bd9Sstevel@tonic-gate static int 855*7c478bd9Sstevel@tonic-gate usb_mid_cleanup(dev_info_t *dip, usb_mid_t *usb_mid) 856*7c478bd9Sstevel@tonic-gate { 857*7c478bd9Sstevel@tonic-gate usb_mid_power_t *midpm; 858*7c478bd9Sstevel@tonic-gate int rval; 859*7c478bd9Sstevel@tonic-gate 860*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_mid->mi_log_handle, 861*7c478bd9Sstevel@tonic-gate "usb_mid_cleanup:"); 862*7c478bd9Sstevel@tonic-gate 863*7c478bd9Sstevel@tonic-gate if ((usb_mid->mi_init_state & USB_MID_LOCK_INIT) == 0) { 864*7c478bd9Sstevel@tonic-gate 865*7c478bd9Sstevel@tonic-gate goto done; 866*7c478bd9Sstevel@tonic-gate } 867*7c478bd9Sstevel@tonic-gate 868*7c478bd9Sstevel@tonic-gate /* 869*7c478bd9Sstevel@tonic-gate * deallocate events, if events are still registered 870*7c478bd9Sstevel@tonic-gate * (ie. children still attached) then we have to fail the detach 871*7c478bd9Sstevel@tonic-gate */ 872*7c478bd9Sstevel@tonic-gate if (usb_mid->mi_ndi_event_hdl && 873*7c478bd9Sstevel@tonic-gate (ndi_event_free_hdl(usb_mid->mi_ndi_event_hdl) != NDI_SUCCESS)) { 874*7c478bd9Sstevel@tonic-gate 875*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(DPRINT_MASK_ATTA, usb_mid->mi_log_handle, 876*7c478bd9Sstevel@tonic-gate "usb_mid_cleanup: ndi_event_free_hdl failed"); 877*7c478bd9Sstevel@tonic-gate 878*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 879*7c478bd9Sstevel@tonic-gate } 880*7c478bd9Sstevel@tonic-gate 881*7c478bd9Sstevel@tonic-gate /* 882*7c478bd9Sstevel@tonic-gate * Disable the event callbacks, after this point, event 883*7c478bd9Sstevel@tonic-gate * callbacks will never get called. Note we shouldn't hold 884*7c478bd9Sstevel@tonic-gate * mutex while unregistering events because there may be a 885*7c478bd9Sstevel@tonic-gate * competing event callback thread. Event callbacks are done 886*7c478bd9Sstevel@tonic-gate * with ndi mutex held and this can cause a potential deadlock. 887*7c478bd9Sstevel@tonic-gate * Note that cleanup can't fail after deregistration of events. 888*7c478bd9Sstevel@tonic-gate */ 889*7c478bd9Sstevel@tonic-gate if (usb_mid->mi_init_state & USB_MID_EVENTS_REGISTERED) { 890*7c478bd9Sstevel@tonic-gate usb_mid_unregister_events(usb_mid); 891*7c478bd9Sstevel@tonic-gate } 892*7c478bd9Sstevel@tonic-gate 893*7c478bd9Sstevel@tonic-gate midpm = usb_mid->mi_pm; 894*7c478bd9Sstevel@tonic-gate 895*7c478bd9Sstevel@tonic-gate mutex_enter(&usb_mid->mi_mutex); 896*7c478bd9Sstevel@tonic-gate 897*7c478bd9Sstevel@tonic-gate if ((midpm) && (usb_mid->mi_dev_state != USB_DEV_DISCONNECTED)) { 898*7c478bd9Sstevel@tonic-gate 899*7c478bd9Sstevel@tonic-gate mutex_exit(&usb_mid->mi_mutex); 900*7c478bd9Sstevel@tonic-gate 901*7c478bd9Sstevel@tonic-gate (void) pm_busy_component(dip, 0); 902*7c478bd9Sstevel@tonic-gate if (midpm->mip_wakeup_enabled) { 903*7c478bd9Sstevel@tonic-gate 904*7c478bd9Sstevel@tonic-gate /* First bring the device to full power */ 905*7c478bd9Sstevel@tonic-gate (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 906*7c478bd9Sstevel@tonic-gate 907*7c478bd9Sstevel@tonic-gate rval = usb_handle_remote_wakeup(dip, 908*7c478bd9Sstevel@tonic-gate USB_REMOTE_WAKEUP_DISABLE); 909*7c478bd9Sstevel@tonic-gate 910*7c478bd9Sstevel@tonic-gate if (rval != DDI_SUCCESS) { 911*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_EVENTS, 912*7c478bd9Sstevel@tonic-gate usb_mid->mi_log_handle, 913*7c478bd9Sstevel@tonic-gate "usb_cleanup: disable remote " 914*7c478bd9Sstevel@tonic-gate "wakeup failed, rval=%d", rval); 915*7c478bd9Sstevel@tonic-gate } 916*7c478bd9Sstevel@tonic-gate } 917*7c478bd9Sstevel@tonic-gate 918*7c478bd9Sstevel@tonic-gate (void) pm_lower_power(usb_mid->mi_dip, 0, USB_DEV_OS_PWR_OFF); 919*7c478bd9Sstevel@tonic-gate (void) pm_idle_component(dip, 0); 920*7c478bd9Sstevel@tonic-gate } else { 921*7c478bd9Sstevel@tonic-gate mutex_exit(&usb_mid->mi_mutex); 922*7c478bd9Sstevel@tonic-gate } 923*7c478bd9Sstevel@tonic-gate 924*7c478bd9Sstevel@tonic-gate if (midpm) { 925*7c478bd9Sstevel@tonic-gate kmem_free(midpm, sizeof (usb_mid_power_t)); 926*7c478bd9Sstevel@tonic-gate } 927*7c478bd9Sstevel@tonic-gate 928*7c478bd9Sstevel@tonic-gate /* free children list */ 929*7c478bd9Sstevel@tonic-gate if (usb_mid->mi_children_dips) { 930*7c478bd9Sstevel@tonic-gate kmem_free(usb_mid->mi_children_dips, 931*7c478bd9Sstevel@tonic-gate usb_mid->mi_cd_list_length); 932*7c478bd9Sstevel@tonic-gate } 933*7c478bd9Sstevel@tonic-gate 934*7c478bd9Sstevel@tonic-gate if (usb_mid->mi_child_events) { 935*7c478bd9Sstevel@tonic-gate kmem_free(usb_mid->mi_child_events, sizeof (uint8_t) * 936*7c478bd9Sstevel@tonic-gate usb_mid->mi_n_ifs); 937*7c478bd9Sstevel@tonic-gate } 938*7c478bd9Sstevel@tonic-gate 939*7c478bd9Sstevel@tonic-gate if (usb_mid->mi_init_state & USB_MID_MINOR_NODE_CREATED) { 940*7c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 941*7c478bd9Sstevel@tonic-gate } 942*7c478bd9Sstevel@tonic-gate 943*7c478bd9Sstevel@tonic-gate mutex_destroy(&usb_mid->mi_mutex); 944*7c478bd9Sstevel@tonic-gate 945*7c478bd9Sstevel@tonic-gate done: 946*7c478bd9Sstevel@tonic-gate usb_client_detach(dip, usb_mid->mi_dev_data); 947*7c478bd9Sstevel@tonic-gate 948*7c478bd9Sstevel@tonic-gate if (usb_mid->mi_ugen_hdl) { 949*7c478bd9Sstevel@tonic-gate (void) usb_ugen_detach(usb_mid->mi_ugen_hdl, DDI_DETACH); 950*7c478bd9Sstevel@tonic-gate usb_ugen_release_hdl(usb_mid->mi_ugen_hdl); 951*7c478bd9Sstevel@tonic-gate } 952*7c478bd9Sstevel@tonic-gate 953*7c478bd9Sstevel@tonic-gate usb_free_log_hdl(usb_mid->mi_log_handle); 954*7c478bd9Sstevel@tonic-gate ddi_soft_state_free(usb_mid_statep, ddi_get_instance(dip)); 955*7c478bd9Sstevel@tonic-gate 956*7c478bd9Sstevel@tonic-gate ddi_prop_remove_all(dip); 957*7c478bd9Sstevel@tonic-gate 958*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 959*7c478bd9Sstevel@tonic-gate } 960*7c478bd9Sstevel@tonic-gate 961*7c478bd9Sstevel@tonic-gate 962*7c478bd9Sstevel@tonic-gate int 963*7c478bd9Sstevel@tonic-gate usb_mid_devi_bind_driver(usb_mid_t *usb_mid, dev_info_t *dip) 964*7c478bd9Sstevel@tonic-gate { 965*7c478bd9Sstevel@tonic-gate char *name; 966*7c478bd9Sstevel@tonic-gate uint8_t if_num = usba_get_ifno(dip); 967*7c478bd9Sstevel@tonic-gate int rval = USB_SUCCESS; 968*7c478bd9Sstevel@tonic-gate 969*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_mid->mi_log_handle, 970*7c478bd9Sstevel@tonic-gate "usb_mid_devi_bind_driver: dip = 0x%p, if_num = 0x%x", dip, if_num); 971*7c478bd9Sstevel@tonic-gate 972*7c478bd9Sstevel@tonic-gate name = kmem_zalloc(MAXNAMELEN, KM_SLEEP); 973*7c478bd9Sstevel@tonic-gate 974*7c478bd9Sstevel@tonic-gate /* bind device to the driver */ 975*7c478bd9Sstevel@tonic-gate if (ndi_devi_bind_driver(dip, 0) != NDI_SUCCESS) { 976*7c478bd9Sstevel@tonic-gate /* if we fail to bind report an error */ 977*7c478bd9Sstevel@tonic-gate (void) usba_get_mfg_prod_sn_str(dip, name, MAXNAMELEN); 978*7c478bd9Sstevel@tonic-gate if (name[0] != '\0') { 979*7c478bd9Sstevel@tonic-gate if (!usb_owns_device(dip)) { 980*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(DPRINT_MASK_ATTA, 981*7c478bd9Sstevel@tonic-gate usb_mid->mi_log_handle, 982*7c478bd9Sstevel@tonic-gate "no driver found for " 983*7c478bd9Sstevel@tonic-gate "interface %d (nodename: '%s') of %s", 984*7c478bd9Sstevel@tonic-gate if_num, ddi_node_name(dip), name); 985*7c478bd9Sstevel@tonic-gate } else { 986*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(DPRINT_MASK_ATTA, 987*7c478bd9Sstevel@tonic-gate usb_mid->mi_log_handle, 988*7c478bd9Sstevel@tonic-gate "no driver found for device %s", name); 989*7c478bd9Sstevel@tonic-gate } 990*7c478bd9Sstevel@tonic-gate } else { 991*7c478bd9Sstevel@tonic-gate (void) ddi_pathname(dip, name); 992*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(DPRINT_MASK_ATTA, 993*7c478bd9Sstevel@tonic-gate usb_mid->mi_log_handle, 994*7c478bd9Sstevel@tonic-gate "no driver found for device %s", name); 995*7c478bd9Sstevel@tonic-gate } 996*7c478bd9Sstevel@tonic-gate rval = USB_FAILURE; 997*7c478bd9Sstevel@tonic-gate } 998*7c478bd9Sstevel@tonic-gate 999*7c478bd9Sstevel@tonic-gate kmem_free(name, MAXNAMELEN); 1000*7c478bd9Sstevel@tonic-gate 1001*7c478bd9Sstevel@tonic-gate return (rval); 1002*7c478bd9Sstevel@tonic-gate } 1003*7c478bd9Sstevel@tonic-gate 1004*7c478bd9Sstevel@tonic-gate 1005*7c478bd9Sstevel@tonic-gate static void 1006*7c478bd9Sstevel@tonic-gate usb_mid_ugen_attach(usb_mid_t *usb_mid, boolean_t remove_children) 1007*7c478bd9Sstevel@tonic-gate { 1008*7c478bd9Sstevel@tonic-gate _NOTE(NO_COMPETING_THREADS_NOW); 1009*7c478bd9Sstevel@tonic-gate 1010*7c478bd9Sstevel@tonic-gate if (usb_mid->mi_ugen_hdl == NULL) { 1011*7c478bd9Sstevel@tonic-gate usb_ugen_info_t usb_ugen_info; 1012*7c478bd9Sstevel@tonic-gate int rval; 1013*7c478bd9Sstevel@tonic-gate usb_ugen_hdl_t hdl; 1014*7c478bd9Sstevel@tonic-gate 1015*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_mid->mi_log_handle, 1016*7c478bd9Sstevel@tonic-gate "usb_mid_ugen_attach: get handle"); 1017*7c478bd9Sstevel@tonic-gate 1018*7c478bd9Sstevel@tonic-gate bzero(&usb_ugen_info, sizeof (usb_ugen_info)); 1019*7c478bd9Sstevel@tonic-gate 1020*7c478bd9Sstevel@tonic-gate usb_ugen_info.usb_ugen_flags = (remove_children ? 1021*7c478bd9Sstevel@tonic-gate USB_UGEN_REMOVE_CHILDREN : 0); 1022*7c478bd9Sstevel@tonic-gate usb_ugen_info.usb_ugen_minor_node_ugen_bits_mask = 1023*7c478bd9Sstevel@tonic-gate (dev_t)USB_MID_MINOR_UGEN_BITS_MASK; 1024*7c478bd9Sstevel@tonic-gate usb_ugen_info.usb_ugen_minor_node_instance_mask = 1025*7c478bd9Sstevel@tonic-gate (dev_t)~USB_MID_MINOR_UGEN_BITS_MASK; 1026*7c478bd9Sstevel@tonic-gate 1027*7c478bd9Sstevel@tonic-gate mutex_exit(&usb_mid->mi_mutex); 1028*7c478bd9Sstevel@tonic-gate hdl = usb_ugen_get_hdl(usb_mid->mi_dip, 1029*7c478bd9Sstevel@tonic-gate &usb_ugen_info); 1030*7c478bd9Sstevel@tonic-gate 1031*7c478bd9Sstevel@tonic-gate if ((rval = usb_ugen_attach(hdl, DDI_ATTACH)) != USB_SUCCESS) { 1032*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_mid->mi_log_handle, 1033*7c478bd9Sstevel@tonic-gate "failed to create ugen support (%d)", rval); 1034*7c478bd9Sstevel@tonic-gate usb_ugen_release_hdl(hdl); 1035*7c478bd9Sstevel@tonic-gate 1036*7c478bd9Sstevel@tonic-gate mutex_enter(&usb_mid->mi_mutex); 1037*7c478bd9Sstevel@tonic-gate } else { 1038*7c478bd9Sstevel@tonic-gate mutex_enter(&usb_mid->mi_mutex); 1039*7c478bd9Sstevel@tonic-gate usb_mid->mi_ugen_hdl = hdl; 1040*7c478bd9Sstevel@tonic-gate } 1041*7c478bd9Sstevel@tonic-gate } 1042*7c478bd9Sstevel@tonic-gate 1043*7c478bd9Sstevel@tonic-gate _NOTE(COMPETING_THREADS_NOW); 1044*7c478bd9Sstevel@tonic-gate } 1045*7c478bd9Sstevel@tonic-gate 1046*7c478bd9Sstevel@tonic-gate 1047*7c478bd9Sstevel@tonic-gate /* 1048*7c478bd9Sstevel@tonic-gate * usb_mid_create_children: 1049*7c478bd9Sstevel@tonic-gate */ 1050*7c478bd9Sstevel@tonic-gate static void 1051*7c478bd9Sstevel@tonic-gate usb_mid_create_children(usb_mid_t *usb_mid) 1052*7c478bd9Sstevel@tonic-gate { 1053*7c478bd9Sstevel@tonic-gate usba_device_t *usba_device; 1054*7c478bd9Sstevel@tonic-gate uint_t n_ifs; 1055*7c478bd9Sstevel@tonic-gate uint_t i; 1056*7c478bd9Sstevel@tonic-gate dev_info_t *cdip; 1057*7c478bd9Sstevel@tonic-gate uint_t ugen_bound = 0; 1058*7c478bd9Sstevel@tonic-gate uint_t bound_children = 0; 1059*7c478bd9Sstevel@tonic-gate 1060*7c478bd9Sstevel@tonic-gate usba_device = usba_get_usba_device(usb_mid->mi_dip); 1061*7c478bd9Sstevel@tonic-gate 1062*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_mid->mi_log_handle, 1063*7c478bd9Sstevel@tonic-gate "usb_mid_attach_child_drivers: port = %d, address = %d", 1064*7c478bd9Sstevel@tonic-gate usba_device->usb_port, usba_device->usb_addr); 1065*7c478bd9Sstevel@tonic-gate 1066*7c478bd9Sstevel@tonic-gate if (usb_mid->mi_removed_children) { 1067*7c478bd9Sstevel@tonic-gate 1068*7c478bd9Sstevel@tonic-gate return; 1069*7c478bd9Sstevel@tonic-gate } 1070*7c478bd9Sstevel@tonic-gate 1071*7c478bd9Sstevel@tonic-gate n_ifs = usb_mid->mi_n_ifs; 1072*7c478bd9Sstevel@tonic-gate 1073*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_mid->mi_log_handle, 1074*7c478bd9Sstevel@tonic-gate "usb_mid_create_children: #interfaces = %d", n_ifs); 1075*7c478bd9Sstevel@tonic-gate 1076*7c478bd9Sstevel@tonic-gate /* 1077*7c478bd9Sstevel@tonic-gate * create all children if not already present 1078*7c478bd9Sstevel@tonic-gate */ 1079*7c478bd9Sstevel@tonic-gate for (i = 0; i < n_ifs; i++) { 1080*7c478bd9Sstevel@tonic-gate if (usb_mid->mi_children_dips[i] != NULL) { 1081*7c478bd9Sstevel@tonic-gate 1082*7c478bd9Sstevel@tonic-gate continue; 1083*7c478bd9Sstevel@tonic-gate } 1084*7c478bd9Sstevel@tonic-gate 1085*7c478bd9Sstevel@tonic-gate mutex_exit(&usb_mid->mi_mutex); 1086*7c478bd9Sstevel@tonic-gate cdip = usba_ready_interface_node(usb_mid->mi_dip, i); 1087*7c478bd9Sstevel@tonic-gate mutex_enter(&usb_mid->mi_mutex); 1088*7c478bd9Sstevel@tonic-gate if (cdip != NULL) { 1089*7c478bd9Sstevel@tonic-gate if (usb_mid_devi_bind_driver(usb_mid, cdip) == 1090*7c478bd9Sstevel@tonic-gate USB_SUCCESS) { 1091*7c478bd9Sstevel@tonic-gate bound_children++; 1092*7c478bd9Sstevel@tonic-gate if (strcmp(ddi_driver_name(cdip), 1093*7c478bd9Sstevel@tonic-gate "ugen") == 0) { 1094*7c478bd9Sstevel@tonic-gate ugen_bound++; 1095*7c478bd9Sstevel@tonic-gate } 1096*7c478bd9Sstevel@tonic-gate } 1097*7c478bd9Sstevel@tonic-gate 1098*7c478bd9Sstevel@tonic-gate usb_mid->mi_children_dips[i] = cdip; 1099*7c478bd9Sstevel@tonic-gate 1100*7c478bd9Sstevel@tonic-gate } 1101*7c478bd9Sstevel@tonic-gate } 1102*7c478bd9Sstevel@tonic-gate 1103*7c478bd9Sstevel@tonic-gate usb_mid->mi_removed_children = (bound_children ? B_FALSE : B_TRUE); 1104*7c478bd9Sstevel@tonic-gate 1105*7c478bd9Sstevel@tonic-gate /* 1106*7c478bd9Sstevel@tonic-gate * if there are no ugen interface children, create ugen support at 1107*7c478bd9Sstevel@tonic-gate * device level, use a separate thread because we may be at interrupt 1108*7c478bd9Sstevel@tonic-gate * level 1109*7c478bd9Sstevel@tonic-gate */ 1110*7c478bd9Sstevel@tonic-gate if ((ugen_bound == 0) && (usb_mid->mi_ugen_hdl == NULL)) { 1111*7c478bd9Sstevel@tonic-gate /* 1112*7c478bd9Sstevel@tonic-gate * we only need to remove the children if there are 1113*7c478bd9Sstevel@tonic-gate * multiple configurations which would fail if there 1114*7c478bd9Sstevel@tonic-gate * are child interfaces 1115*7c478bd9Sstevel@tonic-gate */ 1116*7c478bd9Sstevel@tonic-gate if ((usb_mid->mi_removed_children == B_FALSE) && 1117*7c478bd9Sstevel@tonic-gate (usba_device->usb_n_cfgs > 1)) { 1118*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(DPRINT_MASK_ATTA, 1119*7c478bd9Sstevel@tonic-gate usb_mid->mi_log_handle, 1120*7c478bd9Sstevel@tonic-gate "can't support ugen for multiple " 1121*7c478bd9Sstevel@tonic-gate "configurations devices that have attached " 1122*7c478bd9Sstevel@tonic-gate "child interface drivers"); 1123*7c478bd9Sstevel@tonic-gate } else { 1124*7c478bd9Sstevel@tonic-gate usb_mid_ugen_attach(usb_mid, 1125*7c478bd9Sstevel@tonic-gate usb_mid->mi_removed_children); 1126*7c478bd9Sstevel@tonic-gate } 1127*7c478bd9Sstevel@tonic-gate } 1128*7c478bd9Sstevel@tonic-gate } 1129*7c478bd9Sstevel@tonic-gate 1130*7c478bd9Sstevel@tonic-gate 1131*7c478bd9Sstevel@tonic-gate /* 1132*7c478bd9Sstevel@tonic-gate * event support 1133*7c478bd9Sstevel@tonic-gate */ 1134*7c478bd9Sstevel@tonic-gate static int 1135*7c478bd9Sstevel@tonic-gate usb_mid_busop_get_eventcookie(dev_info_t *dip, 1136*7c478bd9Sstevel@tonic-gate dev_info_t *rdip, char *eventname, ddi_eventcookie_t *cookie) 1137*7c478bd9Sstevel@tonic-gate { 1138*7c478bd9Sstevel@tonic-gate usb_mid_t *usb_mid = usb_mid_obtain_state(dip); 1139*7c478bd9Sstevel@tonic-gate 1140*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle, 1141*7c478bd9Sstevel@tonic-gate "usb_mid_busop_get_eventcookie: dip=0x%p, rdip=0x%p, " 1142*7c478bd9Sstevel@tonic-gate "event=%s", (void *)dip, (void *)rdip, eventname); 1143*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle, 1144*7c478bd9Sstevel@tonic-gate "(dip=%s%d rdip=%s%d)", 1145*7c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 1146*7c478bd9Sstevel@tonic-gate ddi_driver_name(rdip), ddi_get_instance(rdip)); 1147*7c478bd9Sstevel@tonic-gate 1148*7c478bd9Sstevel@tonic-gate /* return event cookie, iblock cookie, and level */ 1149*7c478bd9Sstevel@tonic-gate return (ndi_event_retrieve_cookie(usb_mid->mi_ndi_event_hdl, 1150*7c478bd9Sstevel@tonic-gate rdip, eventname, cookie, NDI_EVENT_NOPASS)); 1151*7c478bd9Sstevel@tonic-gate } 1152*7c478bd9Sstevel@tonic-gate 1153*7c478bd9Sstevel@tonic-gate 1154*7c478bd9Sstevel@tonic-gate static int 1155*7c478bd9Sstevel@tonic-gate usb_mid_busop_add_eventcall(dev_info_t *dip, 1156*7c478bd9Sstevel@tonic-gate dev_info_t *rdip, 1157*7c478bd9Sstevel@tonic-gate ddi_eventcookie_t cookie, 1158*7c478bd9Sstevel@tonic-gate void (*callback)(dev_info_t *dip, 1159*7c478bd9Sstevel@tonic-gate ddi_eventcookie_t cookie, void *arg, 1160*7c478bd9Sstevel@tonic-gate void *bus_impldata), 1161*7c478bd9Sstevel@tonic-gate void *arg, ddi_callback_id_t *cb_id) 1162*7c478bd9Sstevel@tonic-gate { 1163*7c478bd9Sstevel@tonic-gate usb_mid_t *usb_mid = usb_mid_obtain_state(dip); 1164*7c478bd9Sstevel@tonic-gate int ifno = usba_get_ifno(rdip); 1165*7c478bd9Sstevel@tonic-gate 1166*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle, 1167*7c478bd9Sstevel@tonic-gate "usb_mid_busop_add_eventcall: dip=0x%p, rdip=0x%p " 1168*7c478bd9Sstevel@tonic-gate "cookie=0x%p, cb=0x%p, arg=0x%p", 1169*7c478bd9Sstevel@tonic-gate (void *)dip, (void *)rdip, (void *)cookie, (void *)callback, arg); 1170*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle, 1171*7c478bd9Sstevel@tonic-gate "(dip=%s%d rdip=%s%d event=%s)", 1172*7c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 1173*7c478bd9Sstevel@tonic-gate ddi_driver_name(rdip), ddi_get_instance(rdip), 1174*7c478bd9Sstevel@tonic-gate ndi_event_cookie_to_name(usb_mid->mi_ndi_event_hdl, cookie)); 1175*7c478bd9Sstevel@tonic-gate 1176*7c478bd9Sstevel@tonic-gate /* Set flag on children registering events */ 1177*7c478bd9Sstevel@tonic-gate switch (ndi_event_cookie_to_tag(usb_mid->mi_ndi_event_hdl, cookie)) { 1178*7c478bd9Sstevel@tonic-gate case USBA_EVENT_TAG_HOT_REMOVAL: 1179*7c478bd9Sstevel@tonic-gate mutex_enter(&usb_mid->mi_mutex); 1180*7c478bd9Sstevel@tonic-gate usb_mid->mi_child_events[ifno] |= 1181*7c478bd9Sstevel@tonic-gate USB_MID_CHILD_EVENT_DISCONNECT; 1182*7c478bd9Sstevel@tonic-gate mutex_exit(&usb_mid->mi_mutex); 1183*7c478bd9Sstevel@tonic-gate 1184*7c478bd9Sstevel@tonic-gate break; 1185*7c478bd9Sstevel@tonic-gate case USBA_EVENT_TAG_PRE_SUSPEND: 1186*7c478bd9Sstevel@tonic-gate mutex_enter(&usb_mid->mi_mutex); 1187*7c478bd9Sstevel@tonic-gate usb_mid->mi_child_events[ifno] |= 1188*7c478bd9Sstevel@tonic-gate USB_MID_CHILD_EVENT_PRESUSPEND; 1189*7c478bd9Sstevel@tonic-gate mutex_exit(&usb_mid->mi_mutex); 1190*7c478bd9Sstevel@tonic-gate 1191*7c478bd9Sstevel@tonic-gate break; 1192*7c478bd9Sstevel@tonic-gate default: 1193*7c478bd9Sstevel@tonic-gate 1194*7c478bd9Sstevel@tonic-gate break; 1195*7c478bd9Sstevel@tonic-gate } 1196*7c478bd9Sstevel@tonic-gate /* add callback (perform registration) */ 1197*7c478bd9Sstevel@tonic-gate return (ndi_event_add_callback(usb_mid->mi_ndi_event_hdl, 1198*7c478bd9Sstevel@tonic-gate rdip, cookie, callback, arg, NDI_SLEEP, cb_id)); 1199*7c478bd9Sstevel@tonic-gate } 1200*7c478bd9Sstevel@tonic-gate 1201*7c478bd9Sstevel@tonic-gate 1202*7c478bd9Sstevel@tonic-gate static int 1203*7c478bd9Sstevel@tonic-gate usb_mid_busop_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id) 1204*7c478bd9Sstevel@tonic-gate { 1205*7c478bd9Sstevel@tonic-gate usb_mid_t *usb_mid = usb_mid_obtain_state(dip); 1206*7c478bd9Sstevel@tonic-gate ndi_event_callbacks_t *cb = (ndi_event_callbacks_t *)cb_id; 1207*7c478bd9Sstevel@tonic-gate 1208*7c478bd9Sstevel@tonic-gate ASSERT(cb); 1209*7c478bd9Sstevel@tonic-gate 1210*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle, 1211*7c478bd9Sstevel@tonic-gate "usb_mid_busop_remove_eventcall: dip=0x%p, rdip=0x%p " 1212*7c478bd9Sstevel@tonic-gate "cookie=0x%p", (void *)dip, cb->ndi_evtcb_dip, 1213*7c478bd9Sstevel@tonic-gate cb->ndi_evtcb_cookie); 1214*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle, 1215*7c478bd9Sstevel@tonic-gate "(dip=%s%d rdip=%s%d event=%s)", 1216*7c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 1217*7c478bd9Sstevel@tonic-gate ddi_driver_name(cb->ndi_evtcb_dip), 1218*7c478bd9Sstevel@tonic-gate ddi_get_instance(cb->ndi_evtcb_dip), 1219*7c478bd9Sstevel@tonic-gate ndi_event_cookie_to_name(usb_mid->mi_ndi_event_hdl, 1220*7c478bd9Sstevel@tonic-gate cb->ndi_evtcb_cookie)); 1221*7c478bd9Sstevel@tonic-gate 1222*7c478bd9Sstevel@tonic-gate /* remove event registration from our event set */ 1223*7c478bd9Sstevel@tonic-gate return (ndi_event_remove_callback(usb_mid->mi_ndi_event_hdl, cb_id)); 1224*7c478bd9Sstevel@tonic-gate } 1225*7c478bd9Sstevel@tonic-gate 1226*7c478bd9Sstevel@tonic-gate 1227*7c478bd9Sstevel@tonic-gate static int 1228*7c478bd9Sstevel@tonic-gate usb_mid_busop_post_event(dev_info_t *dip, 1229*7c478bd9Sstevel@tonic-gate dev_info_t *rdip, 1230*7c478bd9Sstevel@tonic-gate ddi_eventcookie_t cookie, 1231*7c478bd9Sstevel@tonic-gate void *bus_impldata) 1232*7c478bd9Sstevel@tonic-gate { 1233*7c478bd9Sstevel@tonic-gate usb_mid_t *usb_mid = usb_mid_obtain_state(dip); 1234*7c478bd9Sstevel@tonic-gate 1235*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle, 1236*7c478bd9Sstevel@tonic-gate "usb_mid_busop_post_event: dip=0x%p, rdip=0x%p " 1237*7c478bd9Sstevel@tonic-gate "cookie=0x%p, impl=0x%p", 1238*7c478bd9Sstevel@tonic-gate (void *)dip, (void *)rdip, (void *)cookie, bus_impldata); 1239*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle, 1240*7c478bd9Sstevel@tonic-gate "(dip=%s%d rdip=%s%d event=%s)", 1241*7c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 1242*7c478bd9Sstevel@tonic-gate ddi_driver_name(rdip), ddi_get_instance(rdip), 1243*7c478bd9Sstevel@tonic-gate ndi_event_cookie_to_name(usb_mid->mi_ndi_event_hdl, cookie)); 1244*7c478bd9Sstevel@tonic-gate 1245*7c478bd9Sstevel@tonic-gate /* post event to all children registered for this event */ 1246*7c478bd9Sstevel@tonic-gate return (ndi_event_run_callbacks(usb_mid->mi_ndi_event_hdl, rdip, 1247*7c478bd9Sstevel@tonic-gate cookie, bus_impldata)); 1248*7c478bd9Sstevel@tonic-gate } 1249*7c478bd9Sstevel@tonic-gate 1250*7c478bd9Sstevel@tonic-gate 1251*7c478bd9Sstevel@tonic-gate /* 1252*7c478bd9Sstevel@tonic-gate * usb_mid_restore_device_state 1253*7c478bd9Sstevel@tonic-gate * set the original configuration of the device 1254*7c478bd9Sstevel@tonic-gate */ 1255*7c478bd9Sstevel@tonic-gate static int 1256*7c478bd9Sstevel@tonic-gate usb_mid_restore_device_state(dev_info_t *dip, usb_mid_t *usb_mid) 1257*7c478bd9Sstevel@tonic-gate { 1258*7c478bd9Sstevel@tonic-gate usb_mid_power_t *midpm; 1259*7c478bd9Sstevel@tonic-gate 1260*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle, 1261*7c478bd9Sstevel@tonic-gate "usb_mid_restore_device_state: usb_mid = %p", usb_mid); 1262*7c478bd9Sstevel@tonic-gate 1263*7c478bd9Sstevel@tonic-gate mutex_enter(&usb_mid->mi_mutex); 1264*7c478bd9Sstevel@tonic-gate midpm = usb_mid->mi_pm; 1265*7c478bd9Sstevel@tonic-gate mutex_exit(&usb_mid->mi_mutex); 1266*7c478bd9Sstevel@tonic-gate 1267*7c478bd9Sstevel@tonic-gate /* First bring the device to full power */ 1268*7c478bd9Sstevel@tonic-gate (void) pm_busy_component(dip, 0); 1269*7c478bd9Sstevel@tonic-gate (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 1270*7c478bd9Sstevel@tonic-gate 1271*7c478bd9Sstevel@tonic-gate if (usb_check_same_device(dip, usb_mid->mi_log_handle, USB_LOG_L0, 1272*7c478bd9Sstevel@tonic-gate DPRINT_MASK_EVENTS, USB_CHK_VIDPID, NULL) != USB_SUCCESS) { 1273*7c478bd9Sstevel@tonic-gate 1274*7c478bd9Sstevel@tonic-gate /* change the device state from suspended to disconnected */ 1275*7c478bd9Sstevel@tonic-gate mutex_enter(&usb_mid->mi_mutex); 1276*7c478bd9Sstevel@tonic-gate usb_mid->mi_dev_state = USB_DEV_DISCONNECTED; 1277*7c478bd9Sstevel@tonic-gate mutex_exit(&usb_mid->mi_mutex); 1278*7c478bd9Sstevel@tonic-gate (void) pm_idle_component(dip, 0); 1279*7c478bd9Sstevel@tonic-gate 1280*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 1281*7c478bd9Sstevel@tonic-gate } 1282*7c478bd9Sstevel@tonic-gate 1283*7c478bd9Sstevel@tonic-gate /* 1284*7c478bd9Sstevel@tonic-gate * if the device had remote wakeup earlier, 1285*7c478bd9Sstevel@tonic-gate * enable it again 1286*7c478bd9Sstevel@tonic-gate */ 1287*7c478bd9Sstevel@tonic-gate if (midpm->mip_wakeup_enabled) { 1288*7c478bd9Sstevel@tonic-gate (void) usb_handle_remote_wakeup(usb_mid->mi_dip, 1289*7c478bd9Sstevel@tonic-gate USB_REMOTE_WAKEUP_ENABLE); 1290*7c478bd9Sstevel@tonic-gate } 1291*7c478bd9Sstevel@tonic-gate 1292*7c478bd9Sstevel@tonic-gate mutex_enter(&usb_mid->mi_mutex); 1293*7c478bd9Sstevel@tonic-gate usb_mid->mi_dev_state = USB_DEV_ONLINE; 1294*7c478bd9Sstevel@tonic-gate mutex_exit(&usb_mid->mi_mutex); 1295*7c478bd9Sstevel@tonic-gate 1296*7c478bd9Sstevel@tonic-gate (void) pm_idle_component(dip, 0); 1297*7c478bd9Sstevel@tonic-gate 1298*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 1299*7c478bd9Sstevel@tonic-gate } 1300*7c478bd9Sstevel@tonic-gate 1301*7c478bd9Sstevel@tonic-gate 1302*7c478bd9Sstevel@tonic-gate /* 1303*7c478bd9Sstevel@tonic-gate * usb_mid_event_cb() 1304*7c478bd9Sstevel@tonic-gate * handle disconnect and connect events 1305*7c478bd9Sstevel@tonic-gate */ 1306*7c478bd9Sstevel@tonic-gate static void 1307*7c478bd9Sstevel@tonic-gate usb_mid_event_cb(dev_info_t *dip, ddi_eventcookie_t cookie, 1308*7c478bd9Sstevel@tonic-gate void *arg, void *bus_impldata) 1309*7c478bd9Sstevel@tonic-gate { 1310*7c478bd9Sstevel@tonic-gate int i, tag; 1311*7c478bd9Sstevel@tonic-gate usb_mid_t *usb_mid = usb_mid_obtain_state(dip); 1312*7c478bd9Sstevel@tonic-gate dev_info_t *child_dip; 1313*7c478bd9Sstevel@tonic-gate ddi_eventcookie_t rm_cookie, ins_cookie, suspend_cookie, resume_cookie; 1314*7c478bd9Sstevel@tonic-gate 1315*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle, 1316*7c478bd9Sstevel@tonic-gate "usb_mid_event_cb: dip=0x%p, cookie=0x%p, " 1317*7c478bd9Sstevel@tonic-gate "arg=0x%p, impl=0x%p", 1318*7c478bd9Sstevel@tonic-gate (void *)dip, (void *)cookie, arg, bus_impldata); 1319*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle, 1320*7c478bd9Sstevel@tonic-gate "(dip=%s%d event=%s)", 1321*7c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 1322*7c478bd9Sstevel@tonic-gate ndi_event_cookie_to_name(usb_mid->mi_ndi_event_hdl, cookie)); 1323*7c478bd9Sstevel@tonic-gate 1324*7c478bd9Sstevel@tonic-gate tag = NDI_EVENT_TAG(cookie); 1325*7c478bd9Sstevel@tonic-gate rm_cookie = ndi_event_tag_to_cookie( 1326*7c478bd9Sstevel@tonic-gate usb_mid->mi_ndi_event_hdl, USBA_EVENT_TAG_HOT_REMOVAL); 1327*7c478bd9Sstevel@tonic-gate suspend_cookie = ndi_event_tag_to_cookie( 1328*7c478bd9Sstevel@tonic-gate usb_mid->mi_ndi_event_hdl, USBA_EVENT_TAG_PRE_SUSPEND); 1329*7c478bd9Sstevel@tonic-gate ins_cookie = ndi_event_tag_to_cookie( 1330*7c478bd9Sstevel@tonic-gate usb_mid->mi_ndi_event_hdl, USBA_EVENT_TAG_HOT_INSERTION); 1331*7c478bd9Sstevel@tonic-gate resume_cookie = ndi_event_tag_to_cookie( 1332*7c478bd9Sstevel@tonic-gate usb_mid->mi_ndi_event_hdl, USBA_EVENT_TAG_POST_RESUME); 1333*7c478bd9Sstevel@tonic-gate 1334*7c478bd9Sstevel@tonic-gate mutex_enter(&usb_mid->mi_mutex); 1335*7c478bd9Sstevel@tonic-gate switch (tag) { 1336*7c478bd9Sstevel@tonic-gate case USBA_EVENT_TAG_HOT_REMOVAL: 1337*7c478bd9Sstevel@tonic-gate if (usb_mid->mi_dev_state == USB_DEV_DISCONNECTED) { 1338*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_EVENTS, 1339*7c478bd9Sstevel@tonic-gate usb_mid->mi_log_handle, 1340*7c478bd9Sstevel@tonic-gate "usb_mid_event_cb: Device already disconnected"); 1341*7c478bd9Sstevel@tonic-gate } else { 1342*7c478bd9Sstevel@tonic-gate /* we are disconnected so set our state now */ 1343*7c478bd9Sstevel@tonic-gate usb_mid->mi_dev_state = USB_DEV_DISCONNECTED; 1344*7c478bd9Sstevel@tonic-gate for (i = 0; i < usb_mid->mi_n_ifs; i++) { 1345*7c478bd9Sstevel@tonic-gate usb_mid->mi_child_events[i] &= ~ 1346*7c478bd9Sstevel@tonic-gate USB_MID_CHILD_EVENT_DISCONNECT; 1347*7c478bd9Sstevel@tonic-gate } 1348*7c478bd9Sstevel@tonic-gate mutex_exit(&usb_mid->mi_mutex); 1349*7c478bd9Sstevel@tonic-gate 1350*7c478bd9Sstevel@tonic-gate /* pass disconnect event to all the children */ 1351*7c478bd9Sstevel@tonic-gate (void) ndi_event_run_callbacks( 1352*7c478bd9Sstevel@tonic-gate usb_mid->mi_ndi_event_hdl, NULL, 1353*7c478bd9Sstevel@tonic-gate rm_cookie, bus_impldata); 1354*7c478bd9Sstevel@tonic-gate 1355*7c478bd9Sstevel@tonic-gate if (usb_mid->mi_ugen_hdl) { 1356*7c478bd9Sstevel@tonic-gate (void) usb_ugen_disconnect_ev_cb( 1357*7c478bd9Sstevel@tonic-gate usb_mid->mi_ugen_hdl); 1358*7c478bd9Sstevel@tonic-gate } 1359*7c478bd9Sstevel@tonic-gate mutex_enter(&usb_mid->mi_mutex); 1360*7c478bd9Sstevel@tonic-gate } 1361*7c478bd9Sstevel@tonic-gate break; 1362*7c478bd9Sstevel@tonic-gate case USBA_EVENT_TAG_PRE_SUSPEND: 1363*7c478bd9Sstevel@tonic-gate /* set our state *after* suspending children */ 1364*7c478bd9Sstevel@tonic-gate mutex_exit(&usb_mid->mi_mutex); 1365*7c478bd9Sstevel@tonic-gate 1366*7c478bd9Sstevel@tonic-gate /* pass pre_suspend event to all the children */ 1367*7c478bd9Sstevel@tonic-gate (void) ndi_event_run_callbacks(usb_mid->mi_ndi_event_hdl, 1368*7c478bd9Sstevel@tonic-gate NULL, suspend_cookie, bus_impldata); 1369*7c478bd9Sstevel@tonic-gate 1370*7c478bd9Sstevel@tonic-gate mutex_enter(&usb_mid->mi_mutex); 1371*7c478bd9Sstevel@tonic-gate for (i = 0; i < usb_mid->mi_n_ifs; i++) { 1372*7c478bd9Sstevel@tonic-gate usb_mid->mi_child_events[i] &= ~ 1373*7c478bd9Sstevel@tonic-gate USB_MID_CHILD_EVENT_PRESUSPEND; 1374*7c478bd9Sstevel@tonic-gate } 1375*7c478bd9Sstevel@tonic-gate break; 1376*7c478bd9Sstevel@tonic-gate case USBA_EVENT_TAG_HOT_INSERTION: 1377*7c478bd9Sstevel@tonic-gate mutex_exit(&usb_mid->mi_mutex); 1378*7c478bd9Sstevel@tonic-gate if (usb_mid_restore_device_state(dip, usb_mid) == USB_SUCCESS) { 1379*7c478bd9Sstevel@tonic-gate 1380*7c478bd9Sstevel@tonic-gate /* 1381*7c478bd9Sstevel@tonic-gate * Check to see if this child has missed the disconnect 1382*7c478bd9Sstevel@tonic-gate * event before it registered for event cb 1383*7c478bd9Sstevel@tonic-gate */ 1384*7c478bd9Sstevel@tonic-gate mutex_enter(&usb_mid->mi_mutex); 1385*7c478bd9Sstevel@tonic-gate for (i = 0; i < usb_mid->mi_n_ifs; i++) { 1386*7c478bd9Sstevel@tonic-gate if (usb_mid->mi_child_events[i] & 1387*7c478bd9Sstevel@tonic-gate USB_MID_CHILD_EVENT_DISCONNECT) { 1388*7c478bd9Sstevel@tonic-gate usb_mid->mi_child_events[i] &= 1389*7c478bd9Sstevel@tonic-gate ~USB_MID_CHILD_EVENT_DISCONNECT; 1390*7c478bd9Sstevel@tonic-gate child_dip = 1391*7c478bd9Sstevel@tonic-gate usb_mid->mi_children_dips[i]; 1392*7c478bd9Sstevel@tonic-gate mutex_exit(&usb_mid->mi_mutex); 1393*7c478bd9Sstevel@tonic-gate 1394*7c478bd9Sstevel@tonic-gate /* post the missed disconnect */ 1395*7c478bd9Sstevel@tonic-gate (void) ndi_event_do_callback( 1396*7c478bd9Sstevel@tonic-gate usb_mid->mi_ndi_event_hdl, 1397*7c478bd9Sstevel@tonic-gate child_dip, 1398*7c478bd9Sstevel@tonic-gate rm_cookie, 1399*7c478bd9Sstevel@tonic-gate bus_impldata); 1400*7c478bd9Sstevel@tonic-gate mutex_enter(&usb_mid->mi_mutex); 1401*7c478bd9Sstevel@tonic-gate } 1402*7c478bd9Sstevel@tonic-gate } 1403*7c478bd9Sstevel@tonic-gate mutex_exit(&usb_mid->mi_mutex); 1404*7c478bd9Sstevel@tonic-gate 1405*7c478bd9Sstevel@tonic-gate /* pass reconnect event to all the children */ 1406*7c478bd9Sstevel@tonic-gate (void) ndi_event_run_callbacks( 1407*7c478bd9Sstevel@tonic-gate usb_mid->mi_ndi_event_hdl, NULL, 1408*7c478bd9Sstevel@tonic-gate ins_cookie, bus_impldata); 1409*7c478bd9Sstevel@tonic-gate 1410*7c478bd9Sstevel@tonic-gate if (usb_mid->mi_ugen_hdl) { 1411*7c478bd9Sstevel@tonic-gate (void) usb_ugen_reconnect_ev_cb( 1412*7c478bd9Sstevel@tonic-gate usb_mid->mi_ugen_hdl); 1413*7c478bd9Sstevel@tonic-gate } 1414*7c478bd9Sstevel@tonic-gate } 1415*7c478bd9Sstevel@tonic-gate mutex_enter(&usb_mid->mi_mutex); 1416*7c478bd9Sstevel@tonic-gate break; 1417*7c478bd9Sstevel@tonic-gate case USBA_EVENT_TAG_POST_RESUME: 1418*7c478bd9Sstevel@tonic-gate /* 1419*7c478bd9Sstevel@tonic-gate * Check to see if this child has missed the pre-suspend 1420*7c478bd9Sstevel@tonic-gate * event before it registered for event cb 1421*7c478bd9Sstevel@tonic-gate */ 1422*7c478bd9Sstevel@tonic-gate for (i = 0; i < usb_mid->mi_n_ifs; i++) { 1423*7c478bd9Sstevel@tonic-gate if (usb_mid->mi_child_events[i] & 1424*7c478bd9Sstevel@tonic-gate USB_MID_CHILD_EVENT_PRESUSPEND) { 1425*7c478bd9Sstevel@tonic-gate usb_mid->mi_child_events[i] &= 1426*7c478bd9Sstevel@tonic-gate ~USB_MID_CHILD_EVENT_PRESUSPEND; 1427*7c478bd9Sstevel@tonic-gate child_dip = usb_mid->mi_children_dips[i]; 1428*7c478bd9Sstevel@tonic-gate mutex_exit(&usb_mid->mi_mutex); 1429*7c478bd9Sstevel@tonic-gate 1430*7c478bd9Sstevel@tonic-gate /* post the missed pre-suspend event */ 1431*7c478bd9Sstevel@tonic-gate (void) ndi_event_do_callback( 1432*7c478bd9Sstevel@tonic-gate usb_mid->mi_ndi_event_hdl, 1433*7c478bd9Sstevel@tonic-gate child_dip, suspend_cookie, 1434*7c478bd9Sstevel@tonic-gate bus_impldata); 1435*7c478bd9Sstevel@tonic-gate mutex_enter(&usb_mid->mi_mutex); 1436*7c478bd9Sstevel@tonic-gate } 1437*7c478bd9Sstevel@tonic-gate } 1438*7c478bd9Sstevel@tonic-gate mutex_exit(&usb_mid->mi_mutex); 1439*7c478bd9Sstevel@tonic-gate 1440*7c478bd9Sstevel@tonic-gate /* pass post_resume event to all the children */ 1441*7c478bd9Sstevel@tonic-gate (void) ndi_event_run_callbacks(usb_mid->mi_ndi_event_hdl, 1442*7c478bd9Sstevel@tonic-gate NULL, resume_cookie, bus_impldata); 1443*7c478bd9Sstevel@tonic-gate 1444*7c478bd9Sstevel@tonic-gate mutex_enter(&usb_mid->mi_mutex); 1445*7c478bd9Sstevel@tonic-gate break; 1446*7c478bd9Sstevel@tonic-gate } 1447*7c478bd9Sstevel@tonic-gate mutex_exit(&usb_mid->mi_mutex); 1448*7c478bd9Sstevel@tonic-gate 1449*7c478bd9Sstevel@tonic-gate } 1450*7c478bd9Sstevel@tonic-gate 1451*7c478bd9Sstevel@tonic-gate 1452*7c478bd9Sstevel@tonic-gate /* 1453*7c478bd9Sstevel@tonic-gate * register and unregister for events from our parent 1454*7c478bd9Sstevel@tonic-gate * 1455*7c478bd9Sstevel@tonic-gate * Note: usb_mid doesn't use the cookie fields in usba_device structure. 1456*7c478bd9Sstevel@tonic-gate * They are used/shared by children of usb_mid. 1457*7c478bd9Sstevel@tonic-gate */ 1458*7c478bd9Sstevel@tonic-gate static void 1459*7c478bd9Sstevel@tonic-gate usb_mid_register_events(usb_mid_t *usb_mid) 1460*7c478bd9Sstevel@tonic-gate { 1461*7c478bd9Sstevel@tonic-gate int rval; 1462*7c478bd9Sstevel@tonic-gate usba_evdata_t *evdata; 1463*7c478bd9Sstevel@tonic-gate ddi_eventcookie_t cookie; 1464*7c478bd9Sstevel@tonic-gate 1465*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_PM, usb_mid->mi_log_handle, 1466*7c478bd9Sstevel@tonic-gate "usb_mid_register_events:"); 1467*7c478bd9Sstevel@tonic-gate 1468*7c478bd9Sstevel@tonic-gate evdata = usba_get_evdata(usb_mid->mi_dip); 1469*7c478bd9Sstevel@tonic-gate 1470*7c478bd9Sstevel@tonic-gate /* get event cookie, discard level and icookie for now */ 1471*7c478bd9Sstevel@tonic-gate rval = ddi_get_eventcookie(usb_mid->mi_dip, DDI_DEVI_REMOVE_EVENT, 1472*7c478bd9Sstevel@tonic-gate &cookie); 1473*7c478bd9Sstevel@tonic-gate 1474*7c478bd9Sstevel@tonic-gate if (rval == DDI_SUCCESS) { 1475*7c478bd9Sstevel@tonic-gate rval = ddi_add_event_handler(usb_mid->mi_dip, 1476*7c478bd9Sstevel@tonic-gate cookie, usb_mid_event_cb, NULL, &evdata->ev_rm_cb_id); 1477*7c478bd9Sstevel@tonic-gate 1478*7c478bd9Sstevel@tonic-gate if (rval != DDI_SUCCESS) { 1479*7c478bd9Sstevel@tonic-gate 1480*7c478bd9Sstevel@tonic-gate goto fail; 1481*7c478bd9Sstevel@tonic-gate } 1482*7c478bd9Sstevel@tonic-gate } 1483*7c478bd9Sstevel@tonic-gate rval = ddi_get_eventcookie(usb_mid->mi_dip, DDI_DEVI_INSERT_EVENT, 1484*7c478bd9Sstevel@tonic-gate &cookie); 1485*7c478bd9Sstevel@tonic-gate if (rval == DDI_SUCCESS) { 1486*7c478bd9Sstevel@tonic-gate rval = ddi_add_event_handler(usb_mid->mi_dip, 1487*7c478bd9Sstevel@tonic-gate cookie, usb_mid_event_cb, NULL, &evdata->ev_ins_cb_id); 1488*7c478bd9Sstevel@tonic-gate 1489*7c478bd9Sstevel@tonic-gate if (rval != DDI_SUCCESS) { 1490*7c478bd9Sstevel@tonic-gate 1491*7c478bd9Sstevel@tonic-gate goto fail; 1492*7c478bd9Sstevel@tonic-gate } 1493*7c478bd9Sstevel@tonic-gate } 1494*7c478bd9Sstevel@tonic-gate rval = ddi_get_eventcookie(usb_mid->mi_dip, USBA_PRE_SUSPEND_EVENT, 1495*7c478bd9Sstevel@tonic-gate &cookie); 1496*7c478bd9Sstevel@tonic-gate if (rval == DDI_SUCCESS) { 1497*7c478bd9Sstevel@tonic-gate rval = ddi_add_event_handler(usb_mid->mi_dip, 1498*7c478bd9Sstevel@tonic-gate cookie, usb_mid_event_cb, NULL, &evdata->ev_suspend_cb_id); 1499*7c478bd9Sstevel@tonic-gate 1500*7c478bd9Sstevel@tonic-gate if (rval != DDI_SUCCESS) { 1501*7c478bd9Sstevel@tonic-gate 1502*7c478bd9Sstevel@tonic-gate goto fail; 1503*7c478bd9Sstevel@tonic-gate } 1504*7c478bd9Sstevel@tonic-gate } 1505*7c478bd9Sstevel@tonic-gate rval = ddi_get_eventcookie(usb_mid->mi_dip, USBA_POST_RESUME_EVENT, 1506*7c478bd9Sstevel@tonic-gate &cookie); 1507*7c478bd9Sstevel@tonic-gate if (rval == DDI_SUCCESS) { 1508*7c478bd9Sstevel@tonic-gate rval = ddi_add_event_handler(usb_mid->mi_dip, 1509*7c478bd9Sstevel@tonic-gate cookie, usb_mid_event_cb, NULL, 1510*7c478bd9Sstevel@tonic-gate &evdata->ev_resume_cb_id); 1511*7c478bd9Sstevel@tonic-gate 1512*7c478bd9Sstevel@tonic-gate if (rval != DDI_SUCCESS) { 1513*7c478bd9Sstevel@tonic-gate 1514*7c478bd9Sstevel@tonic-gate goto fail; 1515*7c478bd9Sstevel@tonic-gate } 1516*7c478bd9Sstevel@tonic-gate } 1517*7c478bd9Sstevel@tonic-gate 1518*7c478bd9Sstevel@tonic-gate return; 1519*7c478bd9Sstevel@tonic-gate 1520*7c478bd9Sstevel@tonic-gate 1521*7c478bd9Sstevel@tonic-gate fail: 1522*7c478bd9Sstevel@tonic-gate usb_mid_unregister_events(usb_mid); 1523*7c478bd9Sstevel@tonic-gate 1524*7c478bd9Sstevel@tonic-gate } 1525*7c478bd9Sstevel@tonic-gate 1526*7c478bd9Sstevel@tonic-gate 1527*7c478bd9Sstevel@tonic-gate static void 1528*7c478bd9Sstevel@tonic-gate usb_mid_unregister_events(usb_mid_t *usb_mid) 1529*7c478bd9Sstevel@tonic-gate { 1530*7c478bd9Sstevel@tonic-gate int rval; 1531*7c478bd9Sstevel@tonic-gate usba_evdata_t *evdata; 1532*7c478bd9Sstevel@tonic-gate usba_device_t *usba_device = usba_get_usba_device(usb_mid->mi_dip); 1533*7c478bd9Sstevel@tonic-gate 1534*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_PM, usb_mid->mi_log_handle, 1535*7c478bd9Sstevel@tonic-gate "usb_mid_unregister_events:"); 1536*7c478bd9Sstevel@tonic-gate 1537*7c478bd9Sstevel@tonic-gate evdata = usba_get_evdata(usb_mid->mi_dip); 1538*7c478bd9Sstevel@tonic-gate if (evdata) { 1539*7c478bd9Sstevel@tonic-gate if (evdata->ev_rm_cb_id) { 1540*7c478bd9Sstevel@tonic-gate rval = ddi_remove_event_handler(evdata->ev_rm_cb_id); 1541*7c478bd9Sstevel@tonic-gate ASSERT(rval == DDI_SUCCESS); 1542*7c478bd9Sstevel@tonic-gate } 1543*7c478bd9Sstevel@tonic-gate 1544*7c478bd9Sstevel@tonic-gate if (evdata->ev_ins_cb_id) { 1545*7c478bd9Sstevel@tonic-gate rval = ddi_remove_event_handler(evdata->ev_ins_cb_id); 1546*7c478bd9Sstevel@tonic-gate ASSERT(rval == DDI_SUCCESS); 1547*7c478bd9Sstevel@tonic-gate } 1548*7c478bd9Sstevel@tonic-gate 1549*7c478bd9Sstevel@tonic-gate if (evdata->ev_resume_cb_id) { 1550*7c478bd9Sstevel@tonic-gate rval = 1551*7c478bd9Sstevel@tonic-gate ddi_remove_event_handler(evdata->ev_resume_cb_id); 1552*7c478bd9Sstevel@tonic-gate ASSERT(rval == DDI_SUCCESS); 1553*7c478bd9Sstevel@tonic-gate } 1554*7c478bd9Sstevel@tonic-gate 1555*7c478bd9Sstevel@tonic-gate if (evdata->ev_suspend_cb_id) { 1556*7c478bd9Sstevel@tonic-gate rval = 1557*7c478bd9Sstevel@tonic-gate ddi_remove_event_handler(evdata->ev_suspend_cb_id); 1558*7c478bd9Sstevel@tonic-gate ASSERT(rval == DDI_SUCCESS); 1559*7c478bd9Sstevel@tonic-gate } 1560*7c478bd9Sstevel@tonic-gate } 1561*7c478bd9Sstevel@tonic-gate 1562*7c478bd9Sstevel@tonic-gate /* clear event data for children, required for cfgmadm unconfigure */ 1563*7c478bd9Sstevel@tonic-gate usba_free_evdata(usba_device->usb_evdata); 1564*7c478bd9Sstevel@tonic-gate usba_device->usb_evdata = NULL; 1565*7c478bd9Sstevel@tonic-gate usba_device->rm_cookie = NULL; 1566*7c478bd9Sstevel@tonic-gate usba_device->ins_cookie = NULL; 1567*7c478bd9Sstevel@tonic-gate usba_device->suspend_cookie = NULL; 1568*7c478bd9Sstevel@tonic-gate usba_device->resume_cookie = NULL; 1569*7c478bd9Sstevel@tonic-gate } 1570*7c478bd9Sstevel@tonic-gate 1571*7c478bd9Sstevel@tonic-gate 1572*7c478bd9Sstevel@tonic-gate /* 1573*7c478bd9Sstevel@tonic-gate * create the pm components required for power management 1574*7c478bd9Sstevel@tonic-gate */ 1575*7c478bd9Sstevel@tonic-gate static void 1576*7c478bd9Sstevel@tonic-gate usb_mid_create_pm_components(dev_info_t *dip, usb_mid_t *usb_mid) 1577*7c478bd9Sstevel@tonic-gate { 1578*7c478bd9Sstevel@tonic-gate usb_mid_power_t *midpm; 1579*7c478bd9Sstevel@tonic-gate uint_t pwr_states; 1580*7c478bd9Sstevel@tonic-gate 1581*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_PM, usb_mid->mi_log_handle, 1582*7c478bd9Sstevel@tonic-gate "usb_mid_create_pm_components: Begin"); 1583*7c478bd9Sstevel@tonic-gate 1584*7c478bd9Sstevel@tonic-gate /* Allocate the PM state structure */ 1585*7c478bd9Sstevel@tonic-gate midpm = kmem_zalloc(sizeof (usb_mid_power_t), KM_SLEEP); 1586*7c478bd9Sstevel@tonic-gate 1587*7c478bd9Sstevel@tonic-gate mutex_enter(&usb_mid->mi_mutex); 1588*7c478bd9Sstevel@tonic-gate usb_mid->mi_pm = midpm; 1589*7c478bd9Sstevel@tonic-gate midpm->mip_usb_mid = usb_mid; 1590*7c478bd9Sstevel@tonic-gate midpm->mip_pm_capabilities = 0; /* XXXX should this be 0?? */ 1591*7c478bd9Sstevel@tonic-gate midpm->mip_current_power = USB_DEV_OS_FULL_PWR; 1592*7c478bd9Sstevel@tonic-gate mutex_exit(&usb_mid->mi_mutex); 1593*7c478bd9Sstevel@tonic-gate 1594*7c478bd9Sstevel@tonic-gate /* 1595*7c478bd9Sstevel@tonic-gate * By not enabling parental notification, PM enforces 1596*7c478bd9Sstevel@tonic-gate * "strict parental dependency" meaning, usb_mid won't 1597*7c478bd9Sstevel@tonic-gate * power off until any of its children are in full power. 1598*7c478bd9Sstevel@tonic-gate */ 1599*7c478bd9Sstevel@tonic-gate 1600*7c478bd9Sstevel@tonic-gate /* 1601*7c478bd9Sstevel@tonic-gate * there are 3 scenarios: 1602*7c478bd9Sstevel@tonic-gate * 1. a well behaved device should have remote wakeup 1603*7c478bd9Sstevel@tonic-gate * at interface and device level. If the interface 1604*7c478bd9Sstevel@tonic-gate * wakes up, usb_mid will wake up 1605*7c478bd9Sstevel@tonic-gate * 2. if the device doesn't have remote wake up and 1606*7c478bd9Sstevel@tonic-gate * the interface has, PM will still work, ie. 1607*7c478bd9Sstevel@tonic-gate * the interfaces wakes up and usb_mid wakes up 1608*7c478bd9Sstevel@tonic-gate * 3. if neither the interface nor device has remote 1609*7c478bd9Sstevel@tonic-gate * wakeup, the interface will wake up when it is opened 1610*7c478bd9Sstevel@tonic-gate * and goes to sleep after being closed for a while 1611*7c478bd9Sstevel@tonic-gate * In this case usb_mid should also go to sleep shortly 1612*7c478bd9Sstevel@tonic-gate * thereafter 1613*7c478bd9Sstevel@tonic-gate * In all scenarios it doesn't really matter whether 1614*7c478bd9Sstevel@tonic-gate * remote wakeup at the device level is enabled or not 1615*7c478bd9Sstevel@tonic-gate * but we do it anyways 1616*7c478bd9Sstevel@tonic-gate */ 1617*7c478bd9Sstevel@tonic-gate if (usb_handle_remote_wakeup(dip, USB_REMOTE_WAKEUP_ENABLE) == 1618*7c478bd9Sstevel@tonic-gate USB_SUCCESS) { 1619*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_PM, usb_mid->mi_log_handle, 1620*7c478bd9Sstevel@tonic-gate "usb_mid_create_pm_components: " 1621*7c478bd9Sstevel@tonic-gate "Remote Wakeup Enabled"); 1622*7c478bd9Sstevel@tonic-gate midpm->mip_wakeup_enabled = 1; 1623*7c478bd9Sstevel@tonic-gate } 1624*7c478bd9Sstevel@tonic-gate 1625*7c478bd9Sstevel@tonic-gate if (usb_create_pm_components(dip, &pwr_states) == 1626*7c478bd9Sstevel@tonic-gate USB_SUCCESS) { 1627*7c478bd9Sstevel@tonic-gate midpm->mip_pwr_states = (uint8_t)pwr_states; 1628*7c478bd9Sstevel@tonic-gate (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 1629*7c478bd9Sstevel@tonic-gate } 1630*7c478bd9Sstevel@tonic-gate 1631*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_PM, usb_mid->mi_log_handle, 1632*7c478bd9Sstevel@tonic-gate "usb_mid_create_pm_components: End"); 1633*7c478bd9Sstevel@tonic-gate } 1634*7c478bd9Sstevel@tonic-gate 1635*7c478bd9Sstevel@tonic-gate 1636*7c478bd9Sstevel@tonic-gate /* 1637*7c478bd9Sstevel@tonic-gate * usb_mid_obtain_state: 1638*7c478bd9Sstevel@tonic-gate */ 1639*7c478bd9Sstevel@tonic-gate usb_mid_t * 1640*7c478bd9Sstevel@tonic-gate usb_mid_obtain_state(dev_info_t *dip) 1641*7c478bd9Sstevel@tonic-gate { 1642*7c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 1643*7c478bd9Sstevel@tonic-gate usb_mid_t *statep = ddi_get_soft_state(usb_mid_statep, instance); 1644*7c478bd9Sstevel@tonic-gate 1645*7c478bd9Sstevel@tonic-gate ASSERT(statep != NULL); 1646*7c478bd9Sstevel@tonic-gate 1647*7c478bd9Sstevel@tonic-gate return (statep); 1648*7c478bd9Sstevel@tonic-gate } 1649*7c478bd9Sstevel@tonic-gate 1650*7c478bd9Sstevel@tonic-gate 1651*7c478bd9Sstevel@tonic-gate /* 1652*7c478bd9Sstevel@tonic-gate * ugen support 1653*7c478bd9Sstevel@tonic-gate */ 1654*7c478bd9Sstevel@tonic-gate /* ARGSUSED3 */ 1655*7c478bd9Sstevel@tonic-gate static int 1656*7c478bd9Sstevel@tonic-gate usb_mid_open(dev_t *devp, int flags, int otyp, cred_t *credp) 1657*7c478bd9Sstevel@tonic-gate { 1658*7c478bd9Sstevel@tonic-gate struct usb_mid *usb_mid; 1659*7c478bd9Sstevel@tonic-gate int rval; 1660*7c478bd9Sstevel@tonic-gate 1661*7c478bd9Sstevel@tonic-gate if ((usb_mid = ddi_get_soft_state(usb_mid_statep, 1662*7c478bd9Sstevel@tonic-gate USB_MID_MINOR_TO_INSTANCE(getminor(*devp)))) == NULL) { 1663*7c478bd9Sstevel@tonic-gate 1664*7c478bd9Sstevel@tonic-gate return (ENXIO); 1665*7c478bd9Sstevel@tonic-gate } 1666*7c478bd9Sstevel@tonic-gate 1667*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_CBOPS, usb_mid->mi_log_handle, 1668*7c478bd9Sstevel@tonic-gate "usb_mid_open: usb_mid = 0x%p *devp = 0x%lx", usb_mid, *devp); 1669*7c478bd9Sstevel@tonic-gate 1670*7c478bd9Sstevel@tonic-gate /* First bring the device to full power */ 1671*7c478bd9Sstevel@tonic-gate (void) pm_busy_component(usb_mid->mi_dip, 0); 1672*7c478bd9Sstevel@tonic-gate (void) pm_raise_power(usb_mid->mi_dip, 0, USB_DEV_OS_FULL_PWR); 1673*7c478bd9Sstevel@tonic-gate 1674*7c478bd9Sstevel@tonic-gate 1675*7c478bd9Sstevel@tonic-gate rval = usb_ugen_open(usb_mid->mi_ugen_hdl, devp, flags, otyp, 1676*7c478bd9Sstevel@tonic-gate credp); 1677*7c478bd9Sstevel@tonic-gate if (rval) { 1678*7c478bd9Sstevel@tonic-gate (void) pm_idle_component(usb_mid->mi_dip, 0); 1679*7c478bd9Sstevel@tonic-gate } else { 1680*7c478bd9Sstevel@tonic-gate /* 1681*7c478bd9Sstevel@tonic-gate * since all ugen opens are exclusive we can count the 1682*7c478bd9Sstevel@tonic-gate * opens 1683*7c478bd9Sstevel@tonic-gate */ 1684*7c478bd9Sstevel@tonic-gate mutex_enter(&usb_mid->mi_mutex); 1685*7c478bd9Sstevel@tonic-gate usb_mid->mi_ugen_open_count++; 1686*7c478bd9Sstevel@tonic-gate mutex_exit(&usb_mid->mi_mutex); 1687*7c478bd9Sstevel@tonic-gate } 1688*7c478bd9Sstevel@tonic-gate 1689*7c478bd9Sstevel@tonic-gate return (rval); 1690*7c478bd9Sstevel@tonic-gate } 1691*7c478bd9Sstevel@tonic-gate 1692*7c478bd9Sstevel@tonic-gate 1693*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1694*7c478bd9Sstevel@tonic-gate static int 1695*7c478bd9Sstevel@tonic-gate usb_mid_close(dev_t dev, int flag, int otyp, cred_t *credp) 1696*7c478bd9Sstevel@tonic-gate { 1697*7c478bd9Sstevel@tonic-gate struct usb_mid *usb_mid; 1698*7c478bd9Sstevel@tonic-gate int rval; 1699*7c478bd9Sstevel@tonic-gate 1700*7c478bd9Sstevel@tonic-gate if ((usb_mid = ddi_get_soft_state(usb_mid_statep, 1701*7c478bd9Sstevel@tonic-gate USB_MID_MINOR_TO_INSTANCE(getminor(dev)))) == NULL) { 1702*7c478bd9Sstevel@tonic-gate 1703*7c478bd9Sstevel@tonic-gate return (ENXIO); 1704*7c478bd9Sstevel@tonic-gate } 1705*7c478bd9Sstevel@tonic-gate 1706*7c478bd9Sstevel@tonic-gate rval = usb_ugen_close(usb_mid->mi_ugen_hdl, dev, flag, otyp, 1707*7c478bd9Sstevel@tonic-gate credp); 1708*7c478bd9Sstevel@tonic-gate if (rval == 0) { 1709*7c478bd9Sstevel@tonic-gate (void) pm_idle_component(usb_mid->mi_dip, 0); 1710*7c478bd9Sstevel@tonic-gate mutex_enter(&usb_mid->mi_mutex); 1711*7c478bd9Sstevel@tonic-gate usb_mid->mi_ugen_open_count--; 1712*7c478bd9Sstevel@tonic-gate mutex_exit(&usb_mid->mi_mutex); 1713*7c478bd9Sstevel@tonic-gate } 1714*7c478bd9Sstevel@tonic-gate 1715*7c478bd9Sstevel@tonic-gate return (rval); 1716*7c478bd9Sstevel@tonic-gate } 1717*7c478bd9Sstevel@tonic-gate 1718*7c478bd9Sstevel@tonic-gate 1719*7c478bd9Sstevel@tonic-gate static int 1720*7c478bd9Sstevel@tonic-gate usb_mid_read(dev_t dev, struct uio *uio, cred_t *credp) 1721*7c478bd9Sstevel@tonic-gate { 1722*7c478bd9Sstevel@tonic-gate struct usb_mid *usb_mid; 1723*7c478bd9Sstevel@tonic-gate 1724*7c478bd9Sstevel@tonic-gate if ((usb_mid = ddi_get_soft_state(usb_mid_statep, 1725*7c478bd9Sstevel@tonic-gate USB_MID_MINOR_TO_INSTANCE(getminor(dev)))) == NULL) { 1726*7c478bd9Sstevel@tonic-gate 1727*7c478bd9Sstevel@tonic-gate return (ENXIO); 1728*7c478bd9Sstevel@tonic-gate } 1729*7c478bd9Sstevel@tonic-gate 1730*7c478bd9Sstevel@tonic-gate return (usb_ugen_read(usb_mid->mi_ugen_hdl, dev, uio, credp)); 1731*7c478bd9Sstevel@tonic-gate } 1732*7c478bd9Sstevel@tonic-gate 1733*7c478bd9Sstevel@tonic-gate 1734*7c478bd9Sstevel@tonic-gate static int 1735*7c478bd9Sstevel@tonic-gate usb_mid_write(dev_t dev, struct uio *uio, cred_t *credp) 1736*7c478bd9Sstevel@tonic-gate { 1737*7c478bd9Sstevel@tonic-gate struct usb_mid *usb_mid; 1738*7c478bd9Sstevel@tonic-gate 1739*7c478bd9Sstevel@tonic-gate if ((usb_mid = ddi_get_soft_state(usb_mid_statep, 1740*7c478bd9Sstevel@tonic-gate USB_MID_MINOR_TO_INSTANCE(getminor(dev)))) == NULL) { 1741*7c478bd9Sstevel@tonic-gate 1742*7c478bd9Sstevel@tonic-gate return (ENXIO); 1743*7c478bd9Sstevel@tonic-gate } 1744*7c478bd9Sstevel@tonic-gate 1745*7c478bd9Sstevel@tonic-gate return (usb_ugen_write(usb_mid->mi_ugen_hdl, dev, uio, credp)); 1746*7c478bd9Sstevel@tonic-gate } 1747*7c478bd9Sstevel@tonic-gate 1748*7c478bd9Sstevel@tonic-gate 1749*7c478bd9Sstevel@tonic-gate static int 1750*7c478bd9Sstevel@tonic-gate usb_mid_poll(dev_t dev, short events, int anyyet, short *reventsp, 1751*7c478bd9Sstevel@tonic-gate struct pollhead **phpp) 1752*7c478bd9Sstevel@tonic-gate { 1753*7c478bd9Sstevel@tonic-gate struct usb_mid *usb_mid; 1754*7c478bd9Sstevel@tonic-gate 1755*7c478bd9Sstevel@tonic-gate if ((usb_mid = ddi_get_soft_state(usb_mid_statep, 1756*7c478bd9Sstevel@tonic-gate USB_MID_MINOR_TO_INSTANCE(getminor(dev)))) == NULL) { 1757*7c478bd9Sstevel@tonic-gate 1758*7c478bd9Sstevel@tonic-gate return (ENXIO); 1759*7c478bd9Sstevel@tonic-gate } 1760*7c478bd9Sstevel@tonic-gate 1761*7c478bd9Sstevel@tonic-gate return (usb_ugen_poll(usb_mid->mi_ugen_hdl, dev, events, 1762*7c478bd9Sstevel@tonic-gate anyyet, reventsp, phpp)); 1763*7c478bd9Sstevel@tonic-gate } 1764