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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 * 22 * Copyright 2005 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_L1(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_L1(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_L1(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 _NOTE(COMPETING_THREADS_NOW); 1044 } 1045 1046 1047 /* 1048 * usb_mid_create_children: 1049 */ 1050 static void 1051 usb_mid_create_children(usb_mid_t *usb_mid) 1052 { 1053 usba_device_t *usba_device; 1054 uint_t n_ifs; 1055 uint_t i; 1056 dev_info_t *cdip; 1057 uint_t ugen_bound = 0; 1058 uint_t bound_children = 0; 1059 1060 usba_device = usba_get_usba_device(usb_mid->mi_dip); 1061 1062 USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_mid->mi_log_handle, 1063 "usb_mid_attach_child_drivers: port = %d, address = %d", 1064 usba_device->usb_port, usba_device->usb_addr); 1065 1066 if (usb_mid->mi_removed_children) { 1067 1068 return; 1069 } 1070 1071 n_ifs = usb_mid->mi_n_ifs; 1072 1073 USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_mid->mi_log_handle, 1074 "usb_mid_create_children: #interfaces = %d", n_ifs); 1075 1076 /* 1077 * create all children if not already present 1078 */ 1079 for (i = 0; i < n_ifs; i++) { 1080 if (usb_mid->mi_children_dips[i] != NULL) { 1081 if (i_ddi_node_state( 1082 usb_mid->mi_children_dips[i]) >= 1083 DS_BOUND) { 1084 bound_children++; 1085 } 1086 1087 continue; 1088 } 1089 1090 mutex_exit(&usb_mid->mi_mutex); 1091 cdip = usba_ready_interface_node(usb_mid->mi_dip, i); 1092 mutex_enter(&usb_mid->mi_mutex); 1093 if (cdip != NULL) { 1094 if (usb_mid_devi_bind_driver(usb_mid, cdip) == 1095 USB_SUCCESS) { 1096 bound_children++; 1097 if (strcmp(ddi_driver_name(cdip), 1098 "ugen") == 0) { 1099 ugen_bound++; 1100 } 1101 } 1102 1103 usb_mid->mi_children_dips[i] = cdip; 1104 1105 } 1106 } 1107 1108 usb_mid->mi_removed_children = (bound_children ? B_FALSE : B_TRUE); 1109 1110 /* 1111 * if there are no ugen interface children, create ugen support at 1112 * device level, use a separate thread because we may be at interrupt 1113 * level 1114 */ 1115 if ((ugen_bound == 0) && (usb_mid->mi_ugen_hdl == NULL)) { 1116 /* 1117 * we only need to remove the children if there are 1118 * multiple configurations which would fail if there 1119 * are child interfaces 1120 */ 1121 if ((usb_mid->mi_removed_children == B_FALSE) && 1122 (usba_device->usb_n_cfgs > 1)) { 1123 USB_DPRINTF_L1(DPRINT_MASK_ATTA, 1124 usb_mid->mi_log_handle, 1125 "can't support ugen for multiple " 1126 "configurations devices that have attached " 1127 "child interface drivers"); 1128 } else { 1129 usb_mid_ugen_attach(usb_mid, 1130 usb_mid->mi_removed_children); 1131 } 1132 } 1133 } 1134 1135 1136 /* 1137 * event support 1138 */ 1139 static int 1140 usb_mid_busop_get_eventcookie(dev_info_t *dip, 1141 dev_info_t *rdip, char *eventname, ddi_eventcookie_t *cookie) 1142 { 1143 usb_mid_t *usb_mid = usb_mid_obtain_state(dip); 1144 1145 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle, 1146 "usb_mid_busop_get_eventcookie: dip=0x%p, rdip=0x%p, " 1147 "event=%s", (void *)dip, (void *)rdip, eventname); 1148 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle, 1149 "(dip=%s%d rdip=%s%d)", 1150 ddi_driver_name(dip), ddi_get_instance(dip), 1151 ddi_driver_name(rdip), ddi_get_instance(rdip)); 1152 1153 /* return event cookie, iblock cookie, and level */ 1154 return (ndi_event_retrieve_cookie(usb_mid->mi_ndi_event_hdl, 1155 rdip, eventname, cookie, NDI_EVENT_NOPASS)); 1156 } 1157 1158 1159 static int 1160 usb_mid_busop_add_eventcall(dev_info_t *dip, 1161 dev_info_t *rdip, 1162 ddi_eventcookie_t cookie, 1163 void (*callback)(dev_info_t *dip, 1164 ddi_eventcookie_t cookie, void *arg, 1165 void *bus_impldata), 1166 void *arg, ddi_callback_id_t *cb_id) 1167 { 1168 usb_mid_t *usb_mid = usb_mid_obtain_state(dip); 1169 int ifno = usba_get_ifno(rdip); 1170 1171 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle, 1172 "usb_mid_busop_add_eventcall: dip=0x%p, rdip=0x%p " 1173 "cookie=0x%p, cb=0x%p, arg=0x%p", 1174 (void *)dip, (void *)rdip, (void *)cookie, (void *)callback, arg); 1175 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle, 1176 "(dip=%s%d rdip=%s%d event=%s)", 1177 ddi_driver_name(dip), ddi_get_instance(dip), 1178 ddi_driver_name(rdip), ddi_get_instance(rdip), 1179 ndi_event_cookie_to_name(usb_mid->mi_ndi_event_hdl, cookie)); 1180 1181 /* Set flag on children registering events */ 1182 switch (ndi_event_cookie_to_tag(usb_mid->mi_ndi_event_hdl, cookie)) { 1183 case USBA_EVENT_TAG_HOT_REMOVAL: 1184 mutex_enter(&usb_mid->mi_mutex); 1185 usb_mid->mi_child_events[ifno] |= 1186 USB_MID_CHILD_EVENT_DISCONNECT; 1187 mutex_exit(&usb_mid->mi_mutex); 1188 1189 break; 1190 case USBA_EVENT_TAG_PRE_SUSPEND: 1191 mutex_enter(&usb_mid->mi_mutex); 1192 usb_mid->mi_child_events[ifno] |= 1193 USB_MID_CHILD_EVENT_PRESUSPEND; 1194 mutex_exit(&usb_mid->mi_mutex); 1195 1196 break; 1197 default: 1198 1199 break; 1200 } 1201 /* add callback (perform registration) */ 1202 return (ndi_event_add_callback(usb_mid->mi_ndi_event_hdl, 1203 rdip, cookie, callback, arg, NDI_SLEEP, cb_id)); 1204 } 1205 1206 1207 static int 1208 usb_mid_busop_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id) 1209 { 1210 usb_mid_t *usb_mid = usb_mid_obtain_state(dip); 1211 ndi_event_callbacks_t *cb = (ndi_event_callbacks_t *)cb_id; 1212 1213 ASSERT(cb); 1214 1215 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle, 1216 "usb_mid_busop_remove_eventcall: dip=0x%p, rdip=0x%p " 1217 "cookie=0x%p", (void *)dip, cb->ndi_evtcb_dip, 1218 cb->ndi_evtcb_cookie); 1219 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle, 1220 "(dip=%s%d rdip=%s%d event=%s)", 1221 ddi_driver_name(dip), ddi_get_instance(dip), 1222 ddi_driver_name(cb->ndi_evtcb_dip), 1223 ddi_get_instance(cb->ndi_evtcb_dip), 1224 ndi_event_cookie_to_name(usb_mid->mi_ndi_event_hdl, 1225 cb->ndi_evtcb_cookie)); 1226 1227 /* remove event registration from our event set */ 1228 return (ndi_event_remove_callback(usb_mid->mi_ndi_event_hdl, cb_id)); 1229 } 1230 1231 1232 static int 1233 usb_mid_busop_post_event(dev_info_t *dip, 1234 dev_info_t *rdip, 1235 ddi_eventcookie_t cookie, 1236 void *bus_impldata) 1237 { 1238 usb_mid_t *usb_mid = usb_mid_obtain_state(dip); 1239 1240 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle, 1241 "usb_mid_busop_post_event: dip=0x%p, rdip=0x%p " 1242 "cookie=0x%p, impl=0x%p", 1243 (void *)dip, (void *)rdip, (void *)cookie, bus_impldata); 1244 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle, 1245 "(dip=%s%d rdip=%s%d event=%s)", 1246 ddi_driver_name(dip), ddi_get_instance(dip), 1247 ddi_driver_name(rdip), ddi_get_instance(rdip), 1248 ndi_event_cookie_to_name(usb_mid->mi_ndi_event_hdl, cookie)); 1249 1250 /* post event to all children registered for this event */ 1251 return (ndi_event_run_callbacks(usb_mid->mi_ndi_event_hdl, rdip, 1252 cookie, bus_impldata)); 1253 } 1254 1255 1256 /* 1257 * usb_mid_restore_device_state 1258 * set the original configuration of the device 1259 */ 1260 static int 1261 usb_mid_restore_device_state(dev_info_t *dip, usb_mid_t *usb_mid) 1262 { 1263 usb_mid_power_t *midpm; 1264 1265 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle, 1266 "usb_mid_restore_device_state: usb_mid = %p", usb_mid); 1267 1268 mutex_enter(&usb_mid->mi_mutex); 1269 midpm = usb_mid->mi_pm; 1270 mutex_exit(&usb_mid->mi_mutex); 1271 1272 /* First bring the device to full power */ 1273 (void) pm_busy_component(dip, 0); 1274 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 1275 1276 if (usb_check_same_device(dip, usb_mid->mi_log_handle, USB_LOG_L0, 1277 DPRINT_MASK_EVENTS, USB_CHK_VIDPID, NULL) != USB_SUCCESS) { 1278 1279 /* change the device state from suspended to disconnected */ 1280 mutex_enter(&usb_mid->mi_mutex); 1281 usb_mid->mi_dev_state = USB_DEV_DISCONNECTED; 1282 mutex_exit(&usb_mid->mi_mutex); 1283 (void) pm_idle_component(dip, 0); 1284 1285 return (USB_FAILURE); 1286 } 1287 1288 /* 1289 * if the device had remote wakeup earlier, 1290 * enable it again 1291 */ 1292 if (midpm->mip_wakeup_enabled) { 1293 (void) usb_handle_remote_wakeup(usb_mid->mi_dip, 1294 USB_REMOTE_WAKEUP_ENABLE); 1295 } 1296 1297 mutex_enter(&usb_mid->mi_mutex); 1298 usb_mid->mi_dev_state = USB_DEV_ONLINE; 1299 mutex_exit(&usb_mid->mi_mutex); 1300 1301 (void) pm_idle_component(dip, 0); 1302 1303 return (USB_SUCCESS); 1304 } 1305 1306 1307 /* 1308 * usb_mid_event_cb() 1309 * handle disconnect and connect events 1310 */ 1311 static void 1312 usb_mid_event_cb(dev_info_t *dip, ddi_eventcookie_t cookie, 1313 void *arg, void *bus_impldata) 1314 { 1315 int i, tag; 1316 usb_mid_t *usb_mid = usb_mid_obtain_state(dip); 1317 dev_info_t *child_dip; 1318 ddi_eventcookie_t rm_cookie, ins_cookie, suspend_cookie, resume_cookie; 1319 1320 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle, 1321 "usb_mid_event_cb: dip=0x%p, cookie=0x%p, " 1322 "arg=0x%p, impl=0x%p", 1323 (void *)dip, (void *)cookie, arg, bus_impldata); 1324 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle, 1325 "(dip=%s%d event=%s)", 1326 ddi_driver_name(dip), ddi_get_instance(dip), 1327 ndi_event_cookie_to_name(usb_mid->mi_ndi_event_hdl, cookie)); 1328 1329 tag = NDI_EVENT_TAG(cookie); 1330 rm_cookie = ndi_event_tag_to_cookie( 1331 usb_mid->mi_ndi_event_hdl, USBA_EVENT_TAG_HOT_REMOVAL); 1332 suspend_cookie = ndi_event_tag_to_cookie( 1333 usb_mid->mi_ndi_event_hdl, USBA_EVENT_TAG_PRE_SUSPEND); 1334 ins_cookie = ndi_event_tag_to_cookie( 1335 usb_mid->mi_ndi_event_hdl, USBA_EVENT_TAG_HOT_INSERTION); 1336 resume_cookie = ndi_event_tag_to_cookie( 1337 usb_mid->mi_ndi_event_hdl, USBA_EVENT_TAG_POST_RESUME); 1338 1339 mutex_enter(&usb_mid->mi_mutex); 1340 switch (tag) { 1341 case USBA_EVENT_TAG_HOT_REMOVAL: 1342 if (usb_mid->mi_dev_state == USB_DEV_DISCONNECTED) { 1343 USB_DPRINTF_L2(DPRINT_MASK_EVENTS, 1344 usb_mid->mi_log_handle, 1345 "usb_mid_event_cb: Device already disconnected"); 1346 } else { 1347 /* we are disconnected so set our state now */ 1348 usb_mid->mi_dev_state = USB_DEV_DISCONNECTED; 1349 for (i = 0; i < usb_mid->mi_n_ifs; i++) { 1350 usb_mid->mi_child_events[i] &= ~ 1351 USB_MID_CHILD_EVENT_DISCONNECT; 1352 } 1353 mutex_exit(&usb_mid->mi_mutex); 1354 1355 /* pass disconnect event to all the children */ 1356 (void) ndi_event_run_callbacks( 1357 usb_mid->mi_ndi_event_hdl, NULL, 1358 rm_cookie, bus_impldata); 1359 1360 if (usb_mid->mi_ugen_hdl) { 1361 (void) usb_ugen_disconnect_ev_cb( 1362 usb_mid->mi_ugen_hdl); 1363 } 1364 mutex_enter(&usb_mid->mi_mutex); 1365 } 1366 break; 1367 case USBA_EVENT_TAG_PRE_SUSPEND: 1368 /* set our state *after* suspending children */ 1369 mutex_exit(&usb_mid->mi_mutex); 1370 1371 /* pass pre_suspend event to all the children */ 1372 (void) ndi_event_run_callbacks(usb_mid->mi_ndi_event_hdl, 1373 NULL, suspend_cookie, bus_impldata); 1374 1375 mutex_enter(&usb_mid->mi_mutex); 1376 for (i = 0; i < usb_mid->mi_n_ifs; i++) { 1377 usb_mid->mi_child_events[i] &= ~ 1378 USB_MID_CHILD_EVENT_PRESUSPEND; 1379 } 1380 break; 1381 case USBA_EVENT_TAG_HOT_INSERTION: 1382 mutex_exit(&usb_mid->mi_mutex); 1383 if (usb_mid_restore_device_state(dip, usb_mid) == USB_SUCCESS) { 1384 1385 /* 1386 * Check to see if this child has missed the disconnect 1387 * event before it registered for event cb 1388 */ 1389 mutex_enter(&usb_mid->mi_mutex); 1390 for (i = 0; i < usb_mid->mi_n_ifs; i++) { 1391 if (usb_mid->mi_child_events[i] & 1392 USB_MID_CHILD_EVENT_DISCONNECT) { 1393 usb_mid->mi_child_events[i] &= 1394 ~USB_MID_CHILD_EVENT_DISCONNECT; 1395 child_dip = 1396 usb_mid->mi_children_dips[i]; 1397 mutex_exit(&usb_mid->mi_mutex); 1398 1399 /* post the missed disconnect */ 1400 (void) ndi_event_do_callback( 1401 usb_mid->mi_ndi_event_hdl, 1402 child_dip, 1403 rm_cookie, 1404 bus_impldata); 1405 mutex_enter(&usb_mid->mi_mutex); 1406 } 1407 } 1408 mutex_exit(&usb_mid->mi_mutex); 1409 1410 /* pass reconnect event to all the children */ 1411 (void) ndi_event_run_callbacks( 1412 usb_mid->mi_ndi_event_hdl, NULL, 1413 ins_cookie, bus_impldata); 1414 1415 if (usb_mid->mi_ugen_hdl) { 1416 (void) usb_ugen_reconnect_ev_cb( 1417 usb_mid->mi_ugen_hdl); 1418 } 1419 } 1420 mutex_enter(&usb_mid->mi_mutex); 1421 break; 1422 case USBA_EVENT_TAG_POST_RESUME: 1423 /* 1424 * Check to see if this child has missed the pre-suspend 1425 * event before it registered for event cb 1426 */ 1427 for (i = 0; i < usb_mid->mi_n_ifs; i++) { 1428 if (usb_mid->mi_child_events[i] & 1429 USB_MID_CHILD_EVENT_PRESUSPEND) { 1430 usb_mid->mi_child_events[i] &= 1431 ~USB_MID_CHILD_EVENT_PRESUSPEND; 1432 child_dip = usb_mid->mi_children_dips[i]; 1433 mutex_exit(&usb_mid->mi_mutex); 1434 1435 /* post the missed pre-suspend event */ 1436 (void) ndi_event_do_callback( 1437 usb_mid->mi_ndi_event_hdl, 1438 child_dip, suspend_cookie, 1439 bus_impldata); 1440 mutex_enter(&usb_mid->mi_mutex); 1441 } 1442 } 1443 mutex_exit(&usb_mid->mi_mutex); 1444 1445 /* pass post_resume event to all the children */ 1446 (void) ndi_event_run_callbacks(usb_mid->mi_ndi_event_hdl, 1447 NULL, resume_cookie, bus_impldata); 1448 1449 mutex_enter(&usb_mid->mi_mutex); 1450 break; 1451 } 1452 mutex_exit(&usb_mid->mi_mutex); 1453 1454 } 1455 1456 1457 /* 1458 * register and unregister for events from our parent 1459 * 1460 * Note: usb_mid doesn't use the cookie fields in usba_device structure. 1461 * They are used/shared by children of usb_mid. 1462 */ 1463 static void 1464 usb_mid_register_events(usb_mid_t *usb_mid) 1465 { 1466 int rval; 1467 usba_evdata_t *evdata; 1468 ddi_eventcookie_t cookie; 1469 1470 USB_DPRINTF_L4(DPRINT_MASK_PM, usb_mid->mi_log_handle, 1471 "usb_mid_register_events:"); 1472 1473 evdata = usba_get_evdata(usb_mid->mi_dip); 1474 1475 /* get event cookie, discard level and icookie for now */ 1476 rval = ddi_get_eventcookie(usb_mid->mi_dip, DDI_DEVI_REMOVE_EVENT, 1477 &cookie); 1478 1479 if (rval == DDI_SUCCESS) { 1480 rval = ddi_add_event_handler(usb_mid->mi_dip, 1481 cookie, usb_mid_event_cb, NULL, &evdata->ev_rm_cb_id); 1482 1483 if (rval != DDI_SUCCESS) { 1484 1485 goto fail; 1486 } 1487 } 1488 rval = ddi_get_eventcookie(usb_mid->mi_dip, DDI_DEVI_INSERT_EVENT, 1489 &cookie); 1490 if (rval == DDI_SUCCESS) { 1491 rval = ddi_add_event_handler(usb_mid->mi_dip, 1492 cookie, usb_mid_event_cb, NULL, &evdata->ev_ins_cb_id); 1493 1494 if (rval != DDI_SUCCESS) { 1495 1496 goto fail; 1497 } 1498 } 1499 rval = ddi_get_eventcookie(usb_mid->mi_dip, USBA_PRE_SUSPEND_EVENT, 1500 &cookie); 1501 if (rval == DDI_SUCCESS) { 1502 rval = ddi_add_event_handler(usb_mid->mi_dip, 1503 cookie, usb_mid_event_cb, NULL, &evdata->ev_suspend_cb_id); 1504 1505 if (rval != DDI_SUCCESS) { 1506 1507 goto fail; 1508 } 1509 } 1510 rval = ddi_get_eventcookie(usb_mid->mi_dip, USBA_POST_RESUME_EVENT, 1511 &cookie); 1512 if (rval == DDI_SUCCESS) { 1513 rval = ddi_add_event_handler(usb_mid->mi_dip, 1514 cookie, usb_mid_event_cb, NULL, 1515 &evdata->ev_resume_cb_id); 1516 1517 if (rval != DDI_SUCCESS) { 1518 1519 goto fail; 1520 } 1521 } 1522 1523 return; 1524 1525 1526 fail: 1527 usb_mid_unregister_events(usb_mid); 1528 1529 } 1530 1531 1532 static void 1533 usb_mid_unregister_events(usb_mid_t *usb_mid) 1534 { 1535 int rval; 1536 usba_evdata_t *evdata; 1537 usba_device_t *usba_device = usba_get_usba_device(usb_mid->mi_dip); 1538 1539 USB_DPRINTF_L4(DPRINT_MASK_PM, usb_mid->mi_log_handle, 1540 "usb_mid_unregister_events:"); 1541 1542 evdata = usba_get_evdata(usb_mid->mi_dip); 1543 if (evdata) { 1544 if (evdata->ev_rm_cb_id) { 1545 rval = ddi_remove_event_handler(evdata->ev_rm_cb_id); 1546 ASSERT(rval == DDI_SUCCESS); 1547 } 1548 1549 if (evdata->ev_ins_cb_id) { 1550 rval = ddi_remove_event_handler(evdata->ev_ins_cb_id); 1551 ASSERT(rval == DDI_SUCCESS); 1552 } 1553 1554 if (evdata->ev_resume_cb_id) { 1555 rval = 1556 ddi_remove_event_handler(evdata->ev_resume_cb_id); 1557 ASSERT(rval == DDI_SUCCESS); 1558 } 1559 1560 if (evdata->ev_suspend_cb_id) { 1561 rval = 1562 ddi_remove_event_handler(evdata->ev_suspend_cb_id); 1563 ASSERT(rval == DDI_SUCCESS); 1564 } 1565 } 1566 1567 /* clear event data for children, required for cfgmadm unconfigure */ 1568 usba_free_evdata(usba_device->usb_evdata); 1569 usba_device->usb_evdata = NULL; 1570 usba_device->rm_cookie = NULL; 1571 usba_device->ins_cookie = NULL; 1572 usba_device->suspend_cookie = NULL; 1573 usba_device->resume_cookie = NULL; 1574 } 1575 1576 1577 /* 1578 * create the pm components required for power management 1579 */ 1580 static void 1581 usb_mid_create_pm_components(dev_info_t *dip, usb_mid_t *usb_mid) 1582 { 1583 usb_mid_power_t *midpm; 1584 uint_t pwr_states; 1585 1586 USB_DPRINTF_L4(DPRINT_MASK_PM, usb_mid->mi_log_handle, 1587 "usb_mid_create_pm_components: Begin"); 1588 1589 /* Allocate the PM state structure */ 1590 midpm = kmem_zalloc(sizeof (usb_mid_power_t), KM_SLEEP); 1591 1592 mutex_enter(&usb_mid->mi_mutex); 1593 usb_mid->mi_pm = midpm; 1594 midpm->mip_usb_mid = usb_mid; 1595 midpm->mip_pm_capabilities = 0; /* XXXX should this be 0?? */ 1596 midpm->mip_current_power = USB_DEV_OS_FULL_PWR; 1597 mutex_exit(&usb_mid->mi_mutex); 1598 1599 /* 1600 * By not enabling parental notification, PM enforces 1601 * "strict parental dependency" meaning, usb_mid won't 1602 * power off until any of its children are in full power. 1603 */ 1604 1605 /* 1606 * there are 3 scenarios: 1607 * 1. a well behaved device should have remote wakeup 1608 * at interface and device level. If the interface 1609 * wakes up, usb_mid will wake up 1610 * 2. if the device doesn't have remote wake up and 1611 * the interface has, PM will still work, ie. 1612 * the interfaces wakes up and usb_mid wakes up 1613 * 3. if neither the interface nor device has remote 1614 * wakeup, the interface will wake up when it is opened 1615 * and goes to sleep after being closed for a while 1616 * In this case usb_mid should also go to sleep shortly 1617 * thereafter 1618 * In all scenarios it doesn't really matter whether 1619 * remote wakeup at the device level is enabled or not 1620 * but we do it anyways 1621 */ 1622 if (usb_handle_remote_wakeup(dip, USB_REMOTE_WAKEUP_ENABLE) == 1623 USB_SUCCESS) { 1624 USB_DPRINTF_L3(DPRINT_MASK_PM, usb_mid->mi_log_handle, 1625 "usb_mid_create_pm_components: " 1626 "Remote Wakeup Enabled"); 1627 midpm->mip_wakeup_enabled = 1; 1628 } 1629 1630 if (usb_create_pm_components(dip, &pwr_states) == 1631 USB_SUCCESS) { 1632 midpm->mip_pwr_states = (uint8_t)pwr_states; 1633 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 1634 } 1635 1636 USB_DPRINTF_L4(DPRINT_MASK_PM, usb_mid->mi_log_handle, 1637 "usb_mid_create_pm_components: End"); 1638 } 1639 1640 1641 /* 1642 * usb_mid_obtain_state: 1643 */ 1644 usb_mid_t * 1645 usb_mid_obtain_state(dev_info_t *dip) 1646 { 1647 int instance = ddi_get_instance(dip); 1648 usb_mid_t *statep = ddi_get_soft_state(usb_mid_statep, instance); 1649 1650 ASSERT(statep != NULL); 1651 1652 return (statep); 1653 } 1654 1655 1656 /* 1657 * ugen support 1658 */ 1659 /* ARGSUSED3 */ 1660 static int 1661 usb_mid_open(dev_t *devp, int flags, int otyp, cred_t *credp) 1662 { 1663 struct usb_mid *usb_mid; 1664 int rval; 1665 1666 if ((usb_mid = ddi_get_soft_state(usb_mid_statep, 1667 USB_MID_MINOR_TO_INSTANCE(getminor(*devp)))) == NULL) { 1668 1669 return (ENXIO); 1670 } 1671 1672 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, usb_mid->mi_log_handle, 1673 "usb_mid_open: usb_mid = 0x%p *devp = 0x%lx", usb_mid, *devp); 1674 1675 /* First bring the device to full power */ 1676 (void) pm_busy_component(usb_mid->mi_dip, 0); 1677 (void) pm_raise_power(usb_mid->mi_dip, 0, USB_DEV_OS_FULL_PWR); 1678 1679 1680 rval = usb_ugen_open(usb_mid->mi_ugen_hdl, devp, flags, otyp, 1681 credp); 1682 if (rval) { 1683 (void) pm_idle_component(usb_mid->mi_dip, 0); 1684 } else { 1685 /* 1686 * since all ugen opens are exclusive we can count the 1687 * opens 1688 */ 1689 mutex_enter(&usb_mid->mi_mutex); 1690 usb_mid->mi_ugen_open_count++; 1691 mutex_exit(&usb_mid->mi_mutex); 1692 } 1693 1694 return (rval); 1695 } 1696 1697 1698 /* ARGSUSED */ 1699 static int 1700 usb_mid_close(dev_t dev, int flag, int otyp, cred_t *credp) 1701 { 1702 struct usb_mid *usb_mid; 1703 int rval; 1704 1705 if ((usb_mid = ddi_get_soft_state(usb_mid_statep, 1706 USB_MID_MINOR_TO_INSTANCE(getminor(dev)))) == NULL) { 1707 1708 return (ENXIO); 1709 } 1710 1711 rval = usb_ugen_close(usb_mid->mi_ugen_hdl, dev, flag, otyp, 1712 credp); 1713 if (rval == 0) { 1714 (void) pm_idle_component(usb_mid->mi_dip, 0); 1715 mutex_enter(&usb_mid->mi_mutex); 1716 usb_mid->mi_ugen_open_count--; 1717 mutex_exit(&usb_mid->mi_mutex); 1718 } 1719 1720 return (rval); 1721 } 1722 1723 1724 static int 1725 usb_mid_read(dev_t dev, struct uio *uio, cred_t *credp) 1726 { 1727 struct usb_mid *usb_mid; 1728 1729 if ((usb_mid = ddi_get_soft_state(usb_mid_statep, 1730 USB_MID_MINOR_TO_INSTANCE(getminor(dev)))) == NULL) { 1731 1732 return (ENXIO); 1733 } 1734 1735 return (usb_ugen_read(usb_mid->mi_ugen_hdl, dev, uio, credp)); 1736 } 1737 1738 1739 static int 1740 usb_mid_write(dev_t dev, struct uio *uio, cred_t *credp) 1741 { 1742 struct usb_mid *usb_mid; 1743 1744 if ((usb_mid = ddi_get_soft_state(usb_mid_statep, 1745 USB_MID_MINOR_TO_INSTANCE(getminor(dev)))) == NULL) { 1746 1747 return (ENXIO); 1748 } 1749 1750 return (usb_ugen_write(usb_mid->mi_ugen_hdl, dev, uio, credp)); 1751 } 1752 1753 1754 static int 1755 usb_mid_poll(dev_t dev, short events, int anyyet, short *reventsp, 1756 struct pollhead **phpp) 1757 { 1758 struct usb_mid *usb_mid; 1759 1760 if ((usb_mid = ddi_get_soft_state(usb_mid_statep, 1761 USB_MID_MINOR_TO_INSTANCE(getminor(dev)))) == NULL) { 1762 1763 return (ENXIO); 1764 } 1765 1766 return (usb_ugen_poll(usb_mid->mi_ugen_hdl, dev, events, 1767 anyyet, reventsp, phpp)); 1768 } 1769