1d73ae94eSgc /* 2d73ae94eSgc * CDDL HEADER START 3d73ae94eSgc * 4d73ae94eSgc * The contents of this file are subject to the terms of the 5d73ae94eSgc * Common Development and Distribution License (the "License"). 6d73ae94eSgc * You may not use this file except in compliance with the License. 7d73ae94eSgc * 8d73ae94eSgc * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9d73ae94eSgc * or http://www.opensolaris.org/os/licensing. 10d73ae94eSgc * See the License for the specific language governing permissions 11d73ae94eSgc * and limitations under the License. 12d73ae94eSgc * 13d73ae94eSgc * When distributing Covered Code, include this CDDL HEADER in each 14d73ae94eSgc * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15d73ae94eSgc * If applicable, add the following below this CDDL HEADER, with the 16d73ae94eSgc * fields enclosed by brackets "[]" replaced with your own identifying 17d73ae94eSgc * information: Portions Copyright [yyyy] [name of copyright owner] 18d73ae94eSgc * 19d73ae94eSgc * CDDL HEADER END 20d73ae94eSgc */ 21d73ae94eSgc /* 22be529ebcSRaymond Chen * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23d73ae94eSgc * Use is subject to license terms. 24d73ae94eSgc */ 25*cd21e7c5SGarrett D'Amore /* 26*cd21e7c5SGarrett D'Amore * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved. 27*cd21e7c5SGarrett D'Amore */ 28d73ae94eSgc 29d73ae94eSgc 30d73ae94eSgc /* 31d73ae94eSgc * usb interface association driver 32d73ae94eSgc * 33d73ae94eSgc * this driver attempts to the interface association node and 34d73ae94eSgc * creates/manages child nodes for the included interfaces. 35d73ae94eSgc */ 36d73ae94eSgc 37d73ae94eSgc #if defined(lint) && !defined(DEBUG) 38d73ae94eSgc #define DEBUG 1 39d73ae94eSgc #endif 40d73ae94eSgc #include <sys/usb/usba/usbai_version.h> 41d73ae94eSgc #include <sys/usb/usba.h> 42d73ae94eSgc #include <sys/usb/usba/usba_types.h> 43d73ae94eSgc #include <sys/usb/usba/usba_impl.h> 44d73ae94eSgc #include <sys/usb/usb_ia/usb_iavar.h> 45d73ae94eSgc 46d73ae94eSgc /* Debugging support */ 47d73ae94eSgc uint_t usb_ia_errlevel = USB_LOG_L4; 48d73ae94eSgc uint_t usb_ia_errmask = (uint_t)DPRINT_MASK_ALL; 49d73ae94eSgc uint_t usb_ia_instance_debug = (uint_t)-1; 50d73ae94eSgc uint_t usb_ia_bus_config_debug = 0; 51d73ae94eSgc 52d73ae94eSgc _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ia_errlevel)) 53d73ae94eSgc _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ia_errmask)) 54d73ae94eSgc _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ia_instance_debug)) 55d73ae94eSgc 56d73ae94eSgc _NOTE(SCHEME_PROTECTS_DATA("unique", msgb)) 57d73ae94eSgc _NOTE(SCHEME_PROTECTS_DATA("unique", dev_info)) 58d73ae94eSgc _NOTE(SCHEME_PROTECTS_DATA("unique", usb_pipe_policy)) 59d73ae94eSgc 60d73ae94eSgc static struct cb_ops usb_ia_cb_ops = { 61d73ae94eSgc nodev, /* open */ 62d73ae94eSgc nodev, /* close */ 63d73ae94eSgc nodev, /* strategy */ 64d73ae94eSgc nodev, /* print */ 65d73ae94eSgc nodev, /* dump */ 66d73ae94eSgc nodev, /* read */ 67d73ae94eSgc nodev, /* write */ 68d73ae94eSgc nodev, /* ioctl */ 69d73ae94eSgc nodev, /* devmap */ 70d73ae94eSgc nodev, /* mmap */ 71d73ae94eSgc nodev, /* segmap */ 72d73ae94eSgc nochpoll, /* poll */ 73d73ae94eSgc ddi_prop_op, /* prop_op */ 74d73ae94eSgc NULL, /* aread */ 75d73ae94eSgc D_MP 76d73ae94eSgc }; 77d73ae94eSgc 78d73ae94eSgc static int usb_ia_busop_get_eventcookie(dev_info_t *dip, 79d73ae94eSgc dev_info_t *rdip, 80d73ae94eSgc char *eventname, 81d73ae94eSgc ddi_eventcookie_t *cookie); 82d73ae94eSgc static int usb_ia_busop_add_eventcall(dev_info_t *dip, 83d73ae94eSgc dev_info_t *rdip, 84d73ae94eSgc ddi_eventcookie_t cookie, 85d73ae94eSgc void (*callback)(dev_info_t *dip, 86d73ae94eSgc ddi_eventcookie_t cookie, void *arg, 87d73ae94eSgc void *bus_impldata), 88d73ae94eSgc void *arg, ddi_callback_id_t *cb_id); 89d73ae94eSgc static int usb_ia_busop_remove_eventcall(dev_info_t *dip, 90d73ae94eSgc ddi_callback_id_t cb_id); 91d73ae94eSgc static int usb_ia_busop_post_event(dev_info_t *dip, 92d73ae94eSgc dev_info_t *rdip, 93d73ae94eSgc ddi_eventcookie_t cookie, 94d73ae94eSgc void *bus_impldata); 95d73ae94eSgc static int usb_ia_bus_config(dev_info_t *dip, 96d73ae94eSgc uint_t flag, 97d73ae94eSgc ddi_bus_config_op_t op, 98d73ae94eSgc void *arg, 99d73ae94eSgc dev_info_t **child); 100d73ae94eSgc static int usb_ia_bus_unconfig(dev_info_t *dip, 101d73ae94eSgc uint_t flag, 102d73ae94eSgc ddi_bus_config_op_t op, 103d73ae94eSgc void *arg); 104d73ae94eSgc 105d73ae94eSgc /* 106d73ae94eSgc * autoconfiguration data and routines. 107d73ae94eSgc */ 108d73ae94eSgc static int usb_ia_info(dev_info_t *, ddi_info_cmd_t, 109d73ae94eSgc void *, void **); 110d73ae94eSgc static int usb_ia_attach(dev_info_t *, ddi_attach_cmd_t); 111d73ae94eSgc static int usb_ia_detach(dev_info_t *, ddi_detach_cmd_t); 112d73ae94eSgc 113d73ae94eSgc /* other routines */ 114d73ae94eSgc static void usb_ia_create_pm_components(dev_info_t *, usb_ia_t *); 115d73ae94eSgc static int usb_ia_bus_ctl(dev_info_t *, dev_info_t *, 116d73ae94eSgc ddi_ctl_enum_t, void *, void *); 117d73ae94eSgc static int usb_ia_power(dev_info_t *, int, int); 118d73ae94eSgc static int usb_ia_restore_device_state(dev_info_t *, usb_ia_t *); 119d73ae94eSgc static usb_ia_t *usb_ia_obtain_state(dev_info_t *); 120d73ae94eSgc static void usb_ia_event_cb(dev_info_t *, ddi_eventcookie_t, void *, void *); 121d73ae94eSgc 122d73ae94eSgc /* prototypes */ 123d73ae94eSgc static void usb_ia_create_children(usb_ia_t *); 124d73ae94eSgc static int usb_ia_cleanup(usb_ia_t *); 125d73ae94eSgc 126d73ae94eSgc /* 127d73ae94eSgc * Busops vector 128d73ae94eSgc */ 129d73ae94eSgc static struct bus_ops usb_ia_busops = { 130d73ae94eSgc BUSO_REV, 131d73ae94eSgc nullbusmap, /* bus_map */ 132d73ae94eSgc NULL, /* bus_get_intrspec */ 133d73ae94eSgc NULL, /* bus_add_intrspec */ 134d73ae94eSgc NULL, /* bus_remove_intrspec */ 135d73ae94eSgc NULL, /* XXXX bus_map_fault */ 136*cd21e7c5SGarrett D'Amore NULL, /* bus_dma_map */ 137d73ae94eSgc ddi_dma_allochdl, 138d73ae94eSgc ddi_dma_freehdl, 139d73ae94eSgc ddi_dma_bindhdl, 140d73ae94eSgc ddi_dma_unbindhdl, 141d73ae94eSgc ddi_dma_flush, 142d73ae94eSgc ddi_dma_win, 143d73ae94eSgc ddi_dma_mctl, /* bus_dma_ctl */ 144d73ae94eSgc usb_ia_bus_ctl, /* bus_ctl */ 145d73ae94eSgc ddi_bus_prop_op, /* bus_prop_op */ 146d73ae94eSgc usb_ia_busop_get_eventcookie, 147d73ae94eSgc usb_ia_busop_add_eventcall, 148d73ae94eSgc usb_ia_busop_remove_eventcall, 149d73ae94eSgc usb_ia_busop_post_event, /* bus_post_event */ 150d73ae94eSgc NULL, /* bus_intr_ctl */ 151d73ae94eSgc usb_ia_bus_config, /* bus_config */ 152d73ae94eSgc usb_ia_bus_unconfig, /* bus_unconfig */ 153d73ae94eSgc NULL, /* bus_fm_init */ 154d73ae94eSgc NULL, /* bus_fm_fini */ 155d73ae94eSgc NULL, /* bus_fm_access_enter */ 156d73ae94eSgc NULL, /* bus_fm_access_exit */ 157d73ae94eSgc NULL /* bus_power */ 158d73ae94eSgc }; 159d73ae94eSgc 160d73ae94eSgc 161d73ae94eSgc static struct dev_ops usb_ia_ops = { 162d73ae94eSgc DEVO_REV, /* devo_rev, */ 163d73ae94eSgc 0, /* refcnt */ 164d73ae94eSgc usb_ia_info, /* info */ 165d73ae94eSgc nulldev, /* identify */ 166d73ae94eSgc nulldev, /* probe */ 167d73ae94eSgc usb_ia_attach, /* attach */ 168d73ae94eSgc usb_ia_detach, /* detach */ 169d73ae94eSgc nodev, /* reset */ 170d73ae94eSgc &usb_ia_cb_ops, /* driver operations */ 171d73ae94eSgc &usb_ia_busops, /* bus operations */ 17219397407SSherry Moore usb_ia_power, /* power */ 173be529ebcSRaymond Chen ddi_quiesce_not_needed, /* devo_quiesce */ 174d73ae94eSgc }; 175d73ae94eSgc 176d73ae94eSgc static struct modldrv modldrv = { 177d73ae94eSgc &mod_driverops, /* Type of module. This one is a driver */ 17877e51571Sgongtian zhao - Sun Microsystems - Beijing China "USB Interface Association Driver", /* Name of the module. */ 179d73ae94eSgc &usb_ia_ops, /* driver ops */ 180d73ae94eSgc }; 181d73ae94eSgc 182d73ae94eSgc static struct modlinkage modlinkage = { 183d73ae94eSgc MODREV_1, (void *)&modldrv, NULL 184d73ae94eSgc }; 185d73ae94eSgc 186d73ae94eSgc #define USB_IA_INITIAL_SOFT_SPACE 4 187d73ae94eSgc static void *usb_ia_statep; 188d73ae94eSgc 189d73ae94eSgc /* 190d73ae94eSgc * event definition 191d73ae94eSgc */ 192d73ae94eSgc static ndi_event_definition_t usb_ia_ndi_event_defs[] = { 193d73ae94eSgc {USBA_EVENT_TAG_HOT_REMOVAL, DDI_DEVI_REMOVE_EVENT, EPL_KERNEL, 194d73ae94eSgc NDI_EVENT_POST_TO_ALL}, 195d73ae94eSgc {USBA_EVENT_TAG_HOT_INSERTION, DDI_DEVI_INSERT_EVENT, EPL_KERNEL, 196d73ae94eSgc NDI_EVENT_POST_TO_ALL}, 197d73ae94eSgc {USBA_EVENT_TAG_POST_RESUME, USBA_POST_RESUME_EVENT, EPL_KERNEL, 198d73ae94eSgc NDI_EVENT_POST_TO_ALL}, 199d73ae94eSgc {USBA_EVENT_TAG_PRE_SUSPEND, USBA_PRE_SUSPEND_EVENT, EPL_KERNEL, 200d73ae94eSgc NDI_EVENT_POST_TO_ALL} 201d73ae94eSgc }; 202d73ae94eSgc 203d73ae94eSgc #define USB_IA_N_NDI_EVENTS \ 204d73ae94eSgc (sizeof (usb_ia_ndi_event_defs) / sizeof (ndi_event_definition_t)) 205d73ae94eSgc 206d73ae94eSgc static ndi_event_set_t usb_ia_ndi_events = { 207d73ae94eSgc NDI_EVENTS_REV1, USB_IA_N_NDI_EVENTS, usb_ia_ndi_event_defs}; 208d73ae94eSgc 209d73ae94eSgc 210d73ae94eSgc /* 211d73ae94eSgc * standard driver entry points 212d73ae94eSgc */ 213d73ae94eSgc int 214d73ae94eSgc _init(void) 215d73ae94eSgc { 216d73ae94eSgc int rval; 217d73ae94eSgc 218d73ae94eSgc rval = ddi_soft_state_init(&usb_ia_statep, sizeof (struct usb_ia), 219d73ae94eSgc USB_IA_INITIAL_SOFT_SPACE); 220d73ae94eSgc if (rval != 0) { 221d73ae94eSgc return (rval); 222d73ae94eSgc } 223d73ae94eSgc 224d73ae94eSgc if ((rval = mod_install(&modlinkage)) != 0) { 225d73ae94eSgc ddi_soft_state_fini(&usb_ia_statep); 226d73ae94eSgc return (rval); 227d73ae94eSgc } 228d73ae94eSgc 229d73ae94eSgc return (rval); 230d73ae94eSgc } 231d73ae94eSgc 232d73ae94eSgc 233d73ae94eSgc int 234d73ae94eSgc _fini(void) 235d73ae94eSgc { 236d73ae94eSgc int rval; 237d73ae94eSgc 238d73ae94eSgc rval = mod_remove(&modlinkage); 239d73ae94eSgc 240d73ae94eSgc if (rval) { 241d73ae94eSgc return (rval); 242d73ae94eSgc } 243d73ae94eSgc 244d73ae94eSgc ddi_soft_state_fini(&usb_ia_statep); 245d73ae94eSgc 246d73ae94eSgc return (rval); 247d73ae94eSgc } 248d73ae94eSgc 249d73ae94eSgc 250d73ae94eSgc int 251d73ae94eSgc _info(struct modinfo *modinfop) 252d73ae94eSgc { 253d73ae94eSgc return (mod_info(&modlinkage, modinfop)); 254d73ae94eSgc } 255d73ae94eSgc 256d73ae94eSgc 257d73ae94eSgc /*ARGSUSED*/ 258d73ae94eSgc static int 259d73ae94eSgc usb_ia_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 260d73ae94eSgc { 261d73ae94eSgc usb_ia_t *usb_ia; 262d73ae94eSgc int instance = getminor((dev_t)arg); 263d73ae94eSgc int error = DDI_FAILURE; 264d73ae94eSgc 265d73ae94eSgc switch (infocmd) { 266d73ae94eSgc case DDI_INFO_DEVT2DEVINFO: 267d73ae94eSgc if ((usb_ia = ddi_get_soft_state(usb_ia_statep, 268d73ae94eSgc instance)) != NULL) { 269d73ae94eSgc *result = (void *)usb_ia->ia_dip; 270d73ae94eSgc if (*result != NULL) { 271d73ae94eSgc error = DDI_SUCCESS; 272d73ae94eSgc } 273d73ae94eSgc } else { 274d73ae94eSgc *result = NULL; 275d73ae94eSgc } 276d73ae94eSgc break; 277d73ae94eSgc 278d73ae94eSgc case DDI_INFO_DEVT2INSTANCE: 279d73ae94eSgc *result = (void *)(intptr_t)instance; 280d73ae94eSgc error = DDI_SUCCESS; 281d73ae94eSgc break; 282d73ae94eSgc default: 283d73ae94eSgc break; 284d73ae94eSgc } 285d73ae94eSgc 286d73ae94eSgc return (error); 287d73ae94eSgc } 288d73ae94eSgc 289d73ae94eSgc 290d73ae94eSgc /* 291d73ae94eSgc * child post attach/detach notification 292d73ae94eSgc */ 293d73ae94eSgc static void 294d73ae94eSgc usb_ia_post_attach(usb_ia_t *usb_ia, uint8_t ifno, struct attachspec *as) 295d73ae94eSgc { 296d73ae94eSgc USB_DPRINTF_L4(DPRINT_MASK_PM, usb_ia->ia_log_handle, 297d73ae94eSgc "usb_ia_post_attach: ifno = %d result = %d", ifno, as->result); 298d73ae94eSgc 299d73ae94eSgc } 300d73ae94eSgc 301d73ae94eSgc 302d73ae94eSgc static void 303d73ae94eSgc usb_ia_post_detach(usb_ia_t *usb_ia, uint8_t ifno, struct detachspec *ds) 304d73ae94eSgc { 305d73ae94eSgc USB_DPRINTF_L4(DPRINT_MASK_PM, usb_ia->ia_log_handle, 306d73ae94eSgc "usb_ia_post_detach: ifno = %d result = %d", ifno, ds->result); 307d73ae94eSgc 308d73ae94eSgc } 309d73ae94eSgc 310d73ae94eSgc 311d73ae94eSgc /* 312d73ae94eSgc * bus ctl support. we handle notifications here and the 313d73ae94eSgc * rest goes up to root hub/hcd 314d73ae94eSgc */ 315d73ae94eSgc /*ARGSUSED*/ 316d73ae94eSgc static int 317d73ae94eSgc usb_ia_bus_ctl(dev_info_t *dip, 318d73ae94eSgc dev_info_t *rdip, 319d73ae94eSgc ddi_ctl_enum_t op, 320d73ae94eSgc void *arg, 321d73ae94eSgc void *result) 322d73ae94eSgc { 323d73ae94eSgc usba_device_t *hub_usba_device = usba_get_usba_device(rdip); 324d73ae94eSgc dev_info_t *root_hub_dip = hub_usba_device->usb_root_hub_dip; 325d73ae94eSgc usb_ia_t *usb_ia; 326d73ae94eSgc struct attachspec *as; 327d73ae94eSgc struct detachspec *ds; 328d73ae94eSgc 329d73ae94eSgc usb_ia = usb_ia_obtain_state(dip); 330d73ae94eSgc 331d73ae94eSgc USB_DPRINTF_L4(DPRINT_MASK_PM, usb_ia->ia_log_handle, 332d73ae94eSgc "usb_ia_bus_ctl:\n\t" 333d73ae94eSgc "dip = 0x%p, rdip = 0x%p, op = 0x%x, arg = 0x%p", 334112116d8Sfb (void *)dip, (void *)rdip, op, arg); 335d73ae94eSgc 336d73ae94eSgc switch (op) { 337d73ae94eSgc case DDI_CTLOPS_ATTACH: 338d73ae94eSgc as = (struct attachspec *)arg; 339d73ae94eSgc 340d73ae94eSgc switch (as->when) { 341d73ae94eSgc case DDI_PRE : 342d73ae94eSgc /* nothing to do basically */ 343d73ae94eSgc USB_DPRINTF_L2(DPRINT_MASK_PM, usb_ia->ia_log_handle, 344d73ae94eSgc "DDI_PRE DDI_CTLOPS_ATTACH"); 345d73ae94eSgc break; 346d73ae94eSgc case DDI_POST : 347d73ae94eSgc usb_ia_post_attach(usb_ia, usba_get_ifno(rdip), 348d73ae94eSgc (struct attachspec *)arg); 349d73ae94eSgc break; 350d73ae94eSgc } 351d73ae94eSgc 352d73ae94eSgc break; 353d73ae94eSgc case DDI_CTLOPS_DETACH: 354d73ae94eSgc ds = (struct detachspec *)arg; 355d73ae94eSgc 356d73ae94eSgc switch (ds->when) { 357d73ae94eSgc case DDI_PRE : 358d73ae94eSgc /* nothing to do basically */ 359d73ae94eSgc USB_DPRINTF_L2(DPRINT_MASK_PM, usb_ia->ia_log_handle, 360d73ae94eSgc "DDI_PRE DDI_CTLOPS_DETACH"); 361d73ae94eSgc break; 362d73ae94eSgc case DDI_POST : 363d73ae94eSgc usb_ia_post_detach(usb_ia, usba_get_ifno(rdip), 364d73ae94eSgc (struct detachspec *)arg); 365d73ae94eSgc break; 366d73ae94eSgc } 367d73ae94eSgc 368d73ae94eSgc break; 369d73ae94eSgc default: 370d73ae94eSgc /* pass to root hub to handle */ 371d73ae94eSgc return (usba_bus_ctl(root_hub_dip, rdip, op, arg, result)); 372d73ae94eSgc } 373d73ae94eSgc 374d73ae94eSgc return (DDI_SUCCESS); 375d73ae94eSgc } 376d73ae94eSgc 377d73ae94eSgc 378d73ae94eSgc /* 379d73ae94eSgc * bus enumeration entry points 380d73ae94eSgc */ 381d73ae94eSgc static int 382d73ae94eSgc usb_ia_bus_config(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op, 383d73ae94eSgc void *arg, dev_info_t **child) 384d73ae94eSgc { 385d73ae94eSgc int rval, circ; 386d73ae94eSgc usb_ia_t *usb_ia = usb_ia_obtain_state(dip); 387d73ae94eSgc 388d73ae94eSgc USB_DPRINTF_L4(DPRINT_MASK_ALL, usb_ia->ia_log_handle, 389d73ae94eSgc "usb_ia_bus_config: op=%d", op); 390d73ae94eSgc 391d73ae94eSgc if (usb_ia_bus_config_debug) { 392d73ae94eSgc flag |= NDI_DEVI_DEBUG; 393d73ae94eSgc } 394d73ae94eSgc 395d73ae94eSgc ndi_devi_enter(dip, &circ); 396d73ae94eSgc 397d73ae94eSgc /* enumerate each interface below us */ 398d73ae94eSgc mutex_enter(&usb_ia->ia_mutex); 399d73ae94eSgc usb_ia_create_children(usb_ia); 400d73ae94eSgc mutex_exit(&usb_ia->ia_mutex); 401d73ae94eSgc 402d73ae94eSgc rval = ndi_busop_bus_config(dip, flag, op, arg, child, 0); 403d73ae94eSgc ndi_devi_exit(dip, circ); 404d73ae94eSgc 405d73ae94eSgc return (rval); 406d73ae94eSgc } 407d73ae94eSgc 408d73ae94eSgc 409d73ae94eSgc static int 410d73ae94eSgc usb_ia_bus_unconfig(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op, 411d73ae94eSgc void *arg) 412d73ae94eSgc { 413d73ae94eSgc usb_ia_t *usb_ia = usb_ia_obtain_state(dip); 414d73ae94eSgc 415d73ae94eSgc dev_info_t *cdip, *mdip; 416d73ae94eSgc int interface, circular_count; 417d73ae94eSgc int rval = NDI_SUCCESS; 418d73ae94eSgc 419d73ae94eSgc USB_DPRINTF_L4(DPRINT_MASK_ALL, usb_ia->ia_log_handle, 420d73ae94eSgc "usb_ia_bus_unconfig: op=%d", op); 421d73ae94eSgc 422d73ae94eSgc if (usb_ia_bus_config_debug) { 423d73ae94eSgc flag |= NDI_DEVI_DEBUG; 424d73ae94eSgc } 425d73ae94eSgc 426d73ae94eSgc /* 427d73ae94eSgc * first offline and if offlining successful, then 428d73ae94eSgc * remove children 429d73ae94eSgc */ 430d73ae94eSgc if (op == BUS_UNCONFIG_ALL) { 431d73ae94eSgc flag &= ~(NDI_DEVI_REMOVE | NDI_UNCONFIG); 432d73ae94eSgc } 433d73ae94eSgc 434d73ae94eSgc ndi_devi_enter(dip, &circular_count); 435d73ae94eSgc rval = ndi_busop_bus_unconfig(dip, flag, op, arg); 436d73ae94eSgc 437d73ae94eSgc if (op == BUS_UNCONFIG_ALL && rval == NDI_SUCCESS && 438d73ae94eSgc (flag & NDI_AUTODETACH) == 0) { 439d73ae94eSgc flag |= NDI_DEVI_REMOVE; 440d73ae94eSgc rval = ndi_busop_bus_unconfig(dip, flag, op, arg); 441d73ae94eSgc } 442d73ae94eSgc 443d73ae94eSgc /* update children's list */ 444d73ae94eSgc mutex_enter(&usb_ia->ia_mutex); 445d73ae94eSgc for (interface = 0; usb_ia->ia_children_dips && 446d73ae94eSgc (interface < usb_ia->ia_n_ifs); interface++) { 447d73ae94eSgc mdip = usb_ia->ia_children_dips[interface]; 448d73ae94eSgc 449d73ae94eSgc /* now search if this dip still exists */ 450112116d8Sfb for (cdip = ddi_get_child(dip); cdip && (cdip != mdip); ) 451112116d8Sfb cdip = ddi_get_next_sibling(cdip); 452d73ae94eSgc 453d73ae94eSgc if (cdip != mdip) { 454d73ae94eSgc /* we lost the dip on this interface */ 455d73ae94eSgc usb_ia->ia_children_dips[interface] = NULL; 456d73ae94eSgc } else if (cdip) { 457d73ae94eSgc /* 458d73ae94eSgc * keep in DS_INITALIZED to prevent parent 459d73ae94eSgc * from detaching 460d73ae94eSgc */ 461d73ae94eSgc (void) ddi_initchild(ddi_get_parent(cdip), cdip); 462d73ae94eSgc } 463d73ae94eSgc } 464d73ae94eSgc mutex_exit(&usb_ia->ia_mutex); 465d73ae94eSgc 466d73ae94eSgc ndi_devi_exit(dip, circular_count); 467d73ae94eSgc 468d73ae94eSgc USB_DPRINTF_L4(DPRINT_MASK_ALL, usb_ia->ia_log_handle, 469d73ae94eSgc "usb_ia_bus_config: rval=%d", rval); 470d73ae94eSgc 471d73ae94eSgc return (rval); 472d73ae94eSgc } 473d73ae94eSgc 474d73ae94eSgc 475d73ae94eSgc /* power entry point */ 476d73ae94eSgc /* ARGSUSED */ 477d73ae94eSgc static int 478d73ae94eSgc usb_ia_power(dev_info_t *dip, int comp, int level) 479d73ae94eSgc { 480d73ae94eSgc usb_ia_t *usb_ia; 481d73ae94eSgc usb_common_power_t *pm; 482d73ae94eSgc int rval = DDI_FAILURE; 483d73ae94eSgc 484d73ae94eSgc usb_ia = usb_ia_obtain_state(dip); 485d73ae94eSgc 486d73ae94eSgc USB_DPRINTF_L4(DPRINT_MASK_PM, usb_ia->ia_log_handle, 487112116d8Sfb "usb_ia_power: Begin: usb_ia = %p, level = %d", 488112116d8Sfb (void *)usb_ia, level); 489d73ae94eSgc 490d73ae94eSgc mutex_enter(&usb_ia->ia_mutex); 491d73ae94eSgc pm = usb_ia->ia_pm; 492d73ae94eSgc 493d73ae94eSgc /* check if we are transitioning to a legal power level */ 494d73ae94eSgc if (USB_DEV_PWRSTATE_OK(pm->uc_pwr_states, level)) { 495d73ae94eSgc USB_DPRINTF_L2(DPRINT_MASK_PM, usb_ia->ia_log_handle, 496d73ae94eSgc "usb_ia_power: illegal power level = %d " 497d73ae94eSgc "uc_pwr_states = %x", level, pm->uc_pwr_states); 498d73ae94eSgc 499d73ae94eSgc mutex_exit(&usb_ia->ia_mutex); 500d73ae94eSgc 501d73ae94eSgc return (rval); 502d73ae94eSgc } 503d73ae94eSgc 504036aa261Sgc rval = usba_common_power(dip, &(pm->uc_current_power), 505036aa261Sgc &(usb_ia->ia_dev_state), level); 506d73ae94eSgc 507d73ae94eSgc mutex_exit(&usb_ia->ia_mutex); 508d73ae94eSgc 509d73ae94eSgc return (rval); 510d73ae94eSgc } 511d73ae94eSgc 512d73ae94eSgc /* 513d73ae94eSgc * attach/resume entry point 514d73ae94eSgc */ 515d73ae94eSgc static int 516d73ae94eSgc usb_ia_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 517d73ae94eSgc { 518d73ae94eSgc int instance = ddi_get_instance(dip); 519d73ae94eSgc usb_ia_t *usb_ia = NULL; 520d73ae94eSgc uint_t n_ifs; 521d73ae94eSgc size_t size; 522d73ae94eSgc 523d73ae94eSgc switch (cmd) { 524d73ae94eSgc case DDI_ATTACH: 525d73ae94eSgc 526d73ae94eSgc break; 527d73ae94eSgc case DDI_RESUME: 528d73ae94eSgc usb_ia = ddi_get_soft_state(usb_ia_statep, instance); 529d73ae94eSgc (void) usb_ia_restore_device_state(dip, usb_ia); 530d73ae94eSgc 531d73ae94eSgc return (DDI_SUCCESS); 532d73ae94eSgc default: 533d73ae94eSgc 534d73ae94eSgc return (DDI_FAILURE); 535d73ae94eSgc } 536d73ae94eSgc 537d73ae94eSgc /* 538d73ae94eSgc * Attach: 539d73ae94eSgc * 540d73ae94eSgc * Allocate soft state and initialize 541d73ae94eSgc */ 542d73ae94eSgc if (ddi_soft_state_zalloc(usb_ia_statep, instance) != DDI_SUCCESS) { 543d73ae94eSgc goto fail; 544d73ae94eSgc } 545d73ae94eSgc 546d73ae94eSgc usb_ia = ddi_get_soft_state(usb_ia_statep, instance); 547d73ae94eSgc if (usb_ia == NULL) { 548d73ae94eSgc 549d73ae94eSgc goto fail; 550d73ae94eSgc } 551d73ae94eSgc 552d73ae94eSgc /* allocate handle for logging of messages */ 553d73ae94eSgc usb_ia->ia_log_handle = usb_alloc_log_hdl(dip, "ia", 554112116d8Sfb &usb_ia_errlevel, 555112116d8Sfb &usb_ia_errmask, &usb_ia_instance_debug, 556112116d8Sfb 0); 557d73ae94eSgc 558d73ae94eSgc usb_ia->ia_dip = dip; 559d73ae94eSgc usb_ia->ia_instance = instance; 560d73ae94eSgc usb_ia->ia_first_if = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 561d73ae94eSgc DDI_PROP_DONTPASS, "interface", -1); 562d73ae94eSgc usb_ia->ia_n_ifs = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 563d73ae94eSgc DDI_PROP_DONTPASS, "interface-count", -1); 564d73ae94eSgc 565d73ae94eSgc if (usb_ia->ia_first_if < 0 || usb_ia->ia_n_ifs < 0) { 566d73ae94eSgc USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle, 567d73ae94eSgc "interface-association property failed"); 568d73ae94eSgc 569d73ae94eSgc goto fail; 570d73ae94eSgc } 571d73ae94eSgc 572d73ae94eSgc /* attach client driver to USBA */ 573d73ae94eSgc if (usb_client_attach(dip, USBDRV_VERSION, 0) != USB_SUCCESS) { 574d73ae94eSgc USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle, 575d73ae94eSgc "usb_client_attach failed"); 576d73ae94eSgc goto fail; 577d73ae94eSgc } 578d73ae94eSgc if (usb_get_dev_data(dip, &usb_ia->ia_dev_data, USB_PARSE_LVL_NONE, 579d73ae94eSgc 0) != USB_SUCCESS) { 580d73ae94eSgc USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle, 581d73ae94eSgc "usb_get_dev_data failed"); 582d73ae94eSgc goto fail; 583d73ae94eSgc } 584d73ae94eSgc 585d73ae94eSgc mutex_init(&usb_ia->ia_mutex, NULL, MUTEX_DRIVER, 586d73ae94eSgc usb_ia->ia_dev_data->dev_iblock_cookie); 587d73ae94eSgc 588d73ae94eSgc usb_free_dev_data(dip, usb_ia->ia_dev_data); 589d73ae94eSgc usb_ia->ia_dev_data = NULL; 590d73ae94eSgc 591d73ae94eSgc usb_ia->ia_init_state |= USB_IA_LOCK_INIT; 592d73ae94eSgc 593d73ae94eSgc if (ddi_create_minor_node(dip, "usb_ia", S_IFCHR, instance, 594d73ae94eSgc DDI_NT_NEXUS, 0) != DDI_SUCCESS) { 595d73ae94eSgc USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle, 596d73ae94eSgc "cannot create devctl minor node"); 597d73ae94eSgc goto fail; 598d73ae94eSgc } 599d73ae94eSgc 600d73ae94eSgc usb_ia->ia_init_state |= USB_IA_MINOR_NODE_CREATED; 601d73ae94eSgc 602d73ae94eSgc /* 603d73ae94eSgc * allocate array for keeping track of child dips 604d73ae94eSgc */ 605d73ae94eSgc n_ifs = usb_ia->ia_n_ifs; 606d73ae94eSgc usb_ia->ia_cd_list_length = size = (sizeof (dev_info_t *)) * n_ifs; 607d73ae94eSgc 608d73ae94eSgc usb_ia->ia_children_dips = kmem_zalloc(size, KM_SLEEP); 609d73ae94eSgc usb_ia->ia_child_events = kmem_zalloc(sizeof (uint8_t) * n_ifs, 610112116d8Sfb KM_SLEEP); 611d73ae94eSgc /* 612d73ae94eSgc * Event handling: definition and registration 613d73ae94eSgc * get event handle for events that we have defined 614d73ae94eSgc */ 615d73ae94eSgc (void) ndi_event_alloc_hdl(dip, 0, &usb_ia->ia_ndi_event_hdl, 616112116d8Sfb NDI_SLEEP); 617d73ae94eSgc 618d73ae94eSgc /* bind event set to the handle */ 619d73ae94eSgc if (ndi_event_bind_set(usb_ia->ia_ndi_event_hdl, &usb_ia_ndi_events, 620d73ae94eSgc NDI_SLEEP)) { 621d73ae94eSgc USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle, 622d73ae94eSgc "usb_ia_attach: binding event set failed"); 623d73ae94eSgc 624d73ae94eSgc goto fail; 625d73ae94eSgc } 626d73ae94eSgc 627d73ae94eSgc usb_ia->ia_dev_state = USB_DEV_ONLINE; 628d73ae94eSgc 629d73ae94eSgc /* 630d73ae94eSgc * now create components to power manage this device 631d73ae94eSgc * before attaching children 632d73ae94eSgc */ 633d73ae94eSgc usb_ia_create_pm_components(dip, usb_ia); 634d73ae94eSgc 635d73ae94eSgc /* event registration for events from our parent */ 636d73ae94eSgc usba_common_register_events(dip, n_ifs, usb_ia_event_cb); 637d73ae94eSgc 638d73ae94eSgc usb_ia->ia_init_state |= USB_IA_EVENTS_REGISTERED; 639d73ae94eSgc 640d73ae94eSgc ddi_report_dev(dip); 641d73ae94eSgc 642d73ae94eSgc return (DDI_SUCCESS); 643d73ae94eSgc 644d73ae94eSgc fail: 645d73ae94eSgc USB_DPRINTF_L2(DPRINT_MASK_ATTA, NULL, "usb_ia%d cannot attach", 646d73ae94eSgc instance); 647d73ae94eSgc 648d73ae94eSgc if (usb_ia) { 649d73ae94eSgc (void) usb_ia_cleanup(usb_ia); 650d73ae94eSgc } 651d73ae94eSgc 652d73ae94eSgc return (DDI_FAILURE); 653d73ae94eSgc } 654d73ae94eSgc 655d73ae94eSgc 656d73ae94eSgc /* detach or suspend this instance */ 657d73ae94eSgc static int 658d73ae94eSgc usb_ia_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 659d73ae94eSgc { 660d73ae94eSgc usb_ia_t *usb_ia = usb_ia_obtain_state(dip); 661d73ae94eSgc 662d73ae94eSgc USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_ia->ia_log_handle, 663d73ae94eSgc "usb_ia_detach: cmd = 0x%x", cmd); 664d73ae94eSgc 665d73ae94eSgc switch (cmd) { 666d73ae94eSgc case DDI_DETACH: 667d73ae94eSgc 668d73ae94eSgc return (usb_ia_cleanup(usb_ia)); 669d73ae94eSgc case DDI_SUSPEND: 670d73ae94eSgc /* nothing to do */ 671d73ae94eSgc mutex_enter(&usb_ia->ia_mutex); 672d73ae94eSgc usb_ia->ia_dev_state = USB_DEV_SUSPENDED; 673d73ae94eSgc mutex_exit(&usb_ia->ia_mutex); 674d73ae94eSgc 675d73ae94eSgc return (DDI_SUCCESS); 676d73ae94eSgc default: 677d73ae94eSgc 678d73ae94eSgc return (DDI_FAILURE); 679d73ae94eSgc } 680d73ae94eSgc 681d73ae94eSgc _NOTE(NOT_REACHED) 682d73ae94eSgc /* NOTREACHED */ 683d73ae94eSgc } 684d73ae94eSgc 685d73ae94eSgc 686d73ae94eSgc /* 687d73ae94eSgc * usb_ia_cleanup: 688d73ae94eSgc * cleanup usb_ia and deallocate. this function is called for 689d73ae94eSgc * handling attach failures and detaching including dynamic 690d73ae94eSgc * reconfiguration 691d73ae94eSgc */ 692d73ae94eSgc /*ARGSUSED*/ 693d73ae94eSgc static int 694d73ae94eSgc usb_ia_cleanup(usb_ia_t *usb_ia) 695d73ae94eSgc { 696d73ae94eSgc usb_common_power_t *iapm; 697d73ae94eSgc int rval; 698d73ae94eSgc dev_info_t *dip = usb_ia->ia_dip; 699d73ae94eSgc 700d73ae94eSgc USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_ia->ia_log_handle, 701d73ae94eSgc "usb_ia_cleanup:"); 702d73ae94eSgc 703d73ae94eSgc if ((usb_ia->ia_init_state & USB_IA_LOCK_INIT) == 0) { 704d73ae94eSgc 705d73ae94eSgc goto done; 706d73ae94eSgc } 707d73ae94eSgc 708d73ae94eSgc /* 709d73ae94eSgc * deallocate events, if events are still registered 710d73ae94eSgc * (ie. children still attached) then we have to fail the detach 711d73ae94eSgc */ 712d73ae94eSgc if (usb_ia->ia_ndi_event_hdl && 713d73ae94eSgc (ndi_event_free_hdl(usb_ia->ia_ndi_event_hdl) != NDI_SUCCESS)) { 714d73ae94eSgc 715d73ae94eSgc USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle, 716d73ae94eSgc "usb_ia_cleanup: ndi_event_free_hdl failed"); 717d73ae94eSgc 718d73ae94eSgc return (DDI_FAILURE); 719d73ae94eSgc } 720d73ae94eSgc 721d73ae94eSgc /* 722d73ae94eSgc * Disable the event callbacks, after this point, event 723d73ae94eSgc * callbacks will never get called. Note we shouldn't hold 724d73ae94eSgc * mutex while unregistering events because there may be a 725d73ae94eSgc * competing event callback thread. Event callbacks are done 726d73ae94eSgc * with ndi mutex held and this can cause a potential deadlock. 727d73ae94eSgc * Note that cleanup can't fail after deregistration of events. 728d73ae94eSgc */ 729d73ae94eSgc if (usb_ia->ia_init_state & USB_IA_EVENTS_REGISTERED) { 730d73ae94eSgc 731d73ae94eSgc usba_common_unregister_events(usb_ia->ia_dip, usb_ia->ia_n_ifs); 732d73ae94eSgc } 733d73ae94eSgc 734d73ae94eSgc iapm = usb_ia->ia_pm; 735d73ae94eSgc 736d73ae94eSgc mutex_enter(&usb_ia->ia_mutex); 737d73ae94eSgc 738d73ae94eSgc if ((iapm) && (usb_ia->ia_dev_state != USB_DEV_DISCONNECTED)) { 739d73ae94eSgc 740d73ae94eSgc mutex_exit(&usb_ia->ia_mutex); 741d73ae94eSgc 742d73ae94eSgc (void) pm_busy_component(dip, 0); 743d73ae94eSgc if (iapm->uc_wakeup_enabled) { 744d73ae94eSgc 745d73ae94eSgc /* First bring the device to full power */ 746d73ae94eSgc (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 747d73ae94eSgc 748d73ae94eSgc rval = usb_handle_remote_wakeup(dip, 749d73ae94eSgc USB_REMOTE_WAKEUP_DISABLE); 750d73ae94eSgc 751d73ae94eSgc if (rval != DDI_SUCCESS) { 752d73ae94eSgc USB_DPRINTF_L2(DPRINT_MASK_EVENTS, 753d73ae94eSgc usb_ia->ia_log_handle, 754d73ae94eSgc "usb_cleanup: disable remote " 755d73ae94eSgc "wakeup failed, rval=%d", rval); 756d73ae94eSgc } 757d73ae94eSgc } 758d73ae94eSgc 759d73ae94eSgc (void) pm_lower_power(usb_ia->ia_dip, 0, USB_DEV_OS_PWR_OFF); 760d73ae94eSgc (void) pm_idle_component(dip, 0); 761d73ae94eSgc } else { 762d73ae94eSgc mutex_exit(&usb_ia->ia_mutex); 763d73ae94eSgc } 764d73ae94eSgc 765d73ae94eSgc if (iapm) { 766d73ae94eSgc kmem_free(iapm, sizeof (usb_common_power_t)); 767d73ae94eSgc } 768d73ae94eSgc 769d73ae94eSgc /* free children list */ 770d73ae94eSgc if (usb_ia->ia_children_dips) { 771d73ae94eSgc kmem_free(usb_ia->ia_children_dips, 772112116d8Sfb usb_ia->ia_cd_list_length); 773d73ae94eSgc } 774d73ae94eSgc 775d73ae94eSgc if (usb_ia->ia_child_events) { 776d73ae94eSgc kmem_free(usb_ia->ia_child_events, sizeof (uint8_t) * 777112116d8Sfb usb_ia->ia_n_ifs); 778d73ae94eSgc } 779d73ae94eSgc 780d73ae94eSgc if (usb_ia->ia_init_state & USB_IA_MINOR_NODE_CREATED) { 781d73ae94eSgc ddi_remove_minor_node(dip, NULL); 782d73ae94eSgc } 783d73ae94eSgc 784d73ae94eSgc mutex_destroy(&usb_ia->ia_mutex); 785d73ae94eSgc 786d73ae94eSgc done: 787d73ae94eSgc usb_client_detach(dip, usb_ia->ia_dev_data); 788d73ae94eSgc 789d73ae94eSgc usb_free_log_hdl(usb_ia->ia_log_handle); 790d73ae94eSgc ddi_soft_state_free(usb_ia_statep, ddi_get_instance(dip)); 791d73ae94eSgc 792d73ae94eSgc ddi_prop_remove_all(dip); 793d73ae94eSgc 794d73ae94eSgc return (DDI_SUCCESS); 795d73ae94eSgc } 796d73ae94eSgc 797d73ae94eSgc /* 798d73ae94eSgc * usb_ia_create_children: 799d73ae94eSgc */ 800d73ae94eSgc static void 801d73ae94eSgc usb_ia_create_children(usb_ia_t *usb_ia) 802d73ae94eSgc { 803d73ae94eSgc usba_device_t *usba_device; 804d73ae94eSgc uint_t n_ifs, first_if; 805d73ae94eSgc uint_t i; 806d73ae94eSgc dev_info_t *cdip; 807d73ae94eSgc 808d73ae94eSgc usba_device = usba_get_usba_device(usb_ia->ia_dip); 809d73ae94eSgc 810d73ae94eSgc USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_ia->ia_log_handle, 811d73ae94eSgc "usb_ia_attach_child_drivers: port = %d, address = %d", 812d73ae94eSgc usba_device->usb_port, usba_device->usb_addr); 813d73ae94eSgc 814d73ae94eSgc n_ifs = usb_ia->ia_n_ifs; 815d73ae94eSgc first_if = usb_ia->ia_first_if; 816d73ae94eSgc 817d73ae94eSgc /* 818d73ae94eSgc * create all children if not already present 819d73ae94eSgc */ 820d73ae94eSgc for (i = 0; i < n_ifs; i++) { 821d73ae94eSgc if (usb_ia->ia_children_dips[i] != NULL) { 822d73ae94eSgc 823d73ae94eSgc continue; 824d73ae94eSgc } 825d73ae94eSgc 826d73ae94eSgc mutex_exit(&usb_ia->ia_mutex); 827d73ae94eSgc cdip = usba_ready_interface_node(usb_ia->ia_dip, first_if + i); 828d73ae94eSgc mutex_enter(&usb_ia->ia_mutex); 829d73ae94eSgc 830d73ae94eSgc if (cdip != NULL) { 831d73ae94eSgc (void) usba_bind_driver(cdip); 832d73ae94eSgc usb_ia->ia_children_dips[i] = cdip; 833d73ae94eSgc } 834d73ae94eSgc } 835d73ae94eSgc 836d73ae94eSgc } 837d73ae94eSgc 838d73ae94eSgc 839d73ae94eSgc /* 840d73ae94eSgc * event support 841d73ae94eSgc */ 842d73ae94eSgc static int 843d73ae94eSgc usb_ia_busop_get_eventcookie(dev_info_t *dip, 844d73ae94eSgc dev_info_t *rdip, char *eventname, ddi_eventcookie_t *cookie) 845d73ae94eSgc { 846d73ae94eSgc usb_ia_t *usb_ia = usb_ia_obtain_state(dip); 847d73ae94eSgc 848d73ae94eSgc USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle, 849d73ae94eSgc "usb_ia_busop_get_eventcookie: dip=0x%p, rdip=0x%p, " 850d73ae94eSgc "event=%s", (void *)dip, (void *)rdip, eventname); 851d73ae94eSgc USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle, 852d73ae94eSgc "(dip=%s%d rdip=%s%d)", 853d73ae94eSgc ddi_driver_name(dip), ddi_get_instance(dip), 854d73ae94eSgc ddi_driver_name(rdip), ddi_get_instance(rdip)); 855d73ae94eSgc 856d73ae94eSgc /* return event cookie, iblock cookie, and level */ 857d73ae94eSgc return (ndi_event_retrieve_cookie(usb_ia->ia_ndi_event_hdl, 858d73ae94eSgc rdip, eventname, cookie, NDI_EVENT_NOPASS)); 859d73ae94eSgc } 860d73ae94eSgc 861d73ae94eSgc 862d73ae94eSgc static int 863d73ae94eSgc usb_ia_busop_add_eventcall(dev_info_t *dip, 864d73ae94eSgc dev_info_t *rdip, 865d73ae94eSgc ddi_eventcookie_t cookie, 866d73ae94eSgc void (*callback)(dev_info_t *dip, 867d73ae94eSgc ddi_eventcookie_t cookie, void *arg, 868d73ae94eSgc void *bus_impldata), 869d73ae94eSgc void *arg, ddi_callback_id_t *cb_id) 870d73ae94eSgc { 871d73ae94eSgc int ifno; 872d73ae94eSgc usb_ia_t *usb_ia = usb_ia_obtain_state(dip); 873d73ae94eSgc 874d73ae94eSgc mutex_enter(&usb_ia->ia_mutex); 875d73ae94eSgc ifno = usba_get_ifno(rdip)- usb_ia->ia_first_if; 876d73ae94eSgc mutex_exit(&usb_ia->ia_mutex); 877d73ae94eSgc 878d73ae94eSgc if (ifno < 0) { 879d73ae94eSgc ifno = 0; 880d73ae94eSgc } 881d73ae94eSgc 882d73ae94eSgc USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle, 883d73ae94eSgc "usb_ia_busop_add_eventcall: dip=0x%p, rdip=0x%p " 884d73ae94eSgc "cookie=0x%p, cb=0x%p, arg=0x%p", 885d73ae94eSgc (void *)dip, (void *)rdip, (void *)cookie, (void *)callback, arg); 886d73ae94eSgc USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle, 887d73ae94eSgc "(dip=%s%d rdip=%s%d event=%s)", 888d73ae94eSgc ddi_driver_name(dip), ddi_get_instance(dip), 889d73ae94eSgc ddi_driver_name(rdip), ddi_get_instance(rdip), 890d73ae94eSgc ndi_event_cookie_to_name(usb_ia->ia_ndi_event_hdl, cookie)); 891d73ae94eSgc 892d73ae94eSgc /* Set flag on children registering events */ 893d73ae94eSgc switch (ndi_event_cookie_to_tag(usb_ia->ia_ndi_event_hdl, cookie)) { 894d73ae94eSgc case USBA_EVENT_TAG_HOT_REMOVAL: 895d73ae94eSgc mutex_enter(&usb_ia->ia_mutex); 896d73ae94eSgc usb_ia->ia_child_events[ifno] |= 897d73ae94eSgc USB_IA_CHILD_EVENT_DISCONNECT; 898d73ae94eSgc mutex_exit(&usb_ia->ia_mutex); 899d73ae94eSgc 900d73ae94eSgc break; 901d73ae94eSgc case USBA_EVENT_TAG_PRE_SUSPEND: 902d73ae94eSgc mutex_enter(&usb_ia->ia_mutex); 903d73ae94eSgc usb_ia->ia_child_events[ifno] |= 904d73ae94eSgc USB_IA_CHILD_EVENT_PRESUSPEND; 905d73ae94eSgc mutex_exit(&usb_ia->ia_mutex); 906d73ae94eSgc 907d73ae94eSgc break; 908d73ae94eSgc default: 909d73ae94eSgc 910d73ae94eSgc break; 911d73ae94eSgc } 912d73ae94eSgc /* add callback (perform registration) */ 913d73ae94eSgc return (ndi_event_add_callback(usb_ia->ia_ndi_event_hdl, 914d73ae94eSgc rdip, cookie, callback, arg, NDI_SLEEP, cb_id)); 915d73ae94eSgc } 916d73ae94eSgc 917d73ae94eSgc 918d73ae94eSgc static int 919d73ae94eSgc usb_ia_busop_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id) 920d73ae94eSgc { 921d73ae94eSgc usb_ia_t *usb_ia = usb_ia_obtain_state(dip); 922d73ae94eSgc ndi_event_callbacks_t *cb = (ndi_event_callbacks_t *)cb_id; 923d73ae94eSgc 924d73ae94eSgc ASSERT(cb); 925d73ae94eSgc 926d73ae94eSgc USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle, 927d73ae94eSgc "usb_ia_busop_remove_eventcall: dip=0x%p, rdip=0x%p " 928112116d8Sfb "cookie=0x%p", (void *)dip, (void *)cb->ndi_evtcb_dip, 929112116d8Sfb (void *)cb->ndi_evtcb_cookie); 930d73ae94eSgc USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle, 931d73ae94eSgc "(dip=%s%d rdip=%s%d event=%s)", 932d73ae94eSgc ddi_driver_name(dip), ddi_get_instance(dip), 933d73ae94eSgc ddi_driver_name(cb->ndi_evtcb_dip), 934d73ae94eSgc ddi_get_instance(cb->ndi_evtcb_dip), 935d73ae94eSgc ndi_event_cookie_to_name(usb_ia->ia_ndi_event_hdl, 936d73ae94eSgc cb->ndi_evtcb_cookie)); 937d73ae94eSgc 938d73ae94eSgc /* remove event registration from our event set */ 939d73ae94eSgc return (ndi_event_remove_callback(usb_ia->ia_ndi_event_hdl, cb_id)); 940d73ae94eSgc } 941d73ae94eSgc 942d73ae94eSgc 943d73ae94eSgc static int 944d73ae94eSgc usb_ia_busop_post_event(dev_info_t *dip, 945d73ae94eSgc dev_info_t *rdip, 946d73ae94eSgc ddi_eventcookie_t cookie, 947d73ae94eSgc void *bus_impldata) 948d73ae94eSgc { 949d73ae94eSgc usb_ia_t *usb_ia = usb_ia_obtain_state(dip); 950d73ae94eSgc 951d73ae94eSgc USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle, 952d73ae94eSgc "usb_ia_busop_post_event: dip=0x%p, rdip=0x%p " 953d73ae94eSgc "cookie=0x%p, impl=0x%p", 954d73ae94eSgc (void *)dip, (void *)rdip, (void *)cookie, bus_impldata); 955d73ae94eSgc USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle, 956d73ae94eSgc "(dip=%s%d rdip=%s%d event=%s)", 957d73ae94eSgc ddi_driver_name(dip), ddi_get_instance(dip), 958d73ae94eSgc ddi_driver_name(rdip), ddi_get_instance(rdip), 959d73ae94eSgc ndi_event_cookie_to_name(usb_ia->ia_ndi_event_hdl, cookie)); 960d73ae94eSgc 961d73ae94eSgc /* post event to all children registered for this event */ 962d73ae94eSgc return (ndi_event_run_callbacks(usb_ia->ia_ndi_event_hdl, rdip, 963d73ae94eSgc cookie, bus_impldata)); 964d73ae94e