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