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