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