1*d73ae94eSgc /* 2*d73ae94eSgc * CDDL HEADER START 3*d73ae94eSgc * 4*d73ae94eSgc * The contents of this file are subject to the terms of the 5*d73ae94eSgc * Common Development and Distribution License (the "License"). 6*d73ae94eSgc * You may not use this file except in compliance with the License. 7*d73ae94eSgc * 8*d73ae94eSgc * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*d73ae94eSgc * or http://www.opensolaris.org/os/licensing. 10*d73ae94eSgc * See the License for the specific language governing permissions 11*d73ae94eSgc * and limitations under the License. 12*d73ae94eSgc * 13*d73ae94eSgc * When distributing Covered Code, include this CDDL HEADER in each 14*d73ae94eSgc * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*d73ae94eSgc * If applicable, add the following below this CDDL HEADER, with the 16*d73ae94eSgc * fields enclosed by brackets "[]" replaced with your own identifying 17*d73ae94eSgc * information: Portions Copyright [yyyy] [name of copyright owner] 18*d73ae94eSgc * 19*d73ae94eSgc * CDDL HEADER END 20*d73ae94eSgc */ 21*d73ae94eSgc /* 22*d73ae94eSgc * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23*d73ae94eSgc * Use is subject to license terms. 24*d73ae94eSgc */ 25*d73ae94eSgc 26*d73ae94eSgc #pragma ident "%Z%%M% %I% %E% SMI" 27*d73ae94eSgc 28*d73ae94eSgc /* 29*d73ae94eSgc * usb interface association driver 30*d73ae94eSgc * 31*d73ae94eSgc * this driver attempts to the interface association node and 32*d73ae94eSgc * creates/manages child nodes for the included interfaces. 33*d73ae94eSgc */ 34*d73ae94eSgc 35*d73ae94eSgc #if defined(lint) && !defined(DEBUG) 36*d73ae94eSgc #define DEBUG 1 37*d73ae94eSgc #endif 38*d73ae94eSgc #include <sys/usb/usba/usbai_version.h> 39*d73ae94eSgc #include <sys/usb/usba.h> 40*d73ae94eSgc #include <sys/usb/usba/usba_types.h> 41*d73ae94eSgc #include <sys/usb/usba/usba_impl.h> 42*d73ae94eSgc #include <sys/usb/usb_ia/usb_iavar.h> 43*d73ae94eSgc 44*d73ae94eSgc /* Debugging support */ 45*d73ae94eSgc uint_t usb_ia_errlevel = USB_LOG_L4; 46*d73ae94eSgc uint_t usb_ia_errmask = (uint_t)DPRINT_MASK_ALL; 47*d73ae94eSgc uint_t usb_ia_instance_debug = (uint_t)-1; 48*d73ae94eSgc uint_t usb_ia_bus_config_debug = 0; 49*d73ae94eSgc 50*d73ae94eSgc _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ia_errlevel)) 51*d73ae94eSgc _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ia_errmask)) 52*d73ae94eSgc _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ia_instance_debug)) 53*d73ae94eSgc 54*d73ae94eSgc _NOTE(SCHEME_PROTECTS_DATA("unique", msgb)) 55*d73ae94eSgc _NOTE(SCHEME_PROTECTS_DATA("unique", dev_info)) 56*d73ae94eSgc _NOTE(SCHEME_PROTECTS_DATA("unique", usb_pipe_policy)) 57*d73ae94eSgc 58*d73ae94eSgc static struct cb_ops usb_ia_cb_ops = { 59*d73ae94eSgc nodev, /* open */ 60*d73ae94eSgc nodev, /* close */ 61*d73ae94eSgc nodev, /* strategy */ 62*d73ae94eSgc nodev, /* print */ 63*d73ae94eSgc nodev, /* dump */ 64*d73ae94eSgc nodev, /* read */ 65*d73ae94eSgc nodev, /* write */ 66*d73ae94eSgc nodev, /* ioctl */ 67*d73ae94eSgc nodev, /* devmap */ 68*d73ae94eSgc nodev, /* mmap */ 69*d73ae94eSgc nodev, /* segmap */ 70*d73ae94eSgc nochpoll, /* poll */ 71*d73ae94eSgc ddi_prop_op, /* prop_op */ 72*d73ae94eSgc NULL, /* aread */ 73*d73ae94eSgc D_MP 74*d73ae94eSgc }; 75*d73ae94eSgc 76*d73ae94eSgc static int usb_ia_busop_get_eventcookie(dev_info_t *dip, 77*d73ae94eSgc dev_info_t *rdip, 78*d73ae94eSgc char *eventname, 79*d73ae94eSgc ddi_eventcookie_t *cookie); 80*d73ae94eSgc static int usb_ia_busop_add_eventcall(dev_info_t *dip, 81*d73ae94eSgc dev_info_t *rdip, 82*d73ae94eSgc ddi_eventcookie_t cookie, 83*d73ae94eSgc void (*callback)(dev_info_t *dip, 84*d73ae94eSgc ddi_eventcookie_t cookie, void *arg, 85*d73ae94eSgc void *bus_impldata), 86*d73ae94eSgc void *arg, ddi_callback_id_t *cb_id); 87*d73ae94eSgc static int usb_ia_busop_remove_eventcall(dev_info_t *dip, 88*d73ae94eSgc ddi_callback_id_t cb_id); 89*d73ae94eSgc static int usb_ia_busop_post_event(dev_info_t *dip, 90*d73ae94eSgc dev_info_t *rdip, 91*d73ae94eSgc ddi_eventcookie_t cookie, 92*d73ae94eSgc void *bus_impldata); 93*d73ae94eSgc static int usb_ia_bus_config(dev_info_t *dip, 94*d73ae94eSgc uint_t flag, 95*d73ae94eSgc ddi_bus_config_op_t op, 96*d73ae94eSgc void *arg, 97*d73ae94eSgc dev_info_t **child); 98*d73ae94eSgc static int usb_ia_bus_unconfig(dev_info_t *dip, 99*d73ae94eSgc uint_t flag, 100*d73ae94eSgc ddi_bus_config_op_t op, 101*d73ae94eSgc void *arg); 102*d73ae94eSgc 103*d73ae94eSgc /* 104*d73ae94eSgc * autoconfiguration data and routines. 105*d73ae94eSgc */ 106*d73ae94eSgc static int usb_ia_info(dev_info_t *, ddi_info_cmd_t, 107*d73ae94eSgc void *, void **); 108*d73ae94eSgc static int usb_ia_attach(dev_info_t *, ddi_attach_cmd_t); 109*d73ae94eSgc static int usb_ia_detach(dev_info_t *, ddi_detach_cmd_t); 110*d73ae94eSgc 111*d73ae94eSgc /* other routines */ 112*d73ae94eSgc static void usb_ia_create_pm_components(dev_info_t *, usb_ia_t *); 113*d73ae94eSgc static int usb_ia_bus_ctl(dev_info_t *, dev_info_t *, 114*d73ae94eSgc ddi_ctl_enum_t, void *, void *); 115*d73ae94eSgc static int usb_ia_power(dev_info_t *, int, int); 116*d73ae94eSgc static int usb_ia_restore_device_state(dev_info_t *, usb_ia_t *); 117*d73ae94eSgc static usb_ia_t *usb_ia_obtain_state(dev_info_t *); 118*d73ae94eSgc static void usb_ia_event_cb(dev_info_t *, ddi_eventcookie_t, void *, void *); 119*d73ae94eSgc 120*d73ae94eSgc /* prototypes */ 121*d73ae94eSgc static void usb_ia_create_children(usb_ia_t *); 122*d73ae94eSgc static int usb_ia_cleanup(usb_ia_t *); 123*d73ae94eSgc 124*d73ae94eSgc /* 125*d73ae94eSgc * Busops vector 126*d73ae94eSgc */ 127*d73ae94eSgc static struct bus_ops usb_ia_busops = { 128*d73ae94eSgc BUSO_REV, 129*d73ae94eSgc nullbusmap, /* bus_map */ 130*d73ae94eSgc NULL, /* bus_get_intrspec */ 131*d73ae94eSgc NULL, /* bus_add_intrspec */ 132*d73ae94eSgc NULL, /* bus_remove_intrspec */ 133*d73ae94eSgc NULL, /* XXXX bus_map_fault */ 134*d73ae94eSgc ddi_dma_map, /* bus_dma_map */ 135*d73ae94eSgc ddi_dma_allochdl, 136*d73ae94eSgc ddi_dma_freehdl, 137*d73ae94eSgc ddi_dma_bindhdl, 138*d73ae94eSgc ddi_dma_unbindhdl, 139*d73ae94eSgc ddi_dma_flush, 140*d73ae94eSgc ddi_dma_win, 141*d73ae94eSgc ddi_dma_mctl, /* bus_dma_ctl */ 142*d73ae94eSgc usb_ia_bus_ctl, /* bus_ctl */ 143*d73ae94eSgc ddi_bus_prop_op, /* bus_prop_op */ 144*d73ae94eSgc usb_ia_busop_get_eventcookie, 145*d73ae94eSgc usb_ia_busop_add_eventcall, 146*d73ae94eSgc usb_ia_busop_remove_eventcall, 147*d73ae94eSgc usb_ia_busop_post_event, /* bus_post_event */ 148*d73ae94eSgc NULL, /* bus_intr_ctl */ 149*d73ae94eSgc usb_ia_bus_config, /* bus_config */ 150*d73ae94eSgc usb_ia_bus_unconfig, /* bus_unconfig */ 151*d73ae94eSgc NULL, /* bus_fm_init */ 152*d73ae94eSgc NULL, /* bus_fm_fini */ 153*d73ae94eSgc NULL, /* bus_fm_access_enter */ 154*d73ae94eSgc NULL, /* bus_fm_access_exit */ 155*d73ae94eSgc NULL /* bus_power */ 156*d73ae94eSgc }; 157*d73ae94eSgc 158*d73ae94eSgc 159*d73ae94eSgc static struct dev_ops usb_ia_ops = { 160*d73ae94eSgc DEVO_REV, /* devo_rev, */ 161*d73ae94eSgc 0, /* refcnt */ 162*d73ae94eSgc usb_ia_info, /* info */ 163*d73ae94eSgc nulldev, /* identify */ 164*d73ae94eSgc nulldev, /* probe */ 165*d73ae94eSgc usb_ia_attach, /* attach */ 166*d73ae94eSgc usb_ia_detach, /* detach */ 167*d73ae94eSgc nodev, /* reset */ 168*d73ae94eSgc &usb_ia_cb_ops, /* driver operations */ 169*d73ae94eSgc &usb_ia_busops, /* bus operations */ 170*d73ae94eSgc usb_ia_power /* power */ 171*d73ae94eSgc }; 172*d73ae94eSgc 173*d73ae94eSgc static struct modldrv modldrv = { 174*d73ae94eSgc &mod_driverops, /* Type of module. This one is a driver */ 175*d73ae94eSgc "USB Interface Association Driver %I%", /* Name of the module. */ 176*d73ae94eSgc &usb_ia_ops, /* driver ops */ 177*d73ae94eSgc }; 178*d73ae94eSgc 179*d73ae94eSgc static struct modlinkage modlinkage = { 180*d73ae94eSgc MODREV_1, (void *)&modldrv, NULL 181*d73ae94eSgc }; 182*d73ae94eSgc 183*d73ae94eSgc #define USB_IA_INITIAL_SOFT_SPACE 4 184*d73ae94eSgc static void *usb_ia_statep; 185*d73ae94eSgc 186*d73ae94eSgc /* 187*d73ae94eSgc * event definition 188*d73ae94eSgc */ 189*d73ae94eSgc static ndi_event_definition_t usb_ia_ndi_event_defs[] = { 190*d73ae94eSgc {USBA_EVENT_TAG_HOT_REMOVAL, DDI_DEVI_REMOVE_EVENT, EPL_KERNEL, 191*d73ae94eSgc NDI_EVENT_POST_TO_ALL}, 192*d73ae94eSgc {USBA_EVENT_TAG_HOT_INSERTION, DDI_DEVI_INSERT_EVENT, EPL_KERNEL, 193*d73ae94eSgc NDI_EVENT_POST_TO_ALL}, 194*d73ae94eSgc {USBA_EVENT_TAG_POST_RESUME, USBA_POST_RESUME_EVENT, EPL_KERNEL, 195*d73ae94eSgc NDI_EVENT_POST_TO_ALL}, 196*d73ae94eSgc {USBA_EVENT_TAG_PRE_SUSPEND, USBA_PRE_SUSPEND_EVENT, EPL_KERNEL, 197*d73ae94eSgc NDI_EVENT_POST_TO_ALL} 198*d73ae94eSgc }; 199*d73ae94eSgc 200*d73ae94eSgc #define USB_IA_N_NDI_EVENTS \ 201*d73ae94eSgc (sizeof (usb_ia_ndi_event_defs) / sizeof (ndi_event_definition_t)) 202*d73ae94eSgc 203*d73ae94eSgc static ndi_event_set_t usb_ia_ndi_events = { 204*d73ae94eSgc NDI_EVENTS_REV1, USB_IA_N_NDI_EVENTS, usb_ia_ndi_event_defs}; 205*d73ae94eSgc 206*d73ae94eSgc 207*d73ae94eSgc /* 208*d73ae94eSgc * standard driver entry points 209*d73ae94eSgc */ 210*d73ae94eSgc int 211*d73ae94eSgc _init(void) 212*d73ae94eSgc { 213*d73ae94eSgc int rval; 214*d73ae94eSgc 215*d73ae94eSgc rval = ddi_soft_state_init(&usb_ia_statep, sizeof (struct usb_ia), 216*d73ae94eSgc USB_IA_INITIAL_SOFT_SPACE); 217*d73ae94eSgc if (rval != 0) { 218*d73ae94eSgc return (rval); 219*d73ae94eSgc } 220*d73ae94eSgc 221*d73ae94eSgc if ((rval = mod_install(&modlinkage)) != 0) { 222*d73ae94eSgc ddi_soft_state_fini(&usb_ia_statep); 223*d73ae94eSgc return (rval); 224*d73ae94eSgc } 225*d73ae94eSgc 226*d73ae94eSgc return (rval); 227*d73ae94eSgc } 228*d73ae94eSgc 229*d73ae94eSgc 230*d73ae94eSgc int 231*d73ae94eSgc _fini(void) 232*d73ae94eSgc { 233*d73ae94eSgc int rval; 234*d73ae94eSgc 235*d73ae94eSgc rval = mod_remove(&modlinkage); 236*d73ae94eSgc 237*d73ae94eSgc if (rval) { 238*d73ae94eSgc return (rval); 239*d73ae94eSgc } 240*d73ae94eSgc 241*d73ae94eSgc ddi_soft_state_fini(&usb_ia_statep); 242*d73ae94eSgc 243*d73ae94eSgc return (rval); 244*d73ae94eSgc } 245*d73ae94eSgc 246*d73ae94eSgc 247*d73ae94eSgc int 248*d73ae94eSgc _info(struct modinfo *modinfop) 249*d73ae94eSgc { 250*d73ae94eSgc return (mod_info(&modlinkage, modinfop)); 251*d73ae94eSgc } 252*d73ae94eSgc 253*d73ae94eSgc 254*d73ae94eSgc /*ARGSUSED*/ 255*d73ae94eSgc static int 256*d73ae94eSgc usb_ia_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 257*d73ae94eSgc { 258*d73ae94eSgc usb_ia_t *usb_ia; 259*d73ae94eSgc int instance = getminor((dev_t)arg); 260*d73ae94eSgc int error = DDI_FAILURE; 261*d73ae94eSgc 262*d73ae94eSgc switch (infocmd) { 263*d73ae94eSgc case DDI_INFO_DEVT2DEVINFO: 264*d73ae94eSgc if ((usb_ia = ddi_get_soft_state(usb_ia_statep, 265*d73ae94eSgc instance)) != NULL) { 266*d73ae94eSgc *result = (void *)usb_ia->ia_dip; 267*d73ae94eSgc if (*result != NULL) { 268*d73ae94eSgc error = DDI_SUCCESS; 269*d73ae94eSgc } 270*d73ae94eSgc } else { 271*d73ae94eSgc *result = NULL; 272*d73ae94eSgc } 273*d73ae94eSgc break; 274*d73ae94eSgc 275*d73ae94eSgc case DDI_INFO_DEVT2INSTANCE: 276*d73ae94eSgc *result = (void *)(intptr_t)instance; 277*d73ae94eSgc error = DDI_SUCCESS; 278*d73ae94eSgc break; 279*d73ae94eSgc default: 280*d73ae94eSgc break; 281*d73ae94eSgc } 282*d73ae94eSgc 283*d73ae94eSgc return (error); 284*d73ae94eSgc } 285*d73ae94eSgc 286*d73ae94eSgc 287*d73ae94eSgc /* 288*d73ae94eSgc * child post attach/detach notification 289*d73ae94eSgc */ 290*d73ae94eSgc static void 291*d73ae94eSgc usb_ia_post_attach(usb_ia_t *usb_ia, uint8_t ifno, struct attachspec *as) 292*d73ae94eSgc { 293*d73ae94eSgc USB_DPRINTF_L4(DPRINT_MASK_PM, usb_ia->ia_log_handle, 294*d73ae94eSgc "usb_ia_post_attach: ifno = %d result = %d", ifno, as->result); 295*d73ae94eSgc 296*d73ae94eSgc } 297*d73ae94eSgc 298*d73ae94eSgc 299*d73ae94eSgc static void 300*d73ae94eSgc usb_ia_post_detach(usb_ia_t *usb_ia, uint8_t ifno, struct detachspec *ds) 301*d73ae94eSgc { 302*d73ae94eSgc USB_DPRINTF_L4(DPRINT_MASK_PM, usb_ia->ia_log_handle, 303*d73ae94eSgc "usb_ia_post_detach: ifno = %d result = %d", ifno, ds->result); 304*d73ae94eSgc 305*d73ae94eSgc } 306*d73ae94eSgc 307*d73ae94eSgc 308*d73ae94eSgc /* 309*d73ae94eSgc * bus ctl support. we handle notifications here and the 310*d73ae94eSgc * rest goes up to root hub/hcd 311*d73ae94eSgc */ 312*d73ae94eSgc /*ARGSUSED*/ 313*d73ae94eSgc static int 314*d73ae94eSgc usb_ia_bus_ctl(dev_info_t *dip, 315*d73ae94eSgc dev_info_t *rdip, 316*d73ae94eSgc ddi_ctl_enum_t op, 317*d73ae94eSgc void *arg, 318*d73ae94eSgc void *result) 319*d73ae94eSgc { 320*d73ae94eSgc usba_device_t *hub_usba_device = usba_get_usba_device(rdip); 321*d73ae94eSgc dev_info_t *root_hub_dip = hub_usba_device->usb_root_hub_dip; 322*d73ae94eSgc usb_ia_t *usb_ia; 323*d73ae94eSgc struct attachspec *as; 324*d73ae94eSgc struct detachspec *ds; 325*d73ae94eSgc 326*d73ae94eSgc usb_ia = usb_ia_obtain_state(dip); 327*d73ae94eSgc 328*d73ae94eSgc USB_DPRINTF_L4(DPRINT_MASK_PM, usb_ia->ia_log_handle, 329*d73ae94eSgc "usb_ia_bus_ctl:\n\t" 330*d73ae94eSgc "dip = 0x%p, rdip = 0x%p, op = 0x%x, arg = 0x%p", 331*d73ae94eSgc dip, rdip, op, arg); 332*d73ae94eSgc 333*d73ae94eSgc switch (op) { 334*d73ae94eSgc case DDI_CTLOPS_ATTACH: 335*d73ae94eSgc as = (struct attachspec *)arg; 336*d73ae94eSgc 337*d73ae94eSgc switch (as->when) { 338*d73ae94eSgc case DDI_PRE : 339*d73ae94eSgc /* nothing to do basically */ 340*d73ae94eSgc USB_DPRINTF_L2(DPRINT_MASK_PM, usb_ia->ia_log_handle, 341*d73ae94eSgc "DDI_PRE DDI_CTLOPS_ATTACH"); 342*d73ae94eSgc break; 343*d73ae94eSgc case DDI_POST : 344*d73ae94eSgc usb_ia_post_attach(usb_ia, usba_get_ifno(rdip), 345*d73ae94eSgc (struct attachspec *)arg); 346*d73ae94eSgc break; 347*d73ae94eSgc } 348*d73ae94eSgc 349*d73ae94eSgc break; 350*d73ae94eSgc case DDI_CTLOPS_DETACH: 351*d73ae94eSgc ds = (struct detachspec *)arg; 352*d73ae94eSgc 353*d73ae94eSgc switch (ds->when) { 354*d73ae94eSgc case DDI_PRE : 355*d73ae94eSgc /* nothing to do basically */ 356*d73ae94eSgc USB_DPRINTF_L2(DPRINT_MASK_PM, usb_ia->ia_log_handle, 357*d73ae94eSgc "DDI_PRE DDI_CTLOPS_DETACH"); 358*d73ae94eSgc break; 359*d73ae94eSgc case DDI_POST : 360*d73ae94eSgc usb_ia_post_detach(usb_ia, usba_get_ifno(rdip), 361*d73ae94eSgc (struct detachspec *)arg); 362*d73ae94eSgc break; 363*d73ae94eSgc } 364*d73ae94eSgc 365*d73ae94eSgc break; 366*d73ae94eSgc default: 367*d73ae94eSgc /* pass to root hub to handle */ 368*d73ae94eSgc return (usba_bus_ctl(root_hub_dip, rdip, op, arg, result)); 369*d73ae94eSgc } 370*d73ae94eSgc 371*d73ae94eSgc return (DDI_SUCCESS); 372*d73ae94eSgc } 373*d73ae94eSgc 374*d73ae94eSgc 375*d73ae94eSgc /* 376*d73ae94eSgc * bus enumeration entry points 377*d73ae94eSgc */ 378*d73ae94eSgc static int 379*d73ae94eSgc usb_ia_bus_config(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op, 380*d73ae94eSgc void *arg, dev_info_t **child) 381*d73ae94eSgc { 382*d73ae94eSgc int rval, circ; 383*d73ae94eSgc usb_ia_t *usb_ia = usb_ia_obtain_state(dip); 384*d73ae94eSgc 385*d73ae94eSgc USB_DPRINTF_L4(DPRINT_MASK_ALL, usb_ia->ia_log_handle, 386*d73ae94eSgc "usb_ia_bus_config: op=%d", op); 387*d73ae94eSgc 388*d73ae94eSgc if (usb_ia_bus_config_debug) { 389*d73ae94eSgc flag |= NDI_DEVI_DEBUG; 390*d73ae94eSgc } 391*d73ae94eSgc 392*d73ae94eSgc ndi_devi_enter(dip, &circ); 393*d73ae94eSgc 394*d73ae94eSgc /* enumerate each interface below us */ 395*d73ae94eSgc mutex_enter(&usb_ia->ia_mutex); 396*d73ae94eSgc usb_ia_create_children(usb_ia); 397*d73ae94eSgc mutex_exit(&usb_ia->ia_mutex); 398*d73ae94eSgc 399*d73ae94eSgc rval = ndi_busop_bus_config(dip, flag, op, arg, child, 0); 400*d73ae94eSgc ndi_devi_exit(dip, circ); 401*d73ae94eSgc 402*d73ae94eSgc return (rval); 403*d73ae94eSgc } 404*d73ae94eSgc 405*d73ae94eSgc 406*d73ae94eSgc static int 407*d73ae94eSgc usb_ia_bus_unconfig(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op, 408*d73ae94eSgc void *arg) 409*d73ae94eSgc { 410*d73ae94eSgc usb_ia_t *usb_ia = usb_ia_obtain_state(dip); 411*d73ae94eSgc 412*d73ae94eSgc dev_info_t *cdip, *mdip; 413*d73ae94eSgc int interface, circular_count; 414*d73ae94eSgc int rval = NDI_SUCCESS; 415*d73ae94eSgc 416*d73ae94eSgc USB_DPRINTF_L4(DPRINT_MASK_ALL, usb_ia->ia_log_handle, 417*d73ae94eSgc "usb_ia_bus_unconfig: op=%d", op); 418*d73ae94eSgc 419*d73ae94eSgc if (usb_ia_bus_config_debug) { 420*d73ae94eSgc flag |= NDI_DEVI_DEBUG; 421*d73ae94eSgc } 422*d73ae94eSgc 423*d73ae94eSgc /* 424*d73ae94eSgc * first offline and if offlining successful, then 425*d73ae94eSgc * remove children 426*d73ae94eSgc */ 427*d73ae94eSgc if (op == BUS_UNCONFIG_ALL) { 428*d73ae94eSgc flag &= ~(NDI_DEVI_REMOVE | NDI_UNCONFIG); 429*d73ae94eSgc } 430*d73ae94eSgc 431*d73ae94eSgc ndi_devi_enter(dip, &circular_count); 432*d73ae94eSgc rval = ndi_busop_bus_unconfig(dip, flag, op, arg); 433*d73ae94eSgc 434*d73ae94eSgc if (op == BUS_UNCONFIG_ALL && rval == NDI_SUCCESS && 435*d73ae94eSgc (flag & NDI_AUTODETACH) == 0) { 436*d73ae94eSgc flag |= NDI_DEVI_REMOVE; 437*d73ae94eSgc rval = ndi_busop_bus_unconfig(dip, flag, op, arg); 438*d73ae94eSgc } 439*d73ae94eSgc 440*d73ae94eSgc /* update children's list */ 441*d73ae94eSgc mutex_enter(&usb_ia->ia_mutex); 442*d73ae94eSgc for (interface = 0; usb_ia->ia_children_dips && 443*d73ae94eSgc (interface < usb_ia->ia_n_ifs); interface++) { 444*d73ae94eSgc mdip = usb_ia->ia_children_dips[interface]; 445*d73ae94eSgc 446*d73ae94eSgc /* now search if this dip still exists */ 447*d73ae94eSgc for (cdip = ddi_get_child(dip); cdip && (cdip != mdip); 448*d73ae94eSgc cdip = ddi_get_next_sibling(cdip)); 449*d73ae94eSgc 450*d73ae94eSgc if (cdip != mdip) { 451*d73ae94eSgc /* we lost the dip on this interface */ 452*d73ae94eSgc usb_ia->ia_children_dips[interface] = NULL; 453*d73ae94eSgc } else if (cdip) { 454*d73ae94eSgc /* 455*d73ae94eSgc * keep in DS_INITALIZED to prevent parent 456*d73ae94eSgc * from detaching 457*d73ae94eSgc */ 458*d73ae94eSgc (void) ddi_initchild(ddi_get_parent(cdip), cdip); 459*d73ae94eSgc } 460*d73ae94eSgc } 461*d73ae94eSgc mutex_exit(&usb_ia->ia_mutex); 462*d73ae94eSgc 463*d73ae94eSgc ndi_devi_exit(dip, circular_count); 464*d73ae94eSgc 465*d73ae94eSgc USB_DPRINTF_L4(DPRINT_MASK_ALL, usb_ia->ia_log_handle, 466*d73ae94eSgc "usb_ia_bus_config: rval=%d", rval); 467*d73ae94eSgc 468*d73ae94eSgc return (rval); 469*d73ae94eSgc } 470*d73ae94eSgc 471*d73ae94eSgc 472*d73ae94eSgc /* power entry point */ 473*d73ae94eSgc /* ARGSUSED */ 474*d73ae94eSgc static int 475*d73ae94eSgc usb_ia_power(dev_info_t *dip, int comp, int level) 476*d73ae94eSgc { 477*d73ae94eSgc usb_ia_t *usb_ia; 478*d73ae94eSgc usb_common_power_t *pm; 479*d73ae94eSgc int rval = DDI_FAILURE; 480*d73ae94eSgc 481*d73ae94eSgc usb_ia = usb_ia_obtain_state(dip); 482*d73ae94eSgc 483*d73ae94eSgc USB_DPRINTF_L4(DPRINT_MASK_PM, usb_ia->ia_log_handle, 484*d73ae94eSgc "usb_ia_power: Begin: usb_ia = %p, level = %d", usb_ia, level); 485*d73ae94eSgc 486*d73ae94eSgc mutex_enter(&usb_ia->ia_mutex); 487*d73ae94eSgc pm = usb_ia->ia_pm; 488*d73ae94eSgc 489*d73ae94eSgc /* check if we are transitioning to a legal power level */ 490*d73ae94eSgc if (USB_DEV_PWRSTATE_OK(pm->uc_pwr_states, level)) { 491*d73ae94eSgc USB_DPRINTF_L2(DPRINT_MASK_PM, usb_ia->ia_log_handle, 492*d73ae94eSgc "usb_ia_power: illegal power level = %d " 493*d73ae94eSgc "uc_pwr_states = %x", level, pm->uc_pwr_states); 494*d73ae94eSgc 495*d73ae94eSgc mutex_exit(&usb_ia->ia_mutex); 496*d73ae94eSgc 497*d73ae94eSgc return (rval); 498*d73ae94eSgc } 499*d73ae94eSgc 500*d73ae94eSgc rval = usba_common_power(dip, pm, &(usb_ia->ia_dev_state), level); 501*d73ae94eSgc 502*d73ae94eSgc mutex_exit(&usb_ia->ia_mutex); 503*d73ae94eSgc 504*d73ae94eSgc return (rval); 505*d73ae94eSgc } 506*d73ae94eSgc 507*d73ae94eSgc /* 508*d73ae94eSgc * attach/resume entry point 509*d73ae94eSgc */ 510*d73ae94eSgc static int 511*d73ae94eSgc usb_ia_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 512*d73ae94eSgc { 513*d73ae94eSgc int instance = ddi_get_instance(dip); 514*d73ae94eSgc usb_ia_t *usb_ia = NULL; 515*d73ae94eSgc uint_t n_ifs; 516*d73ae94eSgc size_t size; 517*d73ae94eSgc 518*d73ae94eSgc switch (cmd) { 519*d73ae94eSgc case DDI_ATTACH: 520*d73ae94eSgc 521*d73ae94eSgc break; 522*d73ae94eSgc case DDI_RESUME: 523*d73ae94eSgc usb_ia = ddi_get_soft_state(usb_ia_statep, instance); 524*d73ae94eSgc (void) usb_ia_restore_device_state(dip, usb_ia); 525*d73ae94eSgc 526*d73ae94eSgc return (DDI_SUCCESS); 527*d73ae94eSgc default: 528*d73ae94eSgc 529*d73ae94eSgc return (DDI_FAILURE); 530*d73ae94eSgc } 531*d73ae94eSgc 532*d73ae94eSgc /* 533*d73ae94eSgc * Attach: 534*d73ae94eSgc * 535*d73ae94eSgc * Allocate soft state and initialize 536*d73ae94eSgc */ 537*d73ae94eSgc if (ddi_soft_state_zalloc(usb_ia_statep, instance) != DDI_SUCCESS) { 538*d73ae94eSgc goto fail; 539*d73ae94eSgc } 540*d73ae94eSgc 541*d73ae94eSgc usb_ia = ddi_get_soft_state(usb_ia_statep, instance); 542*d73ae94eSgc if (usb_ia == NULL) { 543*d73ae94eSgc 544*d73ae94eSgc goto fail; 545*d73ae94eSgc } 546*d73ae94eSgc 547*d73ae94eSgc /* allocate handle for logging of messages */ 548*d73ae94eSgc usb_ia->ia_log_handle = usb_alloc_log_hdl(dip, "ia", 549*d73ae94eSgc &usb_ia_errlevel, 550*d73ae94eSgc &usb_ia_errmask, &usb_ia_instance_debug, 551*d73ae94eSgc 0); 552*d73ae94eSgc 553*d73ae94eSgc usb_ia->ia_dip = dip; 554*d73ae94eSgc usb_ia->ia_instance = instance; 555*d73ae94eSgc usb_ia->ia_first_if = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 556*d73ae94eSgc DDI_PROP_DONTPASS, "interface", -1); 557*d73ae94eSgc usb_ia->ia_n_ifs = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 558*d73ae94eSgc DDI_PROP_DONTPASS, "interface-count", -1); 559*d73ae94eSgc 560*d73ae94eSgc if (usb_ia->ia_first_if < 0 || usb_ia->ia_n_ifs < 0) { 561*d73ae94eSgc USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle, 562*d73ae94eSgc "interface-association property failed"); 563*d73ae94eSgc 564*d73ae94eSgc goto fail; 565*d73ae94eSgc } 566*d73ae94eSgc 567*d73ae94eSgc /* attach client driver to USBA */ 568*d73ae94eSgc if (usb_client_attach(dip, USBDRV_VERSION, 0) != USB_SUCCESS) { 569*d73ae94eSgc USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle, 570*d73ae94eSgc "usb_client_attach failed"); 571*d73ae94eSgc goto fail; 572*d73ae94eSgc } 573*d73ae94eSgc if (usb_get_dev_data(dip, &usb_ia->ia_dev_data, USB_PARSE_LVL_NONE, 574*d73ae94eSgc 0) != USB_SUCCESS) { 575*d73ae94eSgc USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle, 576*d73ae94eSgc "usb_get_dev_data failed"); 577*d73ae94eSgc goto fail; 578*d73ae94eSgc } 579*d73ae94eSgc 580*d73ae94eSgc mutex_init(&usb_ia->ia_mutex, NULL, MUTEX_DRIVER, 581*d73ae94eSgc usb_ia->ia_dev_data->dev_iblock_cookie); 582*d73ae94eSgc 583*d73ae94eSgc usb_free_dev_data(dip, usb_ia->ia_dev_data); 584*d73ae94eSgc usb_ia->ia_dev_data = NULL; 585*d73ae94eSgc 586*d73ae94eSgc usb_ia->ia_init_state |= USB_IA_LOCK_INIT; 587*d73ae94eSgc 588*d73ae94eSgc if (ddi_create_minor_node(dip, "usb_ia", S_IFCHR, instance, 589*d73ae94eSgc DDI_NT_NEXUS, 0) != DDI_SUCCESS) { 590*d73ae94eSgc USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle, 591*d73ae94eSgc "cannot create devctl minor node"); 592*d73ae94eSgc goto fail; 593*d73ae94eSgc } 594*d73ae94eSgc 595*d73ae94eSgc usb_ia->ia_init_state |= USB_IA_MINOR_NODE_CREATED; 596*d73ae94eSgc 597*d73ae94eSgc /* 598*d73ae94eSgc * allocate array for keeping track of child dips 599*d73ae94eSgc */ 600*d73ae94eSgc n_ifs = usb_ia->ia_n_ifs; 601*d73ae94eSgc usb_ia->ia_cd_list_length = size = (sizeof (dev_info_t *)) * n_ifs; 602*d73ae94eSgc 603*d73ae94eSgc usb_ia->ia_children_dips = kmem_zalloc(size, KM_SLEEP); 604*d73ae94eSgc usb_ia->ia_child_events = kmem_zalloc(sizeof (uint8_t) * n_ifs, 605*d73ae94eSgc KM_SLEEP); 606*d73ae94eSgc /* 607*d73ae94eSgc * Event handling: definition and registration 608*d73ae94eSgc * get event handle for events that we have defined 609*d73ae94eSgc */ 610*d73ae94eSgc (void) ndi_event_alloc_hdl(dip, 0, &usb_ia->ia_ndi_event_hdl, 611*d73ae94eSgc NDI_SLEEP); 612*d73ae94eSgc 613*d73ae94eSgc /* bind event set to the handle */ 614*d73ae94eSgc if (ndi_event_bind_set(usb_ia->ia_ndi_event_hdl, &usb_ia_ndi_events, 615*d73ae94eSgc NDI_SLEEP)) { 616*d73ae94eSgc USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle, 617*d73ae94eSgc "usb_ia_attach: binding event set failed"); 618*d73ae94eSgc 619*d73ae94eSgc goto fail; 620*d73ae94eSgc } 621*d73ae94eSgc 622*d73ae94eSgc usb_ia->ia_dev_state = USB_DEV_ONLINE; 623*d73ae94eSgc 624*d73ae94eSgc /* 625*d73ae94eSgc * now create components to power manage this device 626*d73ae94eSgc * before attaching children 627*d73ae94eSgc */ 628*d73ae94eSgc usb_ia_create_pm_components(dip, usb_ia); 629*d73ae94eSgc 630*d73ae94eSgc /* event registration for events from our parent */ 631*d73ae94eSgc usba_common_register_events(dip, n_ifs, usb_ia_event_cb); 632*d73ae94eSgc 633*d73ae94eSgc usb_ia->ia_init_state |= USB_IA_EVENTS_REGISTERED; 634*d73ae94eSgc 635*d73ae94eSgc ddi_report_dev(dip); 636*d73ae94eSgc 637*d73ae94eSgc return (DDI_SUCCESS); 638*d73ae94eSgc 639*d73ae94eSgc fail: 640*d73ae94eSgc USB_DPRINTF_L2(DPRINT_MASK_ATTA, NULL, "usb_ia%d cannot attach", 641*d73ae94eSgc instance); 642*d73ae94eSgc 643*d73ae94eSgc if (usb_ia) { 644*d73ae94eSgc (void) usb_ia_cleanup(usb_ia); 645*d73ae94eSgc } 646*d73ae94eSgc 647*d73ae94eSgc return (DDI_FAILURE); 648*d73ae94eSgc } 649*d73ae94eSgc 650*d73ae94eSgc 651*d73ae94eSgc /* detach or suspend this instance */ 652*d73ae94eSgc static int 653*d73ae94eSgc usb_ia_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 654*d73ae94eSgc { 655*d73ae94eSgc usb_ia_t *usb_ia = usb_ia_obtain_state(dip); 656*d73ae94eSgc 657*d73ae94eSgc USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_ia->ia_log_handle, 658*d73ae94eSgc "usb_ia_detach: cmd = 0x%x", cmd); 659*d73ae94eSgc 660*d73ae94eSgc switch (cmd) { 661*d73ae94eSgc case DDI_DETACH: 662*d73ae94eSgc 663*d73ae94eSgc return (usb_ia_cleanup(usb_ia)); 664*d73ae94eSgc case DDI_SUSPEND: 665*d73ae94eSgc /* nothing to do */ 666*d73ae94eSgc mutex_enter(&usb_ia->ia_mutex); 667*d73ae94eSgc usb_ia->ia_dev_state = USB_DEV_SUSPENDED; 668*d73ae94eSgc mutex_exit(&usb_ia->ia_mutex); 669*d73ae94eSgc 670*d73ae94eSgc return (DDI_SUCCESS); 671*d73ae94eSgc default: 672*d73ae94eSgc 673*d73ae94eSgc return (DDI_FAILURE); 674*d73ae94eSgc } 675*d73ae94eSgc 676*d73ae94eSgc _NOTE(NOT_REACHED) 677*d73ae94eSgc /* NOTREACHED */ 678*d73ae94eSgc } 679*d73ae94eSgc 680*d73ae94eSgc 681*d73ae94eSgc /* 682*d73ae94eSgc * usb_ia_cleanup: 683*d73ae94eSgc * cleanup usb_ia and deallocate. this function is called for 684*d73ae94eSgc * handling attach failures and detaching including dynamic 685*d73ae94eSgc * reconfiguration 686*d73ae94eSgc */ 687*d73ae94eSgc /*ARGSUSED*/ 688*d73ae94eSgc static int 689*d73ae94eSgc usb_ia_cleanup(usb_ia_t *usb_ia) 690*d73ae94eSgc { 691*d73ae94eSgc usb_common_power_t *iapm; 692*d73ae94eSgc int rval; 693*d73ae94eSgc dev_info_t *dip = usb_ia->ia_dip; 694*d73ae94eSgc 695*d73ae94eSgc USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_ia->ia_log_handle, 696*d73ae94eSgc "usb_ia_cleanup:"); 697*d73ae94eSgc 698*d73ae94eSgc if ((usb_ia->ia_init_state & USB_IA_LOCK_INIT) == 0) { 699*d73ae94eSgc 700*d73ae94eSgc goto done; 701*d73ae94eSgc } 702*d73ae94eSgc 703*d73ae94eSgc /* 704*d73ae94eSgc * deallocate events, if events are still registered 705*d73ae94eSgc * (ie. children still attached) then we have to fail the detach 706*d73ae94eSgc */ 707*d73ae94eSgc if (usb_ia->ia_ndi_event_hdl && 708*d73ae94eSgc (ndi_event_free_hdl(usb_ia->ia_ndi_event_hdl) != NDI_SUCCESS)) { 709*d73ae94eSgc 710*d73ae94eSgc USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle, 711*d73ae94eSgc "usb_ia_cleanup: ndi_event_free_hdl failed"); 712*d73ae94eSgc 713*d73ae94eSgc return (DDI_FAILURE); 714*d73ae94eSgc } 715*d73ae94eSgc 716*d73ae94eSgc /* 717*d73ae94eSgc * Disable the event callbacks, after this point, event 718*d73ae94eSgc * callbacks will never get called. Note we shouldn't hold 719*d73ae94eSgc * mutex while unregistering events because there may be a 720*d73ae94eSgc * competing event callback thread. Event callbacks are done 721*d73ae94eSgc * with ndi mutex held and this can cause a potential deadlock. 722*d73ae94eSgc * Note that cleanup can't fail after deregistration of events. 723*d73ae94eSgc */ 724*d73ae94eSgc if (usb_ia->ia_init_state & USB_IA_EVENTS_REGISTERED) { 725*d73ae94eSgc 726*d73ae94eSgc usba_common_unregister_events(usb_ia->ia_dip, usb_ia->ia_n_ifs); 727*d73ae94eSgc } 728*d73ae94eSgc 729*d73ae94eSgc iapm = usb_ia->ia_pm; 730*d73ae94eSgc 731*d73ae94eSgc mutex_enter(&usb_ia->ia_mutex); 732*d73ae94eSgc 733*d73ae94eSgc if ((iapm) && (usb_ia->ia_dev_state != USB_DEV_DISCONNECTED)) { 734*d73ae94eSgc 735*d73ae94eSgc mutex_exit(&usb_ia->ia_mutex); 736*d73ae94eSgc 737*d73ae94eSgc (void) pm_busy_component(dip, 0); 738*d73ae94eSgc if (iapm->uc_wakeup_enabled) { 739*d73ae94eSgc 740*d73ae94eSgc /* First bring the device to full power */ 741*d73ae94eSgc (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 742*d73ae94eSgc 743*d73ae94eSgc rval = usb_handle_remote_wakeup(dip, 744*d73ae94eSgc USB_REMOTE_WAKEUP_DISABLE); 745*d73ae94eSgc 746*d73ae94eSgc if (rval != DDI_SUCCESS) { 747*d73ae94eSgc USB_DPRINTF_L2(DPRINT_MASK_EVENTS, 748*d73ae94eSgc usb_ia->ia_log_handle, 749*d73ae94eSgc "usb_cleanup: disable remote " 750*d73ae94eSgc "wakeup failed, rval=%d", rval); 751*d73ae94eSgc } 752*d73ae94eSgc } 753*d73ae94eSgc 754*d73ae94eSgc (void) pm_lower_power(usb_ia->ia_dip, 0, USB_DEV_OS_PWR_OFF); 755*d73ae94eSgc (void) pm_idle_component(dip, 0); 756*d73ae94eSgc } else { 757*d73ae94eSgc mutex_exit(&usb_ia->ia_mutex); 758*d73ae94eSgc } 759*d73ae94eSgc 760*d73ae94eSgc if (iapm) { 761*d73ae94eSgc kmem_free(iapm, sizeof (usb_common_power_t)); 762*d73ae94eSgc } 763*d73ae94eSgc 764*d73ae94eSgc /* free children list */ 765*d73ae94eSgc if (usb_ia->ia_children_dips) { 766*d73ae94eSgc kmem_free(usb_ia->ia_children_dips, 767*d73ae94eSgc usb_ia->ia_cd_list_length); 768*d73ae94eSgc } 769*d73ae94eSgc 770*d73ae94eSgc if (usb_ia->ia_child_events) { 771*d73ae94eSgc kmem_free(usb_ia->ia_child_events, sizeof (uint8_t) * 772*d73ae94eSgc usb_ia->ia_n_ifs); 773*d73ae94eSgc } 774*d73ae94eSgc 775*d73ae94eSgc if (usb_ia->ia_init_state & USB_IA_MINOR_NODE_CREATED) { 776*d73ae94eSgc ddi_remove_minor_node(dip, NULL); 777*d73ae94eSgc } 778*d73ae94eSgc 779*d73ae94eSgc mutex_destroy(&usb_ia->ia_mutex); 780*d73ae94eSgc 781*d73ae94eSgc done: 782*d73ae94eSgc usb_client_detach(dip, usb_ia->ia_dev_data); 783*d73ae94eSgc 784*d73ae94eSgc usb_free_log_hdl(usb_ia->ia_log_handle); 785*d73ae94eSgc ddi_soft_state_free(usb_ia_statep, ddi_get_instance(dip)); 786*d73ae94eSgc 787*d73ae94eSgc ddi_prop_remove_all(dip); 788*d73ae94eSgc 789*d73ae94eSgc return (DDI_SUCCESS); 790*d73ae94eSgc } 791*d73ae94eSgc 792*d73ae94eSgc /* 793*d73ae94eSgc * usb_ia_create_children: 794*d73ae94eSgc */ 795*d73ae94eSgc static void 796*d73ae94eSgc usb_ia_create_children(usb_ia_t *usb_ia) 797*d73ae94eSgc { 798*d73ae94eSgc usba_device_t *usba_device; 799*d73ae94eSgc uint_t n_ifs, first_if; 800*d73ae94eSgc uint_t i; 801*d73ae94eSgc dev_info_t *cdip; 802*d73ae94eSgc 803*d73ae94eSgc usba_device = usba_get_usba_device(usb_ia->ia_dip); 804*d73ae94eSgc 805*d73ae94eSgc USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_ia->ia_log_handle, 806*d73ae94eSgc "usb_ia_attach_child_drivers: port = %d, address = %d", 807*d73ae94eSgc usba_device->usb_port, usba_device->usb_addr); 808*d73ae94eSgc 809*d73ae94eSgc n_ifs = usb_ia->ia_n_ifs; 810*d73ae94eSgc first_if = usb_ia->ia_first_if; 811*d73ae94eSgc 812*d73ae94eSgc /* 813*d73ae94eSgc * create all children if not already present 814*d73ae94eSgc */ 815*d73ae94eSgc for (i = 0; i < n_ifs; i++) { 816*d73ae94eSgc if (usb_ia->ia_children_dips[i] != NULL) { 817*d73ae94eSgc 818*d73ae94eSgc continue; 819*d73ae94eSgc } 820*d73ae94eSgc 821*d73ae94eSgc mutex_exit(&usb_ia->ia_mutex); 822*d73ae94eSgc cdip = usba_ready_interface_node(usb_ia->ia_dip, first_if + i); 823*d73ae94eSgc mutex_enter(&usb_ia->ia_mutex); 824*d73ae94eSgc 825*d73ae94eSgc if (cdip != NULL) { 826*d73ae94eSgc (void) usba_bind_driver(cdip); 827*d73ae94eSgc usb_ia->ia_children_dips[i] = cdip; 828*d73ae94eSgc } 829*d73ae94eSgc } 830*d73ae94eSgc 831*d73ae94eSgc } 832*d73ae94eSgc 833*d73ae94eSgc 834*d73ae94eSgc /* 835*d73ae94eSgc * event support 836*d73ae94eSgc */ 837*d73ae94eSgc static int 838*d73ae94eSgc usb_ia_busop_get_eventcookie(dev_info_t *dip, 839*d73ae94eSgc dev_info_t *rdip, char *eventname, ddi_eventcookie_t *cookie) 840*d73ae94eSgc { 841*d73ae94eSgc usb_ia_t *usb_ia = usb_ia_obtain_state(dip); 842*d73ae94eSgc 843*d73ae94eSgc USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle, 844*d73ae94eSgc "usb_ia_busop_get_eventcookie: dip=0x%p, rdip=0x%p, " 845*d73ae94eSgc "event=%s", (void *)dip, (void *)rdip, eventname); 846*d73ae94eSgc USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle, 847*d73ae94eSgc "(dip=%s%d rdip=%s%d)", 848*d73ae94eSgc ddi_driver_name(dip), ddi_get_instance(dip), 849*d73ae94eSgc ddi_driver_name(rdip), ddi_get_instance(rdip)); 850*d73ae94eSgc 851*d73ae94eSgc /* return event cookie, iblock cookie, and level */ 852*d73ae94eSgc return (ndi_event_retrieve_cookie(usb_ia->ia_ndi_event_hdl, 853*d73ae94eSgc rdip, eventname, cookie, NDI_EVENT_NOPASS)); 854*d73ae94eSgc } 855*d73ae94eSgc 856*d73ae94eSgc 857*d73ae94eSgc static int 858*d73ae94eSgc usb_ia_busop_add_eventcall(dev_info_t *dip, 859*d73ae94eSgc dev_info_t *rdip, 860*d73ae94eSgc ddi_eventcookie_t cookie, 861*d73ae94eSgc void (*callback)(dev_info_t *dip, 862*d73ae94eSgc ddi_eventcookie_t cookie, void *arg, 863*d73ae94eSgc void *bus_impldata), 864*d73ae94eSgc void *arg, ddi_callback_id_t *cb_id) 865*d73ae94eSgc { 866*d73ae94eSgc int ifno; 867*d73ae94eSgc usb_ia_t *usb_ia = usb_ia_obtain_state(dip); 868*d73ae94eSgc 869*d73ae94eSgc mutex_enter(&usb_ia->ia_mutex); 870*d73ae94eSgc ifno = usba_get_ifno(rdip)- usb_ia->ia_first_if; 871*d73ae94eSgc mutex_exit(&usb_ia->ia_mutex); 872*d73ae94eSgc 873*d73ae94eSgc if (ifno < 0) { 874*d73ae94eSgc ifno = 0; 875*d73ae94eSgc } 876*d73ae94eSgc 877*d73ae94eSgc USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle, 878*d73ae94eSgc "usb_ia_busop_add_eventcall: dip=0x%p, rdip=0x%p " 879*d73ae94eSgc "cookie=0x%p, cb=0x%p, arg=0x%p", 880*d73ae94eSgc (void *)dip, (void *)rdip, (void *)cookie, (void *)callback, arg); 881*d73ae94eSgc USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle, 882*d73ae94eSgc "(dip=%s%d rdip=%s%d event=%s)", 883*d73ae94eSgc ddi_driver_name(dip), ddi_get_instance(dip), 884*d73ae94eSgc ddi_driver_name(rdip), ddi_get_instance(rdip), 885*d73ae94eSgc ndi_event_cookie_to_name(usb_ia->ia_ndi_event_hdl, cookie)); 886*d73ae94eSgc 887*d73ae94eSgc /* Set flag on children registering events */ 888*d73ae94eSgc switch (ndi_event_cookie_to_tag(usb_ia->ia_ndi_event_hdl, cookie)) { 889*d73ae94eSgc case USBA_EVENT_TAG_HOT_REMOVAL: 890*d73ae94eSgc mutex_enter(&usb_ia->ia_mutex); 891*d73ae94eSgc usb_ia->ia_child_events[ifno] |= 892*d73ae94eSgc USB_IA_CHILD_EVENT_DISCONNECT; 893*d73ae94eSgc mutex_exit(&usb_ia->ia_mutex); 894*d73ae94eSgc 895*d73ae94eSgc break; 896*d73ae94eSgc case USBA_EVENT_TAG_PRE_SUSPEND: 897*d73ae94eSgc mutex_enter(&usb_ia->ia_mutex); 898*d73ae94eSgc usb_ia->ia_child_events[ifno] |= 899*d73ae94eSgc USB_IA_CHILD_EVENT_PRESUSPEND; 900*d73ae94eSgc mutex_exit(&usb_ia->ia_mutex); 901*d73ae94eSgc 902*d73ae94eSgc break; 903*d73ae94eSgc default: 904*d73ae94eSgc 905*d73ae94eSgc break; 906*d73ae94eSgc } 907*d73ae94eSgc /* add callback (perform registration) */ 908*d73ae94eSgc return (ndi_event_add_callback(usb_ia->ia_ndi_event_hdl, 909*d73ae94eSgc rdip, cookie, callback, arg, NDI_SLEEP, cb_id)); 910*d73ae94eSgc } 911*d73ae94eSgc 912*d73ae94eSgc 913*d73ae94eSgc static int 914*d73ae94eSgc usb_ia_busop_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id) 915*d73ae94eSgc { 916*d73ae94eSgc usb_ia_t *usb_ia = usb_ia_obtain_state(dip); 917*d73ae94eSgc ndi_event_callbacks_t *cb = (ndi_event_callbacks_t *)cb_id; 918*d73ae94eSgc 919*d73ae94eSgc ASSERT(cb); 920*d73ae94eSgc 921*d73ae94eSgc USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle, 922*d73ae94eSgc "usb_ia_busop_remove_eventcall: dip=0x%p, rdip=0x%p " 923*d73ae94eSgc "cookie=0x%p", (void *)dip, cb->ndi_evtcb_dip, 924*d73ae94eSgc cb->ndi_evtcb_cookie); 925*d73ae94eSgc USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle, 926*d73ae94eSgc "(dip=%s%d rdip=%s%d event=%s)", 927*d73ae94eSgc ddi_driver_name(dip), ddi_get_instance(dip), 928*d73ae94eSgc ddi_driver_name(cb->ndi_evtcb_dip), 929*d73ae94eSgc ddi_get_instance(cb->ndi_evtcb_dip), 930*d73ae94eSgc ndi_event_cookie_to_name(usb_ia->ia_ndi_event_hdl, 931*d73ae94eSgc cb->ndi_evtcb_cookie)); 932*d73ae94eSgc 933*d73ae94eSgc /* remove event registration from our event set */ 934*d73ae94eSgc return (ndi_event_remove_callback(usb_ia->ia_ndi_event_hdl, cb_id)); 935*d73ae94eSgc } 936*d73ae94eSgc 937*d73ae94eSgc 938*d73ae94eSgc static int 939*d73ae94eSgc usb_ia_busop_post_event(dev_info_t *dip, 940*d73ae94eSgc dev_info_t *rdip, 941*d73ae94eSgc ddi_eventcookie_t cookie, 942*d73ae94eSgc void *bus_impldata) 943*d73ae94eSgc { 944*d73ae94eSgc usb_ia_t *usb_ia = usb_ia_obtain_state(dip); 945*d73ae94eSgc 946*d73ae94eSgc USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle, 947*d73ae94eSgc "usb_ia_busop_post_event: dip=0x%p, rdip=0x%p " 948*d73ae94eSgc "cookie=0x%p, impl=0x%p", 949*d73ae94eSgc (void *)dip, (void *)rdip, (void *)cookie, bus_impldata); 950*d73ae94eSgc USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle, 951*d73ae94eSgc "(dip=%s%d rdip=%s%d event=%s)", 952*d73ae94eSgc ddi_driver_name(dip), ddi_get_instance(dip), 953*d73ae94eSgc ddi_driver_name(rdip), ddi_get_instance(rdip), 954*d73ae94eSgc ndi_event_cookie_to_name(usb_ia->ia_ndi_event_hdl, cookie)); 955*d73ae94eSgc 956*d73ae94eSgc /* post event to all children registered for this event */ 957*d73ae94eSgc return (ndi_event_run_callbacks(usb_ia->ia_ndi_event_hdl, rdip, 958*d73ae94eSgc cookie, bus_impldata)); 959*d73ae94eSgc } 960*d73ae94eSgc 961*d73ae94eSgc 962*d73ae94eSgc /* 963*d73ae94eSgc * usb_ia_restore_device_state 964*d73ae94eSgc * set the original configuration of the device 965*d73ae94eSgc */ 966*d73ae94eSgc static int 967*d73ae94eSgc usb_ia_restore_device_state(dev_info_t *dip, usb_ia_t *usb_ia) 968*d73ae94eSgc { 969*d73ae94eSgc usb_common_power_t *iapm; 970*d73ae94eSgc 971*d73ae94eSgc USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle, 972*d73ae94eSgc "usb_ia_restore_device_state: usb_ia = %p", usb_ia); 973*d73ae94eSgc 974*d73ae94eSgc mutex_enter(&usb_ia->ia_mutex); 975*d73ae94eSgc iapm = usb_ia->ia_pm; 976*d73ae94eSgc mutex_exit(&usb_ia->ia_mutex); 977*d73ae94eSgc 978*d73ae94eSgc /* First bring the device to full power */ 979*d73ae94eSgc (void) pm_busy_component(dip, 0); 980*d73ae94eSgc (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 981*d73ae94eSgc 982*d73ae94eSgc if (usb_check_same_device(dip, usb_ia->ia_log_handle, USB_LOG_L0, 983*d73ae94eSgc DPRINT_MASK_EVENTS, USB_CHK_VIDPID, NULL) != USB_SUCCESS) { 984*d73ae94eSgc 985*d73ae94eSgc /* change the device state from suspended to disconnected */ 986*d73ae94eSgc mutex_enter(&usb_ia->ia_mutex); 987*d73ae94eSgc usb_ia->ia_dev_state = USB_DEV_DISCONNECTED; 988*d73ae94eSgc mutex_exit(&usb_ia->ia_mutex); 989*d73ae94eSgc (void) pm_idle_component(dip, 0); 990*d73ae94eSgc 991*d73ae94eSgc return (USB_FAILURE); 992*d73ae94eSgc } 993*d73ae94eSgc 994*d73ae94eSgc /* 995*d73ae94eSgc * if the device had remote wakeup earlier, 996*d73ae94eSgc * enable it again 997*d73ae94eSgc */ 998*d73ae94eSgc if (iapm->uc_wakeup_enabled) { 999*d73ae94eSgc (void) usb_handle_remote_wakeup(usb_ia->ia_dip, 1000*d73ae94eSgc USB_REMOTE_WAKEUP_ENABLE); 1001*d73ae94eSgc } 1002*d73ae94eSgc 1003*d73ae94eSgc mutex_enter(&usb_ia->ia_mutex); 1004*d73ae94eSgc usb_ia->ia_dev_state = USB_DEV_ONLINE; 1005*d73ae94eSgc mutex_exit(&usb_ia->ia_mutex); 1006*d73ae94eSgc 1007*d73ae94eSgc (void) pm_idle_component(dip, 0); 1008*d73ae94eSgc 1009*d73ae94eSgc return (USB_SUCCESS); 1010*d73ae94eSgc } 1011*d73ae94eSgc 1012*d73ae94eSgc 1013*d73ae94eSgc /* 1014*d73ae94eSgc * usb_ia_event_cb() 1015*d73ae94eSgc * handle disconnect and connect events 1016*d73ae94eSgc */ 1017*d73ae94eSgc static void 1018*d73ae94eSgc usb_ia_event_cb(dev_info_t *dip, ddi_eventcookie_t cookie, 1019*d73ae94eSgc void *arg, void *bus_impldata) 1020*d73ae94eSgc { 1021*d73ae94eSgc int i, tag; 1022*d73ae94eSgc usb_ia_t *usb_ia = usb_ia_obtain_state(dip); 1023*d73ae94eSgc dev_info_t *child_dip; 1024*d73ae94eSgc ddi_eventcookie_t rm_cookie, ins_cookie, suspend_cookie, resume_cookie; 1025*d73ae94eSgc 1026*d73ae94eSgc USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle, 1027*d73ae94eSgc "usb_ia_event_cb: dip=0x%p, cookie=0x%p, " 1028*d73ae94eSgc "arg=0x%p, impl=0x%p", 1029*d73ae94eSgc (void *)dip, (void *)cookie, arg, bus_impldata); 1030*d73ae94eSgc USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle, 1031*d73ae94eSgc "(dip=%s%d event=%s)", 1032*d73ae94eSgc ddi_driver_name(dip), ddi_get_instance(dip), 1033*d73ae94eSgc ndi_event_cookie_to_name(usb_ia->ia_ndi_event_hdl, cookie)); 1034*d73ae94eSgc 1035*d73ae94eSgc tag = NDI_EVENT_TAG(cookie); 1036*d73ae94eSgc rm_cookie = ndi_event_tag_to_cookie( 1037*d73ae94eSgc usb_ia->ia_ndi_event_hdl, USBA_EVENT_TAG_HOT_REMOVAL); 1038*d73ae94eSgc suspend_cookie = ndi_event_tag_to_cookie( 1039*d73ae94eSgc usb_ia->ia_ndi_event_hdl, USBA_EVENT_TAG_PRE_SUSPEND); 1040*d73ae94eSgc ins_cookie = ndi_event_tag_to_cookie( 1041*d73ae94eSgc usb_ia->ia_ndi_event_hdl, USBA_EVENT_TAG_HOT_INSERTION); 1042*d73ae94eSgc resume_cookie = ndi_event_tag_to_cookie( 1043*d73ae94eSgc usb_ia->ia_ndi_event_hdl, USBA_EVENT_TAG_POST_RESUME); 1044*d73ae94eSgc 1045*d73ae94eSgc mutex_enter(&usb_ia->ia_mutex); 1046*d73ae94eSgc switch (tag) { 1047*d73ae94eSgc case USBA_EVENT_TAG_HOT_REMOVAL: 1048*d73ae94eSgc if (usb_ia->ia_dev_state == USB_DEV_DISCONNECTED) { 1049*d73ae94eSgc USB_DPRINTF_L2(DPRINT_MASK_EVENTS, 1050*d73ae94eSgc usb_ia->ia_log_handle, 1051*d73ae94eSgc "usb_ia_event_cb: Device already disconnected"); 1052*d73ae94eSgc } else { 1053*d73ae94eSgc /* we are disconnected so set our state now */ 1054*d73ae94eSgc usb_ia->ia_dev_state = USB_DEV_DISCONNECTED; 1055*d73ae94eSgc for (i = 0; i < usb_ia->ia_n_ifs; i++) { 1056*d73ae94eSgc usb_ia->ia_child_events[i] &= ~ 1057*d73ae94eSgc USB_IA_CHILD_EVENT_DISCONNECT; 1058*d73ae94eSgc } 1059*d73ae94eSgc mutex_exit(&usb_ia->ia_mutex); 1060*d73ae94eSgc 1061*d73ae94eSgc /* pass disconnect event to all the children */ 1062*d73ae94eSgc (void) ndi_event_run_callbacks( 1063*d73ae94eSgc usb_ia->ia_ndi_event_hdl, NULL, 1064*d73ae94eSgc rm_cookie, bus_impldata); 1065*d73ae94eSgc 1066*d73ae94eSgc mutex_enter(&usb_ia->ia_mutex); 1067*d73ae94eSgc } 1068*d73ae94eSgc break; 1069*d73ae94eSgc case USBA_EVENT_TAG_PRE_SUSPEND: 1070*d73ae94eSgc /* set our state *after* suspending children */ 1071*d73ae94eSgc mutex_exit(&usb_ia->ia_mutex); 1072*d73ae94eSgc 1073*d73ae94eSgc /* pass pre_suspend event to all the children */ 1074*d73ae94eSgc (void) ndi_event_run_callbacks(usb_ia->ia_ndi_event_hdl, 1075*d73ae94eSgc NULL, suspend_cookie, bus_impldata); 1076*d73ae94eSgc 1077*d73ae94eSgc mutex_enter(&usb_ia->ia_mutex); 1078*d73ae94eSgc for (i = 0; i < usb_ia->ia_n_ifs; i++) { 1079*d73ae94eSgc usb_ia->ia_child_events[i] &= ~ 1080*d73ae94eSgc USB_IA_CHILD_EVENT_PRESUSPEND; 1081*d73ae94eSgc } 1082*d73ae94eSgc break; 1083*d73ae94eSgc case USBA_EVENT_TAG_HOT_INSERTION: 1084*d73ae94eSgc mutex_exit(&usb_ia->ia_mutex); 1085*d73ae94eSgc if (usb_ia_restore_device_state(dip, usb_ia) == USB_SUCCESS) { 1086*d73ae94eSgc 1087*d73ae94eSgc /* 1088*d73ae94eSgc * Check to see if this child has missed the disconnect 1089*d73ae94eSgc * event before it registered for event cb 1090*d73ae94eSgc */ 1091*d73ae94eSgc mutex_enter(&usb_ia->ia_mutex); 1092*d73ae94eSgc for (i = 0; i < usb_ia->ia_n_ifs; i++) { 1093*d73ae94eSgc if (usb_ia->ia_child_events[i] & 1094*d73ae94eSgc USB_IA_CHILD_EVENT_DISCONNECT) { 1095*d73ae94eSgc usb_ia->ia_child_events[i] &= 1096*d73ae94eSgc ~USB_IA_CHILD_EVENT_DISCONNECT; 1097*d73ae94eSgc child_dip = 1098*d73ae94eSgc usb_ia->ia_children_dips[i]; 1099*d73ae94eSgc mutex_exit(&usb_ia->ia_mutex); 1100*d73ae94eSgc 1101*d73ae94eSgc /* post the missed disconnect */ 1102*d73ae94eSgc (void) ndi_event_do_callback( 1103*d73ae94eSgc usb_ia->ia_ndi_event_hdl, 1104*d73ae94eSgc child_dip, 1105*d73ae94eSgc rm_cookie, 1106*d73ae94eSgc bus_impldata); 1107*d73ae94eSgc mutex_enter(&usb_ia->ia_mutex); 1108*d73ae94eSgc } 1109*d73ae94eSgc } 1110*d73ae94eSgc mutex_exit(&usb_ia->ia_mutex); 1111*d73ae94eSgc 1112*d73ae94eSgc /* pass reconnect event to all the children */ 1113*d73ae94eSgc (void) ndi_event_run_callbacks( 1114*d73ae94eSgc usb_ia->ia_ndi_event_hdl, NULL, 1115*d73ae94eSgc ins_cookie, bus_impldata); 1116*d73ae94eSgc 1117*d73ae94eSgc } 1118*d73ae94eSgc mutex_enter(&usb_ia->ia_mutex); 1119*d73ae94eSgc break; 1120*d73ae94eSgc case USBA_EVENT_TAG_POST_RESUME: 1121*d73ae94eSgc /* 1122*d73ae94eSgc * Check to see if this child has missed the pre-suspend 1123*d73ae94eSgc * event before it registered for event cb 1124*d73ae94eSgc */ 1125*d73ae94eSgc for (i = 0; i < usb_ia->ia_n_ifs; i++) { 1126*d73ae94eSgc if (usb_ia->ia_child_events[i] & 1127*d73ae94eSgc USB_IA_CHILD_EVENT_PRESUSPEND) { 1128*d73ae94eSgc usb_ia->ia_child_events[i] &= 1129*d73ae94eSgc ~USB_IA_CHILD_EVENT_PRESUSPEND; 1130*d73ae94eSgc child_dip = usb_ia->ia_children_dips[i]; 1131*d73ae94eSgc mutex_exit(&usb_ia->ia_mutex); 1132*d73ae94eSgc 1133*d73ae94eSgc /* post the missed pre-suspend event */ 1134*d73ae94eSgc (void) ndi_event_do_callback( 1135*d73ae94eSgc usb_ia->ia_ndi_event_hdl, 1136*d73ae94eSgc child_dip, suspend_cookie, 1137*d73ae94eSgc bus_impldata); 1138*d73ae94eSgc mutex_enter(&usb_ia->ia_mutex); 1139*d73ae94eSgc } 1140*d73ae94eSgc } 1141*d73ae94eSgc mutex_exit(&usb_ia->ia_mutex); 1142*d73ae94eSgc 1143*d73ae94eSgc /* pass post_resume event to all the children */ 1144*d73ae94eSgc (void) ndi_event_run_callbacks(usb_ia->ia_ndi_event_hdl, 1145*d73ae94eSgc NULL, resume_cookie, bus_impldata); 1146*d73ae94eSgc 1147*d73ae94eSgc mutex_enter(&usb_ia->ia_mutex); 1148*d73ae94eSgc break; 1149*d73ae94eSgc } 1150*d73ae94eSgc mutex_exit(&usb_ia->ia_mutex); 1151*d73ae94eSgc 1152*d73ae94eSgc } 1153*d73ae94eSgc 1154*d73ae94eSgc /* 1155*d73ae94eSgc * create the pm components required for power management 1156*d73ae94eSgc */ 1157*d73ae94eSgc static void 1158*d73ae94eSgc usb_ia_create_pm_components(dev_info_t *dip, usb_ia_t *usb_ia) 1159*d73ae94eSgc { 1160*d73ae94eSgc usb_common_power_t *iapm; 1161*d73ae94eSgc uint_t pwr_states; 1162*d73ae94eSgc 1163*d73ae94eSgc USB_DPRINTF_L4(DPRINT_MASK_PM, usb_ia->ia_log_handle, 1164*d73ae94eSgc "usb_ia_create_pm_components: Begin"); 1165*d73ae94eSgc 1166*d73ae94eSgc /* Allocate the PM state structure */ 1167*d73ae94eSgc iapm = kmem_zalloc(sizeof (usb_common_power_t), KM_SLEEP); 1168*d73ae94eSgc 1169*d73ae94eSgc mutex_enter(&usb_ia->ia_mutex); 1170*d73ae94eSgc usb_ia->ia_pm = iapm; 1171*d73ae94eSgc iapm->uc_usb_statep = usb_ia; 1172*d73ae94eSgc iapm->uc_pm_capabilities = 0; /* XXXX should this be 0?? */ 1173*d73ae94eSgc iapm->uc_current_power = USB_DEV_OS_FULL_PWR; 1174*d73ae94eSgc mutex_exit(&usb_ia->ia_mutex); 1175*d73ae94eSgc 1176*d73ae94eSgc /* 1177*d73ae94eSgc * By not enabling parental notification, PM enforces 1178*d73ae94eSgc * "strict parental dependency" meaning, usb_ia won't 1179*d73ae94eSgc * power off until any of its children are in full power. 1180*d73ae94eSgc */ 1181*d73ae94eSgc 1182*d73ae94eSgc /* 1183*d73ae94eSgc * there are 3 scenarios: 1184*d73ae94eSgc * 1. a well behaved device should have remote wakeup 1185*d73ae94eSgc * at interface and device level. If the interface 1186*d73ae94eSgc * wakes up, usb_ia will wake up 1187*d73ae94eSgc * 2. if the device doesn't have remote wake up and 1188*d73ae94eSgc * the interface has, PM will still work, ie. 1189*d73ae94eSgc * the interfaces wakes up and usb_ia wakes up 1190*d73ae94eSgc * 3. if neither the interface nor device has remote 1191*d73ae94eSgc * wakeup, the interface will wake up when it is opened 1192*d73ae94eSgc * and goes to sleep after being closed for a while 1193*d73ae94eSgc * In this case usb_ia should also go to sleep shortly 1194*d73ae94eSgc * thereafter 1195*d73ae94eSgc * In all scenarios it doesn't really matter whether 1196*d73ae94eSgc * remote wakeup at the device level is enabled or not 1197*d73ae94eSgc * but we do it anyways 1198*d73ae94eSgc */ 1199*d73ae94eSgc if (usb_handle_remote_wakeup(dip, USB_REMOTE_WAKEUP_ENABLE) == 1200*d73ae94eSgc USB_SUCCESS) { 1201*d73ae94eSgc USB_DPRINTF_L3(DPRINT_MASK_PM, usb_ia->ia_log_handle, 1202*d73ae94eSgc "usb_ia_create_pm_components: " 1203*d73ae94eSgc "Remote Wakeup Enabled"); 1204*d73ae94eSgc iapm->uc_wakeup_enabled = 1; 1205*d73ae94eSgc } 1206*d73ae94eSgc 1207*d73ae94eSgc if (usb_create_pm_components(dip, &pwr_states) == 1208*d73ae94eSgc USB_SUCCESS) { 1209*d73ae94eSgc iapm->uc_pwr_states = (uint8_t)pwr_states; 1210*d73ae94eSgc (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 1211*d73ae94eSgc } 1212*d73ae94eSgc 1213*d73ae94eSgc USB_DPRINTF_L4(DPRINT_MASK_PM, usb_ia->ia_log_handle, 1214*d73ae94eSgc "usb_ia_create_pm_components: End"); 1215*d73ae94eSgc } 1216*d73ae94eSgc 1217*d73ae94eSgc 1218*d73ae94eSgc /* 1219*d73ae94eSgc * usb_ia_obtain_state: 1220*d73ae94eSgc */ 1221*d73ae94eSgc static usb_ia_t * 1222*d73ae94eSgc usb_ia_obtain_state(dev_info_t *dip) 1223*d73ae94eSgc { 1224*d73ae94eSgc int instance = ddi_get_instance(dip); 1225*d73ae94eSgc usb_ia_t *statep = ddi_get_soft_state(usb_ia_statep, instance); 1226*d73ae94eSgc 1227*d73ae94eSgc ASSERT(statep != NULL); 1228*d73ae94eSgc 1229*d73ae94eSgc return (statep); 1230*d73ae94eSgc } 1231