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