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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 27 /* 28 * Sample skeleton USB driver. 29 * This driver provides a framework for developing USB client drivers. 30 * 31 * As a simplistic example, usbskel implements a data transfer by reading 32 * raw configuration data, which every USB device has. It is expected that 33 * the caller will issue an initial 4-byte read to get the total length of the 34 * first configuration, and follow up with a second read, passing the total 35 * length to read the entire configuration cloud. 36 * 37 * The device has four states (refer to usbai.h): 38 * USB_DEV_ONLINE: In action or ready for action. 39 * USB_DEV_DISCONNECTED: Hotplug removed, or device not present/correct on 40 * resume (CPR). 41 * USB_DEV_SUSPENDED: Device has been suspended along with the system. 42 * USB_DEV_PWRED_DOWN: Device has been powered down. (Note that this 43 * driver supports only two power states, powered down and 44 * full power.) 45 * 46 * In order to avoid race conditions between driver entry points, 47 * access to the device is serialized. Race conditions are an issue in 48 * particular between disconnect event callbacks, detach, power, open 49 * and data transfer callbacks. The functions usbskel_serialize/release_access 50 * are implemented for this purpose. 51 * 52 * Mutexes should never be held when making calls into USBA or when 53 * sleeping. 54 * 55 * pm_busy_component and pm_idle_component mark the device as busy or idle to 56 * the system. These functions are paired, and are called only from code 57 * bracketed by usbskel_serialize_access and usbskel_release_access. 58 * 59 * NOTE: PM and CPR will be enabled at a later release of S10. 60 */ 61 62 #if defined(lint) && !defined(DEBUG) 63 #define DEBUG 64 #endif 65 66 #define USBDRV_MAJOR_VER 2 67 #define USBDRV_MINOR_VER 0 68 69 /* Uncomment to enable Power Management, when the OS PM framework is ready. */ 70 /* 71 * #ifndef USBSKEL_PM 72 * #define USBSKEL_PM 73 * #endif 74 */ 75 76 /* 77 * Uncomment to enable Check Point Resume (system suspend and resume) when the 78 * OS CPR framework is ready. 79 */ 80 /* 81 * #ifndef USBSKEL_CPR 82 * #define USBSKEL_CPR 83 * #endif 84 */ 85 86 #include <sys/usb/usba.h> 87 #include <sys/strsun.h> 88 #include <sys/usb/clients/usbskel/usbskel.h> 89 90 int usbskel_errlevel = USBSKEL_LOG_LOG; 91 static char *name = "usbskl"; /* Driver name, used all over. */ 92 93 /* 94 * Boolean set to whether or not to dump the device's descriptor tree. 95 * Can be changed with the usblog_dumptree property in a usbskel.conf file. 96 */ 97 static boolean_t usbskel_dumptree; 98 99 /* 100 * Function Prototypes 101 */ 102 static int usbskel_attach(dev_info_t *, ddi_attach_cmd_t); 103 static int usbskel_detach(dev_info_t *, ddi_detach_cmd_t); 104 static int usbskel_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 105 static int usbskel_cleanup(dev_info_t *, usbskel_state_t *); 106 static int usbskel_open(dev_t *, int, int, cred_t *); 107 static int usbskel_close(dev_t, int, int, cred_t *); 108 static int usbskel_read(dev_t, struct uio *uip_p, cred_t *); 109 static int usbskel_strategy(struct buf *); 110 static void usbskel_minphys(struct buf *); 111 static void usbskel_normal_callback(usb_pipe_handle_t, usb_ctrl_req_t *); 112 static void usbskel_exception_callback(usb_pipe_handle_t, usb_ctrl_req_t *); 113 static int usbskel_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 114 static int usbskel_disconnect_callback(dev_info_t *); 115 static int usbskel_reconnect_callback(dev_info_t *); 116 static void usbskel_restore_device_state(dev_info_t *, usbskel_state_t *); 117 static int usbskel_cpr_suspend(dev_info_t *); 118 static void usbskel_cpr_resume(dev_info_t *); 119 static int usbskel_test_and_adjust_device_state(usbskel_state_t *); 120 static int usbskel_open_pipes(usbskel_state_t *); 121 static void usbskel_close_pipes(usbskel_state_t *); 122 static int usbskel_pm_busy_component(usbskel_state_t *); 123 static void usbskel_pm_idle_component(usbskel_state_t *); 124 static int usbskel_power(dev_info_t *, int, int); 125 #ifdef USBSKEL_PM 126 static int usbskel_init_power_mgmt(usbskel_state_t *); 127 static void usbskel_destroy_power_mgmt(usbskel_state_t *); 128 #endif 129 static int usbskel_serialize_access(usbskel_state_t *, boolean_t); 130 static void usbskel_release_access(usbskel_state_t *); 131 static int usbskel_check_same_device(usbskel_state_t *); 132 133 /*PRINTFLIKE3*/ 134 static void usbskel_log(usbskel_state_t *, int, char *, ...); 135 136 /* _NOTE is an advice for locklint. Locklint checks lock use for deadlocks. */ 137 _NOTE(SCHEME_PROTECTS_DATA("unique per call", usb_ctrl_req)) 138 _NOTE(SCHEME_PROTECTS_DATA("unique per call", buf)) 139 140 /* module loading stuff */ 141 struct cb_ops usbskel_cb_ops = { 142 usbskel_open, /* open */ 143 usbskel_close, /* close */ 144 usbskel_strategy, /* strategy */ 145 nulldev, /* print */ 146 nulldev, /* dump */ 147 usbskel_read, /* read */ 148 nodev, /* write */ 149 usbskel_ioctl, /* ioctl */ 150 nulldev, /* devmap */ 151 nodev, /* mmap */ 152 nodev, /* segmap */ 153 nochpoll, /* poll */ 154 ddi_prop_op, /* cb_prop_op */ 155 NULL, /* streamtab */ 156 D_MP 157 }; 158 159 static struct dev_ops usbskel_ops = { 160 DEVO_REV, /* devo_rev, */ 161 0, /* refcnt */ 162 usbskel_info, /* info */ 163 nulldev, /* identify */ 164 nulldev, /* probe */ 165 usbskel_attach, /* attach */ 166 usbskel_detach, /* detach */ 167 nodev, /* reset */ 168 &usbskel_cb_ops, /* driver operations */ 169 NULL, /* bus operations */ 170 usbskel_power, /* power */ 171 ddi_quiesce_not_needed, /* devo_quiesce */ 172 }; 173 174 static struct modldrv usbskel_modldrv = { 175 &mod_driverops, 176 "USB skeleton driver", 177 &usbskel_ops 178 }; 179 180 static struct modlinkage modlinkage = { 181 MODREV_1, 182 { &usbskel_modldrv, NULL } 183 }; 184 185 /* local variables */ 186 187 /* Soft state structures */ 188 #define USBSKEL_INITIAL_SOFT_SPACE 1 189 static void *usbskel_statep; 190 191 192 /* 193 * Module-wide initialization routine. 194 */ 195 int 196 _init(void) 197 { 198 int rval; 199 200 usbskel_log(NULL, USBSKEL_LOG_LOG, "usbskel _init"); 201 202 if ((rval = ddi_soft_state_init(&usbskel_statep, 203 sizeof (usbskel_state_t), USBSKEL_INITIAL_SOFT_SPACE)) != 0) { 204 205 return (rval); 206 } 207 208 if ((rval = mod_install(&modlinkage)) != 0) { 209 ddi_soft_state_fini(&usbskel_statep); 210 } 211 212 usbskel_log(NULL, USBSKEL_LOG_LOG, "usbskel _init done"); 213 214 return (rval); 215 } 216 217 218 /* 219 * Module-wide tear-down routine. 220 */ 221 int 222 _fini(void) 223 { 224 int rval; 225 226 usbskel_log(NULL, USBSKEL_LOG_LOG, "usbskel _fini"); 227 if ((rval = mod_remove(&modlinkage)) != 0) { 228 229 return (rval); 230 } 231 232 ddi_soft_state_fini(&usbskel_statep); 233 usbskel_log(NULL, USBSKEL_LOG_LOG, "usbskel _fini done"); 234 235 return (rval); 236 } 237 238 239 int 240 _info(struct modinfo *modinfop) 241 { 242 return (mod_info(&modlinkage, modinfop)); 243 } 244 245 246 /* 247 * usbskel_info: 248 * Get minor number, soft state structure, etc. 249 */ 250 /*ARGSUSED*/ 251 static int 252 usbskel_info(dev_info_t *dip, ddi_info_cmd_t infocmd, 253 void *arg, void **result) 254 { 255 usbskel_state_t *usbskelp; 256 int error = DDI_FAILURE; 257 258 switch (infocmd) { 259 case DDI_INFO_DEVT2DEVINFO: 260 if ((usbskelp = ddi_get_soft_state(usbskel_statep, 261 getminor((dev_t)arg))) != NULL) { 262 *result = usbskelp->usbskel_dip; 263 if (*result != NULL) { 264 error = DDI_SUCCESS; 265 } 266 } else { 267 *result = NULL; 268 } 269 break; 270 case DDI_INFO_DEVT2INSTANCE: 271 *result = (void *)(uintptr_t)getminor((dev_t)arg); 272 error = DDI_SUCCESS; 273 break; 274 default: 275 break; 276 } 277 278 return (error); 279 } 280 281 282 /* 283 * usbskel_attach: 284 * Attach or resume. 285 * 286 * For attach, initialize state and device, including: 287 * state variables, locks, device node 288 * device registration with system 289 * power management, hotplugging 290 * For resume, restore device and state 291 */ 292 static int 293 usbskel_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 294 { 295 int instance = ddi_get_instance(dip); 296 char *devinst; 297 int devinstlen; 298 usbskel_state_t *usbskelp = NULL; 299 usb_reg_parse_lvl_t parse_level; 300 usb_ep_data_t *ep_datap; 301 int status; 302 303 switch (cmd) { 304 case DDI_ATTACH: 305 break; 306 307 case DDI_RESUME: 308 usbskel_cpr_resume(dip); 309 310 /* 311 * Always return success to work around enumeration failures. 312 * This works around an issue where devices which are present 313 * before a suspend and absent upon resume could cause a system 314 * panic on resume. 315 */ 316 return (DDI_SUCCESS); 317 default: 318 return (DDI_FAILURE); 319 } 320 321 if (ddi_soft_state_zalloc(usbskel_statep, instance) == DDI_SUCCESS) { 322 usbskelp = ddi_get_soft_state(usbskel_statep, instance); 323 } 324 if (usbskelp == NULL) { 325 326 return (DDI_FAILURE); 327 } 328 329 usbskelp->usbskel_dip = dip; 330 331 devinst = kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP); 332 devinstlen = snprintf(devinst, USB_MAXSTRINGLEN, "%s%d: ", 333 ddi_driver_name(dip), instance); 334 335 usbskelp->usbskel_devinst = kmem_zalloc(devinstlen + 1, KM_SLEEP); 336 (void) strncpy(usbskelp->usbskel_devinst, devinst, devinstlen); 337 kmem_free(devinst, USB_MAXSTRINGLEN); 338 339 usbskel_log(usbskelp, USBSKEL_LOG_LOG, "Attach: enter for attach"); 340 341 usbskel_dumptree = (ddi_prop_exists(DDI_DEV_T_ANY, dip, 342 DDI_PROP_DONTPASS, "usbskel_dumptree") == 1); 343 344 usbskel_log(usbskelp, USBSKEL_LOG_LOG, "Tree will %sbe dumped", 345 ((usbskel_dumptree) ? "" : "not ")); 346 347 parse_level = (usb_reg_parse_lvl_t)ddi_prop_get_int( 348 DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 349 "usbskel_parse_level", USB_PARSE_LVL_ALL); 350 351 switch (parse_level) { 352 case USB_PARSE_LVL_NONE: 353 /* This driver needs a tree. */ 354 usbskel_log(usbskelp, USBSKEL_LOG_LOG, 355 "parse_level requested to NOT DUMP"); 356 parse_level = USB_PARSE_LVL_IF; 357 /*FALLTHROUGH*/ 358 case USB_PARSE_LVL_IF: 359 usbskel_log(usbskelp, USBSKEL_LOG_LOG, 360 "parse_level set to dump specific interface"); 361 break; 362 case USB_PARSE_LVL_CFG: 363 usbskel_log(usbskelp, USBSKEL_LOG_LOG, 364 "parse_level set to dump specific config"); 365 break; 366 case USB_PARSE_LVL_ALL: 367 usbskel_log(usbskelp, USBSKEL_LOG_LOG, 368 "parse_level set to dump everything"); 369 break; 370 default: 371 usbskel_log(usbskelp, USBSKEL_LOG_LOG, 372 "attach: parse_level will default to dump everything"); 373 parse_level = USB_PARSE_LVL_ALL; 374 } 375 376 if ((status = usb_client_attach(dip, USBDRV_VERSION, 0)) != 377 USB_SUCCESS) { 378 usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 379 "attach: usb_client_attach failed, error code:%d", status); 380 goto fail; 381 } 382 383 if ((status = usb_get_dev_data(dip, &usbskelp->usbskel_reg, parse_level, 384 0)) != USB_SUCCESS) { 385 usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 386 "attach: usb_get_dev_data failed, error code:%d", status); 387 goto fail; 388 } 389 390 if (usbskel_dumptree) { 391 (void) usb_print_descr_tree( 392 usbskelp->usbskel_dip, usbskelp->usbskel_reg); 393 } 394 395 /* 396 * Get the descriptor for an intr pipe at alt 0 of current interface. 397 * This will be used later to open the pipe. 398 */ 399 if ((ep_datap = usb_lookup_ep_data(dip, usbskelp->usbskel_reg, 400 usbskelp->usbskel_reg->dev_curr_if, 0, 0, 401 USB_EP_ATTR_INTR, USB_EP_DIR_IN)) == NULL) { 402 usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 403 "attach: Error getting intr endpoint descriptor"); 404 goto fail; 405 } 406 usbskelp->usbskel_intr_ep_descr = ep_datap->ep_descr; 407 408 usb_free_descr_tree(dip, usbskelp->usbskel_reg); 409 410 mutex_init(&usbskelp->usbskel_mutex, NULL, MUTEX_DRIVER, 411 usbskelp->usbskel_reg->dev_iblock_cookie); 412 413 cv_init(&usbskelp->usbskel_serial_cv, NULL, CV_DRIVER, NULL); 414 usbskelp->usbskel_serial_inuse = B_FALSE; 415 416 usbskelp->usbskel_locks_initialized = B_TRUE; 417 418 /* create minor node */ 419 if (ddi_create_minor_node(dip, name, S_IFCHR, instance, 420 "usb_skeleton", 0) != DDI_SUCCESS) { 421 usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 422 "attach: Error creating minor node"); 423 goto fail; 424 } 425 426 /* Put online before PM init as can get power managed afterward. */ 427 usbskelp->usbskel_dev_state = USB_DEV_ONLINE; 428 429 #ifdef USBSKEL_PM 430 /* initialize power management */ 431 if (usbskel_init_power_mgmt(usbskelp) != USB_SUCCESS) { 432 usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 433 "attach: Could not initialize power mgmt"); 434 } 435 #endif 436 437 if (usb_register_hotplug_cbs(dip, usbskel_disconnect_callback, 438 usbskel_reconnect_callback) != USB_SUCCESS) { 439 440 goto fail; 441 } 442 443 /* Report device */ 444 ddi_report_dev(dip); 445 446 return (DDI_SUCCESS); 447 448 fail: 449 if (usbskelp) { 450 (void) usbskel_cleanup(dip, usbskelp); 451 } 452 453 return (DDI_FAILURE); 454 } 455 456 457 /* 458 * usbskel_detach: 459 * detach or suspend driver instance 460 * 461 * Note: in detach, only contention threads is from pm and disconnnect. 462 */ 463 static int 464 usbskel_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 465 { 466 int instance = ddi_get_instance(dip); 467 usbskel_state_t *usbskelp = 468 ddi_get_soft_state(usbskel_statep, instance); 469 int rval = DDI_FAILURE; 470 471 switch (cmd) { 472 case DDI_DETACH: 473 mutex_enter(&usbskelp->usbskel_mutex); 474 ASSERT((usbskelp->usbskel_drv_state & USBSKEL_OPEN) == 0); 475 mutex_exit(&usbskelp->usbskel_mutex); 476 477 usbskel_log(usbskelp, USBSKEL_LOG_LOG, 478 "Detach: enter for detach"); 479 480 rval = usbskel_cleanup(dip, usbskelp); 481 482 break; 483 case DDI_SUSPEND: 484 usbskel_log(usbskelp, USBSKEL_LOG_LOG, 485 "Detach: enter for suspend"); 486 487 rval = usbskel_cpr_suspend(dip); 488 default: 489 490 break; 491 } 492 493 return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE); 494 } 495 496 497 /* 498 * usbskel_cleanup: 499 * clean up the driver state for detach 500 */ 501 static int 502 usbskel_cleanup(dev_info_t *dip, usbskel_state_t *usbskelp) 503 { 504 usbskel_log(usbskelp, USBSKEL_LOG_LOG, "Cleanup: enter"); 505 506 if (usbskelp->usbskel_locks_initialized) { 507 508 /* This must be done 1st to prevent more events from coming. */ 509 usb_unregister_hotplug_cbs(dip); 510 511 /* 512 * At this point, no new activity can be initiated. The driver 513 * has disabled hotplug callbacks. The Solaris framework has 514 * disabled new opens on a device being detached, and does not 515 * allow detaching an open device. 516 * 517 * The following ensures that all driver activity has drained. 518 */ 519 mutex_enter(&usbskelp->usbskel_mutex); 520 (void) usbskel_serialize_access(usbskelp, USBSKEL_SER_NOSIG); 521 usbskel_release_access(usbskelp); 522 mutex_exit(&usbskelp->usbskel_mutex); 523 524 #ifdef USBSKEL_PM 525 /* All device activity has died down. */ 526 usbskel_destroy_power_mgmt(usbskelp); 527 #endif 528 529 /* start dismantling */ 530 ddi_remove_minor_node(dip, NULL); 531 532 cv_destroy(&usbskelp->usbskel_serial_cv); 533 mutex_destroy(&usbskelp->usbskel_mutex); 534 } 535 536 usb_client_detach(dip, usbskelp->usbskel_reg); 537 538 if (usbskelp->usbskel_devinst != NULL) { 539 kmem_free(usbskelp->usbskel_devinst, 540 strlen(usbskelp->usbskel_devinst) + 1); 541 } 542 543 ddi_soft_state_free(usbskel_statep, ddi_get_instance(dip)); 544 ddi_prop_remove_all(dip); 545 546 return (USB_SUCCESS); 547 } 548 549 550 /*ARGSUSED*/ 551 static int 552 usbskel_open(dev_t *devp, int flag, int otyp, cred_t *cred_p) 553 { 554 usbskel_state_t *usbskelp = 555 ddi_get_soft_state(usbskel_statep, getminor(*devp)); 556 int rval = 0; 557 558 if (usbskelp == NULL) { 559 560 return (ENXIO); 561 } 562 563 usbskel_log(usbskelp, USBSKEL_LOG_LOG, "open: enter"); 564 565 /* 566 * Keep it simple: one client at a time. 567 * Exclusive open only 568 */ 569 mutex_enter(&usbskelp->usbskel_mutex); 570 if ((usbskelp->usbskel_drv_state & USBSKEL_OPEN) != 0) { 571 mutex_exit(&usbskelp->usbskel_mutex); 572 573 return (EBUSY); 574 } 575 usbskelp->usbskel_drv_state |= USBSKEL_OPEN; 576 577 /* 578 * This is in place so that a disconnect or CPR doesn't interfere with 579 * pipe opens. 580 */ 581 if (usbskel_serialize_access(usbskelp, USBSKEL_SER_SIG) == 0) { 582 usbskelp->usbskel_drv_state &= ~USBSKEL_OPEN; 583 mutex_exit(&usbskelp->usbskel_mutex); 584 585 return (EINTR); 586 } 587 588 mutex_exit(&usbskelp->usbskel_mutex); 589 if (usbskel_pm_busy_component(usbskelp) != DDI_SUCCESS) { 590 usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 591 "open: Error raising power"); 592 rval = EIO; 593 goto done; 594 } 595 mutex_enter(&usbskelp->usbskel_mutex); 596 597 /* Fail if device is no longer ready. */ 598 if (usbskelp->usbskel_dev_state != USB_DEV_ONLINE) { 599 mutex_exit(&usbskelp->usbskel_mutex); 600 rval = EIO; 601 goto done; 602 } 603 604 mutex_exit(&usbskelp->usbskel_mutex); 605 if (usbskel_open_pipes(usbskelp) != USB_SUCCESS) { 606 rval = EIO; 607 goto done; 608 } 609 610 /* Device specific initialization goes here. */ 611 612 done: 613 if (rval != 0) { 614 mutex_enter(&usbskelp->usbskel_mutex); 615 usbskelp->usbskel_drv_state &= ~USBSKEL_OPEN; 616 617 usbskel_release_access(usbskelp); 618 mutex_exit(&usbskelp->usbskel_mutex); 619 620 usbskel_pm_idle_component(usbskelp); 621 } else { 622 623 /* Device is idle until it is used. */ 624 mutex_enter(&usbskelp->usbskel_mutex); 625 usbskel_release_access(usbskelp); 626 mutex_exit(&usbskelp->usbskel_mutex); 627 } 628 629 return (rval); 630 } 631 632 633 /*ARGSUSED*/ 634 static int 635 usbskel_close(dev_t dev, int flag, int otyp, cred_t *cred_p) 636 { 637 usbskel_state_t *usbskelp = 638 ddi_get_soft_state(usbskel_statep, getminor(dev)); 639 640 usbskel_log(usbskelp, USBSKEL_LOG_LOG, "close: enter"); 641 642 mutex_enter(&usbskelp->usbskel_mutex); 643 (void) usbskel_serialize_access(usbskelp, USBSKEL_SER_NOSIG); 644 mutex_exit(&usbskelp->usbskel_mutex); 645 646 /* Perform device session cleanup here. */ 647 648 usbskel_log(usbskelp, USBSKEL_LOG_LOG, "close: cleaning up..."); 649 650 /* 651 * USBA automatically flushes/resets active non-default pipes 652 * when they are closed. We can't reset default pipe, but we 653 * can wait for all requests on it from this dip to drain. 654 */ 655 (void) usb_pipe_drain_reqs(usbskelp->usbskel_dip, 656 usbskelp->usbskel_reg->dev_default_ph, 0, 657 USB_FLAGS_SLEEP, NULL, 0); 658 659 mutex_enter(&usbskelp->usbskel_mutex); 660 usbskel_close_pipes(usbskelp); 661 662 usbskelp->usbskel_drv_state &= ~USBSKEL_OPEN; 663 664 usbskel_release_access(usbskelp); 665 mutex_exit(&usbskelp->usbskel_mutex); 666 667 usbskel_pm_idle_component(usbskelp); 668 669 return (0); 670 } 671 672 673 /*ARGSUSED*/ 674 static int 675 usbskel_read(dev_t dev, struct uio *uio_p, cred_t *cred_p) 676 { 677 usbskel_state_t *usbskelp = 678 ddi_get_soft_state(usbskel_statep, getminor(dev)); 679 680 usbskel_log(usbskelp, USBSKEL_LOG_LOG, "read enter"); 681 682 return (physio(usbskel_strategy, NULL, dev, B_READ, 683 usbskel_minphys, uio_p)); 684 } 685 686 687 /* 688 * strategy: 689 * Called through physio to setup and start the transfer. 690 */ 691 static int 692 usbskel_strategy(struct buf *bp) 693 { 694 usbskel_state_t *usbskelp = ddi_get_soft_state(usbskel_statep, 695 getminor(bp->b_edev)); 696 usb_pipe_handle_t pipe = usbskelp->usbskel_reg->dev_default_ph; 697 usb_ctrl_req_t *request; 698 int status; 699 700 usbskel_log(usbskelp, USBSKEL_LOG_LOG, "strategy enter"); 701 702 /* 703 * Initialize residual count here in case transfer doesn't even get 704 * started. 705 */ 706 bp->b_resid = bp->b_bcount; 707 708 /* Needed as this is a character driver. */ 709 if (bp->b_flags & (B_PHYS | B_PAGEIO)) { 710 bp_mapin(bp); 711 } 712 713 mutex_enter(&usbskelp->usbskel_mutex); 714 (void) usbskel_serialize_access(usbskelp, USBSKEL_SER_NOSIG); 715 716 /* Make sure device has not been disconnected. */ 717 if (usbskelp->usbskel_dev_state != USB_DEV_ONLINE) { 718 usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 719 "usbskel_strategy: device can't be accessed"); 720 mutex_exit(&usbskelp->usbskel_mutex); 721 goto fail; 722 } 723 mutex_exit(&usbskelp->usbskel_mutex); 724 725 /* 726 * Since every device has raw configuration data, set up a control 727 * transfer to read the raw configuration data. In a production driver 728 * a read would probably be done on a pipe other than the default pipe, 729 * and would be reading data streamed by the device. 730 */ 731 732 /* Allocate and initialize the request. */ 733 if ((bp->b_private = request = usb_alloc_ctrl_req( 734 usbskelp->usbskel_dip, bp->b_bcount, USB_FLAGS_SLEEP)) == 735 NULL) { 736 usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 737 "usbskel_read: Error allocating request"); 738 goto fail; 739 } 740 741 request->ctrl_bmRequestType = 742 USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD | 743 USB_DEV_REQ_RCPT_DEV; 744 request->ctrl_bRequest = USB_REQ_GET_DESCR; 745 746 /* For now, return only the first configuration. */ 747 request->ctrl_wValue = USB_DESCR_TYPE_SETUP_CFG | 0; 748 request->ctrl_wIndex = 0; 749 request->ctrl_wLength = bp->b_bcount; 750 request->ctrl_timeout = 3; 751 752 /* Autoclearing automatically set on default pipe. */ 753 request->ctrl_attributes = USB_ATTRS_SHORT_XFER_OK; 754 755 request->ctrl_cb = usbskel_normal_callback; 756 request->ctrl_exc_cb = usbskel_exception_callback; 757 758 /* Hook the req to the bp, so callback knows where to put the data. */ 759 /* Now both bp and request know about each other. */ 760 request->ctrl_client_private = (usb_opaque_t)bp; 761 762 /* 763 * Issue the request asynchronously. Physio will block waiting for an 764 * "interrupt" which comes as a callback. The callback calls biodone 765 * to release physio from its wait. 766 */ 767 if ((status = usb_pipe_ctrl_xfer(pipe, request, USB_FLAGS_NOSLEEP)) != 768 USB_SUCCESS) { 769 usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 770 "usbskel_strategy: can't start transfer: status: %d", 771 status); 772 goto fail; 773 } 774 775 /* 776 * Normally, usbskel_release_access() and usbskel_pm_idle_component 777 * is called in callback handler. 778 */ 779 780 return (0); 781 782 fail: 783 mutex_enter(&usbskelp->usbskel_mutex); 784 usbskel_release_access(usbskelp); 785 mutex_exit(&usbskelp->usbskel_mutex); 786 787 bioerror(bp, EIO); 788 biodone(bp); 789 790 return (0); 791 } 792 793 794 static void 795 usbskel_minphys(struct buf *bp) 796 { 797 /* the config cloud is limited to 64k */ 798 if (bp->b_bcount > USBSKEL_REQUEST_SIZE) { 799 bp->b_bcount = USBSKEL_REQUEST_SIZE; 800 } 801 minphys(bp); 802 } 803 804 805 /* 806 * usbskel_normal_callback: 807 * Completion handler for successful transfer. 808 * Copy data from mblk returned by USBA, into 809 * buffer passed by physio, to get it back to user. 810 * Idle device 811 * update counts, etc. 812 * release request. 813 * signal completion via biodone 814 */ 815 /*ARGSUSED*/ 816 static void 817 usbskel_normal_callback(usb_pipe_handle_t pipe, usb_ctrl_req_t *request) 818 { 819 struct buf *bp = (struct buf *)request->ctrl_client_private; 820 usbskel_state_t *usbskelp = ddi_get_soft_state(usbskel_statep, 821 getminor(bp->b_edev)); 822 mblk_t *data = request->ctrl_data; 823 int amt_transferred = MBLKL(data); 824 825 usbskel_log(usbskelp, USBSKEL_LOG_LOG, "normal callback enter"); 826 827 ASSERT((request->ctrl_cb_flags & USB_CB_INTR_CONTEXT) == 0); 828 829 usbskel_log(usbskelp, USBSKEL_LOG_LOG, 830 "at entry, b_bcount = %lu, b_resid = %lu, trans = %d", bp->b_bcount, 831 bp->b_resid, amt_transferred); 832 833 mutex_enter(&usbskelp->usbskel_mutex); 834 usbskel_release_access(usbskelp); 835 mutex_exit(&usbskelp->usbskel_mutex); 836 837 /* Copy data out of mblk, into buffer. */ 838 if (amt_transferred) { 839 bcopy(data->b_rptr, bp->b_un.b_addr, amt_transferred); 840 } 841 842 usbskel_log(usbskelp, USBSKEL_LOG_LOG, 843 "normal callback: transferring %d bytes from 0x%p to 0x%p", 844 amt_transferred, (void *)data, (void *)(bp->b_un.b_addr)); 845 846 /* Unhook. */ 847 bp->b_private = NULL; 848 request->ctrl_client_private = NULL; 849 850 /* Free request. */ 851 usb_free_ctrl_req(request); 852 853 /* Finish up. */ 854 bp->b_resid = bp->b_bcount - amt_transferred; 855 856 usbskel_log(usbskelp, USBSKEL_LOG_LOG, 857 "at exit, b_bcount = %lu, b_resid = %lu, trans = %d", bp->b_bcount, 858 bp->b_resid, amt_transferred); 859 860 biodone(bp); 861 } 862 863 864 /* 865 * usbskel_exception_callback: 866 * Completion handler for an erred transfer. 867 * Copy data from mblk returned by USBA, if any, into 868 * buffer passed by physio, to get it back to user. 869 * Idle device 870 * update counts, etc. 871 * release request. 872 * signal completion via biodone 873 */ 874 /*ARGSUSED*/ 875 static void 876 usbskel_exception_callback(usb_pipe_handle_t pipe, usb_ctrl_req_t *request) 877 { 878 struct buf *bp = (struct buf *)request->ctrl_client_private; 879 usbskel_state_t *usbskelp = ddi_get_soft_state(usbskel_statep, 880 getminor(bp->b_edev)); 881 mblk_t *data = request->ctrl_data; 882 int amt_transferred = (data ? MBLKL(data) : 0); 883 884 usbskel_log(usbskelp, USBSKEL_LOG_LOG, 885 "at except cb entry, b_bcount = %lu, b_resid = %lu, trans = %d", 886 bp->b_bcount, bp->b_resid, amt_transferred); 887 888 ASSERT((request->ctrl_cb_flags & USB_CB_INTR_CONTEXT) == 0); 889 890 mutex_enter(&usbskelp->usbskel_mutex); 891 usbskel_release_access(usbskelp); 892 mutex_exit(&usbskelp->usbskel_mutex); 893 894 /* Copy data, if any, out of mblk, into buffer. */ 895 if (amt_transferred) { 896 bcopy(data, bp->b_un.b_addr, amt_transferred); 897 } 898 bp->b_resid = bp->b_bcount - amt_transferred; 899 900 usbskel_log(usbskelp, USBSKEL_LOG_LOG, 901 "exception cb: req = 0x%p, cr = %d\n\t cb_flags = 0x%x " 902 "data = 0x%p, amt xfered = %d", (void *)request, 903 request->ctrl_completion_reason, request->ctrl_cb_flags, 904 (void *)(request->ctrl_data), amt_transferred); 905 906 /* Unhook */ 907 bp->b_private = NULL; 908 request->ctrl_client_private = NULL; 909 910 /* Free request. */ 911 usb_free_ctrl_req(request); 912 913 usbskel_log(usbskelp, USBSKEL_LOG_LOG, 914 "at except cb exit, b_bcount = %lu, b_resid = %lu, trans = %d", 915 bp->b_bcount, bp->b_resid, amt_transferred); 916 917 bioerror(bp, EIO); 918 biodone(bp); 919 } 920 921 922 /* 923 * XXX Empty ioctl for now. 924 */ 925 /*ARGSUSED*/ 926 static int 927 usbskel_ioctl(dev_t dev, int cmd, intptr_t arg, 928 int mode, cred_t *cred_p, int *rval_p) 929 { 930 usbskel_state_t *usbskelp = 931 ddi_get_soft_state(usbskel_statep, getminor(dev)); 932 933 usbskel_log(usbskelp, USBSKEL_LOG_LOG, "ioctl enter"); 934 935 return (ENOTTY); 936 } 937 938 939 /* 940 * usbskel_disconnect_callback: 941 * Called when device hotplug-removed. 942 * Close pipes. (This does not attempt to contact device.) 943 * Set state to DISCONNECTED 944 */ 945 static int 946 usbskel_disconnect_callback(dev_info_t *dip) 947 { 948 int instance = ddi_get_instance(dip); 949 usbskel_state_t *usbskelp = 950 ddi_get_soft_state(usbskel_statep, instance); 951 952 usbskel_log(usbskelp, USBSKEL_LOG_LOG, "disconnect: enter"); 953 954 mutex_enter(&usbskelp->usbskel_mutex); 955 (void) usbskel_serialize_access(usbskelp, USBSKEL_SER_NOSIG); 956 957 /* 958 * Save any state of device or IO in progress required by 959 * usbskel_restore_device_state for proper device "thawing" later. 960 */ 961 usbskelp->usbskel_dev_state = USB_DEV_DISCONNECTED; 962 963 usbskel_release_access(usbskelp); 964 mutex_exit(&usbskelp->usbskel_mutex); 965 966 return (USB_SUCCESS); 967 } 968 969 970 /* 971 * usbskel_reconnect_callback: 972 * Called with device hotplug-inserted 973 * Restore state 974 */ 975 static int 976 usbskel_reconnect_callback(dev_info_t *dip) 977 { 978 int instance = ddi_get_instance(dip); 979 usbskel_state_t *usbskelp = 980 ddi_get_soft_state(usbskel_statep, instance); 981 982 usbskel_log(usbskelp, USBSKEL_LOG_LOG, "reconnect: enter"); 983 984 mutex_enter(&usbskelp->usbskel_mutex); 985 (void) usbskel_serialize_access(usbskelp, USBSKEL_SER_NOSIG); 986 usbskel_restore_device_state(dip, usbskelp); 987 usbskel_release_access(usbskelp); 988 mutex_exit(&usbskelp->usbskel_mutex); 989 990 return (USB_SUCCESS); 991 } 992 993 994 /* 995 * usbskel_restore_device_state: 996 * Called during hotplug-reconnect and resume. 997 * reenable power management 998 * Verify the device is the same as before the disconnect/suspend. 999 * Restore device state 1000 * Thaw any IO which was frozen. 1001 * Quiesce device. (Other routines will activate if thawed IO.) 1002 * Set device online. 1003 * Leave device disconnected if there are problems. 1004 */ 1005 static void 1006 usbskel_restore_device_state(dev_info_t *dip, usbskel_state_t *usbskelp) 1007 { 1008 int rval; 1009 1010 usbskel_log(usbskelp, USBSKEL_LOG_LOG, 1011 "usbskel_restore_device_state: enter"); 1012 1013 ASSERT(mutex_owned(&usbskelp->usbskel_mutex)); 1014 1015 ASSERT((usbskelp->usbskel_dev_state == USB_DEV_DISCONNECTED) || 1016 (usbskelp->usbskel_dev_state == USB_DEV_SUSPENDED)); 1017 1018 mutex_exit(&usbskelp->usbskel_mutex); 1019 1020 if (usbskel_pm_busy_component(usbskelp) != DDI_SUCCESS) { 1021 usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 1022 "usbskel_restore_device_state: Error raising power"); 1023 1024 goto fail; 1025 } 1026 1027 /* Check if we are talking to the same device */ 1028 if (usbskel_check_same_device(usbskelp) != USB_SUCCESS) { 1029 1030 goto fail; 1031 } 1032 1033 mutex_enter(&usbskelp->usbskel_mutex); 1034 if ((rval = usbskel_test_and_adjust_device_state(usbskelp)) != 1035 USB_SUCCESS) { 1036 mutex_exit(&usbskelp->usbskel_mutex); 1037 usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 1038 "usbskel_restore_device_state: " 1039 "Error adjusting device: rval = %d", rval); 1040 1041 goto fail; 1042 } 1043 usbskelp->usbskel_dev_state = USB_DEV_ONLINE; 1044 mutex_exit(&usbskelp->usbskel_mutex); 1045 1046 if (usbskelp->usbskel_pm) { 1047 1048 /* Failure here means device disappeared again. */ 1049 if (usb_handle_remote_wakeup(dip, USB_REMOTE_WAKEUP_ENABLE) != 1050 USB_SUCCESS) { 1051 usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 1052 "device may or may not be accessible. " 1053 "Please verify reconnection"); 1054 } 1055 usbskel_pm_idle_component(usbskelp); 1056 } 1057 1058 1059 mutex_enter(&usbskelp->usbskel_mutex); 1060 1061 usbskel_log(usbskelp, USBSKEL_LOG_LOG, 1062 "usbskel_restore_device_state: end"); 1063 1064 return; 1065 1066 fail: 1067 /* change the device state from suspended to disconnected */ 1068 mutex_enter(&usbskelp->usbskel_mutex); 1069 usbskelp->usbskel_dev_state = USB_DEV_DISCONNECTED; 1070 mutex_exit(&usbskelp->usbskel_mutex); 1071 1072 usbskel_pm_idle_component(usbskelp); 1073 mutex_enter(&usbskelp->usbskel_mutex); 1074 } 1075 1076 1077 /* 1078 * usbskel_cpr_suspend: 1079 * Clean up device. 1080 * Wait for any IO to finish, then close pipes. 1081 * Quiesce device. 1082 */ 1083 static int 1084 usbskel_cpr_suspend(dev_info_t *dip) 1085 { 1086 int instance = ddi_get_instance(dip); 1087 usbskel_state_t *usbskelp = ddi_get_soft_state(usbskel_statep, 1088 instance); 1089 1090 usbskel_log(usbskelp, USBSKEL_LOG_LOG, "suspend enter"); 1091 1092 /* Serialize to prevent races with detach, open, device access. */ 1093 mutex_enter(&usbskelp->usbskel_mutex); 1094 (void) usbskel_serialize_access(usbskelp, USBSKEL_SER_NOSIG); 1095 mutex_exit(&usbskelp->usbskel_mutex); 1096 1097 if (usbskel_pm_busy_component(usbskelp) != DDI_SUCCESS) { 1098 usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 1099 "suspend: Error raising power"); 1100 usbskel_pm_idle_component(usbskelp); 1101 1102 return (USB_FAILURE); 1103 } 1104 1105 mutex_enter(&usbskelp->usbskel_mutex); 1106 1107 /* 1108 * Set dev_state to suspended so other driver threads don't start any 1109 * new I/O. In a real driver, there may be draining of requests done 1110 * afterwards, and we don't want the draining to compete with new 1111 * requests being queued. 1112 */ 1113 1114 /* Don't suspend if the device is open. */ 1115 if ((usbskelp->usbskel_drv_state & USBSKEL_OPEN) != 0) { 1116 usbskel_log(usbskelp, USBSKEL_LOG_LOG, 1117 "suspend: Device is open. Can't suspend"); 1118 1119 usbskel_release_access(usbskelp); 1120 mutex_exit(&usbskelp->usbskel_mutex); 1121 1122 usbskel_pm_idle_component(usbskelp); 1123 1124 return (USB_FAILURE); 1125 } 1126 1127 /* Access device here to clean it up. */ 1128 1129 usbskelp->usbskel_dev_state = USB_DEV_SUSPENDED; 1130 1131 /* 1132 * Save any state of device required by usbskel_restore_device_state 1133 * for proper device "thawing" later. 1134 */ 1135 1136 usbskel_release_access(usbskelp); 1137 mutex_exit(&usbskelp->usbskel_mutex); 1138 1139 usbskel_pm_idle_component(usbskelp); 1140 1141 usbskel_log(usbskelp, USBSKEL_LOG_LOG, "suspend: success"); 1142 1143 return (USB_SUCCESS); 1144 } 1145 1146 1147 /* 1148 * usbskel_cpr_resume: 1149 * 1150 * usbskel_restore_device_state marks success by putting device back online 1151 */ 1152 static void 1153 usbskel_cpr_resume(dev_info_t *dip) 1154 { 1155 int instance = ddi_get_instance(dip); 1156 usbskel_state_t *usbskelp = ddi_get_soft_state(usbskel_statep, 1157 instance); 1158 1159 usbskel_log(usbskelp, USBSKEL_LOG_LOG, "resume: enter"); 1160 1161 /* 1162 * NOTE: A pm_raise_power in usbskel_restore_device_state will bring 1163 * the power-up state of device into synch with the system. 1164 */ 1165 mutex_enter(&usbskelp->usbskel_mutex); 1166 usbskel_restore_device_state(dip, usbskelp); 1167 mutex_exit(&usbskelp->usbskel_mutex); 1168 } 1169 1170 1171 /* 1172 * usbskel_test_and_adjust_device_state: 1173 * Place any device-specific initialization or sanity verification here. 1174 */ 1175 static int 1176 usbskel_test_and_adjust_device_state(usbskel_state_t *usbskelp) 1177 { 1178 usbskel_log(usbskelp, USBSKEL_LOG_LOG, "test and adjust enter"); 1179 1180 return (USB_SUCCESS); 1181 } 1182 1183 1184 /* 1185 * usbskel_open_pipes: 1186 * Open any pipes other than default pipe. 1187 * Mutex is assumed to be held. 1188 */ 1189 static int 1190 usbskel_open_pipes(usbskel_state_t *usbskelp) 1191 { 1192 1193 int rval = USB_SUCCESS; 1194 usb_pipe_policy_t pipe_policy; 1195 usb_pipe_handle_t pipe_handle; 1196 1197 usbskel_log(usbskelp, USBSKEL_LOG_LOG, "open_pipes enter"); 1198 1199 bzero(&pipe_policy, sizeof (pipe_policy)); 1200 1201 /* 1202 * Allow that pipes can support at least two asynchronous operations 1203 * going on simultaneously. Operations include asynchronous callbacks, 1204 * resets, closures. 1205 */ 1206 pipe_policy.pp_max_async_reqs = 2; 1207 1208 if ((rval = usb_pipe_open(usbskelp->usbskel_dip, 1209 &usbskelp->usbskel_intr_ep_descr, &pipe_policy, 1210 USB_FLAGS_SLEEP, &pipe_handle)) != USB_SUCCESS) { 1211 usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 1212 "usbskel_open_pipes: Error opening intr pipe: status = %d", 1213 rval); 1214 rval = USB_FAILURE; 1215 } 1216 mutex_enter(&usbskelp->usbskel_mutex); 1217 usbskelp->usbskel_intr_ph = pipe_handle; 1218 mutex_exit(&usbskelp->usbskel_mutex); 1219 1220 /* 1221 * At this point, polling could be started on the pipe by making an 1222 * asynchronous input request on the pipe. Allocate a request by 1223 * calling usb_alloc_intr_req(9F) with a zero length, initialize 1224 * attributes with USB_ATTRS_SHORT_XFER_OK | USB_ATTRS_AUTOCLEARING, 1225 * initialize length to be packetsize of the endpoint, specify the 1226 * callbacks. Pass this request to usb_pipe_intr_xfer to start polling. 1227 * Call usb_pipe_stop_intr_poling(9F) to stop polling. 1228 */ 1229 1230 return (rval); 1231 } 1232 1233 1234 /* 1235 * usbskel_close_pipes: 1236 * Close pipes. Mutex is assumed to be held. 1237 */ 1238 /*ARGSUSED*/ 1239 static void 1240 usbskel_close_pipes(usbskel_state_t *usbskelp) 1241 { 1242 usbskel_log(usbskelp, USBSKEL_LOG_LOG, "close_pipes enter"); 1243 1244 if (usbskelp->usbskel_intr_ph) { 1245 usb_pipe_handle_t pipe_handle = usbskelp->usbskel_intr_ph; 1246 usbskelp->usbskel_intr_ph = NULL; 1247 mutex_exit(&usbskelp->usbskel_mutex); 1248 1249 usb_pipe_close(usbskelp->usbskel_dip, pipe_handle, 1250 USB_FLAGS_SLEEP, NULL, 0); 1251 1252 mutex_enter(&usbskelp->usbskel_mutex); 1253 } 1254 } 1255 1256 static int 1257 usbskel_pm_busy_component(usbskel_state_t *usbskelp) 1258 { 1259 int rval = DDI_SUCCESS; 1260 1261 mutex_enter(&usbskelp->usbskel_mutex); 1262 if (usbskelp->usbskel_pm != NULL) { 1263 usbskelp->usbskel_pm->usbskel_pm_busy++; 1264 mutex_exit(&usbskelp->usbskel_mutex); 1265 if (pm_busy_component(usbskelp->usbskel_dip, 0) == 1266 DDI_SUCCESS) { 1267 (void) pm_raise_power( 1268 usbskelp->usbskel_dip, 0, USB_DEV_OS_FULL_PWR); 1269 mutex_enter(&usbskelp->usbskel_mutex); 1270 } else { 1271 mutex_enter(&usbskelp->usbskel_mutex); 1272 usbskelp->usbskel_pm->usbskel_pm_busy--; 1273 rval = DDI_FAILURE; 1274 } 1275 } 1276 mutex_exit(&usbskelp->usbskel_mutex); 1277 1278 return (rval); 1279 } 1280 1281 static void 1282 usbskel_pm_idle_component(usbskel_state_t *usbskelp) 1283 { 1284 mutex_enter(&usbskelp->usbskel_mutex); 1285 if (usbskelp->usbskel_pm != NULL) { 1286 mutex_exit(&usbskelp->usbskel_mutex); 1287 if (pm_idle_component(usbskelp->usbskel_dip, 0) == 1288 DDI_SUCCESS) { 1289 mutex_enter(&usbskelp->usbskel_mutex); 1290 ASSERT(usbskelp->usbskel_pm->usbskel_pm_busy > 0); 1291 usbskelp->usbskel_pm->usbskel_pm_busy--; 1292 mutex_exit(&usbskelp->usbskel_mutex); 1293 } 1294 mutex_enter(&usbskelp->usbskel_mutex); 1295 usbskel_log(usbskelp, USBSKEL_LOG_LOG, 1296 "usbskel_pm_idle_component: %d", 1297 usbskelp->usbskel_pm->usbskel_pm_busy); 1298 } 1299 mutex_exit(&usbskelp->usbskel_mutex); 1300 } 1301 1302 /* 1303 * usbskel_power : 1304 * Power entry point, the workhorse behind pm_raise_power, pm_lower_power, 1305 * usb_req_raise_power and usb_req_lower_power. 1306 */ 1307 /* ARGSUSED */ 1308 static int 1309 usbskel_power(dev_info_t *dip, int comp, int level) 1310 { 1311 usbskel_state_t *usbskelp; 1312 usbskel_power_t *pm; 1313 int rval = USB_FAILURE; 1314 1315 usbskelp = ddi_get_soft_state(usbskel_statep, ddi_get_instance(dip)); 1316 1317 usbskel_log(usbskelp, USBSKEL_LOG_LOG, 1318 "usbskel_power: enter: level = %d", level); 1319 1320 mutex_enter(&usbskelp->usbskel_mutex); 1321 (void) usbskel_serialize_access(usbskelp, USBSKEL_SER_NOSIG); 1322 1323 1324 /* 1325 * If we are disconnected/suspended, return success. Note that if we 1326 * return failure, bringing down the system will hang when 1327 * PM tries to power up all devices 1328 */ 1329 if ((usbskelp->usbskel_dev_state == USB_DEV_DISCONNECTED) || 1330 (usbskelp->usbskel_dev_state == USB_DEV_SUSPENDED)) { 1331 1332 usbskel_log(usbskelp, USBSKEL_LOG_LOG, 1333 "usbskel_power: disconnected/suspended " 1334 "dev_state=%d", usbskelp->usbskel_dev_state); 1335 rval = USB_SUCCESS; 1336 1337 goto done; 1338 } 1339 1340 if (usbskelp->usbskel_pm == NULL) { 1341 1342 goto done; 1343 } 1344 1345 pm = usbskelp->usbskel_pm; 1346 1347 /* Check if we are transitioning to a legal power level */ 1348 if (USB_DEV_PWRSTATE_OK(pm->usbskel_pwr_states, level)) { 1349 usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 1350 "usbskel_power: illegal power level = %d " 1351 "pwr_states: %x", level, pm->usbskel_pwr_states); 1352 1353 goto done; 1354 } 1355 1356 switch (level) { 1357 case USB_DEV_OS_PWR_OFF : 1358 /* fail attempt to go to low power if busy */ 1359 if (pm->usbskel_pm_busy) { 1360 1361 goto done; 1362 } 1363 if (usbskelp->usbskel_dev_state == USB_DEV_ONLINE) { 1364 usbskelp->usbskel_dev_state = USB_DEV_PWRED_DOWN; 1365 usbskelp->usbskel_pm->usbskel_current_power = 1366 USB_DEV_OS_PWR_OFF; 1367 } else { 1368 rval = USB_SUCCESS; 1369 } 1370 break; 1371 1372 case USB_DEV_OS_FULL_PWR : 1373 /* 1374 * PM framework tries to put us in full power during system 1375 * shutdown. 1376 */ 1377 usbskelp->usbskel_dev_state = USB_DEV_ONLINE; 1378 usbskelp->usbskel_pm->usbskel_current_power = 1379 USB_DEV_OS_FULL_PWR; 1380 break; 1381 1382 /* Levels 1 and 2 are not supported by this driver to keep it simple. */ 1383 default: 1384 usbskel_log(usbskelp, USBSKEL_LOG_LOG, 1385 "usbskel_power: power level %d not supported", level); 1386 break; 1387 } 1388 done: 1389 usbskel_release_access(usbskelp); 1390 mutex_exit(&usbskelp->usbskel_mutex); 1391 1392 return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE); 1393 } 1394 1395 1396 #ifdef USBSKEL_PM 1397 /* 1398 * usbskel_init_power_mgmt: 1399 * Initialize power management and remote wakeup functionality. 1400 * No mutex is necessary in this function as it's called only by attach. 1401 */ 1402 static int 1403 usbskel_init_power_mgmt(usbskel_state_t *usbskelp) 1404 { 1405 int rval = USB_FAILURE; 1406 1407 usbskel_log(usbskelp, USBSKEL_LOG_LOG, "init_power_mgmt enter"); 1408 1409 /* 1410 * If remote wakeup is not available you may not want to do 1411 * power management. 1412 */ 1413 if (usb_handle_remote_wakeup(usbskelp->usbskel_dip, 1414 USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS) { 1415 usbskel_power_t *usbskelpm; 1416 uint_t pwr_states; 1417 1418 /* Allocate the state structure */ 1419 usbskelpm = kmem_zalloc(sizeof (usbskel_power_t), KM_SLEEP); 1420 usbskelp->usbskel_pm = usbskelpm; 1421 usbskelpm->usbskel_state = usbskelp; 1422 usbskelpm->usbskel_pm_capabilities = 0; 1423 usbskelpm->usbskel_current_power = USB_DEV_OS_FULL_PWR; 1424 1425 if ((rval = usb_create_pm_components( 1426 usbskelp->usbskel_dip, &pwr_states)) == USB_SUCCESS) { 1427 1428 usbskel_log(usbskelp, USBSKEL_LOG_LOG, 1429 "usbskel_init_power_mgmt: created PM components"); 1430 1431 usbskelpm->usbskel_pwr_states = 1432 (uint8_t)pwr_states; 1433 (void) pm_raise_power( 1434 usbskelp->usbskel_dip, 0, USB_DEV_OS_FULL_PWR); 1435 } else { 1436 usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 1437 "usbskel_init_power_mgmt: create_pm_compts failed"); 1438 } 1439 } else { 1440 usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 1441 "usbskel_init_power_mgmt: failure enabling remote wakeup"); 1442 } 1443 usbskel_log(usbskelp, USBSKEL_LOG_LOG, "usbskel_init_power_mgmt: end"); 1444 1445 return (rval); 1446 } 1447 1448 1449 /* 1450 * usbskel_destroy_power_mgmt: 1451 * Shut down and destroy power management and remote wakeup functionality. 1452 */ 1453 static void 1454 usbskel_destroy_power_mgmt(usbskel_state_t *usbskelp) 1455 { 1456 usbskel_log(usbskelp, USBSKEL_LOG_LOG, "destroy_power_mgmt enter"); 1457 1458 ASSERT(!mutex_owned(&usbskelp->usbskel_mutex)); 1459 1460 if (usbskelp->usbskel_pm) { 1461 (void) usbskel_pm_busy_component(usbskelp); 1462 1463 mutex_enter(&usbskelp->usbskel_mutex); 1464 if (usbskelp->usbskel_dev_state != USB_DEV_DISCONNECTED) { 1465 int rval; 1466 1467 mutex_exit(&usbskelp->usbskel_mutex); 1468 1469 if ((rval = usb_handle_remote_wakeup( 1470 usbskelp->usbskel_dip, 1471 USB_REMOTE_WAKEUP_DISABLE)) != 1472 USB_SUCCESS) { 1473 usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 1474 "usbskel_destroy_power_mgmt: " 1475 "Error disabling rmt wakeup: rval = %d", 1476 rval); 1477 } 1478 } else { 1479 mutex_exit(&usbskelp->usbskel_mutex); 1480 } 1481 1482 /* 1483 * Since remote wakeup is disabled now, 1484 * no one can raise power 1485 * and get to device once power is lowered here. 1486 */ 1487 pm_lower_power(usbskelp->usbskel_dip, 0, USB_DEV_OS_PWR_OFF); 1488 usbskel_pm_idle_component(usbskelp); 1489 kmem_free(usbskelp->usbskel_pm, sizeof (usbskel_power_t)); 1490 usbskelp->usbskel_pm = NULL; 1491 } 1492 } 1493 #endif 1494 1495 1496 /* 1497 * usbskel_serialize_access: 1498 * Get the serial synchronization object before returning. 1499 * 1500 * Arguments: 1501 * usbskelp - Pointer to usbskel state structure 1502 * waitsig - Set to: 1503 * USBSKEL_SER_SIG - to wait such that a signal can interrupt 1504 * USBSKEL_SER_NOSIG - to wait such that a signal cannot interrupt 1505 */ 1506 static int 1507 usbskel_serialize_access(usbskel_state_t *usbskelp, boolean_t waitsig) 1508 { 1509 int rval = 1; 1510 1511 ASSERT(mutex_owned(&usbskelp->usbskel_mutex)); 1512 1513 while (usbskelp->usbskel_serial_inuse) { 1514 if (waitsig == USBSKEL_SER_SIG) { 1515 rval = cv_wait_sig(&usbskelp->usbskel_serial_cv, 1516 &usbskelp->usbskel_mutex); 1517 } else { 1518 cv_wait(&usbskelp->usbskel_serial_cv, 1519 &usbskelp->usbskel_mutex); 1520 } 1521 } 1522 usbskelp->usbskel_serial_inuse = B_TRUE; 1523 1524 return (rval); 1525 } 1526 1527 1528 /* 1529 * usbskel_release_access: 1530 * Release the serial synchronization object. 1531 */ 1532 static void 1533 usbskel_release_access(usbskel_state_t *usbskelp) 1534 { 1535 ASSERT(mutex_owned(&usbskelp->usbskel_mutex)); 1536 usbskelp->usbskel_serial_inuse = B_FALSE; 1537 cv_broadcast(&usbskelp->usbskel_serial_cv); 1538 } 1539 1540 1541 /* 1542 * usbskel_check_same_device: 1543 * Check if the device connected to the port is the same as 1544 * the previous device that was in the port. The previous device is 1545 * represented by the dip on record for the port. Print a message 1546 * if the device is different. Can block. 1547 * 1548 * return values: 1549 * USB_SUCCESS: same device 1550 * USB_INVALID_VERSION not same device 1551 * USB_FAILURE: Failure processing request 1552 */ 1553 static int 1554 usbskel_check_same_device(usbskel_state_t *usbskelp) 1555 { 1556 usb_dev_descr_t *orig_usb_dev_descr; 1557 usb_dev_descr_t usb_dev_descr; 1558 mblk_t *pdata = NULL; 1559 int rval; 1560 char *buf; 1561 usb_cr_t completion_reason; 1562 usb_cb_flags_t cb_flags; 1563 boolean_t match = B_TRUE; 1564 1565 usb_ctrl_setup_t setup = { 1566 USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD | 1567 USB_DEV_REQ_RCPT_DEV, 1568 USB_REQ_GET_DESCR, /* bRequest */ 1569 USB_DESCR_TYPE_SETUP_DEV, /* wValue */ 1570 0, /* wIndex */ 1571 USB_DEV_DESCR_SIZE, /* wLength */ 1572 0 /* request attributes */ 1573 }; 1574 1575 ASSERT(!mutex_owned(&usbskelp->usbskel_mutex)); 1576 1577 orig_usb_dev_descr = usbskelp->usbskel_reg->dev_descr; 1578 1579 /* get the "new" device descriptor */ 1580 rval = usb_pipe_ctrl_xfer_wait(usbskelp->usbskel_reg->dev_default_ph, 1581 &setup, &pdata, &completion_reason, &cb_flags, USB_FLAGS_SLEEP); 1582 1583 if (rval != USB_SUCCESS) { 1584 usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 1585 "usbskel_check_same_device: " 1586 "getting device descriptor failed " 1587 "rval=%d, cr=%d, cb=0x%x\n", 1588 rval, completion_reason, cb_flags); 1589 freemsg(pdata); 1590 1591 return (USB_FAILURE); 1592 } 1593 1594 ASSERT(pdata != NULL); 1595 1596 (void) usb_parse_data("2cs4c3s4c", pdata->b_rptr, 1597 MBLKL(pdata), &usb_dev_descr, 1598 sizeof (usb_dev_descr_t)); 1599 1600 freemsg(pdata); 1601 pdata = NULL; 1602 1603 /* Always check the device descriptor length. */ 1604 if (usb_dev_descr.bLength != USB_DEV_DESCR_SIZE) { 1605 match = B_FALSE; 1606 1607 /* Always check the device descriptor. */ 1608 } else if (bcmp(orig_usb_dev_descr, 1609 (char *)&usb_dev_descr, USB_DEV_DESCR_SIZE) != 0) { 1610 match = B_FALSE; 1611 } 1612 1613 /* if requested & this device has a serial number check and compare */ 1614 if ((match == B_TRUE) && 1615 (usbskelp->usbskel_reg->dev_serial != NULL)) { 1616 buf = kmem_alloc(USB_MAXSTRINGLEN, KM_SLEEP); 1617 if (usb_get_string_descr(usbskelp->usbskel_dip, USB_LANG_ID, 1618 usb_dev_descr.iSerialNumber, buf, 1619 USB_MAXSTRINGLEN) == USB_SUCCESS) { 1620 match = 1621 (strcmp(buf, 1622 usbskelp->usbskel_reg->dev_serial) == 0); 1623 } 1624 kmem_free(buf, USB_MAXSTRINGLEN); 1625 } 1626 1627 if (match == B_FALSE) { 1628 usbskel_log(usbskelp, USBSKEL_LOG_CONSOLE, 1629 "Device is not identical to the " 1630 "previous one this port.\n" 1631 "Please disconnect and reconnect"); 1632 1633 return (USB_INVALID_VERSION); 1634 } 1635 1636 return (USB_SUCCESS); 1637 } 1638 1639 /* 1640 * usbskel_log: 1641 * Switchable logging to logfile and screen. 1642 * 1643 * Arguments: 1644 * usbskelp: usbskel state pointer. 1645 * if NULL, driver name and instance won't print with the message 1646 * msglevel: 1647 * if USBSKEL_LOG_LOG, goes only to logfile. 1648 * (usbskel_errlevel must be set to USBSKEL_LOG_LOG too.) 1649 * if USBSKEL_LOG_CONSOLE, goes to both logfile and screen 1650 * (usbskel_errlevel can be either value for this to work.) 1651 * cmn_err_level: error level passed to cmn_err(9F) 1652 * format and args: as you would call cmn_err, except without special 1653 * first routing character. 1654 * 1655 * Do not call this in an interrupt context, since kmem_alloc can sleep. 1656 */ 1657 static void 1658 usbskel_log(usbskel_state_t *usbskelp, int msglevel, char *formatarg, ...) 1659 { 1660 va_list ap; 1661 1662 if (msglevel <= usbskel_errlevel) { 1663 char *format; 1664 int formatlen = strlen(formatarg) + 2; /* '!' and NULL char */ 1665 int devinst_start = 0; 1666 1667 /* Allocate extra room if driver name and instance is present */ 1668 if (usbskelp != NULL) { 1669 formatlen += strlen(usbskelp->usbskel_devinst); 1670 } 1671 1672 format = kmem_zalloc(formatlen, KM_SLEEP); 1673 1674 if (msglevel == USBSKEL_LOG_LOG) { 1675 format[0] = '!'; 1676 devinst_start = 1; 1677 } 1678 1679 if (usbskelp != NULL) { 1680 (void) strcpy(&format[devinst_start], 1681 usbskelp->usbskel_devinst); 1682 } 1683 1684 va_start(ap, formatarg); 1685 (void) strcat(format, formatarg); 1686 vcmn_err(CE_CONT, format, ap); 1687 va_end(ap); 1688 1689 kmem_free(format, formatlen); 1690 } 1691 }