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