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