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