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 multi interface and common class driver 30 * 31 * this driver attempts to attach each interface to a driver 32 * and may eventually handle common class features such as 33 * shared endpoints 34 */ 35 36 #if defined(lint) && !defined(DEBUG) 37 #define DEBUG 1 38 #endif 39 #include <sys/usb/usba/usbai_version.h> 40 #include <sys/usb/usba.h> 41 #include <sys/usb/usba/usba_types.h> 42 #include <sys/usb/usba/usba_impl.h> 43 #include <sys/usb/usba/usba_ugen.h> 44 #include <sys/usb/usb_mid/usb_midvar.h> 45 46 void usba_free_evdata(usba_evdata_t *); 47 48 /* Debugging support */ 49 uint_t usb_mid_errlevel = USB_LOG_L4; 50 uint_t usb_mid_errmask = (uint_t)DPRINT_MASK_ALL; 51 uint_t usb_mid_instance_debug = (uint_t)-1; 52 uint_t usb_mid_bus_config_debug = 0; 53 54 _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_mid_errlevel)) 55 _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_mid_errmask)) 56 _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_mid_instance_debug)) 57 58 _NOTE(SCHEME_PROTECTS_DATA("unique", msgb)) 59 _NOTE(SCHEME_PROTECTS_DATA("unique", dev_info)) 60 _NOTE(SCHEME_PROTECTS_DATA("unique", usb_pipe_policy)) 61 62 /* 63 * Hotplug support 64 * Leaf ops (hotplug controls for client devices) 65 */ 66 static int usb_mid_open(dev_t *, int, int, cred_t *); 67 static int usb_mid_close(dev_t, int, int, cred_t *); 68 static int usb_mid_read(dev_t, struct uio *, cred_t *); 69 static int usb_mid_write(dev_t, struct uio *, cred_t *); 70 static int usb_mid_poll(dev_t, short, int, short *, 71 struct pollhead **); 72 73 static struct cb_ops usb_mid_cb_ops = { 74 usb_mid_open, 75 usb_mid_close, 76 nodev, /* strategy */ 77 nodev, /* print */ 78 nodev, /* dump */ 79 usb_mid_read, /* read */ 80 usb_mid_write, /* write */ 81 nodev, 82 nodev, /* devmap */ 83 nodev, /* mmap */ 84 nodev, /* segmap */ 85 usb_mid_poll, /* poll */ 86 ddi_prop_op, /* prop_op */ 87 NULL, 88 D_MP 89 }; 90 91 static int usb_mid_busop_get_eventcookie(dev_info_t *dip, 92 dev_info_t *rdip, 93 char *eventname, 94 ddi_eventcookie_t *cookie); 95 static int usb_mid_busop_add_eventcall(dev_info_t *dip, 96 dev_info_t *rdip, 97 ddi_eventcookie_t cookie, 98 void (*callback)(dev_info_t *dip, 99 ddi_eventcookie_t cookie, void *arg, 100 void *bus_impldata), 101 void *arg, ddi_callback_id_t *cb_id); 102 static int usb_mid_busop_remove_eventcall(dev_info_t *dip, 103 ddi_callback_id_t cb_id); 104 static int usb_mid_busop_post_event(dev_info_t *dip, 105 dev_info_t *rdip, 106 ddi_eventcookie_t cookie, 107 void *bus_impldata); 108 static int usb_mid_bus_config(dev_info_t *dip, 109 uint_t flag, 110 ddi_bus_config_op_t op, 111 void *arg, 112 dev_info_t **child); 113 static int usb_mid_bus_unconfig(dev_info_t *dip, 114 uint_t flag, 115 ddi_bus_config_op_t op, 116 void *arg); 117 118 119 /* 120 * autoconfiguration data and routines. 121 */ 122 static int usb_mid_info(dev_info_t *, ddi_info_cmd_t, 123 void *, void **); 124 static int usb_mid_attach(dev_info_t *, ddi_attach_cmd_t); 125 static int usb_mid_detach(dev_info_t *, ddi_detach_cmd_t); 126 127 /* other routines */ 128 static void usb_mid_create_pm_components(dev_info_t *, usb_mid_t *); 129 static int usb_mid_bus_ctl(dev_info_t *, dev_info_t *, 130 ddi_ctl_enum_t, void *, void *); 131 static int usb_mid_power(dev_info_t *, int, int); 132 static int usb_mid_restore_device_state(dev_info_t *, usb_mid_t *); 133 static usb_mid_t *usb_mid_obtain_state(dev_info_t *); 134 135 /* 136 * Busops vector 137 */ 138 static struct bus_ops usb_mid_busops = { 139 BUSO_REV, 140 nullbusmap, /* bus_map */ 141 NULL, /* bus_get_intrspec */ 142 NULL, /* bus_add_intrspec */ 143 NULL, /* bus_remove_intrspec */ 144 NULL, /* XXXX bus_map_fault */ 145 ddi_dma_map, /* bus_dma_map */ 146 ddi_dma_allochdl, 147 ddi_dma_freehdl, 148 ddi_dma_bindhdl, 149 ddi_dma_unbindhdl, 150 ddi_dma_flush, 151 ddi_dma_win, 152 ddi_dma_mctl, /* bus_dma_ctl */ 153 usb_mid_bus_ctl, /* bus_ctl */ 154 ddi_bus_prop_op, /* bus_prop_op */ 155 usb_mid_busop_get_eventcookie, 156 usb_mid_busop_add_eventcall, 157 usb_mid_busop_remove_eventcall, 158 usb_mid_busop_post_event, /* bus_post_event */ 159 NULL, /* bus_intr_ctl */ 160 usb_mid_bus_config, /* bus_config */ 161 usb_mid_bus_unconfig, /* bus_unconfig */ 162 NULL, /* bus_fm_init */ 163 NULL, /* bus_fm_fini */ 164 NULL, /* bus_fm_access_enter */ 165 NULL, /* bus_fm_access_exit */ 166 NULL /* bus_power */ 167 }; 168 169 170 static struct dev_ops usb_mid_ops = { 171 DEVO_REV, /* devo_rev, */ 172 0, /* refcnt */ 173 usb_mid_info, /* info */ 174 nulldev, /* identify */ 175 nulldev, /* probe */ 176 usb_mid_attach, /* attach */ 177 usb_mid_detach, /* detach */ 178 nodev, /* reset */ 179 &usb_mid_cb_ops, /* driver operations */ 180 &usb_mid_busops, /* bus operations */ 181 usb_mid_power /* power */ 182 }; 183 184 static struct modldrv modldrv = { 185 &mod_driverops, /* Type of module. This one is a driver */ 186 "USB Multi Interface Driver %I%", /* Name of the module. */ 187 &usb_mid_ops, /* driver ops */ 188 }; 189 190 static struct modlinkage modlinkage = { 191 MODREV_1, (void *)&modldrv, NULL 192 }; 193 194 #define USB_MID_INITIAL_SOFT_SPACE 4 195 static void *usb_mid_statep; 196 197 198 /* 199 * prototypes 200 */ 201 static void usb_mid_create_children(usb_mid_t *usb_mid); 202 static int usb_mid_cleanup(dev_info_t *dip, usb_mid_t *usb_mid); 203 static void usb_mid_register_events(usb_mid_t *usb_mid); 204 static void usb_mid_unregister_events(usb_mid_t *usb_mid); 205 206 /* usbai private */ 207 char *usba_get_mfg_prod_sn_str(dev_info_t *dip, 208 char *buffer, int buflen); 209 210 /* 211 * event definition 212 */ 213 static ndi_event_definition_t usb_mid_ndi_event_defs[] = { 214 {USBA_EVENT_TAG_HOT_REMOVAL, DDI_DEVI_REMOVE_EVENT, EPL_KERNEL, 215 NDI_EVENT_POST_TO_ALL}, 216 {USBA_EVENT_TAG_HOT_INSERTION, DDI_DEVI_INSERT_EVENT, EPL_KERNEL, 217 NDI_EVENT_POST_TO_ALL}, 218 {USBA_EVENT_TAG_POST_RESUME, USBA_POST_RESUME_EVENT, EPL_KERNEL, 219 NDI_EVENT_POST_TO_ALL}, 220 {USBA_EVENT_TAG_PRE_SUSPEND, USBA_PRE_SUSPEND_EVENT, EPL_KERNEL, 221 NDI_EVENT_POST_TO_ALL} 222 }; 223 224 #define USB_MID_N_NDI_EVENTS \ 225 (sizeof (usb_mid_ndi_event_defs) / sizeof (ndi_event_definition_t)) 226 227 static ndi_event_set_t usb_mid_ndi_events = { 228 NDI_EVENTS_REV1, USB_MID_N_NDI_EVENTS, usb_mid_ndi_event_defs}; 229 230 231 /* 232 * standard driver entry points 233 */ 234 int 235 _init(void) 236 { 237 int rval; 238 239 rval = ddi_soft_state_init(&usb_mid_statep, sizeof (struct usb_mid), 240 USB_MID_INITIAL_SOFT_SPACE); 241 if (rval != 0) { 242 return (rval); 243 } 244 245 if ((rval = mod_install(&modlinkage)) != 0) { 246 ddi_soft_state_fini(&usb_mid_statep); 247 return (rval); 248 } 249 250 return (rval); 251 } 252 253 254 int 255 _fini(void) 256 { 257 int rval; 258 259 rval = mod_remove(&modlinkage); 260 261 if (rval) { 262 return (rval); 263 } 264 265 ddi_soft_state_fini(&usb_mid_statep); 266 267 return (rval); 268 } 269 270 271 int 272 _info(struct modinfo *modinfop) 273 { 274 return (mod_info(&modlinkage, modinfop)); 275 } 276 277 278 /*ARGSUSED*/ 279 static int 280 usb_mid_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 281 { 282 usb_mid_t *usb_mid; 283 int instance = 284 USB_MID_MINOR_TO_INSTANCE(getminor((dev_t)arg)); 285 int error = DDI_FAILURE; 286 287 switch (infocmd) { 288 case DDI_INFO_DEVT2DEVINFO: 289 if ((usb_mid = ddi_get_soft_state(usb_mid_statep, 290 instance)) != NULL) { 291 *result = (void *)usb_mid->mi_dip; 292 if (*result != NULL) { 293 error = DDI_SUCCESS; 294 } 295 } else { 296 *result = NULL; 297 } 298 break; 299 300 case DDI_INFO_DEVT2INSTANCE: 301 *result = (void *)(intptr_t)instance; 302 error = DDI_SUCCESS; 303 break; 304 default: 305 break; 306 } 307 308 return (error); 309 } 310 311 312 /* 313 * child post attach/detach notification 314 */ 315 static void 316 usb_mid_post_attach(usb_mid_t *usb_mid, uint8_t ifno, struct attachspec *as) 317 { 318 USB_DPRINTF_L2(DPRINT_MASK_PM, usb_mid->mi_log_handle, 319 "usb_mid_post_attach: ifno = %d result = %d", ifno, as->result); 320 321 /* if child successfully attached, set power */ 322 if (as->result == DDI_SUCCESS) { 323 /* 324 * Check if the child created wants to be power managed. 325 * If yes, the childs power level gets automatically tracked 326 * by DDI_CTLOPS_POWER busctl. 327 * If no, we set power of the new child by default 328 * to USB_DEV_OS_FULL_PWR. Because we should never suspend. 329 */ 330 mutex_enter(&usb_mid->mi_mutex); 331 usb_mid->mi_attach_count++; 332 mutex_exit(&usb_mid->mi_mutex); 333 } 334 } 335 336 337 static void 338 usb_mid_post_detach(usb_mid_t *usb_mid, uint8_t ifno, struct detachspec *ds) 339 { 340 USB_DPRINTF_L2(DPRINT_MASK_PM, usb_mid->mi_log_handle, 341 "usb_mid_post_detach: ifno = %d result = %d", ifno, ds->result); 342 343 /* 344 * if the device is successfully detached, 345 * mark component as idle 346 */ 347 if (ds->result == DDI_SUCCESS) { 348 usba_device_t *usba_device = 349 usba_get_usba_device(usb_mid->mi_dip); 350 351 mutex_enter(&usb_mid->mi_mutex); 352 353 /* check for leaks except when where is a ugen open */ 354 if ((ds->cmd == DDI_DETACH) && 355 (--usb_mid->mi_attach_count == 0) && usba_device && 356 (usb_mid->mi_ugen_open_count == 0)) { 357 usba_check_for_leaks(usba_device); 358 } 359 mutex_exit(&usb_mid->mi_mutex); 360 } 361 } 362 363 364 /* 365 * bus ctl support. we handle notifications here and the 366 * rest goes up to root hub/hcd 367 */ 368 /*ARGSUSED*/ 369 static int 370 usb_mid_bus_ctl(dev_info_t *dip, 371 dev_info_t *rdip, 372 ddi_ctl_enum_t op, 373 void *arg, 374 void *result) 375 { 376 usba_device_t *hub_usba_device = usba_get_usba_device(rdip); 377 dev_info_t *root_hub_dip = hub_usba_device->usb_root_hub_dip; 378 usb_mid_t *usb_mid; 379 struct attachspec *as; 380 struct detachspec *ds; 381 382 usb_mid = usb_mid_obtain_state(dip); 383 384 USB_DPRINTF_L2(DPRINT_MASK_PM, usb_mid->mi_log_handle, 385 "usb_mid_bus_ctl:\n\t" 386 "dip = 0x%p, rdip = 0x%p, op = 0x%x, arg = 0x%p", 387 dip, rdip, op, arg); 388 389 switch (op) { 390 case DDI_CTLOPS_ATTACH: 391 as = (struct attachspec *)arg; 392 393 switch (as->when) { 394 case DDI_PRE : 395 /* nothing to do basically */ 396 USB_DPRINTF_L2(DPRINT_MASK_PM, usb_mid->mi_log_handle, 397 "DDI_PRE DDI_CTLOPS_ATTACH"); 398 break; 399 case DDI_POST : 400 usb_mid_post_attach(usb_mid, usba_get_ifno(rdip), 401 (struct attachspec *)arg); 402 break; 403 } 404 405 break; 406 case DDI_CTLOPS_DETACH: 407 ds = (struct detachspec *)arg; 408 409 switch (ds->when) { 410 case DDI_PRE : 411 /* nothing to do basically */ 412 USB_DPRINTF_L2(DPRINT_MASK_PM, usb_mid->mi_log_handle, 413 "DDI_PRE DDI_CTLOPS_DETACH"); 414 break; 415 case DDI_POST : 416 usb_mid_post_detach(usb_mid, usba_get_ifno(rdip), 417 (struct detachspec *)arg); 418 break; 419 } 420 421 break; 422 default: 423 /* pass to root hub to handle */ 424 return (usba_bus_ctl(root_hub_dip, rdip, op, arg, result)); 425 } 426 427 return (DDI_SUCCESS); 428 } 429 430 431 /* 432 * bus enumeration entry points 433 */ 434 static int 435 usb_mid_bus_config(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op, 436 void *arg, dev_info_t **child) 437 { 438 int rval, circ; 439 usb_mid_t *usb_mid = usb_mid_obtain_state(dip); 440 441 USB_DPRINTF_L2(DPRINT_MASK_ALL, usb_mid->mi_log_handle, 442 "usb_mid_bus_config: op=%d", op); 443 444 if (usb_mid_bus_config_debug) { 445 flag |= NDI_DEVI_DEBUG; 446 } 447 448 ndi_devi_enter(dip, &circ); 449 450 /* enumerate each interface below us */ 451 mutex_enter(&usb_mid->mi_mutex); 452 usb_mid_create_children(usb_mid); 453 mutex_exit(&usb_mid->mi_mutex); 454 455 rval = ndi_busop_bus_config(dip, flag, op, arg, child, 0); 456 ndi_devi_exit(dip, circ); 457 458 return (rval); 459 } 460 461 462 static int 463 usb_mid_bus_unconfig(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op, 464 void *arg) 465 { 466 usb_mid_t *usb_mid = usb_mid_obtain_state(dip); 467 468 dev_info_t *cdip, *mdip; 469 int interface, circular_count; 470 int rval = NDI_SUCCESS; 471 472 USB_DPRINTF_L4(DPRINT_MASK_ALL, usb_mid->mi_log_handle, 473 "usb_mid_bus_unconfig: op=%d", op); 474 475 if (usb_mid_bus_config_debug) { 476 flag |= NDI_DEVI_DEBUG; 477 } 478 479 /* 480 * first offline and if offlining successful, then 481 * remove children 482 */ 483 if (op == BUS_UNCONFIG_ALL) { 484 flag &= ~(NDI_DEVI_REMOVE | NDI_UNCONFIG); 485 } 486 487 ndi_devi_enter(dip, &circular_count); 488 rval = ndi_busop_bus_unconfig(dip, flag, op, arg); 489 490 if (op == BUS_UNCONFIG_ALL && rval == NDI_SUCCESS && 491 (flag & NDI_AUTODETACH) == 0) { 492 flag |= NDI_DEVI_REMOVE; 493 rval = ndi_busop_bus_unconfig(dip, flag, op, arg); 494 } 495 496 /* update children's list */ 497 mutex_enter(&usb_mid->mi_mutex); 498 for (interface = 0; usb_mid->mi_children_dips && 499 (interface < usb_mid->mi_n_ifs); interface++) { 500 mdip = usb_mid->mi_children_dips[interface]; 501 502 /* now search if this dip still exists */ 503 for (cdip = ddi_get_child(dip); cdip && (cdip != mdip); 504 cdip = ddi_get_next_sibling(cdip)); 505 506 if (cdip != mdip) { 507 /* we lost the dip on this interface */ 508 usb_mid->mi_children_dips[interface] = NULL; 509 } else if (cdip) { 510 /* 511 * keep in DS_INITALIZED to prevent parent 512 * from detaching 513 */ 514 (void) ddi_initchild(ddi_get_parent(cdip), cdip); 515 } 516 } 517 mutex_exit(&usb_mid->mi_mutex); 518 519 ndi_devi_exit(dip, circular_count); 520 521 USB_DPRINTF_L4(DPRINT_MASK_ALL, usb_mid->mi_log_handle, 522 "usb_mid_bus_config: rval=%d", rval); 523 524 return (rval); 525 } 526 527 /* 528 * functions to handle power transition for OS levels 0 -> 3 529 */ 530 static int 531 usb_mid_pwrlvl0(usb_mid_t *usb_mid) 532 { 533 int rval; 534 535 switch (usb_mid->mi_dev_state) { 536 case USB_DEV_ONLINE: 537 /* Issue USB D3 command to the device here */ 538 rval = usb_set_device_pwrlvl3(usb_mid->mi_dip); 539 ASSERT(rval == USB_SUCCESS); 540 541 usb_mid->mi_dev_state = USB_DEV_PWRED_DOWN; 542 usb_mid->mi_pm->mip_current_power = 543 USB_DEV_OS_PWR_OFF; 544 /* FALLTHRU */ 545 case USB_DEV_DISCONNECTED: 546 case USB_DEV_SUSPENDED: 547 /* allow a disconnected/cpr'ed device to go to low pwr */ 548 549 return (USB_SUCCESS); 550 case USB_DEV_PWRED_DOWN: 551 default: 552 return (USB_FAILURE); 553 } 554 } 555 556 557 /* ARGSUSED */ 558 static int 559 usb_mid_pwrlvl1(usb_mid_t *usb_mid) 560 { 561 int rval; 562 563 /* Issue USB D2 command to the device here */ 564 rval = usb_set_device_pwrlvl2(usb_mid->mi_dip); 565 ASSERT(rval == USB_SUCCESS); 566 567 return (USB_FAILURE); 568 } 569 570 571 /* ARGSUSED */ 572 static int 573 usb_mid_pwrlvl2(usb_mid_t *usb_mid) 574 { 575 int rval; 576 577 /* Issue USB D1 command to the device here */ 578 rval = usb_set_device_pwrlvl1(usb_mid->mi_dip); 579 ASSERT(rval == USB_SUCCESS); 580 581 return (USB_FAILURE); 582 } 583 584 585 static int 586 usb_mid_pwrlvl3(usb_mid_t *usb_mid) 587 { 588 int rval; 589 590 switch (usb_mid->mi_dev_state) { 591 case USB_DEV_PWRED_DOWN: 592 /* Issue USB D0 command to the device here */ 593 rval = usb_set_device_pwrlvl0(usb_mid->mi_dip); 594 ASSERT(rval == USB_SUCCESS); 595 596 usb_mid->mi_dev_state = USB_DEV_ONLINE; 597 usb_mid->mi_pm->mip_current_power = USB_DEV_OS_FULL_PWR; 598 599 /* FALLTHRU */ 600 case USB_DEV_ONLINE: 601 /* we are already in full power */ 602 603 /* FALLTHRU */ 604 case USB_DEV_DISCONNECTED: 605 case USB_DEV_SUSPENDED: 606 /* allow a disconnected/cpr'ed device to go to low power */ 607 608 return (USB_SUCCESS); 609 default: 610 USB_DPRINTF_L2(DPRINT_MASK_PM, usb_mid->mi_log_handle, 611 "usb_mid_pwrlvl3: Illegal state (%s)", 612 usb_str_dev_state(usb_mid->mi_dev_state)); 613 614 return (USB_FAILURE); 615 } 616 } 617 618 619 /* power entry point */ 620 /* ARGSUSED */ 621 static int 622 usb_mid_power(dev_info_t *dip, int comp, int level) 623 { 624 usb_mid_t *usb_mid; 625 usb_mid_power_t *midpm; 626 int rval = DDI_FAILURE; 627 628 usb_mid = usb_mid_obtain_state(dip); 629 630 USB_DPRINTF_L4(DPRINT_MASK_PM, usb_mid->mi_log_handle, 631 "usb_mid_power: Begin: usb_mid = %p, level = %d", usb_mid, level); 632 633 mutex_enter(&usb_mid->mi_mutex); 634 midpm = usb_mid->mi_pm; 635 636 /* check if we are transitioning to a legal power level */ 637 if (USB_DEV_PWRSTATE_OK(midpm->mip_pwr_states, level)) { 638 USB_DPRINTF_L2(DPRINT_MASK_PM, usb_mid->mi_log_handle, 639 "usb_mid_power: illegal power level = %d " 640 "mip_pwr_states = %x", level, midpm->mip_pwr_states); 641 642 mutex_exit(&usb_mid->mi_mutex); 643 644 return (rval); 645 } 646 647 switch (level) { 648 case USB_DEV_OS_PWR_OFF: 649 rval = usb_mid_pwrlvl0(usb_mid); 650 break; 651 case USB_DEV_OS_PWR_1: 652 rval = usb_mid_pwrlvl1(usb_mid); 653 break; 654 case USB_DEV_OS_PWR_2: 655 rval = usb_mid_pwrlvl2(usb_mid); 656 break; 657 case USB_DEV_OS_FULL_PWR: 658 rval = usb_mid_pwrlvl3(usb_mid); 659 break; 660 } 661 662 mutex_exit(&usb_mid->mi_mutex); 663 664 return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE); 665 } 666 667 668 /* 669 * attach/resume entry point 670 */ 671 static int 672 usb_mid_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 673 { 674 int instance = ddi_get_instance(dip); 675 usb_mid_t *usb_mid = NULL; 676 uint_t n_ifs; 677 size_t size; 678 679 switch (cmd) { 680 case DDI_ATTACH: 681 682 break; 683 case DDI_RESUME: 684 usb_mid = (usb_mid_t *)ddi_get_soft_state(usb_mid_statep, 685 instance); 686 (void) usb_mid_restore_device_state(dip, usb_mid); 687 688 if (usb_mid->mi_ugen_hdl) { 689 (void) usb_ugen_attach(usb_mid->mi_ugen_hdl, 690 DDI_RESUME); 691 } 692 693 return (DDI_SUCCESS); 694 default: 695 696 return (DDI_FAILURE); 697 } 698 699 /* 700 * Attach: 701 * 702 * Allocate soft state and initialize 703 */ 704 if (ddi_soft_state_zalloc(usb_mid_statep, instance) != DDI_SUCCESS) { 705 goto fail; 706 } 707 708 usb_mid = ddi_get_soft_state(usb_mid_statep, instance); 709 if (usb_mid == NULL) { 710 711 goto fail; 712 } 713 714 /* allocate handle for logging of messages */ 715 usb_mid->mi_log_handle = usb_alloc_log_hdl(dip, "mid", 716 &usb_mid_errlevel, 717 &usb_mid_errmask, &usb_mid_instance_debug, 718 0); 719 720 usb_mid->mi_usba_device = usba_get_usba_device(dip); 721 usb_mid->mi_dip = dip; 722 usb_mid->mi_instance = instance; 723 usb_mid->mi_n_ifs = usb_mid->mi_usba_device->usb_n_ifs; 724 725 /* attach client driver to USBA */ 726 if (usb_client_attach(dip, USBDRV_VERSION, 0) != USB_SUCCESS) { 727 USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_mid->mi_log_handle, 728 "usb_client_attach failed"); 729 goto fail; 730 } 731 if (usb_get_dev_data(dip, &usb_mid->mi_dev_data, USB_PARSE_LVL_NONE, 732 0) != USB_SUCCESS) { 733 USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_mid->mi_log_handle, 734 "usb_get_dev_data failed"); 735 goto fail; 736 } 737 738 mutex_init(&usb_mid->mi_mutex, NULL, MUTEX_DRIVER, 739 usb_mid->mi_dev_data->dev_iblock_cookie); 740 741 usb_free_dev_data(dip, usb_mid->mi_dev_data); 742 usb_mid->mi_dev_data = NULL; 743 744 usb_mid->mi_init_state |= USB_MID_LOCK_INIT; 745 746 if (ddi_create_minor_node(dip, "usb_mid", S_IFCHR, 747 instance << USB_MID_MINOR_INSTANCE_SHIFT, 748 DDI_NT_NEXUS, 0) != DDI_SUCCESS) { 749 USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_mid->mi_log_handle, 750 "cannot create devctl minor node"); 751 goto fail; 752 } 753 754 usb_mid->mi_init_state |= USB_MID_MINOR_NODE_CREATED; 755 756 /* 757 * allocate array for keeping track of child dips 758 */ 759 n_ifs = usb_mid->mi_n_ifs; 760 usb_mid->mi_cd_list_length = size = (sizeof (dev_info_t *)) * n_ifs; 761 762 usb_mid->mi_children_dips = kmem_zalloc(size, KM_SLEEP); 763 usb_mid->mi_child_events = kmem_zalloc(sizeof (uint8_t) * n_ifs, 764 KM_SLEEP); 765 /* 766 * Event handling: definition and registration 767 * get event handle for events that we have defined 768 */ 769 (void) ndi_event_alloc_hdl(dip, 0, &usb_mid->mi_ndi_event_hdl, 770 NDI_SLEEP); 771 772 /* bind event set to the handle */ 773 if (ndi_event_bind_set(usb_mid->mi_ndi_event_hdl, &usb_mid_ndi_events, 774 NDI_SLEEP)) { 775 USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_mid->mi_log_handle, 776 "usb_mid_attach: binding event set failed"); 777 778 goto fail; 779 } 780 781 usb_mid->mi_dev_state = USB_DEV_ONLINE; 782 783 /* 784 * now create components to power manage this device 785 * before attaching children 786 */ 787 usb_mid_create_pm_components(dip, usb_mid); 788 789 /* event registration for events from our parent */ 790 usb_mid_register_events(usb_mid); 791 792 usb_mid->mi_init_state |= USB_MID_EVENTS_REGISTERED; 793 794 ddi_report_dev(dip); 795 796 return (DDI_SUCCESS); 797 798 fail: 799 USB_DPRINTF_L2(DPRINT_MASK_ATTA, NULL, "usb_mid%d cannot attach", 800 instance); 801 802 if (usb_mid) { 803 (void) usb_mid_cleanup(dip, usb_mid); 804 } 805 806 return (DDI_FAILURE); 807 } 808 809 810 /* detach or suspend this instance */ 811 static int 812 usb_mid_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 813 { 814 usb_mid_t *usb_mid = usb_mid_obtain_state(dip); 815 816 USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_mid->mi_log_handle, 817 "usb_mid_detach: cmd = 0x%x", cmd); 818 819 switch (cmd) { 820 case DDI_DETACH: 821 822 return (usb_mid_cleanup(dip, usb_mid)); 823 case DDI_SUSPEND: 824 /* nothing to do */ 825 mutex_enter(&usb_mid->mi_mutex); 826 usb_mid->mi_dev_state = USB_DEV_SUSPENDED; 827 mutex_exit(&usb_mid->mi_mutex); 828 829 if (usb_mid->mi_ugen_hdl) { 830 int rval = usb_ugen_detach(usb_mid->mi_ugen_hdl, 831 DDI_SUSPEND); 832 return (rval == USB_SUCCESS ? DDI_SUCCESS : 833 DDI_FAILURE); 834 } 835 836 return (DDI_SUCCESS); 837 default: 838 839 return (DDI_FAILURE); 840 } 841 842 _NOTE(NOT_REACHED) 843 /* NOTREACHED */ 844 } 845 846 847 /* 848 * usb_mid_cleanup: 849 * cleanup usb_mid and deallocate. this function is called for 850 * handling attach failures and detaching including dynamic 851 * reconfiguration 852 */ 853 /*ARGSUSED*/ 854 static int 855 usb_mid_cleanup(dev_info_t *dip, usb_mid_t *usb_mid) 856 { 857 usb_mid_power_t *midpm; 858 int rval; 859 860 USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_mid->mi_log_handle, 861 "usb_mid_cleanup:"); 862 863 if ((usb_mid->mi_init_state & USB_MID_LOCK_INIT) == 0) { 864 865 goto done; 866 } 867 868 /* 869 * deallocate events, if events are still registered 870 * (ie. children still attached) then we have to fail the detach 871 */ 872 if (usb_mid->mi_ndi_event_hdl && 873 (ndi_event_free_hdl(usb_mid->mi_ndi_event_hdl) != NDI_SUCCESS)) { 874 875 USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_mid->mi_log_handle, 876 "usb_mid_cleanup: ndi_event_free_hdl failed"); 877 878 return (DDI_FAILURE); 879 } 880 881 /* 882 * Disable the event callbacks, after this point, event 883 * callbacks will never get called. Note we shouldn't hold 884 * mutex while unregistering events because there may be a 885 * competing event callback thread. Event callbacks are done 886 * with ndi mutex held and this can cause a potential deadlock. 887 * Note that cleanup can't fail after deregistration of events. 888 */ 889 if (usb_mid->mi_init_state & USB_MID_EVENTS_REGISTERED) { 890 usb_mid_unregister_events(usb_mid); 891 } 892 893 midpm = usb_mid->mi_pm; 894 895 mutex_enter(&usb_mid->mi_mutex); 896 897 if ((midpm) && (usb_mid->mi_dev_state != USB_DEV_DISCONNECTED)) { 898 899 mutex_exit(&usb_mid->mi_mutex); 900 901 (void) pm_busy_component(dip, 0); 902 if (midpm->mip_wakeup_enabled) { 903 904 /* First bring the device to full power */ 905 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 906 907 rval = usb_handle_remote_wakeup(dip, 908 USB_REMOTE_WAKEUP_DISABLE); 909 910 if (rval != DDI_SUCCESS) { 911 USB_DPRINTF_L2(DPRINT_MASK_EVENTS, 912 usb_mid->mi_log_handle, 913 "usb_cleanup: disable remote " 914 "wakeup failed, rval=%d", rval); 915 } 916 } 917 918 (void) pm_lower_power(usb_mid->mi_dip, 0, USB_DEV_OS_PWR_OFF); 919 (void) pm_idle_component(dip, 0); 920 } else { 921 mutex_exit(&usb_mid->mi_mutex); 922 } 923 924 if (midpm) { 925 kmem_free(midpm, sizeof (usb_mid_power_t)); 926 } 927 928 /* free children list */ 929 if (usb_mid->mi_children_dips) { 930 kmem_free(usb_mid->mi_children_dips, 931 usb_mid->mi_cd_list_length); 932 } 933 934 if (usb_mid->mi_child_events) { 935 kmem_free(usb_mid->mi_child_events, sizeof (uint8_t) * 936 usb_mid->mi_n_ifs); 937 } 938 939 if (usb_mid->mi_init_state & USB_MID_MINOR_NODE_CREATED) { 940 ddi_remove_minor_node(dip, NULL); 941 } 942 943 mutex_destroy(&usb_mid->mi_mutex); 944 945 done: 946 usb_client_detach(dip, usb_mid->mi_dev_data); 947 948 if (usb_mid->mi_ugen_hdl) { 949 (void) usb_ugen_detach(usb_mid->mi_ugen_hdl, DDI_DETACH); 950 usb_ugen_release_hdl(usb_mid->mi_ugen_hdl); 951 } 952 953 usb_free_log_hdl(usb_mid->mi_log_handle); 954 ddi_soft_state_free(usb_mid_statep, ddi_get_instance(dip)); 955 956 ddi_prop_remove_all(dip); 957 958 return (DDI_SUCCESS); 959 } 960 961 962 int 963 usb_mid_devi_bind_driver(usb_mid_t *usb_mid, dev_info_t *dip) 964 { 965 char *name; 966 uint8_t if_num = usba_get_ifno(dip); 967 int rval = USB_SUCCESS; 968 969 USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_mid->mi_log_handle, 970 "usb_mid_devi_bind_driver: dip = 0x%p, if_num = 0x%x", dip, if_num); 971 972 name = kmem_zalloc(MAXNAMELEN, KM_SLEEP); 973 974 /* bind device to the driver */ 975 if (ndi_devi_bind_driver(dip, 0) != NDI_SUCCESS) { 976 /* if we fail to bind report an error */ 977 (void) usba_get_mfg_prod_sn_str(dip, name, MAXNAMELEN); 978 if (name[0] != '\0') { 979 if (!usb_owns_device(dip)) { 980 USB_DPRINTF_L1(DPRINT_MASK_ATTA, 981 usb_mid->mi_log_handle, 982 "no driver found for " 983 "interface %d (nodename: '%s') of %s", 984 if_num, ddi_node_name(dip), name); 985 } else { 986 USB_DPRINTF_L1(DPRINT_MASK_ATTA, 987 usb_mid->mi_log_handle, 988 "no driver found for device %s", name); 989 } 990 } else { 991 (void) ddi_pathname(dip, name); 992 USB_DPRINTF_L1(DPRINT_MASK_ATTA, 993 usb_mid->mi_log_handle, 994 "no driver found for device %s", name); 995 } 996 rval = USB_FAILURE; 997 } 998 999 kmem_free(name, MAXNAMELEN); 1000 1001 return (rval); 1002 } 1003 1004 1005 static void 1006 usb_mid_ugen_attach(usb_mid_t *usb_mid, boolean_t remove_children) 1007 { 1008 _NOTE(NO_COMPETING_THREADS_NOW); 1009 1010 if (usb_mid->mi_ugen_hdl == NULL) { 1011 usb_ugen_info_t usb_ugen_info; 1012 int rval; 1013 usb_ugen_hdl_t hdl; 1014 1015 USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_mid->mi_log_handle, 1016 "usb_mid_ugen_attach: get handle"); 1017 1018 bzero(&usb_ugen_info, sizeof (usb_ugen_info)); 1019 1020 usb_ugen_info.usb_ugen_flags = (remove_children ? 1021 USB_UGEN_REMOVE_CHILDREN : 0); 1022 usb_ugen_info.usb_ugen_minor_node_ugen_bits_mask = 1023 (dev_t)USB_MID_MINOR_UGEN_BITS_MASK; 1024 usb_ugen_info.usb_ugen_minor_node_instance_mask = 1025 (dev_t)~USB_MID_MINOR_UGEN_BITS_MASK; 1026 1027 mutex_exit(&usb_mid->mi_mutex); 1028 hdl = usb_ugen_get_hdl(usb_mid->mi_dip, 1029 &usb_ugen_info); 1030 1031 if ((rval = usb_ugen_attach(hdl, DDI_ATTACH)) != USB_SUCCESS) { 1032 USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_mid->mi_log_handle, 1033 "failed to create ugen support (%d)", rval); 1034 usb_ugen_release_hdl(hdl); 1035 1036 mutex_enter(&usb_mid->mi_mutex); 1037 } else { 1038 mutex_enter(&usb_mid->mi_mutex); 1039 usb_mid->mi_ugen_hdl = hdl; 1040 } 1041 } 1042 1043 #ifndef lint 1044 _NOTE(COMPETING_THREADS_NOW); 1045 #endif 1046 } 1047 1048 1049 /* 1050 * usb_mid_create_children: 1051 */ 1052 static void 1053 usb_mid_create_children(usb_mid_t *usb_mid) 1054 { 1055 usba_device_t *usba_device; 1056 uint_t n_ifs; 1057 uint_t i; 1058 dev_info_t *cdip; 1059 uint_t ugen_bound = 0; 1060 uint_t bound_children = 0; 1061 1062 usba_device = usba_get_usba_device(usb_mid->mi_dip); 1063 1064 USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_mid->mi_log_handle, 1065 "usb_mid_attach_child_drivers: port = %d, address = %d", 1066 usba_device->usb_port, usba_device->usb_addr); 1067 1068 if (usb_mid->mi_removed_children) { 1069 1070 return; 1071 } 1072 1073 n_ifs = usb_mid->mi_n_ifs; 1074 1075 USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_mid->mi_log_handle, 1076 "usb_mid_create_children: #interfaces = %d", n_ifs); 1077 1078 /* 1079 * create all children if not already present 1080 */ 1081 for (i = 0; i < n_ifs; i++) { 1082 if (usb_mid->mi_children_dips[i] != NULL) { 1083 if (i_ddi_node_state( 1084 usb_mid->mi_children_dips[i]) >= 1085 DS_BOUND) { 1086 bound_children++; 1087 } 1088 1089 continue; 1090 } 1091 1092 mutex_exit(&usb_mid->mi_mutex); 1093 cdip = usba_ready_interface_node(usb_mid->mi_dip, i); 1094 mutex_enter(&usb_mid->mi_mutex); 1095 if (cdip != NULL) { 1096 if (usb_mid_devi_bind_driver(usb_mid, cdip) == 1097 USB_SUCCESS) { 1098 bound_children++; 1099 if (strcmp(ddi_driver_name(cdip), 1100 "ugen") == 0) { 1101 ugen_bound++; 1102 } 1103 } 1104 1105 usb_mid->mi_children_dips[i] = cdip; 1106 1107 } 1108 } 1109 1110 usb_mid->mi_removed_children = (bound_children ? B_FALSE : B_TRUE); 1111 1112 /* 1113 * if there are no ugen interface children, create ugen support at 1114 * device level, use a separate thread because we may be at interrupt 1115 * level 1116 */ 1117 if ((ugen_bound == 0) && (usb_mid->mi_ugen_hdl == NULL)) { 1118 /* 1119 * we only need to remove the children if there are 1120 * multiple configurations which would fail if there 1121 * are child interfaces 1122 */ 1123 if ((usb_mid->mi_removed_children == B_FALSE) && 1124 (usba_device->usb_n_cfgs > 1)) { 1125 USB_DPRINTF_L1(DPRINT_MASK_ATTA, 1126 usb_mid->mi_log_handle, 1127 "can't support ugen for multiple " 1128 "configurations devices that have attached " 1129 "child interface drivers"); 1130 } else { 1131 usb_mid_ugen_attach(usb_mid, 1132 usb_mid->mi_removed_children); 1133 } 1134 } 1135 } 1136 1137 1138 /* 1139 * event support 1140 */ 1141 static int 1142 usb_mid_busop_get_eventcookie(dev_info_t *dip, 1143 dev_info_t *rdip, char *eventname, ddi_eventcookie_t *cookie) 1144 { 1145 usb_mid_t *usb_mid = usb_mid_obtain_state(dip); 1146 1147 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle, 1148 "usb_mid_busop_get_eventcookie: dip=0x%p, rdip=0x%p, " 1149 "event=%s", (void *)dip, (void *)rdip, eventname); 1150 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle, 1151 "(dip=%s%d rdip=%s%d)", 1152 ddi_driver_name(dip), ddi_get_instance(dip), 1153 ddi_driver_name(rdip), ddi_get_instance(rdip)); 1154 1155 /* return event cookie, iblock cookie, and level */ 1156 return (ndi_event_retrieve_cookie(usb_mid->mi_ndi_event_hdl, 1157 rdip, eventname, cookie, NDI_EVENT_NOPASS)); 1158 } 1159 1160 1161 static int 1162 usb_mid_busop_add_eventcall(dev_info_t *dip, 1163 dev_info_t *rdip, 1164 ddi_eventcookie_t cookie, 1165 void (*callback)(dev_info_t *dip, 1166 ddi_eventcookie_t cookie, void *arg, 1167 void *bus_impldata), 1168 void *arg, ddi_callback_id_t *cb_id) 1169 { 1170 usb_mid_t *usb_mid = usb_mid_obtain_state(dip); 1171 int ifno = usba_get_ifno(rdip); 1172 1173 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle, 1174 "usb_mid_busop_add_eventcall: dip=0x%p, rdip=0x%p " 1175 "cookie=0x%p, cb=0x%p, arg=0x%p", 1176 (void *)dip, (void *)rdip, (void *)cookie, (void *)callback, arg); 1177 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle, 1178 "(dip=%s%d rdip=%s%d event=%s)", 1179 ddi_driver_name(dip), ddi_get_instance(dip), 1180 ddi_driver_name(rdip), ddi_get_instance(rdip), 1181 ndi_event_cookie_to_name(usb_mid->mi_ndi_event_hdl, cookie)); 1182 1183 /* Set flag on children registering events */ 1184 switch (ndi_event_cookie_to_tag(usb_mid->mi_ndi_event_hdl, cookie)) { 1185 case USBA_EVENT_TAG_HOT_REMOVAL: 1186 mutex_enter(&usb_mid->mi_mutex); 1187 usb_mid->mi_child_events[ifno] |= 1188 USB_MID_CHILD_EVENT_DISCONNECT; 1189 mutex_exit(&usb_mid->mi_mutex); 1190 1191 break; 1192 case USBA_EVENT_TAG_PRE_SUSPEND: 1193 mutex_enter(&usb_mid->mi_mutex); 1194 usb_mid->mi_child_events[ifno] |= 1195 USB_MID_CHILD_EVENT_PRESUSPEND; 1196 mutex_exit(&usb_mid->mi_mutex); 1197 1198 break; 1199 default: 1200 1201 break; 1202 } 1203 /* add callback (perform registration) */ 1204 return (ndi_event_add_callback(usb_mid->mi_ndi_event_hdl, 1205 rdip, cookie, callback, arg, NDI_SLEEP, cb_id)); 1206 } 1207 1208 1209 static int 1210 usb_mid_busop_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id) 1211 { 1212 usb_mid_t *usb_mid = usb_mid_obtain_state(dip); 1213 ndi_event_callbacks_t *cb = (ndi_event_callbacks_t *)cb_id; 1214 1215 ASSERT(cb); 1216 1217 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle, 1218 "usb_mid_busop_remove_eventcall: dip=0x%p, rdip=0x%p " 1219 "cookie=0x%p", (void *)dip, cb->ndi_evtcb_dip, 1220 cb->ndi_evtcb_cookie); 1221 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle, 1222 "(dip=%s%d rdip=%s%d event=%s)", 1223 ddi_driver_name(dip), ddi_get_instance(dip), 1224 ddi_driver_name(cb->ndi_evtcb_dip), 1225 ddi_get_instance(cb->ndi_evtcb_dip), 1226 ndi_event_cookie_to_name(usb_mid->mi_ndi_event_hdl, 1227 cb->ndi_evtcb_cookie)); 1228 1229 /* remove event registration from our event set */ 1230 return (ndi_event_remove_callback(usb_mid->mi_ndi_event_hdl, cb_id)); 1231 } 1232 1233 1234 static int 1235 usb_mid_busop_post_event(dev_info_t *dip, 1236 dev_info_t *rdip, 1237 ddi_eventcookie_t cookie, 1238 void *bus_impldata) 1239 { 1240 usb_mid_t *usb_mid = usb_mid_obtain_state(dip); 1241 1242 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle, 1243 "usb_mid_busop_post_event: dip=0x%p, rdip=0x%p " 1244 "cookie=0x%p, impl=0x%p", 1245 (void *)dip, (void *)rdip, (void *)cookie, bus_impldata); 1246 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle, 1247 "(dip=%s%d rdip=%s%d event=%s)", 1248 ddi_driver_name(dip), ddi_get_instance(dip), 1249 ddi_driver_name(rdip), ddi_get_instance(rdip), 1250 ndi_event_cookie_to_name(usb_mid->mi_ndi_event_hdl, cookie)); 1251 1252 /* post event to all children registered for this event */ 1253 return (ndi_event_run_callbacks(usb_mid->mi_ndi_event_hdl, rdip, 1254 cookie, bus_impldata)); 1255 } 1256 1257 1258 /* 1259 * usb_mid_restore_device_state 1260 * set the original configuration of the device 1261 */ 1262 static int 1263 usb_mid_restore_device_state(dev_info_t *dip, usb_mid_t *usb_mid) 1264 { 1265 usb_mid_power_t *midpm; 1266 1267 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle, 1268 "usb_mid_restore_device_state: usb_mid = %p", usb_mid); 1269 1270 mutex_enter(&usb_mid->mi_mutex); 1271 midpm = usb_mid->mi_pm; 1272 mutex_exit(&usb_mid->mi_mutex); 1273 1274 /* First bring the device to full power */ 1275 (void) pm_busy_component(dip, 0); 1276 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 1277 1278 if (usb_check_same_device(dip, usb_mid->mi_log_handle, USB_LOG_L0, 1279 DPRINT_MASK_EVENTS, USB_CHK_VIDPID, NULL) != USB_SUCCESS) { 1280 1281 /* change the device state from suspended to disconnected */ 1282 mutex_enter(&usb_mid->mi_mutex); 1283 usb_mid->mi_dev_state = USB_DEV_DISCONNECTED; 1284 mutex_exit(&usb_mid->mi_mutex); 1285 (void) pm_idle_component(dip, 0); 1286 1287 return (USB_FAILURE); 1288 } 1289 1290 /* 1291 * if the device had remote wakeup earlier, 1292 * enable it again 1293 */ 1294 if (midpm->mip_wakeup_enabled) { 1295 (void) usb_handle_remote_wakeup(usb_mid->mi_dip, 1296 USB_REMOTE_WAKEUP_ENABLE); 1297 } 1298 1299 mutex_enter(&usb_mid->mi_mutex); 1300 usb_mid->mi_dev_state = USB_DEV_ONLINE; 1301 mutex_exit(&usb_mid->mi_mutex); 1302 1303 (void) pm_idle_component(dip, 0); 1304 1305 return (USB_SUCCESS); 1306 } 1307 1308 1309 /* 1310 * usb_mid_event_cb() 1311 * handle disconnect and connect events 1312 */ 1313 static void 1314 usb_mid_event_cb(dev_info_t *dip, ddi_eventcookie_t cookie, 1315 void *arg, void *bus_impldata) 1316 { 1317 int i, tag; 1318 usb_mid_t *usb_mid = usb_mid_obtain_state(dip); 1319 dev_info_t *child_dip; 1320 ddi_eventcookie_t rm_cookie, ins_cookie, suspend_cookie, resume_cookie; 1321 1322 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle, 1323 "usb_mid_event_cb: dip=0x%p, cookie=0x%p, " 1324 "arg=0x%p, impl=0x%p", 1325 (void *)dip, (void *)cookie, arg, bus_impldata); 1326 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle, 1327 "(dip=%s%d event=%s)", 1328 ddi_driver_name(dip), ddi_get_instance(dip), 1329 ndi_event_cookie_to_name(usb_mid->mi_ndi_event_hdl, cookie)); 1330 1331 tag = NDI_EVENT_TAG(cookie); 1332 rm_cookie = ndi_event_tag_to_cookie( 1333 usb_mid->mi_ndi_event_hdl, USBA_EVENT_TAG_HOT_REMOVAL); 1334 suspend_cookie = ndi_event_tag_to_cookie( 1335 usb_mid->mi_ndi_event_hdl, USBA_EVENT_TAG_PRE_SUSPEND); 1336 ins_cookie = ndi_event_tag_to_cookie( 1337 usb_mid->mi_ndi_event_hdl, USBA_EVENT_TAG_HOT_INSERTION); 1338 resume_cookie = ndi_event_tag_to_cookie( 1339 usb_mid->mi_ndi_event_hdl, USBA_EVENT_TAG_POST_RESUME); 1340 1341 mutex_enter(&usb_mid->mi_mutex); 1342 switch (tag) { 1343 case USBA_EVENT_TAG_HOT_REMOVAL: 1344 if (usb_mid->mi_dev_state == USB_DEV_DISCONNECTED) { 1345 USB_DPRINTF_L2(DPRINT_MASK_EVENTS, 1346 usb_mid->mi_log_handle, 1347 "usb_mid_event_cb: Device already disconnected"); 1348 } else { 1349 /* we are disconnected so set our state now */ 1350 usb_mid->mi_dev_state = USB_DEV_DISCONNECTED; 1351 for (i = 0; i < usb_mid->mi_n_ifs; i++) { 1352 usb_mid->mi_child_events[i] &= ~ 1353 USB_MID_CHILD_EVENT_DISCONNECT; 1354 } 1355 mutex_exit(&usb_mid->mi_mutex); 1356 1357 /* pass disconnect event to all the children */ 1358 (void) ndi_event_run_callbacks( 1359 usb_mid->mi_ndi_event_hdl, NULL, 1360 rm_cookie, bus_impldata); 1361 1362 if (usb_mid->mi_ugen_hdl) { 1363 (void) usb_ugen_disconnect_ev_cb( 1364 usb_mid->mi_ugen_hdl); 1365 } 1366 mutex_enter(&usb_mid->mi_mutex); 1367 } 1368 break; 1369 case USBA_EVENT_TAG_PRE_SUSPEND: 1370 /* set our state *after* suspending children */ 1371 mutex_exit(&usb_mid->mi_mutex); 1372 1373 /* pass pre_suspend event to all the children */ 1374 (void) ndi_event_run_callbacks(usb_mid->mi_ndi_event_hdl, 1375 NULL, suspend_cookie, bus_impldata); 1376 1377 mutex_enter(&usb_mid->mi_mutex); 1378 for (i = 0; i < usb_mid->mi_n_ifs; i++) { 1379 usb_mid->mi_child_events[i] &= ~ 1380 USB_MID_CHILD_EVENT_PRESUSPEND; 1381 } 1382 break; 1383 case USBA_EVENT_TAG_HOT_INSERTION: 1384 mutex_exit(&usb_mid->mi_mutex); 1385 if (usb_mid_restore_device_state(dip, usb_mid) == USB_SUCCESS) { 1386 1387 /* 1388 * Check to see if this child has missed the disconnect 1389 * event before it registered for event cb 1390 */ 1391 mutex_enter(&usb_mid->mi_mutex); 1392 for (i = 0; i < usb_mid->mi_n_ifs; i++) { 1393 if (usb_mid->mi_child_events[i] & 1394 USB_MID_CHILD_EVENT_DISCONNECT) { 1395 usb_mid->mi_child_events[i] &= 1396 ~USB_MID_CHILD_EVENT_DISCONNECT; 1397 child_dip = 1398 usb_mid->mi_children_dips[i]; 1399 mutex_exit(&usb_mid->mi_mutex); 1400 1401 /* post the missed disconnect */ 1402 (void) ndi_event_do_callback( 1403 usb_mid->mi_ndi_event_hdl, 1404 child_dip, 1405 rm_cookie, 1406 bus_impldata); 1407 mutex_enter(&usb_mid->mi_mutex); 1408 } 1409 } 1410 mutex_exit(&usb_mid->mi_mutex); 1411 1412 /* pass reconnect event to all the children */ 1413 (void) ndi_event_run_callbacks( 1414 usb_mid->mi_ndi_event_hdl, NULL, 1415 ins_cookie, bus_impldata); 1416 1417 if (usb_mid->mi_ugen_hdl) { 1418 (void) usb_ugen_reconnect_ev_cb( 1419 usb_mid->mi_ugen_hdl); 1420 } 1421 } 1422 mutex_enter(&usb_mid->mi_mutex); 1423 break; 1424 case USBA_EVENT_TAG_POST_RESUME: 1425 /* 1426 * Check to see if this child has missed the pre-suspend 1427 * event before it registered for event cb 1428 */ 1429 for (i = 0; i < usb_mid->mi_n_ifs; i++) { 1430 if (usb_mid->mi_child_events[i] & 1431 USB_MID_CHILD_EVENT_PRESUSPEND) { 1432 usb_mid->mi_child_events[i] &= 1433 ~USB_MID_CHILD_EVENT_PRESUSPEND; 1434 child_dip = usb_mid->mi_children_dips[i]; 1435 mutex_exit(&usb_mid->mi_mutex); 1436 1437 /* post the missed pre-suspend event */ 1438 (void) ndi_event_do_callback( 1439 usb_mid->mi_ndi_event_hdl, 1440 child_dip, suspend_cookie, 1441 bus_impldata); 1442 mutex_enter(&usb_mid->mi_mutex); 1443 } 1444 } 1445 mutex_exit(&usb_mid->mi_mutex); 1446 1447 /* pass post_resume event to all the children */ 1448 (void) ndi_event_run_callbacks(usb_mid->mi_ndi_event_hdl, 1449 NULL, resume_cookie, bus_impldata); 1450 1451 mutex_enter(&usb_mid->mi_mutex); 1452 break; 1453 } 1454 mutex_exit(&usb_mid->mi_mutex); 1455 1456 } 1457 1458 1459 /* 1460 * register and unregister for events from our parent 1461 * 1462 * Note: usb_mid doesn't use the cookie fields in usba_device structure. 1463 * They are used/shared by children of usb_mid. 1464 */ 1465 static void 1466 usb_mid_register_events(usb_mid_t *usb_mid) 1467 { 1468 int rval; 1469 usba_evdata_t *evdata; 1470 ddi_eventcookie_t cookie; 1471 1472 USB_DPRINTF_L4(DPRINT_MASK_PM, usb_mid->mi_log_handle, 1473 "usb_mid_register_events:"); 1474 1475 evdata = usba_get_evdata(usb_mid->mi_dip); 1476 1477 /* get event cookie, discard level and icookie for now */ 1478 rval = ddi_get_eventcookie(usb_mid->mi_dip, DDI_DEVI_REMOVE_EVENT, 1479 &cookie); 1480 1481 if (rval == DDI_SUCCESS) { 1482 rval = ddi_add_event_handler(usb_mid->mi_dip, 1483 cookie, usb_mid_event_cb, NULL, &evdata->ev_rm_cb_id); 1484 1485 if (rval != DDI_SUCCESS) { 1486 1487 goto fail; 1488 } 1489 } 1490 rval = ddi_get_eventcookie(usb_mid->mi_dip, DDI_DEVI_INSERT_EVENT, 1491 &cookie); 1492 if (rval == DDI_SUCCESS) { 1493 rval = ddi_add_event_handler(usb_mid->mi_dip, 1494 cookie, usb_mid_event_cb, NULL, &evdata->ev_ins_cb_id); 1495 1496 if (rval != DDI_SUCCESS) { 1497 1498 goto fail; 1499 } 1500 } 1501 rval = ddi_get_eventcookie(usb_mid->mi_dip, USBA_PRE_SUSPEND_EVENT, 1502 &cookie); 1503 if (rval == DDI_SUCCESS) { 1504 rval = ddi_add_event_handler(usb_mid->mi_dip, 1505 cookie, usb_mid_event_cb, NULL, &evdata->ev_suspend_cb_id); 1506 1507 if (rval != DDI_SUCCESS) { 1508 1509 goto fail; 1510 } 1511 } 1512 rval = ddi_get_eventcookie(usb_mid->mi_dip, USBA_POST_RESUME_EVENT, 1513 &cookie); 1514 if (rval == DDI_SUCCESS) { 1515 rval = ddi_add_event_handler(usb_mid->mi_dip, 1516 cookie, usb_mid_event_cb, NULL, 1517 &evdata->ev_resume_cb_id); 1518 1519 if (rval != DDI_SUCCESS) { 1520 1521 goto fail; 1522 } 1523 } 1524 1525 return; 1526 1527 1528 fail: 1529 usb_mid_unregister_events(usb_mid); 1530 1531 } 1532 1533 1534 static void 1535 usb_mid_unregister_events(usb_mid_t *usb_mid) 1536 { 1537 int rval; 1538 usba_evdata_t *evdata; 1539 usba_device_t *usba_device = usba_get_usba_device(usb_mid->mi_dip); 1540 1541 USB_DPRINTF_L4(DPRINT_MASK_PM, usb_mid->mi_log_handle, 1542 "usb_mid_unregister_events:"); 1543 1544 evdata = usba_get_evdata(usb_mid->mi_dip); 1545 if (evdata) { 1546 if (evdata->ev_rm_cb_id) { 1547 rval = ddi_remove_event_handler(evdata->ev_rm_cb_id); 1548 ASSERT(rval == DDI_SUCCESS); 1549 } 1550 1551 if (evdata->ev_ins_cb_id) { 1552 rval = ddi_remove_event_handler(evdata->ev_ins_cb_id); 1553 ASSERT(rval == DDI_SUCCESS); 1554 } 1555 1556 if (evdata->ev_resume_cb_id) { 1557 rval = 1558 ddi_remove_event_handler(evdata->ev_resume_cb_id); 1559 ASSERT(rval == DDI_SUCCESS); 1560 } 1561 1562 if (evdata->ev_suspend_cb_id) { 1563 rval = 1564 ddi_remove_event_handler(evdata->ev_suspend_cb_id); 1565 ASSERT(rval == DDI_SUCCESS); 1566 } 1567 } 1568 1569 /* clear event data for children, required for cfgmadm unconfigure */ 1570 usba_free_evdata(usba_device->usb_evdata); 1571 usba_device->usb_evdata = NULL; 1572 usba_device->rm_cookie = NULL; 1573 usba_device->ins_cookie = NULL; 1574 usba_device->suspend_cookie = NULL; 1575 usba_device->resume_cookie = NULL; 1576 } 1577 1578 1579 /* 1580 * create the pm components required for power management 1581 */ 1582 static void 1583 usb_mid_create_pm_components(dev_info_t *dip, usb_mid_t *usb_mid) 1584 { 1585 usb_mid_power_t *midpm; 1586 uint_t pwr_states; 1587 1588 USB_DPRINTF_L4(DPRINT_MASK_PM, usb_mid->mi_log_handle, 1589 "usb_mid_create_pm_components: Begin"); 1590 1591 /* Allocate the PM state structure */ 1592 midpm = kmem_zalloc(sizeof (usb_mid_power_t), KM_SLEEP); 1593 1594 mutex_enter(&usb_mid->mi_mutex); 1595 usb_mid->mi_pm = midpm; 1596 midpm->mip_usb_mid = usb_mid; 1597 midpm->mip_pm_capabilities = 0; /* XXXX should this be 0?? */ 1598 midpm->mip_current_power = USB_DEV_OS_FULL_PWR; 1599 mutex_exit(&usb_mid->mi_mutex); 1600 1601 /* 1602 * By not enabling parental notification, PM enforces 1603 * "strict parental dependency" meaning, usb_mid won't 1604 * power off until any of its children are in full power. 1605 */ 1606 1607 /* 1608 * there are 3 scenarios: 1609 * 1. a well behaved device should have remote wakeup 1610 * at interface and device level. If the interface 1611 * wakes up, usb_mid will wake up 1612 * 2. if the device doesn't have remote wake up and 1613 * the interface has, PM will still work, ie. 1614 * the interfaces wakes up and usb_mid wakes up 1615 * 3. if neither the interface nor device has remote 1616 * wakeup, the interface will wake up when it is opened 1617 * and goes to sleep after being closed for a while 1618 * In this case usb_mid should also go to sleep shortly 1619 * thereafter 1620 * In all scenarios it doesn't really matter whether 1621 * remote wakeup at the device level is enabled or not 1622 * but we do it anyways 1623 */ 1624 if (usb_handle_remote_wakeup(dip, USB_REMOTE_WAKEUP_ENABLE) == 1625 USB_SUCCESS) { 1626 USB_DPRINTF_L3(DPRINT_MASK_PM, usb_mid->mi_log_handle, 1627 "usb_mid_create_pm_components: " 1628 "Remote Wakeup Enabled"); 1629 midpm->mip_wakeup_enabled = 1; 1630 } 1631 1632 if (usb_create_pm_components(dip, &pwr_states) == 1633 USB_SUCCESS) { 1634 midpm->mip_pwr_states = (uint8_t)pwr_states; 1635 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 1636 } 1637 1638 USB_DPRINTF_L4(DPRINT_MASK_PM, usb_mid->mi_log_handle, 1639 "usb_mid_create_pm_components: End"); 1640 } 1641 1642 1643 /* 1644 * usb_mid_obtain_state: 1645 */ 1646 usb_mid_t * 1647 usb_mid_obtain_state(dev_info_t *dip) 1648 { 1649 int instance = ddi_get_instance(dip); 1650 usb_mid_t *statep = ddi_get_soft_state(usb_mid_statep, instance); 1651 1652 ASSERT(statep != NULL); 1653 1654 return (statep); 1655 } 1656 1657 1658 /* 1659 * ugen support 1660 */ 1661 /* ARGSUSED3 */ 1662 static int 1663 usb_mid_open(dev_t *devp, int flags, int otyp, cred_t *credp) 1664 { 1665 struct usb_mid *usb_mid; 1666 int rval; 1667 1668 if ((usb_mid = ddi_get_soft_state(usb_mid_statep, 1669 USB_MID_MINOR_TO_INSTANCE(getminor(*devp)))) == NULL) { 1670 1671 return (ENXIO); 1672 } 1673 1674 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, usb_mid->mi_log_handle, 1675 "usb_mid_open: usb_mid = 0x%p *devp = 0x%lx", usb_mid, *devp); 1676 1677 /* First bring the device to full power */ 1678 (void) pm_busy_component(usb_mid->mi_dip, 0); 1679 (void) pm_raise_power(usb_mid->mi_dip, 0, USB_DEV_OS_FULL_PWR); 1680 1681 1682 rval = usb_ugen_open(usb_mid->mi_ugen_hdl, devp, flags, otyp, 1683 credp); 1684 if (rval) { 1685 (void) pm_idle_component(usb_mid->mi_dip, 0); 1686 } else { 1687 /* 1688 * since all ugen opens are exclusive we can count the 1689 * opens 1690 */ 1691 mutex_enter(&usb_mid->mi_mutex); 1692 usb_mid->mi_ugen_open_count++; 1693 mutex_exit(&usb_mid->mi_mutex); 1694 } 1695 1696 return (rval); 1697 } 1698 1699 1700 /* ARGSUSED */ 1701 static int 1702 usb_mid_close(dev_t dev, int flag, int otyp, cred_t *credp) 1703 { 1704 struct usb_mid *usb_mid; 1705 int rval; 1706 1707 if ((usb_mid = ddi_get_soft_state(usb_mid_statep, 1708 USB_MID_MINOR_TO_INSTANCE(getminor(dev)))) == NULL) { 1709 1710 return (ENXIO); 1711 } 1712 1713 rval = usb_ugen_close(usb_mid->mi_ugen_hdl, dev, flag, otyp, 1714 credp); 1715 if (rval == 0) { 1716 (void) pm_idle_component(usb_mid->mi_dip, 0); 1717 mutex_enter(&usb_mid->mi_mutex); 1718 usb_mid->mi_ugen_open_count--; 1719 mutex_exit(&usb_mid->mi_mutex); 1720 } 1721 1722 return (rval); 1723 } 1724 1725 1726 static int 1727 usb_mid_read(dev_t dev, struct uio *uio, cred_t *credp) 1728 { 1729 struct usb_mid *usb_mid; 1730 1731 if ((usb_mid = ddi_get_soft_state(usb_mid_statep, 1732 USB_MID_MINOR_TO_INSTANCE(getminor(dev)))) == NULL) { 1733 1734 return (ENXIO); 1735 } 1736 1737 return (usb_ugen_read(usb_mid->mi_ugen_hdl, dev, uio, credp)); 1738 } 1739 1740 1741 static int 1742 usb_mid_write(dev_t dev, struct uio *uio, cred_t *credp) 1743 { 1744 struct usb_mid *usb_mid; 1745 1746 if ((usb_mid = ddi_get_soft_state(usb_mid_statep, 1747 USB_MID_MINOR_TO_INSTANCE(getminor(dev)))) == NULL) { 1748 1749 return (ENXIO); 1750 } 1751 1752 return (usb_ugen_write(usb_mid->mi_ugen_hdl, dev, uio, credp)); 1753 } 1754 1755 1756 static int 1757 usb_mid_poll(dev_t dev, short events, int anyyet, short *reventsp, 1758 struct pollhead **phpp) 1759 { 1760 struct usb_mid *usb_mid; 1761 1762 if ((usb_mid = ddi_get_soft_state(usb_mid_statep, 1763 USB_MID_MINOR_TO_INSTANCE(getminor(dev)))) == NULL) { 1764 1765 return (ENXIO); 1766 } 1767 1768 return (usb_ugen_poll(usb_mid->mi_ugen_hdl, dev, events, 1769 anyyet, reventsp, phpp)); 1770 } 1771