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