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