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 2007 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->uc_current_power), 501 &(usb_ia->ia_dev_state), level); 502 503 mutex_exit(&usb_ia->ia_mutex); 504 505 return (rval); 506 } 507 508 /* 509 * attach/resume entry point 510 */ 511 static int 512 usb_ia_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 513 { 514 int instance = ddi_get_instance(dip); 515 usb_ia_t *usb_ia = NULL; 516 uint_t n_ifs; 517 size_t size; 518 519 switch (cmd) { 520 case DDI_ATTACH: 521 522 break; 523 case DDI_RESUME: 524 usb_ia = ddi_get_soft_state(usb_ia_statep, instance); 525 (void) usb_ia_restore_device_state(dip, usb_ia); 526 527 return (DDI_SUCCESS); 528 default: 529 530 return (DDI_FAILURE); 531 } 532 533 /* 534 * Attach: 535 * 536 * Allocate soft state and initialize 537 */ 538 if (ddi_soft_state_zalloc(usb_ia_statep, instance) != DDI_SUCCESS) { 539 goto fail; 540 } 541 542 usb_ia = ddi_get_soft_state(usb_ia_statep, instance); 543 if (usb_ia == NULL) { 544 545 goto fail; 546 } 547 548 /* allocate handle for logging of messages */ 549 usb_ia->ia_log_handle = usb_alloc_log_hdl(dip, "ia", 550 &usb_ia_errlevel, 551 &usb_ia_errmask, &usb_ia_instance_debug, 552 0); 553 554 usb_ia->ia_dip = dip; 555 usb_ia->ia_instance = instance; 556 usb_ia->ia_first_if = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 557 DDI_PROP_DONTPASS, "interface", -1); 558 usb_ia->ia_n_ifs = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 559 DDI_PROP_DONTPASS, "interface-count", -1); 560 561 if (usb_ia->ia_first_if < 0 || usb_ia->ia_n_ifs < 0) { 562 USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle, 563 "interface-association property failed"); 564 565 goto fail; 566 } 567 568 /* attach client driver to USBA */ 569 if (usb_client_attach(dip, USBDRV_VERSION, 0) != USB_SUCCESS) { 570 USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle, 571 "usb_client_attach failed"); 572 goto fail; 573 } 574 if (usb_get_dev_data(dip, &usb_ia->ia_dev_data, USB_PARSE_LVL_NONE, 575 0) != USB_SUCCESS) { 576 USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle, 577 "usb_get_dev_data failed"); 578 goto fail; 579 } 580 581 mutex_init(&usb_ia->ia_mutex, NULL, MUTEX_DRIVER, 582 usb_ia->ia_dev_data->dev_iblock_cookie); 583 584 usb_free_dev_data(dip, usb_ia->ia_dev_data); 585 usb_ia->ia_dev_data = NULL; 586 587 usb_ia->ia_init_state |= USB_IA_LOCK_INIT; 588 589 if (ddi_create_minor_node(dip, "usb_ia", S_IFCHR, instance, 590 DDI_NT_NEXUS, 0) != DDI_SUCCESS) { 591 USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle, 592 "cannot create devctl minor node"); 593 goto fail; 594 } 595 596 usb_ia->ia_init_state |= USB_IA_MINOR_NODE_CREATED; 597 598 /* 599 * allocate array for keeping track of child dips 600 */ 601 n_ifs = usb_ia->ia_n_ifs; 602 usb_ia->ia_cd_list_length = size = (sizeof (dev_info_t *)) * n_ifs; 603 604 usb_ia->ia_children_dips = kmem_zalloc(size, KM_SLEEP); 605 usb_ia->ia_child_events = kmem_zalloc(sizeof (uint8_t) * n_ifs, 606 KM_SLEEP); 607 /* 608 * Event handling: definition and registration 609 * get event handle for events that we have defined 610 */ 611 (void) ndi_event_alloc_hdl(dip, 0, &usb_ia->ia_ndi_event_hdl, 612 NDI_SLEEP); 613 614 /* bind event set to the handle */ 615 if (ndi_event_bind_set(usb_ia->ia_ndi_event_hdl, &usb_ia_ndi_events, 616 NDI_SLEEP)) { 617 USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle, 618 "usb_ia_attach: binding event set failed"); 619 620 goto fail; 621 } 622 623 usb_ia->ia_dev_state = USB_DEV_ONLINE; 624 625 /* 626 * now create components to power manage this device 627 * before attaching children 628 */ 629 usb_ia_create_pm_components(dip, usb_ia); 630 631 /* event registration for events from our parent */ 632 usba_common_register_events(dip, n_ifs, usb_ia_event_cb); 633 634 usb_ia->ia_init_state |= USB_IA_EVENTS_REGISTERED; 635 636 ddi_report_dev(dip); 637 638 return (DDI_SUCCESS); 639 640 fail: 641 USB_DPRINTF_L2(DPRINT_MASK_ATTA, NULL, "usb_ia%d cannot attach", 642 instance); 643 644 if (usb_ia) { 645 (void) usb_ia_cleanup(usb_ia); 646 } 647 648 return (DDI_FAILURE); 649 } 650 651 652 /* detach or suspend this instance */ 653 static int 654 usb_ia_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 655 { 656 usb_ia_t *usb_ia = usb_ia_obtain_state(dip); 657 658 USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_ia->ia_log_handle, 659 "usb_ia_detach: cmd = 0x%x", cmd); 660 661 switch (cmd) { 662 case DDI_DETACH: 663 664 return (usb_ia_cleanup(usb_ia)); 665 case DDI_SUSPEND: 666 /* nothing to do */ 667 mutex_enter(&usb_ia->ia_mutex); 668 usb_ia->ia_dev_state = USB_DEV_SUSPENDED; 669 mutex_exit(&usb_ia->ia_mutex); 670 671 return (DDI_SUCCESS); 672 default: 673 674 return (DDI_FAILURE); 675 } 676 677 _NOTE(NOT_REACHED) 678 /* NOTREACHED */ 679 } 680 681 682 /* 683 * usb_ia_cleanup: 684 * cleanup usb_ia and deallocate. this function is called for 685 * handling attach failures and detaching including dynamic 686 * reconfiguration 687 */ 688 /*ARGSUSED*/ 689 static int 690 usb_ia_cleanup(usb_ia_t *usb_ia) 691 { 692 usb_common_power_t *iapm; 693 int rval; 694 dev_info_t *dip = usb_ia->ia_dip; 695 696 USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_ia->ia_log_handle, 697 "usb_ia_cleanup:"); 698 699 if ((usb_ia->ia_init_state & USB_IA_LOCK_INIT) == 0) { 700 701 goto done; 702 } 703 704 /* 705 * deallocate events, if events are still registered 706 * (ie. children still attached) then we have to fail the detach 707 */ 708 if (usb_ia->ia_ndi_event_hdl && 709 (ndi_event_free_hdl(usb_ia->ia_ndi_event_hdl) != NDI_SUCCESS)) { 710 711 USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle, 712 "usb_ia_cleanup: ndi_event_free_hdl failed"); 713 714 return (DDI_FAILURE); 715 } 716 717 /* 718 * Disable the event callbacks, after this point, event 719 * callbacks will never get called. Note we shouldn't hold 720 * mutex while unregistering events because there may be a 721 * competing event callback thread. Event callbacks are done 722 * with ndi mutex held and this can cause a potential deadlock. 723 * Note that cleanup can't fail after deregistration of events. 724 */ 725 if (usb_ia->ia_init_state & USB_IA_EVENTS_REGISTERED) { 726 727 usba_common_unregister_events(usb_ia->ia_dip, usb_ia->ia_n_ifs); 728 } 729 730 iapm = usb_ia->ia_pm; 731 732 mutex_enter(&usb_ia->ia_mutex); 733 734 if ((iapm) && (usb_ia->ia_dev_state != USB_DEV_DISCONNECTED)) { 735 736 mutex_exit(&usb_ia->ia_mutex); 737 738 (void) pm_busy_component(dip, 0); 739 if (iapm->uc_wakeup_enabled) { 740 741 /* First bring the device to full power */ 742 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 743 744 rval = usb_handle_remote_wakeup(dip, 745 USB_REMOTE_WAKEUP_DISABLE); 746 747 if (rval != DDI_SUCCESS) { 748 USB_DPRINTF_L2(DPRINT_MASK_EVENTS, 749 usb_ia->ia_log_handle, 750 "usb_cleanup: disable remote " 751 "wakeup failed, rval=%d", rval); 752 } 753 } 754 755 (void) pm_lower_power(usb_ia->ia_dip, 0, USB_DEV_OS_PWR_OFF); 756 (void) pm_idle_component(dip, 0); 757 } else { 758 mutex_exit(&usb_ia->ia_mutex); 759 } 760 761 if (iapm) { 762 kmem_free(iapm, sizeof (usb_common_power_t)); 763 } 764 765 /* free children list */ 766 if (usb_ia->ia_children_dips) { 767 kmem_free(usb_ia->ia_children_dips, 768 usb_ia->ia_cd_list_length); 769 } 770 771 if (usb_ia->ia_child_events) { 772 kmem_free(usb_ia->ia_child_events, sizeof (uint8_t) * 773 usb_ia->ia_n_ifs); 774 } 775 776 if (usb_ia->ia_init_state & USB_IA_MINOR_NODE_CREATED) { 777 ddi_remove_minor_node(dip, NULL); 778 } 779 780 mutex_destroy(&usb_ia->ia_mutex); 781 782 done: 783 usb_client_detach(dip, usb_ia->ia_dev_data); 784 785 usb_free_log_hdl(usb_ia->ia_log_handle); 786 ddi_soft_state_free(usb_ia_statep, ddi_get_instance(dip)); 787 788 ddi_prop_remove_all(dip); 789 790 return (DDI_SUCCESS); 791 } 792 793 /* 794 * usb_ia_create_children: 795 */ 796 static void 797 usb_ia_create_children(usb_ia_t *usb_ia) 798 { 799 usba_device_t *usba_device; 800 uint_t n_ifs, first_if; 801 uint_t i; 802 dev_info_t *cdip; 803 804 usba_device = usba_get_usba_device(usb_ia->ia_dip); 805 806 USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_ia->ia_log_handle, 807 "usb_ia_attach_child_drivers: port = %d, address = %d", 808 usba_device->usb_port, usba_device->usb_addr); 809 810 n_ifs = usb_ia->ia_n_ifs; 811 first_if = usb_ia->ia_first_if; 812 813 /* 814 * create all children if not already present 815 */ 816 for (i = 0; i < n_ifs; i++) { 817 if (usb_ia->ia_children_dips[i] != NULL) { 818 819 continue; 820 } 821 822 mutex_exit(&usb_ia->ia_mutex); 823 cdip = usba_ready_interface_node(usb_ia->ia_dip, first_if + i); 824 mutex_enter(&usb_ia->ia_mutex); 825 826 if (cdip != NULL) { 827 (void) usba_bind_driver(cdip); 828 usb_ia->ia_children_dips[i] = cdip; 829 } 830 } 831 832 } 833 834 835 /* 836 * event support 837 */ 838 static int 839 usb_ia_busop_get_eventcookie(dev_info_t *dip, 840 dev_info_t *rdip, char *eventname, ddi_eventcookie_t *cookie) 841 { 842 usb_ia_t *usb_ia = usb_ia_obtain_state(dip); 843 844 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle, 845 "usb_ia_busop_get_eventcookie: dip=0x%p, rdip=0x%p, " 846 "event=%s", (void *)dip, (void *)rdip, eventname); 847 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle, 848 "(dip=%s%d rdip=%s%d)", 849 ddi_driver_name(dip), ddi_get_instance(dip), 850 ddi_driver_name(rdip), ddi_get_instance(rdip)); 851 852 /* return event cookie, iblock cookie, and level */ 853 return (ndi_event_retrieve_cookie(usb_ia->ia_ndi_event_hdl, 854 rdip, eventname, cookie, NDI_EVENT_NOPASS)); 855 } 856 857 858 static int 859 usb_ia_busop_add_eventcall(dev_info_t *dip, 860 dev_info_t *rdip, 861 ddi_eventcookie_t cookie, 862 void (*callback)(dev_info_t *dip, 863 ddi_eventcookie_t cookie, void *arg, 864 void *bus_impldata), 865 void *arg, ddi_callback_id_t *cb_id) 866 { 867 int ifno; 868 usb_ia_t *usb_ia = usb_ia_obtain_state(dip); 869 870 mutex_enter(&usb_ia->ia_mutex); 871 ifno = usba_get_ifno(rdip)- usb_ia->ia_first_if; 872 mutex_exit(&usb_ia->ia_mutex); 873 874 if (ifno < 0) { 875 ifno = 0; 876 } 877 878 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle, 879 "usb_ia_busop_add_eventcall: dip=0x%p, rdip=0x%p " 880 "cookie=0x%p, cb=0x%p, arg=0x%p", 881 (void *)dip, (void *)rdip, (void *)cookie, (void *)callback, arg); 882 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle, 883 "(dip=%s%d rdip=%s%d event=%s)", 884 ddi_driver_name(dip), ddi_get_instance(dip), 885 ddi_driver_name(rdip), ddi_get_instance(rdip), 886 ndi_event_cookie_to_name(usb_ia->ia_ndi_event_hdl, cookie)); 887 888 /* Set flag on children registering events */ 889 switch (ndi_event_cookie_to_tag(usb_ia->ia_ndi_event_hdl, cookie)) { 890 case USBA_EVENT_TAG_HOT_REMOVAL: 891 mutex_enter(&usb_ia->ia_mutex); 892 usb_ia->ia_child_events[ifno] |= 893 USB_IA_CHILD_EVENT_DISCONNECT; 894 mutex_exit(&usb_ia->ia_mutex); 895 896 break; 897 case USBA_EVENT_TAG_PRE_SUSPEND: 898 mutex_enter(&usb_ia->ia_mutex); 899 usb_ia->ia_child_events[ifno] |= 900 USB_IA_CHILD_EVENT_PRESUSPEND; 901 mutex_exit(&usb_ia->ia_mutex); 902 903 break; 904 default: 905 906 break; 907 } 908 /* add callback (perform registration) */ 909 return (ndi_event_add_callback(usb_ia->ia_ndi_event_hdl, 910 rdip, cookie, callback, arg, NDI_SLEEP, cb_id)); 911 } 912 913 914 static int 915 usb_ia_busop_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id) 916 { 917 usb_ia_t *usb_ia = usb_ia_obtain_state(dip); 918 ndi_event_callbacks_t *cb = (ndi_event_callbacks_t *)cb_id; 919 920 ASSERT(cb); 921 922 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle, 923 "usb_ia_busop_remove_eventcall: dip=0x%p, rdip=0x%p " 924 "cookie=0x%p", (void *)dip, cb->ndi_evtcb_dip, 925 cb->ndi_evtcb_cookie); 926 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle, 927 "(dip=%s%d rdip=%s%d event=%s)", 928 ddi_driver_name(dip), ddi_get_instance(dip), 929 ddi_driver_name(cb->ndi_evtcb_dip), 930 ddi_get_instance(cb->ndi_evtcb_dip), 931 ndi_event_cookie_to_name(usb_ia->ia_ndi_event_hdl, 932 cb->ndi_evtcb_cookie)); 933 934 /* remove event registration from our event set */ 935 return (ndi_event_remove_callback(usb_ia->ia_ndi_event_hdl, cb_id)); 936 } 937 938 939 static int 940 usb_ia_busop_post_event(dev_info_t *dip, 941 dev_info_t *rdip, 942 ddi_eventcookie_t cookie, 943 void *bus_impldata) 944 { 945 usb_ia_t *usb_ia = usb_ia_obtain_state(dip); 946 947 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle, 948 "usb_ia_busop_post_event: dip=0x%p, rdip=0x%p " 949 "cookie=0x%p, impl=0x%p", 950 (void *)dip, (void *)rdip, (void *)cookie, bus_impldata); 951 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle, 952 "(dip=%s%d rdip=%s%d event=%s)", 953 ddi_driver_name(dip), ddi_get_instance(dip), 954 ddi_driver_name(rdip), ddi_get_instance(rdip), 955 ndi_event_cookie_to_name(usb_ia->ia_ndi_event_hdl, cookie)); 956 957 /* post event to all children registered for this event */ 958 return (ndi_event_run_callbacks(usb_ia->ia_ndi_event_hdl, rdip, 959 cookie, bus_impldata)); 960 } 961 962 963 /* 964 * usb_ia_restore_device_state 965 * set the original configuration of the device 966 */ 967 static int 968 usb_ia_restore_device_state(dev_info_t *dip, usb_ia_t *usb_ia) 969 { 970 usb_common_power_t *iapm; 971 972 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle, 973 "usb_ia_restore_device_state: usb_ia = %p", usb_ia); 974 975 mutex_enter(&usb_ia->ia_mutex); 976 iapm = usb_ia->ia_pm; 977 mutex_exit(&usb_ia->ia_mutex); 978 979 /* First bring the device to full power */ 980 (void) pm_busy_component(dip, 0); 981 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 982 983 if (usb_check_same_device(dip, usb_ia->ia_log_handle, USB_LOG_L0, 984 DPRINT_MASK_EVENTS, USB_CHK_VIDPID, NULL) != USB_SUCCESS) { 985 986 /* change the device state from suspended to disconnected */ 987 mutex_enter(&usb_ia->ia_mutex); 988 usb_ia->ia_dev_state = USB_DEV_DISCONNECTED; 989 mutex_exit(&usb_ia->ia_mutex); 990 (void) pm_idle_component(dip, 0); 991 992 return (USB_FAILURE); 993 } 994 995 /* 996 * if the device had remote wakeup earlier, 997 * enable it again 998 */ 999 if (iapm->uc_wakeup_enabled) { 1000 (void) usb_handle_remote_wakeup(usb_ia->ia_dip, 1001 USB_REMOTE_WAKEUP_ENABLE); 1002 } 1003 1004 mutex_enter(&usb_ia->ia_mutex); 1005 usb_ia->ia_dev_state = USB_DEV_ONLINE; 1006 mutex_exit(&usb_ia->ia_mutex); 1007 1008 (void) pm_idle_component(dip, 0); 1009 1010 return (USB_SUCCESS); 1011 } 1012 1013 1014 /* 1015 * usb_ia_event_cb() 1016 * handle disconnect and connect events 1017 */ 1018 static void 1019 usb_ia_event_cb(dev_info_t *dip, ddi_eventcookie_t cookie, 1020 void *arg, void *bus_impldata) 1021 { 1022 int i, tag; 1023 usb_ia_t *usb_ia = usb_ia_obtain_state(dip); 1024 dev_info_t *child_dip; 1025 ddi_eventcookie_t rm_cookie, ins_cookie, suspend_cookie, resume_cookie; 1026 1027 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle, 1028 "usb_ia_event_cb: dip=0x%p, cookie=0x%p, " 1029 "arg=0x%p, impl=0x%p", 1030 (void *)dip, (void *)cookie, arg, bus_impldata); 1031 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle, 1032 "(dip=%s%d event=%s)", 1033 ddi_driver_name(dip), ddi_get_instance(dip), 1034 ndi_event_cookie_to_name(usb_ia->ia_ndi_event_hdl, cookie)); 1035 1036 tag = NDI_EVENT_TAG(cookie); 1037 rm_cookie = ndi_event_tag_to_cookie( 1038 usb_ia->ia_ndi_event_hdl, USBA_EVENT_TAG_HOT_REMOVAL); 1039 suspend_cookie = ndi_event_tag_to_cookie( 1040 usb_ia->ia_ndi_event_hdl, USBA_EVENT_TAG_PRE_SUSPEND); 1041 ins_cookie = ndi_event_tag_to_cookie( 1042 usb_ia->ia_ndi_event_hdl, USBA_EVENT_TAG_HOT_INSERTION); 1043 resume_cookie = ndi_event_tag_to_cookie( 1044 usb_ia->ia_ndi_event_hdl, USBA_EVENT_TAG_POST_RESUME); 1045 1046 mutex_enter(&usb_ia->ia_mutex); 1047 switch (tag) { 1048 case USBA_EVENT_TAG_HOT_REMOVAL: 1049 if (usb_ia->ia_dev_state == USB_DEV_DISCONNECTED) { 1050 USB_DPRINTF_L2(DPRINT_MASK_EVENTS, 1051 usb_ia->ia_log_handle, 1052 "usb_ia_event_cb: Device already disconnected"); 1053 } else { 1054 /* we are disconnected so set our state now */ 1055 usb_ia->ia_dev_state = USB_DEV_DISCONNECTED; 1056 for (i = 0; i < usb_ia->ia_n_ifs; i++) { 1057 usb_ia->ia_child_events[i] &= ~ 1058 USB_IA_CHILD_EVENT_DISCONNECT; 1059 } 1060 mutex_exit(&usb_ia->ia_mutex); 1061 1062 /* pass disconnect event to all the children */ 1063 (void) ndi_event_run_callbacks( 1064 usb_ia->ia_ndi_event_hdl, NULL, 1065 rm_cookie, bus_impldata); 1066 1067 mutex_enter(&usb_ia->ia_mutex); 1068 } 1069 break; 1070 case USBA_EVENT_TAG_PRE_SUSPEND: 1071 /* set our state *after* suspending children */ 1072 mutex_exit(&usb_ia->ia_mutex); 1073 1074 /* pass pre_suspend event to all the children */ 1075 (void) ndi_event_run_callbacks(usb_ia->ia_ndi_event_hdl, 1076 NULL, suspend_cookie, bus_impldata); 1077 1078 mutex_enter(&usb_ia->ia_mutex); 1079 for (i = 0; i < usb_ia->ia_n_ifs; i++) { 1080 usb_ia->ia_child_events[i] &= ~ 1081 USB_IA_CHILD_EVENT_PRESUSPEND; 1082 } 1083 break; 1084 case USBA_EVENT_TAG_HOT_INSERTION: 1085 mutex_exit(&usb_ia->ia_mutex); 1086 if (usb_ia_restore_device_state(dip, usb_ia) == USB_SUCCESS) { 1087 1088 /* 1089 * Check to see if this child has missed the disconnect 1090 * event before it registered for event cb 1091 */ 1092 mutex_enter(&usb_ia->ia_mutex); 1093 for (i = 0; i < usb_ia->ia_n_ifs; i++) { 1094 if (usb_ia->ia_child_events[i] & 1095 USB_IA_CHILD_EVENT_DISCONNECT) { 1096 usb_ia->ia_child_events[i] &= 1097 ~USB_IA_CHILD_EVENT_DISCONNECT; 1098 child_dip = 1099 usb_ia->ia_children_dips[i]; 1100 mutex_exit(&usb_ia->ia_mutex); 1101 1102 /* post the missed disconnect */ 1103 (void) ndi_event_do_callback( 1104 usb_ia->ia_ndi_event_hdl, 1105 child_dip, 1106 rm_cookie, 1107 bus_impldata); 1108 mutex_enter(&usb_ia->ia_mutex); 1109 } 1110 } 1111 mutex_exit(&usb_ia->ia_mutex); 1112 1113 /* pass reconnect event to all the children */ 1114 (void) ndi_event_run_callbacks( 1115 usb_ia->ia_ndi_event_hdl, NULL, 1116 ins_cookie, bus_impldata); 1117 1118 } 1119 mutex_enter(&usb_ia->ia_mutex); 1120 break; 1121 case USBA_EVENT_TAG_POST_RESUME: 1122 /* 1123 * Check to see if this child has missed the pre-suspend 1124 * event before it registered for event cb 1125 */ 1126 for (i = 0; i < usb_ia->ia_n_ifs; i++) { 1127 if (usb_ia->ia_child_events[i] & 1128 USB_IA_CHILD_EVENT_PRESUSPEND) { 1129 usb_ia->ia_child_events[i] &= 1130 ~USB_IA_CHILD_EVENT_PRESUSPEND; 1131 child_dip = usb_ia->ia_children_dips[i]; 1132 mutex_exit(&usb_ia->ia_mutex); 1133 1134 /* post the missed pre-suspend event */ 1135 (void) ndi_event_do_callback( 1136 usb_ia->ia_ndi_event_hdl, 1137 child_dip, suspend_cookie, 1138 bus_impldata); 1139 mutex_enter(&usb_ia->ia_mutex); 1140 } 1141 } 1142 mutex_exit(&usb_ia->ia_mutex); 1143 1144 /* pass post_resume event to all the children */ 1145 (void) ndi_event_run_callbacks(usb_ia->ia_ndi_event_hdl, 1146 NULL, resume_cookie, bus_impldata); 1147 1148 mutex_enter(&usb_ia->ia_mutex); 1149 break; 1150 } 1151 mutex_exit(&usb_ia->ia_mutex); 1152 1153 } 1154 1155 /* 1156 * create the pm components required for power management 1157 */ 1158 static void 1159 usb_ia_create_pm_components(dev_info_t *dip, usb_ia_t *usb_ia) 1160 { 1161 usb_common_power_t *iapm; 1162 uint_t pwr_states; 1163 1164 USB_DPRINTF_L4(DPRINT_MASK_PM, usb_ia->ia_log_handle, 1165 "usb_ia_create_pm_components: Begin"); 1166 1167 /* Allocate the PM state structure */ 1168 iapm = kmem_zalloc(sizeof (usb_common_power_t), KM_SLEEP); 1169 1170 mutex_enter(&usb_ia->ia_mutex); 1171 usb_ia->ia_pm = iapm; 1172 iapm->uc_usb_statep = usb_ia; 1173 iapm->uc_pm_capabilities = 0; /* XXXX should this be 0?? */ 1174 iapm->uc_current_power = USB_DEV_OS_FULL_PWR; 1175 mutex_exit(&usb_ia->ia_mutex); 1176 1177 /* 1178 * By not enabling parental notification, PM enforces 1179 * "strict parental dependency" meaning, usb_ia won't 1180 * power off until any of its children are in full power. 1181 */ 1182 1183 /* 1184 * there are 3 scenarios: 1185 * 1. a well behaved device should have remote wakeup 1186 * at interface and device level. If the interface 1187 * wakes up, usb_ia will wake up 1188 * 2. if the device doesn't have remote wake up and 1189 * the interface has, PM will still work, ie. 1190 * the interfaces wakes up and usb_ia wakes up 1191 * 3. if neither the interface nor device has remote 1192 * wakeup, the interface will wake up when it is opened 1193 * and goes to sleep after being closed for a while 1194 * In this case usb_ia should also go to sleep shortly 1195 * thereafter 1196 * In all scenarios it doesn't really matter whether 1197 * remote wakeup at the device level is enabled or not 1198 * but we do it anyways 1199 */ 1200 if (usb_handle_remote_wakeup(dip, USB_REMOTE_WAKEUP_ENABLE) == 1201 USB_SUCCESS) { 1202 USB_DPRINTF_L3(DPRINT_MASK_PM, usb_ia->ia_log_handle, 1203 "usb_ia_create_pm_components: " 1204 "Remote Wakeup Enabled"); 1205 iapm->uc_wakeup_enabled = 1; 1206 } 1207 1208 if (usb_create_pm_components(dip, &pwr_states) == 1209 USB_SUCCESS) { 1210 iapm->uc_pwr_states = (uint8_t)pwr_states; 1211 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 1212 } 1213 1214 USB_DPRINTF_L4(DPRINT_MASK_PM, usb_ia->ia_log_handle, 1215 "usb_ia_create_pm_components: End"); 1216 } 1217 1218 1219 /* 1220 * usb_ia_obtain_state: 1221 */ 1222 static usb_ia_t * 1223 usb_ia_obtain_state(dev_info_t *dip) 1224 { 1225 int instance = ddi_get_instance(dip); 1226 usb_ia_t *statep = ddi_get_soft_state(usb_ia_statep, instance); 1227 1228 ASSERT(statep != NULL); 1229 1230 return (statep); 1231 } 1232