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 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * usb interface association driver 30 * 31 * this driver attempts to the interface association node and 32 * creates/manages child nodes for the included interfaces. 33 */ 34 35 #if defined(lint) && !defined(DEBUG) 36 #define DEBUG 1 37 #endif 38 #include <sys/usb/usba/usbai_version.h> 39 #include <sys/usb/usba.h> 40 #include <sys/usb/usba/usba_types.h> 41 #include <sys/usb/usba/usba_impl.h> 42 #include <sys/usb/usb_ia/usb_iavar.h> 43 44 /* Debugging support */ 45 uint_t usb_ia_errlevel = USB_LOG_L4; 46 uint_t usb_ia_errmask = (uint_t)DPRINT_MASK_ALL; 47 uint_t usb_ia_instance_debug = (uint_t)-1; 48 uint_t usb_ia_bus_config_debug = 0; 49 50 _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ia_errlevel)) 51 _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ia_errmask)) 52 _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ia_instance_debug)) 53 54 _NOTE(SCHEME_PROTECTS_DATA("unique", msgb)) 55 _NOTE(SCHEME_PROTECTS_DATA("unique", dev_info)) 56 _NOTE(SCHEME_PROTECTS_DATA("unique", usb_pipe_policy)) 57 58 static struct cb_ops usb_ia_cb_ops = { 59 nodev, /* open */ 60 nodev, /* close */ 61 nodev, /* strategy */ 62 nodev, /* print */ 63 nodev, /* dump */ 64 nodev, /* read */ 65 nodev, /* write */ 66 nodev, /* ioctl */ 67 nodev, /* devmap */ 68 nodev, /* mmap */ 69 nodev, /* segmap */ 70 nochpoll, /* poll */ 71 ddi_prop_op, /* prop_op */ 72 NULL, /* aread */ 73 D_MP 74 }; 75 76 static int usb_ia_busop_get_eventcookie(dev_info_t *dip, 77 dev_info_t *rdip, 78 char *eventname, 79 ddi_eventcookie_t *cookie); 80 static int usb_ia_busop_add_eventcall(dev_info_t *dip, 81 dev_info_t *rdip, 82 ddi_eventcookie_t cookie, 83 void (*callback)(dev_info_t *dip, 84 ddi_eventcookie_t cookie, void *arg, 85 void *bus_impldata), 86 void *arg, ddi_callback_id_t *cb_id); 87 static int usb_ia_busop_remove_eventcall(dev_info_t *dip, 88 ddi_callback_id_t cb_id); 89 static int usb_ia_busop_post_event(dev_info_t *dip, 90 dev_info_t *rdip, 91 ddi_eventcookie_t cookie, 92 void *bus_impldata); 93 static int usb_ia_bus_config(dev_info_t *dip, 94 uint_t flag, 95 ddi_bus_config_op_t op, 96 void *arg, 97 dev_info_t **child); 98 static int usb_ia_bus_unconfig(dev_info_t *dip, 99 uint_t flag, 100 ddi_bus_config_op_t op, 101 void *arg); 102 103 /* 104 * autoconfiguration data and routines. 105 */ 106 static int usb_ia_info(dev_info_t *, ddi_info_cmd_t, 107 void *, void **); 108 static int usb_ia_attach(dev_info_t *, ddi_attach_cmd_t); 109 static int usb_ia_detach(dev_info_t *, ddi_detach_cmd_t); 110 111 /* other routines */ 112 static void usb_ia_create_pm_components(dev_info_t *, usb_ia_t *); 113 static int usb_ia_bus_ctl(dev_info_t *, dev_info_t *, 114 ddi_ctl_enum_t, void *, void *); 115 static int usb_ia_power(dev_info_t *, int, int); 116 static int usb_ia_restore_device_state(dev_info_t *, usb_ia_t *); 117 static usb_ia_t *usb_ia_obtain_state(dev_info_t *); 118 static void usb_ia_event_cb(dev_info_t *, ddi_eventcookie_t, void *, void *); 119 120 /* prototypes */ 121 static void usb_ia_create_children(usb_ia_t *); 122 static int usb_ia_cleanup(usb_ia_t *); 123 124 /* 125 * Busops vector 126 */ 127 static struct bus_ops usb_ia_busops = { 128 BUSO_REV, 129 nullbusmap, /* bus_map */ 130 NULL, /* bus_get_intrspec */ 131 NULL, /* bus_add_intrspec */ 132 NULL, /* bus_remove_intrspec */ 133 NULL, /* XXXX bus_map_fault */ 134 ddi_dma_map, /* bus_dma_map */ 135 ddi_dma_allochdl, 136 ddi_dma_freehdl, 137 ddi_dma_bindhdl, 138 ddi_dma_unbindhdl, 139 ddi_dma_flush, 140 ddi_dma_win, 141 ddi_dma_mctl, /* bus_dma_ctl */ 142 usb_ia_bus_ctl, /* bus_ctl */ 143 ddi_bus_prop_op, /* bus_prop_op */ 144 usb_ia_busop_get_eventcookie, 145 usb_ia_busop_add_eventcall, 146 usb_ia_busop_remove_eventcall, 147 usb_ia_busop_post_event, /* bus_post_event */ 148 NULL, /* bus_intr_ctl */ 149 usb_ia_bus_config, /* bus_config */ 150 usb_ia_bus_unconfig, /* bus_unconfig */ 151 NULL, /* bus_fm_init */ 152 NULL, /* bus_fm_fini */ 153 NULL, /* bus_fm_access_enter */ 154 NULL, /* bus_fm_access_exit */ 155 NULL /* bus_power */ 156 }; 157 158 159 static struct dev_ops usb_ia_ops = { 160 DEVO_REV, /* devo_rev, */ 161 0, /* refcnt */ 162 usb_ia_info, /* info */ 163 nulldev, /* identify */ 164 nulldev, /* probe */ 165 usb_ia_attach, /* attach */ 166 usb_ia_detach, /* detach */ 167 nodev, /* reset */ 168 &usb_ia_cb_ops, /* driver operations */ 169 &usb_ia_busops, /* bus operations */ 170 usb_ia_power /* power */ 171 }; 172 173 static struct modldrv modldrv = { 174 &mod_driverops, /* Type of module. This one is a driver */ 175 "USB Interface Association Driver %I%", /* 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 dip, 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", usb_ia, level); 485 486 mutex_enter(&usb_ia->ia_mutex); 487 pm = usb_ia->ia_pm; 488 489 /* check if we are transitioning to a legal power level */ 490 if (USB_DEV_PWRSTATE_OK(pm->uc_pwr_states, level)) { 491 USB_DPRINTF_L2(DPRINT_MASK_PM, usb_ia->ia_log_handle, 492 "usb_ia_power: illegal power level = %d " 493 "uc_pwr_states = %x", level, pm->uc_pwr_states); 494 495 mutex_exit(&usb_ia->ia_mutex); 496 497 return (rval); 498 } 499 500 rval = usba_common_power(dip, pm, &(usb_ia->ia_dev_state), level); 501 502 mutex_exit(&usb_ia->ia_mutex); 503 504 return (rval); 505 } 506 507 /* 508 * attach/resume entry point 509 */ 510 static int 511 usb_ia_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 512 { 513 int instance = ddi_get_instance(dip); 514 usb_ia_t *usb_ia = NULL; 515 uint_t n_ifs; 516 size_t size; 517 518 switch (cmd) { 519 case DDI_ATTACH: 520 521 break; 522 case DDI_RESUME: 523 usb_ia = ddi_get_soft_state(usb_ia_statep, instance); 524 (void) usb_ia_restore_device_state(dip, usb_ia); 525 526 return (DDI_SUCCESS); 527 default: 528 529 return (DDI_FAILURE); 530 } 531 532 /* 533 * Attach: 534 * 535 * Allocate soft state and initialize 536 */ 537 if (ddi_soft_state_zalloc(usb_ia_statep, instance) != DDI_SUCCESS) { 538 goto fail; 539 } 540 541 usb_ia = ddi_get_soft_state(usb_ia_statep, instance); 542 if (usb_ia == NULL) { 543 544 goto fail; 545 } 546 547 /* allocate handle for logging of messages */ 548 usb_ia->ia_log_handle = usb_alloc_log_hdl(dip, "ia", 549 &usb_ia_errlevel, 550 &usb_ia_errmask, &usb_ia_instance_debug, 551 0); 552 553 usb_ia->ia_dip = dip; 554 usb_ia->ia_instance = instance; 555 usb_ia->ia_first_if = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 556 DDI_PROP_DONTPASS, "interface", -1); 557 usb_ia->ia_n_ifs = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 558 DDI_PROP_DONTPASS, "interface-count", -1); 559 560 if (usb_ia->ia_first_if < 0 || usb_ia->ia_n_ifs < 0) { 561 USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle, 562 "interface-association property failed"); 563 564 goto fail; 565 } 566 567 /* attach client driver to USBA */ 568 if (usb_client_attach(dip, USBDRV_VERSION, 0) != USB_SUCCESS) { 569 USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle, 570 "usb_client_attach failed"); 571 goto fail; 572 } 573 if (usb_get_dev_data(dip, &usb_ia->ia_dev_data, USB_PARSE_LVL_NONE, 574 0) != USB_SUCCESS) { 575 USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle, 576 "usb_get_dev_data failed"); 577 goto fail; 578 } 579 580 mutex_init(&usb_ia->ia_mutex, NULL, MUTEX_DRIVER, 581 usb_ia->ia_dev_data->dev_iblock_cookie); 582 583 usb_free_dev_data(dip, usb_ia->ia_dev_data); 584 usb_ia->ia_dev_data = NULL; 585 586 usb_ia->ia_init_state |= USB_IA_LOCK_INIT; 587 588 if (ddi_create_minor_node(dip, "usb_ia", S_IFCHR, instance, 589 DDI_NT_NEXUS, 0) != DDI_SUCCESS) { 590 USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle, 591 "cannot create devctl minor node"); 592 goto fail; 593 } 594 595 usb_ia->ia_init_state |= USB_IA_MINOR_NODE_CREATED; 596 597 /* 598 * allocate array for keeping track of child dips 599 */ 600 n_ifs = usb_ia->ia_n_ifs; 601 usb_ia->ia_cd_list_length = size = (sizeof (dev_info_t *)) * n_ifs; 602 603 usb_ia->ia_children_dips = kmem_zalloc(size, KM_SLEEP); 604 usb_ia->ia_child_events = kmem_zalloc(sizeof (uint8_t) * n_ifs, 605 KM_SLEEP); 606 /* 607 * Event handling: definition and registration 608 * get event handle for events that we have defined 609 */ 610 (void) ndi_event_alloc_hdl(dip, 0, &usb_ia->ia_ndi_event_hdl, 611 NDI_SLEEP); 612 613 /* bind event set to the handle */ 614 if (ndi_event_bind_set(usb_ia->ia_ndi_event_hdl, &usb_ia_ndi_events, 615 NDI_SLEEP)) { 616 USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle, 617 "usb_ia_attach: binding event set failed"); 618 619 goto fail; 620 } 621 622 usb_ia->ia_dev_state = USB_DEV_ONLINE; 623 624 /* 625 * now create components to power manage this device 626 * before attaching children 627 */ 628 usb_ia_create_pm_components(dip, usb_ia); 629 630 /* event registration for events from our parent */ 631 usba_common_register_events(dip, n_ifs, usb_ia_event_cb); 632 633 usb_ia->ia_init_state |= USB_IA_EVENTS_REGISTERED; 634 635 ddi_report_dev(dip); 636 637 return (DDI_SUCCESS); 638 639 fail: 640 USB_DPRINTF_L2(DPRINT_MASK_ATTA, NULL, "usb_ia%d cannot attach", 641 instance); 642 643 if (usb_ia) { 644 (void) usb_ia_cleanup(usb_ia); 645 } 646 647 return (DDI_FAILURE); 648 } 649 650 651 /* detach or suspend this instance */ 652 static int 653 usb_ia_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 654 { 655 usb_ia_t *usb_ia = usb_ia_obtain_state(dip); 656 657 USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_ia->ia_log_handle, 658 "usb_ia_detach: cmd = 0x%x", cmd); 659 660 switch (cmd) { 661 case DDI_DETACH: 662 663 return (usb_ia_cleanup(usb_ia)); 664 case DDI_SUSPEND: 665 /* nothing to do */ 666 mutex_enter(&usb_ia->ia_mutex); 667 usb_ia->ia_dev_state = USB_DEV_SUSPENDED; 668 mutex_exit(&usb_ia->ia_mutex); 669 670 return (DDI_SUCCESS); 671 default: 672 673 return (DDI_FAILURE); 674 } 675 676 _NOTE(NOT_REACHED) 677 /* NOTREACHED */ 678 } 679 680 681 /* 682 * usb_ia_cleanup: 683 * cleanup usb_ia and deallocate. this function is called for 684 * handling attach failures and detaching including dynamic 685 * reconfiguration 686 */ 687 /*ARGSUSED*/ 688 static int 689 usb_ia_cleanup(usb_ia_t *usb_ia) 690 { 691 usb_common_power_t *iapm; 692 int rval; 693 dev_info_t *dip = usb_ia->ia_dip; 694 695 USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_ia->ia_log_handle, 696 "usb_ia_cleanup:"); 697 698 if ((usb_ia->ia_init_state & USB_IA_LOCK_INIT) == 0) { 699 700 goto done; 701 } 702 703 /* 704 * deallocate events, if events are still registered 705 * (ie. children still attached) then we have to fail the detach 706 */ 707 if (usb_ia->ia_ndi_event_hdl && 708 (ndi_event_free_hdl(usb_ia->ia_ndi_event_hdl) != NDI_SUCCESS)) { 709 710 USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle, 711 "usb_ia_cleanup: ndi_event_free_hdl failed"); 712 713 return (DDI_FAILURE); 714 } 715 716 /* 717 * Disable the event callbacks, after this point, event 718 * callbacks will never get called. Note we shouldn't hold 719 * mutex while unregistering events because there may be a 720 * competing event callback thread. Event callbacks are done 721 * with ndi mutex held and this can cause a potential deadlock. 722 * Note that cleanup can't fail after deregistration of events. 723 */ 724 if (usb_ia->ia_init_state & USB_IA_EVENTS_REGISTERED) { 725 726 usba_common_unregister_events(usb_ia->ia_dip, usb_ia->ia_n_ifs); 727 } 728 729 iapm = usb_ia->ia_pm; 730 731 mutex_enter(&usb_ia->ia_mutex); 732 733 if ((iapm) && (usb_ia->ia_dev_state != USB_DEV_DISCONNECTED)) { 734 735 mutex_exit(&usb_ia->ia_mutex); 736 737 (void) pm_busy_component(dip, 0); 738 if (iapm->uc_wakeup_enabled) { 739 740 /* First bring the device to full power */ 741 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 742 743 rval = usb_handle_remote_wakeup(dip, 744 USB_REMOTE_WAKEUP_DISABLE); 745 746 if (rval != DDI_SUCCESS) { 747 USB_DPRINTF_L2(DPRINT_MASK_EVENTS, 748 usb_ia->ia_log_handle, 749 "usb_cleanup: disable remote " 750 "wakeup failed, rval=%d", rval); 751 } 752 } 753 754 (void) pm_lower_power(usb_ia->ia_dip, 0, USB_DEV_OS_PWR_OFF); 755 (void) pm_idle_component(dip, 0); 756 } else { 757 mutex_exit(&usb_ia->ia_mutex); 758 } 759 760 if (iapm) { 761 kmem_free(iapm, sizeof (usb_common_power_t)); 762 } 763 764 /* free children list */ 765 if (usb_ia->ia_children_dips) { 766 kmem_free(usb_ia->ia_children_dips, 767 usb_ia->ia_cd_list_length); 768 } 769 770 if (usb_ia->ia_child_events) { 771 kmem_free(usb_ia->ia_child_events, sizeof (uint8_t) * 772 usb_ia->ia_n_ifs); 773 } 774 775 if (usb_ia->ia_init_state & USB_IA_MINOR_NODE_CREATED) { 776 ddi_remove_minor_node(dip, NULL); 777 } 778 779 mutex_destroy(&usb_ia->ia_mutex); 780 781 done: 782 usb_client_detach(dip, usb_ia->ia_dev_data); 783 784 usb_free_log_hdl(usb_ia->ia_log_handle); 785 ddi_soft_state_free(usb_ia_statep, ddi_get_instance(dip)); 786 787 ddi_prop_remove_all(dip); 788 789 return (DDI_SUCCESS); 790 } 791 792 /* 793 * usb_ia_create_children: 794 */ 795 static void 796 usb_ia_create_children(usb_ia_t *usb_ia) 797 { 798 usba_device_t *usba_device; 799 uint_t n_ifs, first_if; 800 uint_t i; 801 dev_info_t *cdip; 802 803 usba_device = usba_get_usba_device(usb_ia->ia_dip); 804 805 USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_ia->ia_log_handle, 806 "usb_ia_attach_child_drivers: port = %d, address = %d", 807 usba_device->usb_port, usba_device->usb_addr); 808 809 n_ifs = usb_ia->ia_n_ifs; 810 first_if = usb_ia->ia_first_if; 811 812 /* 813 * create all children if not already present 814 */ 815 for (i = 0; i < n_ifs; i++) { 816 if (usb_ia->ia_children_dips[i] != NULL) { 817 818 continue; 819 } 820 821 mutex_exit(&usb_ia->ia_mutex); 822 cdip = usba_ready_interface_node(usb_ia->ia_dip, first_if + i); 823 mutex_enter(&usb_ia->ia_mutex); 824 825 if (cdip != NULL) { 826 (void) usba_bind_driver(cdip); 827 usb_ia->ia_children_dips[i] = cdip; 828 } 829 } 830 831 } 832 833 834 /* 835 * event support 836 */ 837 static int 838 usb_ia_busop_get_eventcookie(dev_info_t *dip, 839 dev_info_t *rdip, char *eventname, ddi_eventcookie_t *cookie) 840 { 841 usb_ia_t *usb_ia = usb_ia_obtain_state(dip); 842 843 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle, 844 "usb_ia_busop_get_eventcookie: dip=0x%p, rdip=0x%p, " 845 "event=%s", (void *)dip, (void *)rdip, eventname); 846 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle, 847 "(dip=%s%d rdip=%s%d)", 848 ddi_driver_name(dip), ddi_get_instance(dip), 849 ddi_driver_name(rdip), ddi_get_instance(rdip)); 850 851 /* return event cookie, iblock cookie, and level */ 852 return (ndi_event_retrieve_cookie(usb_ia->ia_ndi_event_hdl, 853 rdip, eventname, cookie, NDI_EVENT_NOPASS)); 854 } 855 856 857 static int 858 usb_ia_busop_add_eventcall(dev_info_t *dip, 859 dev_info_t *rdip, 860 ddi_eventcookie_t cookie, 861 void (*callback)(dev_info_t *dip, 862 ddi_eventcookie_t cookie, void *arg, 863 void *bus_impldata), 864 void *arg, ddi_callback_id_t *cb_id) 865 { 866 int ifno; 867 usb_ia_t *usb_ia = usb_ia_obtain_state(dip); 868 869 mutex_enter(&usb_ia->ia_mutex); 870 ifno = usba_get_ifno(rdip)- usb_ia->ia_first_if; 871 mutex_exit(&usb_ia->ia_mutex); 872 873 if (ifno < 0) { 874 ifno = 0; 875 } 876 877 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle, 878 "usb_ia_busop_add_eventcall: dip=0x%p, rdip=0x%p " 879 "cookie=0x%p, cb=0x%p, arg=0x%p", 880 (void *)dip, (void *)rdip, (void *)cookie, (void *)callback, arg); 881 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle, 882 "(dip=%s%d rdip=%s%d event=%s)", 883 ddi_driver_name(dip), ddi_get_instance(dip), 884 ddi_driver_name(rdip), ddi_get_instance(rdip), 885 ndi_event_cookie_to_name(usb_ia->ia_ndi_event_hdl, cookie)); 886 887 /* Set flag on children registering events */ 888 switch (ndi_event_cookie_to_tag(usb_ia->ia_ndi_event_hdl, cookie)) { 889 case USBA_EVENT_TAG_HOT_REMOVAL: 890 mutex_enter(&usb_ia->ia_mutex); 891 usb_ia->ia_child_events[ifno] |= 892 USB_IA_CHILD_EVENT_DISCONNECT; 893 mutex_exit(&usb_ia->ia_mutex); 894 895 break; 896 case USBA_EVENT_TAG_PRE_SUSPEND: 897 mutex_enter(&usb_ia->ia_mutex); 898 usb_ia->ia_child_events[ifno] |= 899 USB_IA_CHILD_EVENT_PRESUSPEND; 900 mutex_exit(&usb_ia->ia_mutex); 901 902 break; 903 default: 904 905 break; 906 } 907 /* add callback (perform registration) */ 908 return (ndi_event_add_callback(usb_ia->ia_ndi_event_hdl, 909 rdip, cookie, callback, arg, NDI_SLEEP, cb_id)); 910 } 911 912 913 static int 914 usb_ia_busop_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id) 915 { 916 usb_ia_t *usb_ia = usb_ia_obtain_state(dip); 917 ndi_event_callbacks_t *cb = (ndi_event_callbacks_t *)cb_id; 918 919 ASSERT(cb); 920 921 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle, 922 "usb_ia_busop_remove_eventcall: dip=0x%p, rdip=0x%p " 923 "cookie=0x%p", (void *)dip, cb->ndi_evtcb_dip, 924 cb->ndi_evtcb_cookie); 925 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle, 926 "(dip=%s%d rdip=%s%d event=%s)", 927 ddi_driver_name(dip), ddi_get_instance(dip), 928 ddi_driver_name(cb->ndi_evtcb_dip), 929 ddi_get_instance(cb->ndi_evtcb_dip), 930 ndi_event_cookie_to_name(usb_ia->ia_ndi_event_hdl, 931 cb->ndi_evtcb_cookie)); 932 933 /* remove event registration from our event set */ 934 return (ndi_event_remove_callback(usb_ia->ia_ndi_event_hdl, cb_id)); 935 } 936 937 938 static int 939 usb_ia_busop_post_event(dev_info_t *dip, 940 dev_info_t *rdip, 941 ddi_eventcookie_t cookie, 942 void *bus_impldata) 943 { 944 usb_ia_t *usb_ia = usb_ia_obtain_state(dip); 945 946 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle, 947 "usb_ia_busop_post_event: dip=0x%p, rdip=0x%p " 948 "cookie=0x%p, impl=0x%p", 949 (void *)dip, (void *)rdip, (void *)cookie, bus_impldata); 950 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle, 951 "(dip=%s%d rdip=%s%d event=%s)", 952 ddi_driver_name(dip), ddi_get_instance(dip), 953 ddi_driver_name(rdip), ddi_get_instance(rdip), 954 ndi_event_cookie_to_name(usb_ia->ia_ndi_event_hdl, cookie)); 955 956 /* post event to all children registered for this event */ 957 return (ndi_event_run_callbacks(usb_ia->ia_ndi_event_hdl, rdip, 958 cookie, bus_impldata)); 959 } 960 961 962 /* 963 * usb_ia_restore_device_state 964 * set the original configuration of the device 965 */ 966 static int 967 usb_ia_restore_device_state(dev_info_t *dip, usb_ia_t *usb_ia) 968 { 969 usb_common_power_t *iapm; 970 971 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle, 972 "usb_ia_restore_device_state: usb_ia = %p", usb_ia); 973 974 mutex_enter(&usb_ia->ia_mutex); 975 iapm = usb_ia->ia_pm; 976 mutex_exit(&usb_ia->ia_mutex); 977 978 /* First bring the device to full power */ 979 (void) pm_busy_component(dip, 0); 980 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 981 982 if (usb_check_same_device(dip, usb_ia->ia_log_handle, USB_LOG_L0, 983 DPRINT_MASK_EVENTS, USB_CHK_VIDPID, NULL) != USB_SUCCESS) { 984 985 /* change the device state from suspended to disconnected */ 986 mutex_enter(&usb_ia->ia_mutex); 987 usb_ia->ia_dev_state = USB_DEV_DISCONNECTED; 988 mutex_exit(&usb_ia->ia_mutex); 989 (void) pm_idle_component(dip, 0); 990 991 return (USB_FAILURE); 992 } 993 994 /* 995 * if the device had remote wakeup earlier, 996 * enable it again 997 */ 998 if (iapm->uc_wakeup_enabled) { 999 (void) usb_handle_remote_wakeup(usb_ia->ia_dip, 1000 USB_REMOTE_WAKEUP_ENABLE); 1001 } 1002 1003 mutex_enter(&usb_ia->ia_mutex); 1004 usb_ia->ia_dev_state = USB_DEV_ONLINE; 1005 mutex_exit(&usb_ia->ia_mutex); 1006 1007 (void) pm_idle_component(dip, 0); 1008 1009 return (USB_SUCCESS); 1010 } 1011 1012 1013 /* 1014 * usb_ia_event_cb() 1015 * handle disconnect and connect events 1016 */ 1017 static void 1018 usb_ia_event_cb(dev_info_t *dip, ddi_eventcookie_t cookie, 1019 void *arg, void *bus_impldata) 1020 { 1021 int i, tag; 1022 usb_ia_t *usb_ia = usb_ia_obtain_state(dip); 1023 dev_info_t *child_dip; 1024 ddi_eventcookie_t rm_cookie, ins_cookie, suspend_cookie, resume_cookie; 1025 1026 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle, 1027 "usb_ia_event_cb: dip=0x%p, cookie=0x%p, " 1028 "arg=0x%p, impl=0x%p", 1029 (void *)dip, (void *)cookie, arg, bus_impldata); 1030 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle, 1031 "(dip=%s%d event=%s)", 1032 ddi_driver_name(dip), ddi_get_instance(dip), 1033 ndi_event_cookie_to_name(usb_ia->ia_ndi_event_hdl, cookie)); 1034 1035 tag = NDI_EVENT_TAG(cookie); 1036 rm_cookie = ndi_event_tag_to_cookie( 1037 usb_ia->ia_ndi_event_hdl, USBA_EVENT_TAG_HOT_REMOVAL); 1038 suspend_cookie = ndi_event_tag_to_cookie( 1039 usb_ia->ia_ndi_event_hdl, USBA_EVENT_TAG_PRE_SUSPEND); 1040 ins_cookie = ndi_event_tag_to_cookie( 1041 usb_ia->ia_ndi_event_hdl, USBA_EVENT_TAG_HOT_INSERTION); 1042 resume_cookie = ndi_event_tag_to_cookie( 1043 usb_ia->ia_ndi_event_hdl, USBA_EVENT_TAG_POST_RESUME); 1044 1045 mutex_enter(&usb_ia->ia_mutex); 1046 switch (tag) { 1047 case USBA_EVENT_TAG_HOT_REMOVAL: 1048 if (usb_ia->ia_dev_state == USB_DEV_DISCONNECTED) { 1049 USB_DPRINTF_L2(DPRINT_MASK_EVENTS, 1050 usb_ia->ia_log_handle, 1051 "usb_ia_event_cb: Device already disconnected"); 1052 } else { 1053 /* we are disconnected so set our state now */ 1054 usb_ia->ia_dev_state = USB_DEV_DISCONNECTED; 1055 for (i = 0; i < usb_ia->ia_n_ifs; i++) { 1056 usb_ia->ia_child_events[i] &= ~ 1057 USB_IA_CHILD_EVENT_DISCONNECT; 1058 } 1059 mutex_exit(&usb_ia->ia_mutex); 1060 1061 /* pass disconnect event to all the children */ 1062 (void) ndi_event_run_callbacks( 1063 usb_ia->ia_ndi_event_hdl, NULL, 1064 rm_cookie, bus_impldata); 1065 1066 mutex_enter(&usb_ia->ia_mutex); 1067 } 1068 break; 1069 case USBA_EVENT_TAG_PRE_SUSPEND: 1070 /* set our state *after* suspending children */ 1071 mutex_exit(&usb_ia->ia_mutex); 1072 1073 /* pass pre_suspend event to all the children */ 1074 (void) ndi_event_run_callbacks(usb_ia->ia_ndi_event_hdl, 1075 NULL, suspend_cookie, bus_impldata); 1076 1077 mutex_enter(&usb_ia->ia_mutex); 1078 for (i = 0; i < usb_ia->ia_n_ifs; i++) { 1079 usb_ia->ia_child_events[i] &= ~ 1080 USB_IA_CHILD_EVENT_PRESUSPEND; 1081 } 1082 break; 1083 case USBA_EVENT_TAG_HOT_INSERTION: 1084 mutex_exit(&usb_ia->ia_mutex); 1085 if (usb_ia_restore_device_state(dip, usb_ia) == USB_SUCCESS) { 1086 1087 /* 1088 * Check to see if this child has missed the disconnect 1089 * event before it registered for event cb 1090 */ 1091 mutex_enter(&usb_ia->ia_mutex); 1092 for (i = 0; i < usb_ia->ia_n_ifs; i++) { 1093 if (usb_ia->ia_child_events[i] & 1094 USB_IA_CHILD_EVENT_DISCONNECT) { 1095 usb_ia->ia_child_events[i] &= 1096 ~USB_IA_CHILD_EVENT_DISCONNECT; 1097 child_dip = 1098 usb_ia->ia_children_dips[i]; 1099 mutex_exit(&usb_ia->ia_mutex); 1100 1101 /* post the missed disconnect */ 1102 (void) ndi_event_do_callback( 1103 usb_ia->ia_ndi_event_hdl, 1104 child_dip, 1105 rm_cookie, 1106 bus_impldata); 1107 mutex_enter(&usb_ia->ia_mutex); 1108 } 1109 } 1110 mutex_exit(&usb_ia->ia_mutex); 1111 1112 /* pass reconnect event to all the children */ 1113 (void) ndi_event_run_callbacks( 1114 usb_ia->ia_ndi_event_hdl, NULL, 1115 ins_cookie, bus_impldata); 1116 1117 } 1118 mutex_enter(&usb_ia->ia_mutex); 1119 break; 1120 case USBA_EVENT_TAG_POST_RESUME: 1121 /* 1122 * Check to see if this child has missed the pre-suspend 1123 * event before it registered for event cb 1124 */ 1125 for (i = 0; i < usb_ia->ia_n_ifs; i++) { 1126 if (usb_ia->ia_child_events[i] & 1127 USB_IA_CHILD_EVENT_PRESUSPEND) { 1128 usb_ia->ia_child_events[i] &= 1129 ~USB_IA_CHILD_EVENT_PRESUSPEND; 1130 child_dip = usb_ia->ia_children_dips[i]; 1131 mutex_exit(&usb_ia->ia_mutex); 1132 1133 /* post the missed pre-suspend event */ 1134 (void) ndi_event_do_callback( 1135 usb_ia->ia_ndi_event_hdl, 1136 child_dip, suspend_cookie, 1137 bus_impldata); 1138 mutex_enter(&usb_ia->ia_mutex); 1139 } 1140 } 1141 mutex_exit(&usb_ia->ia_mutex); 1142 1143 /* pass post_resume event to all the children */ 1144 (void) ndi_event_run_callbacks(usb_ia->ia_ndi_event_hdl, 1145 NULL, resume_cookie, bus_impldata); 1146 1147 mutex_enter(&usb_ia->ia_mutex); 1148 break; 1149 } 1150 mutex_exit(&usb_ia->ia_mutex); 1151 1152 } 1153 1154 /* 1155 * create the pm components required for power management 1156 */ 1157 static void 1158 usb_ia_create_pm_components(dev_info_t *dip, usb_ia_t *usb_ia) 1159 { 1160 usb_common_power_t *iapm; 1161 uint_t pwr_states; 1162 1163 USB_DPRINTF_L4(DPRINT_MASK_PM, usb_ia->ia_log_handle, 1164 "usb_ia_create_pm_components: Begin"); 1165 1166 /* Allocate the PM state structure */ 1167 iapm = kmem_zalloc(sizeof (usb_common_power_t), KM_SLEEP); 1168 1169 mutex_enter(&usb_ia->ia_mutex); 1170 usb_ia->ia_pm = iapm; 1171 iapm->uc_usb_statep = usb_ia; 1172 iapm->uc_pm_capabilities = 0; /* XXXX should this be 0?? */ 1173 iapm->uc_current_power = USB_DEV_OS_FULL_PWR; 1174 mutex_exit(&usb_ia->ia_mutex); 1175 1176 /* 1177 * By not enabling parental notification, PM enforces 1178 * "strict parental dependency" meaning, usb_ia won't 1179 * power off until any of its children are in full power. 1180 */ 1181 1182 /* 1183 * there are 3 scenarios: 1184 * 1. a well behaved device should have remote wakeup 1185 * at interface and device level. If the interface 1186 * wakes up, usb_ia will wake up 1187 * 2. if the device doesn't have remote wake up and 1188 * the interface has, PM will still work, ie. 1189 * the interfaces wakes up and usb_ia wakes up 1190 * 3. if neither the interface nor device has remote 1191 * wakeup, the interface will wake up when it is opened 1192 * and goes to sleep after being closed for a while 1193 * In this case usb_ia should also go to sleep shortly 1194 * thereafter 1195 * In all scenarios it doesn't really matter whether 1196 * remote wakeup at the device level is enabled or not 1197 * but we do it anyways 1198 */ 1199 if (usb_handle_remote_wakeup(dip, USB_REMOTE_WAKEUP_ENABLE) == 1200 USB_SUCCESS) { 1201 USB_DPRINTF_L3(DPRINT_MASK_PM, usb_ia->ia_log_handle, 1202 "usb_ia_create_pm_components: " 1203 "Remote Wakeup Enabled"); 1204 iapm->uc_wakeup_enabled = 1; 1205 } 1206 1207 if (usb_create_pm_components(dip, &pwr_states) == 1208 USB_SUCCESS) { 1209 iapm->uc_pwr_states = (uint8_t)pwr_states; 1210 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 1211 } 1212 1213 USB_DPRINTF_L4(DPRINT_MASK_PM, usb_ia->ia_log_handle, 1214 "usb_ia_create_pm_components: End"); 1215 } 1216 1217 1218 /* 1219 * usb_ia_obtain_state: 1220 */ 1221 static usb_ia_t * 1222 usb_ia_obtain_state(dev_info_t *dip) 1223 { 1224 int instance = ddi_get_instance(dip); 1225 usb_ia_t *statep = ddi_get_soft_state(usb_ia_statep, instance); 1226 1227 ASSERT(statep != NULL); 1228 1229 return (statep); 1230 } 1231