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 * This driver is to be used for download firmware for devices. 29 */ 30 31 #if defined(lint) && !defined(DEBUG) 32 #define DEBUG 33 #endif 34 35 #define USBDRV_MAJOR_VER 2 36 #define USBDRV_MINOR_VER 0 37 38 #include <sys/kobj.h> 39 #include <sys/usb/usba.h> 40 #include <sys/usb/usba/usbai_private.h> 41 #include <sys/usb/clients/wusb_df/wusb_df.h> 42 43 #define WUSB_DF_INITIAL_SOFT_SPACE 1 44 #define MAX_DAT_FILE_SIZE (512 * 1024) 45 46 uint_t wusb_df_errlevel = USB_LOG_L4; 47 uint_t wusb_df_errmask = (uint_t)PRINT_MASK_ALL; 48 uint_t wusb_df_instance_debug = (uint_t)-1; 49 static char *name = "wusb_df"; /* Driver name, used all over. */ 50 static char wusb_fwmod[] = "hwa1480_fw"; 51 static char wusb_fwsym1[] = "hwa1480_fw"; 52 53 /* Soft state structures */ 54 static void *wusb_df_statep; 55 56 /* 57 * Function Prototypes 58 */ 59 static int wusb_df_attach(dev_info_t *, ddi_attach_cmd_t); 60 static int wusb_df_detach(dev_info_t *, ddi_detach_cmd_t); 61 static int wusb_df_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 62 static int wusb_df_cleanup(dev_info_t *, wusb_df_state_t *); 63 static int wusb_df_disconnect_callback(dev_info_t *); 64 static int wusb_df_reconnect_callback(dev_info_t *); 65 static void wusb_df_restore_device_state(dev_info_t *, wusb_df_state_t *); 66 static int wusb_df_cpr_suspend(dev_info_t *); 67 static void wusb_df_cpr_resume(dev_info_t *); 68 static void wusb_df_pm_busy_component(wusb_df_state_t *); 69 static void wusb_df_pm_idle_component(wusb_df_state_t *); 70 static int wusb_df_power(dev_info_t *, int, int); 71 static void wusb_df_init_power_mgmt(wusb_df_state_t *); 72 static void wusb_df_destroy_power_mgmt(wusb_df_state_t *); 73 static int wusb_df_serialize_access(wusb_df_state_t *, boolean_t); 74 static void wusb_df_release_access(wusb_df_state_t *); 75 static int wusb_df_firmware_download(wusb_df_state_t *wusbp); 76 77 78 /* _NOTE is an advice for locklint. Locklint checks lock use for deadlocks. */ 79 _NOTE(SCHEME_PROTECTS_DATA("unique per call", usb_ctrl_req)) 80 _NOTE(SCHEME_PROTECTS_DATA("unique per call", buf)) 81 82 /* module loading stuff */ 83 struct cb_ops wusb_df_cb_ops = { 84 nodev, /* open */ 85 nodev, /* close */ 86 nodev, /* strategy */ 87 nulldev, /* print */ 88 nulldev, /* dump */ 89 nodev, /* read */ 90 nodev, /* write */ 91 nodev, /* ioctl */ 92 nulldev, /* devmap */ 93 nodev, /* mmap */ 94 nodev, /* segmap */ 95 nochpoll, /* poll */ 96 ddi_prop_op, /* cb_prop_op */ 97 NULL, /* streamtab */ 98 D_MP 99 }; 100 101 static struct dev_ops wusb_df_ops = { 102 DEVO_REV, /* devo_rev, */ 103 0, /* refcnt */ 104 wusb_df_info, /* info */ 105 nulldev, /* identify */ 106 nulldev, /* probe */ 107 wusb_df_attach, /* attach */ 108 wusb_df_detach, /* detach */ 109 nodev, /* reset */ 110 &wusb_df_cb_ops, /* driver operations */ 111 NULL, /* bus operations */ 112 wusb_df_power /* power */ 113 }; 114 115 static struct modldrv wusb_df_modldrv = { 116 &mod_driverops, 117 "WUSB firmware download", 118 &wusb_df_ops 119 }; 120 121 static struct modlinkage modlinkage = { 122 MODREV_1, 123 &wusb_df_modldrv, 124 NULL 125 }; 126 127 /* 128 * Descriptor for a record of firmware 129 */ 130 typedef struct fw_dsc { 131 uint32_t addr; 132 size_t size; 133 uint8_t *data; 134 struct fw_dsc *next; 135 } fw_dsc_t; 136 137 138 /* 139 * Module-wide initialization routine. 140 */ 141 int 142 _init(void) 143 { 144 int rval; 145 146 147 if ((rval = ddi_soft_state_init(&wusb_df_statep, 148 sizeof (wusb_df_state_t), WUSB_DF_INITIAL_SOFT_SPACE)) != 0) { 149 150 return (rval); 151 } 152 153 if ((rval = mod_install(&modlinkage)) != 0) { 154 ddi_soft_state_fini(&wusb_df_statep); 155 } 156 157 158 return (rval); 159 } 160 161 162 /* 163 * Module-wide tear-down routine. 164 */ 165 int 166 _fini(void) 167 { 168 int rval; 169 170 if ((rval = mod_remove(&modlinkage)) != 0) { 171 172 return (rval); 173 } 174 175 ddi_soft_state_fini(&wusb_df_statep); 176 177 return (rval); 178 } 179 180 181 int 182 _info(struct modinfo *modinfop) 183 { 184 return (mod_info(&modlinkage, modinfop)); 185 } 186 187 /* 188 * wusb_df_attach: 189 * Attach or resume. 190 * 191 * For attach, initialize state and device, including: 192 * state variables, locks, device node 193 * device registration with system 194 * power management, hotplugging 195 * For resume, restore device and state 196 */ 197 static int 198 wusb_df_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 199 { 200 int instance = ddi_get_instance(dip); 201 char *devinst; 202 int devinstlen; 203 wusb_df_state_t *wusb_dfp = NULL; 204 usb_ep_data_t *ep_datap; 205 int status; 206 207 switch (cmd) { 208 case DDI_ATTACH: 209 break; 210 211 case DDI_RESUME: 212 wusb_df_cpr_resume(dip); 213 214 /* 215 * Always return success to work around enumeration failures. 216 * This works around an issue where devices which are present 217 * before a suspend and absent upon resume could cause a system 218 * panic on resume. 219 */ 220 return (DDI_SUCCESS); 221 default: 222 return (DDI_FAILURE); 223 } 224 225 if (ddi_soft_state_zalloc(wusb_df_statep, instance) == DDI_SUCCESS) { 226 wusb_dfp = ddi_get_soft_state(wusb_df_statep, instance); 227 } 228 if (wusb_dfp == NULL) { 229 230 return (DDI_FAILURE); 231 } 232 233 wusb_dfp->wusb_df_dip = dip; 234 235 devinst = kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP); 236 devinstlen = snprintf(devinst, USB_MAXSTRINGLEN, "%s%d: ", 237 ddi_driver_name(dip), instance); 238 239 wusb_dfp->wusb_df_devinst = kmem_zalloc(devinstlen + 1, KM_SLEEP); 240 (void) strncpy(wusb_dfp->wusb_df_devinst, devinst, devinstlen); 241 kmem_free(devinst, USB_MAXSTRINGLEN); 242 243 wusb_dfp->wusb_df_log_hdl = usb_alloc_log_hdl(dip, "wusb_df", 244 &wusb_df_errlevel, &wusb_df_errmask, &wusb_df_instance_debug, 0); 245 246 USB_DPRINTF_L4(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl, 247 "Attach: enter for attach"); 248 249 if ((status = usb_client_attach(dip, USBDRV_VERSION, 0)) != 250 USB_SUCCESS) { 251 USB_DPRINTF_L2(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl, 252 "attach: usb_client_attach failed, error code:%d", status); 253 goto fail; 254 } 255 256 if ((status = usb_get_dev_data(dip, &wusb_dfp->wusb_df_reg, 257 USB_PARSE_LVL_ALL, 0)) != USB_SUCCESS) { 258 USB_DPRINTF_L2(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl, 259 "attach: usb_get_dev_data failed, error code:%d", status); 260 goto fail; 261 } 262 263 264 /* 265 * Get the descriptor for an intr pipe at alt 0 of current interface. 266 * This will be used later to open the pipe. 267 */ 268 if ((ep_datap = usb_lookup_ep_data(dip, wusb_dfp->wusb_df_reg, 269 wusb_dfp->wusb_df_reg->dev_curr_if, 0, 0, 270 USB_EP_ATTR_INTR, USB_EP_DIR_IN)) == NULL) { 271 USB_DPRINTF_L2(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl, 272 "attach: Error getting intr endpoint descriptor"); 273 goto fail; 274 } 275 wusb_dfp->wusb_df_intr_ep_descr = ep_datap->ep_descr; 276 277 usb_free_descr_tree(dip, wusb_dfp->wusb_df_reg); 278 279 mutex_init(&wusb_dfp->wusb_df_mutex, NULL, MUTEX_DRIVER, 280 wusb_dfp->wusb_df_reg->dev_iblock_cookie); 281 282 cv_init(&wusb_dfp->wusb_df_serial_cv, NULL, CV_DRIVER, NULL); 283 wusb_dfp->wusb_df_serial_inuse = B_FALSE; 284 285 wusb_dfp->wusb_df_locks_initialized = B_TRUE; 286 287 /* create minor node */ 288 if (ddi_create_minor_node(dip, name, S_IFCHR, instance, 289 "wusb_df", 0) != DDI_SUCCESS) { 290 USB_DPRINTF_L2(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl, 291 "attach: Error creating minor node"); 292 goto fail; 293 } 294 295 /* Put online before PM init as can get power managed afterward. */ 296 wusb_dfp->wusb_df_dev_state = USB_DEV_ONLINE; 297 298 /* initialize power management */ 299 wusb_df_init_power_mgmt(wusb_dfp); 300 301 if (usb_register_hotplug_cbs(dip, wusb_df_disconnect_callback, 302 wusb_df_reconnect_callback) != USB_SUCCESS) { 303 304 goto fail; 305 } 306 307 /* Report device */ 308 ddi_report_dev(dip); 309 310 (void) wusb_df_firmware_download(wusb_dfp); 311 312 if (usb_reset_device(dip, USB_RESET_LVL_REATTACH) != USB_SUCCESS) { 313 USB_DPRINTF_L2(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl, 314 "reset device failed"); 315 316 return (USB_FAILURE); 317 } 318 319 return (DDI_SUCCESS); 320 321 fail: 322 if (wusb_dfp) { 323 (void) wusb_df_cleanup(dip, wusb_dfp); 324 } 325 326 return (DDI_FAILURE); 327 } 328 329 330 /* 331 * wusb_df_detach: 332 * detach or suspend driver instance 333 * 334 * Note: in detach, only contention threads is from pm and disconnnect. 335 */ 336 static int 337 wusb_df_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 338 { 339 int instance = ddi_get_instance(dip); 340 wusb_df_state_t *wusb_dfp = 341 ddi_get_soft_state(wusb_df_statep, instance); 342 int rval = DDI_FAILURE; 343 344 switch (cmd) { 345 case DDI_DETACH: 346 347 USB_DPRINTF_L4(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl, 348 "Detach: enter for detach"); 349 350 rval = wusb_df_cleanup(dip, wusb_dfp); 351 352 break; 353 case DDI_SUSPEND: 354 USB_DPRINTF_L4(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl, 355 "Detach: enter for suspend"); 356 357 rval = wusb_df_cpr_suspend(dip); 358 default: 359 360 break; 361 } 362 363 return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE); 364 } 365 366 367 /* 368 * wusb_df_cleanup: 369 * clean up the driver state for detach 370 */ 371 static int 372 wusb_df_cleanup(dev_info_t *dip, wusb_df_state_t *wusb_dfp) 373 { 374 375 USB_DPRINTF_L3(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl, 376 "Cleanup: enter"); 377 378 if (wusb_dfp->wusb_df_locks_initialized) { 379 380 /* This must be done 1st to prevent more events from coming. */ 381 usb_unregister_hotplug_cbs(dip); 382 383 /* 384 * At this point, no new activity can be initiated. The driver 385 * has disabled hotplug callbacks. The Solaris framework has 386 * disabled new opens on a device being detached, and does not 387 * allow detaching an open device. 388 * 389 * The following ensures that all driver activity has drained. 390 */ 391 mutex_enter(&wusb_dfp->wusb_df_mutex); 392 (void) wusb_df_serialize_access(wusb_dfp, WUSB_DF_SER_NOSIG); 393 wusb_df_release_access(wusb_dfp); 394 mutex_exit(&wusb_dfp->wusb_df_mutex); 395 396 /* All device activity has died down. */ 397 wusb_df_destroy_power_mgmt(wusb_dfp); 398 399 /* start dismantling */ 400 ddi_remove_minor_node(dip, NULL); 401 402 cv_destroy(&wusb_dfp->wusb_df_serial_cv); 403 mutex_destroy(&wusb_dfp->wusb_df_mutex); 404 } 405 406 usb_client_detach(dip, wusb_dfp->wusb_df_reg); 407 408 usb_free_log_hdl(wusb_dfp->wusb_df_log_hdl); 409 410 if (wusb_dfp->wusb_df_devinst != NULL) { 411 kmem_free(wusb_dfp->wusb_df_devinst, 412 strlen(wusb_dfp->wusb_df_devinst) + 1); 413 } 414 415 ddi_soft_state_free(wusb_df_statep, ddi_get_instance(dip)); 416 ddi_prop_remove_all(dip); 417 418 return (USB_SUCCESS); 419 } 420 421 422 /* 423 * wusb_df_disconnect_callback: 424 * Called when device hotplug-removed. 425 * Close pipes. (This does not attempt to contact device.) 426 * Set state to DISCONNECTED 427 */ 428 static int 429 wusb_df_disconnect_callback(dev_info_t *dip) 430 { 431 int instance = ddi_get_instance(dip); 432 wusb_df_state_t *wusb_dfp = 433 ddi_get_soft_state(wusb_df_statep, instance); 434 435 436 USB_DPRINTF_L4(PRINT_MASK_CB, wusb_dfp->wusb_df_log_hdl, 437 "disconnect: enter"); 438 439 mutex_enter(&wusb_dfp->wusb_df_mutex); 440 (void) wusb_df_serialize_access(wusb_dfp, WUSB_DF_SER_NOSIG); 441 442 /* 443 * Save any state of device or IO in progress required by 444 * wusb_df_restore_device_state for proper device "thawing" later. 445 */ 446 wusb_dfp->wusb_df_dev_state = USB_DEV_DISCONNECTED; 447 448 wusb_df_release_access(wusb_dfp); 449 mutex_exit(&wusb_dfp->wusb_df_mutex); 450 451 return (USB_SUCCESS); 452 } 453 454 455 /* 456 * wusb_df_reconnect_callback: 457 * Called with device hotplug-inserted 458 * Restore state 459 */ 460 static int 461 wusb_df_reconnect_callback(dev_info_t *dip) 462 { 463 int instance = ddi_get_instance(dip); 464 wusb_df_state_t *wusb_dfp = 465 ddi_get_soft_state(wusb_df_statep, instance); 466 467 USB_DPRINTF_L4(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl, 468 "reconnect: enter"); 469 470 wusb_df_pm_busy_component(wusb_dfp); 471 (void) pm_raise_power(wusb_dfp->wusb_df_dip, 0, USB_DEV_OS_FULL_PWR); 472 473 mutex_enter(&wusb_dfp->wusb_df_mutex); 474 (void) wusb_df_serialize_access(wusb_dfp, WUSB_DF_SER_NOSIG); 475 wusb_df_restore_device_state(dip, wusb_dfp); 476 wusb_df_release_access(wusb_dfp); 477 mutex_exit(&wusb_dfp->wusb_df_mutex); 478 479 wusb_df_pm_idle_component(wusb_dfp); 480 481 return (USB_SUCCESS); 482 } 483 484 485 /* 486 * wusb_df_restore_device_state: 487 * Called during hotplug-reconnect and resume. 488 * reenable power management 489 * Verify the device is the same as before the disconnect/suspend. 490 * Restore device state 491 * Thaw any IO which was frozen. 492 * Quiesce device. (Other routines will activate if thawed IO.) 493 * Set device online. 494 * Leave device disconnected if there are problems. 495 */ 496 static void 497 wusb_df_restore_device_state(dev_info_t *dip, wusb_df_state_t *wusb_dfp) 498 { 499 USB_DPRINTF_L2(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl, 500 "wusb_df_restore_device_state: enter"); 501 502 ASSERT(mutex_owned(&wusb_dfp->wusb_df_mutex)); 503 504 ASSERT((wusb_dfp->wusb_df_dev_state == USB_DEV_DISCONNECTED) || 505 (wusb_dfp->wusb_df_dev_state == USB_DEV_SUSPENDED)); 506 507 mutex_exit(&wusb_dfp->wusb_df_mutex); 508 509 510 /* Check if we are talking to the same device */ 511 if (usb_check_same_device(dip, wusb_dfp->wusb_df_log_hdl, 512 USB_LOG_L0, PRINT_MASK_ALL, 513 USB_CHK_ALL, NULL) != USB_SUCCESS) { 514 515 /* change the device state from suspended to disconnected */ 516 mutex_enter(&wusb_dfp->wusb_df_mutex); 517 wusb_dfp->wusb_df_dev_state = USB_DEV_SUSPENDED; 518 USB_DPRINTF_L2(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl, 519 "wusb_df_restore_device_state: check same device failed"); 520 return; 521 } 522 523 mutex_enter(&wusb_dfp->wusb_df_mutex); 524 wusb_dfp->wusb_df_dev_state = USB_DEV_ONLINE; 525 526 if (wusb_dfp->wusb_df_pm && 527 wusb_dfp->wusb_df_pm->wusb_df_wakeup_enabled) { 528 529 /* Failure here means device disappeared again. */ 530 mutex_exit(&wusb_dfp->wusb_df_mutex); 531 if (usb_handle_remote_wakeup(dip, USB_REMOTE_WAKEUP_ENABLE) != 532 USB_SUCCESS) { 533 USB_DPRINTF_L2(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl, 534 "device may or may not be accessible. " 535 "Please verify reconnection"); 536 } 537 mutex_enter(&wusb_dfp->wusb_df_mutex); 538 } 539 540 541 USB_DPRINTF_L4(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl, 542 "wusb_df_restore_device_state: end"); 543 544 } 545 546 547 /* 548 * wusb_df_cpr_suspend: 549 * Clean up device. 550 * Wait for any IO to finish, then close pipes. 551 * Quiesce device. 552 */ 553 static int 554 wusb_df_cpr_suspend(dev_info_t *dip) 555 { 556 int instance = ddi_get_instance(dip); 557 wusb_df_state_t *wusb_dfp = 558 ddi_get_soft_state(wusb_df_statep, instance); 559 560 USB_DPRINTF_L4(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl, 561 "suspend enter"); 562 563 /* Serialize to prevent races with detach, open, device access. */ 564 mutex_enter(&wusb_dfp->wusb_df_mutex); 565 (void) wusb_df_serialize_access(wusb_dfp, WUSB_DF_SER_NOSIG); 566 mutex_exit(&wusb_dfp->wusb_df_mutex); 567 568 wusb_df_pm_busy_component(wusb_dfp); 569 570 mutex_enter(&wusb_dfp->wusb_df_mutex); 571 572 /* Access device here to clean it up. */ 573 574 wusb_dfp->wusb_df_dev_state = USB_DEV_SUSPENDED; 575 576 /* 577 * Save any state of device required by wusb_df_restore_device_state 578 * for proper device "thawing" later. 579 */ 580 581 wusb_df_release_access(wusb_dfp); 582 mutex_exit(&wusb_dfp->wusb_df_mutex); 583 584 wusb_df_pm_idle_component(wusb_dfp); 585 586 USB_DPRINTF_L4(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl, 587 "suspend: success"); 588 589 return (USB_SUCCESS); 590 } 591 592 593 /* 594 * wusb_df_cpr_resume: 595 * 596 * wusb_df_restore_device_state marks success by putting device back online 597 */ 598 static void 599 wusb_df_cpr_resume(dev_info_t *dip) 600 { 601 int instance = ddi_get_instance(dip); 602 wusb_df_state_t *wusb_dfp = 603 ddi_get_soft_state(wusb_df_statep, instance); 604 605 USB_DPRINTF_L4(PRINT_MASK_CPR, wusb_dfp->wusb_df_log_hdl, 606 "resume: enter"); 607 608 /* 609 * NOTE: A pm_raise_power in wusb_df_restore_device_state will bring 610 * the power-up state of device into synch with the system. 611 */ 612 wusb_df_pm_busy_component(wusb_dfp); 613 (void) pm_raise_power(wusb_dfp->wusb_df_dip, 0, USB_DEV_OS_FULL_PWR); 614 mutex_enter(&wusb_dfp->wusb_df_mutex); 615 wusb_df_restore_device_state(dip, wusb_dfp); 616 mutex_exit(&wusb_dfp->wusb_df_mutex); 617 wusb_df_pm_idle_component(wusb_dfp); 618 } 619 620 static void 621 wusb_df_pm_busy_component(wusb_df_state_t *wusb_dfp) 622 { 623 ASSERT(!mutex_owned(&wusb_dfp->wusb_df_mutex)); 624 625 mutex_enter(&wusb_dfp->wusb_df_mutex); 626 if (wusb_dfp->wusb_df_pm == NULL) { 627 USB_DPRINTF_L4(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl, 628 "wusb_df_pm_busy_component: pm = NULL"); 629 goto done; 630 } 631 632 wusb_dfp->wusb_df_pm->wusb_df_pm_busy++; 633 USB_DPRINTF_L4(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl, 634 "wusb_df_pm_busy_component: %d", 635 wusb_dfp->wusb_df_pm->wusb_df_pm_busy); 636 637 mutex_exit(&wusb_dfp->wusb_df_mutex); 638 639 if (pm_busy_component(wusb_dfp->wusb_df_dip, 0) != DDI_SUCCESS) { 640 mutex_enter(&wusb_dfp->wusb_df_mutex); 641 wusb_dfp->wusb_df_pm->wusb_df_pm_busy--; 642 643 USB_DPRINTF_L4(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl, 644 "wusb_df_pm_busy_component: %d", 645 wusb_dfp->wusb_df_pm->wusb_df_pm_busy); 646 mutex_exit(&wusb_dfp->wusb_df_mutex); 647 648 649 } 650 return; 651 done: 652 mutex_exit(&wusb_dfp->wusb_df_mutex); 653 654 } 655 656 static void 657 wusb_df_pm_idle_component(wusb_df_state_t *wusb_dfp) 658 { 659 ASSERT(!mutex_owned(&wusb_dfp->wusb_df_mutex)); 660 mutex_enter(&wusb_dfp->wusb_df_mutex); 661 if (wusb_dfp->wusb_df_pm == NULL) { 662 mutex_exit(&wusb_dfp->wusb_df_mutex); 663 return; 664 } 665 mutex_exit(&wusb_dfp->wusb_df_mutex); 666 667 668 if (pm_idle_component(wusb_dfp->wusb_df_dip, 0) == DDI_SUCCESS) { 669 mutex_enter(&wusb_dfp->wusb_df_mutex); 670 ASSERT(wusb_dfp->wusb_df_pm->wusb_df_pm_busy > 0); 671 wusb_dfp->wusb_df_pm->wusb_df_pm_busy--; 672 673 USB_DPRINTF_L4(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl, 674 "wusb_df_pm_idle_component: %d", 675 wusb_dfp->wusb_df_pm->wusb_df_pm_busy); 676 677 mutex_exit(&wusb_dfp->wusb_df_mutex); 678 } 679 } 680 681 /* 682 * wusb_df_power : 683 * Power entry point, the workhorse behind pm_raise_power, pm_lower_power, 684 * usb_req_raise_power and usb_req_lower_power. 685 */ 686 /* ARGSUSED */ 687 static int 688 wusb_df_power(dev_info_t *dip, int comp, int level) 689 { 690 wusb_df_state_t *wusb_dfp; 691 wusb_df_power_t *pm; 692 int rval = USB_SUCCESS; 693 694 wusb_dfp = ddi_get_soft_state(wusb_df_statep, ddi_get_instance(dip)); 695 696 USB_DPRINTF_L3(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl, 697 "wusb_df_power: enter: level = %d", level); 698 699 mutex_enter(&wusb_dfp->wusb_df_mutex); 700 (void) wusb_df_serialize_access(wusb_dfp, WUSB_DF_SER_NOSIG); 701 702 703 /* 704 * If we are disconnected/suspended, return success. Note that if we 705 * return failure, bringing down the system will hang when 706 * PM tries to power up all devices 707 */ 708 if ((wusb_dfp->wusb_df_dev_state == USB_DEV_DISCONNECTED) || 709 (wusb_dfp->wusb_df_dev_state == USB_DEV_SUSPENDED)) { 710 711 USB_DPRINTF_L3(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl, 712 "wusb_df_power: disconnected/suspended " 713 "dev_state=%d", wusb_dfp->wusb_df_dev_state); 714 rval = USB_SUCCESS; 715 716 goto done; 717 } 718 719 if (wusb_dfp->wusb_df_pm == NULL) { 720 721 goto done; 722 } 723 724 pm = wusb_dfp->wusb_df_pm; 725 726 /* Check if we are transitioning to a legal power level */ 727 if (USB_DEV_PWRSTATE_OK(pm->wusb_df_pwr_states, level)) { 728 USB_DPRINTF_L3(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl, 729 "wusb_df_power: illegal power level = %d " 730 "pwr_states: %x", level, pm->wusb_df_pwr_states); 731 732 goto done; 733 } 734 735 switch (level) { 736 case USB_DEV_OS_PWR_OFF : 737 /* fail attempt to go to low power if busy */ 738 if (pm->wusb_df_pm_busy) { 739 740 goto done; 741 } 742 if (wusb_dfp->wusb_df_dev_state == USB_DEV_ONLINE) { 743 wusb_dfp->wusb_df_dev_state = USB_DEV_PWRED_DOWN; 744 wusb_dfp->wusb_df_pm->wusb_df_current_power = 745 USB_DEV_OS_PWR_OFF; 746 } else { 747 rval = USB_SUCCESS; 748 } 749 break; 750 751 case USB_DEV_OS_FULL_PWR : 752 /* 753 * PM framework tries to put us in full power during system 754 * shutdown. 755 */ 756 wusb_dfp->wusb_df_dev_state = USB_DEV_ONLINE; 757 wusb_dfp->wusb_df_pm->wusb_df_current_power = 758 USB_DEV_OS_FULL_PWR; 759 break; 760 761 /* Levels 1 and 2 are not supported by this driver to keep it simple. */ 762 default: 763 USB_DPRINTF_L3(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl, 764 "wusb_df_power: power level %d not supported", level); 765 break; 766 } 767 done: 768 wusb_df_release_access(wusb_dfp); 769 mutex_exit(&wusb_dfp->wusb_df_mutex); 770 771 return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE); 772 } 773 774 775 /* 776 * wusb_df_init_power_mgmt: 777 * Initialize power management and remote wakeup functionality. 778 * No mutex is necessary in this function as it's called only by attach. 779 */ 780 static void 781 wusb_df_init_power_mgmt(wusb_df_state_t *wusb_dfp) 782 { 783 wusb_df_power_t *wusb_dfpm; 784 uint_t pwr_states; 785 786 USB_DPRINTF_L4(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl, 787 "init_power_mgmt enter"); 788 789 /* 790 * If remote wakeup is not available you may not want to do 791 * power management. 792 */ 793 /* Allocate the state structure */ 794 wusb_dfpm = kmem_zalloc(sizeof (wusb_df_power_t), KM_SLEEP); 795 wusb_dfp->wusb_df_pm = wusb_dfpm; 796 wusb_dfpm->wusb_df_state = wusb_dfp; 797 wusb_dfpm->wusb_df_pm_capabilities = 0; 798 wusb_dfpm->wusb_df_current_power = USB_DEV_OS_FULL_PWR; 799 800 if (usb_create_pm_components(wusb_dfp->wusb_df_dip, &pwr_states) == 801 USB_SUCCESS) { 802 803 USB_DPRINTF_L4(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl, 804 "wusb_df_init_power_mgmt: created PM components"); 805 806 wusb_dfpm->wusb_df_pwr_states = (uint8_t)pwr_states; 807 (void) pm_raise_power(wusb_dfp->wusb_df_dip, 0, 808 USB_DEV_OS_FULL_PWR); 809 810 if (usb_handle_remote_wakeup(wusb_dfp->wusb_df_dip, 811 USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS) { 812 wusb_dfpm->wusb_df_wakeup_enabled = 1; 813 } else { 814 USB_DPRINTF_L2(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl, 815 "wusb_df_init_power_mgmt:" 816 "fail to enable remote wakeup"); 817 } 818 819 } else { 820 USB_DPRINTF_L2(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl, 821 "wusb_df_init_power_mgmt: create_pm_compts failed"); 822 } 823 USB_DPRINTF_L4(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl, 824 "wusb_df_init_power_mgmt: end"); 825 826 } 827 828 829 /* 830 * wusb_df_destroy_power_mgmt: 831 * Shut down and destroy power management and remote wakeup functionality. 832 */ 833 static void 834 wusb_df_destroy_power_mgmt(wusb_df_state_t *wusb_dfp) 835 { 836 USB_DPRINTF_L4(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl, 837 "destroy_power_mgmt enter"); 838 839 ASSERT(!mutex_owned(&wusb_dfp->wusb_df_mutex)); 840 841 mutex_enter(&wusb_dfp->wusb_df_mutex); 842 if (!wusb_dfp->wusb_df_pm) { 843 mutex_exit(&wusb_dfp->wusb_df_mutex); 844 return; 845 } 846 mutex_exit(&wusb_dfp->wusb_df_mutex); 847 848 (void) wusb_df_pm_busy_component(wusb_dfp); 849 850 mutex_enter(&wusb_dfp->wusb_df_mutex); 851 if (wusb_dfp->wusb_df_dev_state != USB_DEV_DISCONNECTED) { 852 853 if (wusb_dfp->wusb_df_pm->wusb_df_wakeup_enabled) { 854 mutex_exit(&wusb_dfp->wusb_df_mutex); 855 856 (void) pm_raise_power(wusb_dfp->wusb_df_dip, 0, 857 USB_DEV_OS_FULL_PWR); 858 if (usb_handle_remote_wakeup(wusb_dfp->wusb_df_dip, 859 USB_REMOTE_WAKEUP_DISABLE) != USB_SUCCESS) { 860 USB_DPRINTF_L2(PRINT_MASK_PM, 861 wusb_dfp->wusb_df_log_hdl, 862 "wusb_df_destroy_power_mgmt: " 863 "Error disabling rmt wakeup"); 864 } 865 mutex_enter(&wusb_dfp->wusb_df_mutex); 866 867 } 868 } 869 mutex_exit(&wusb_dfp->wusb_df_mutex); 870 871 /* 872 * Since remote wakeup is disabled now, 873 * no one can raise power 874 * and get to device once power is lowered here. 875 */ 876 (void) pm_lower_power(wusb_dfp->wusb_df_dip, 0, USB_DEV_OS_PWR_OFF); 877 wusb_df_pm_idle_component(wusb_dfp); 878 879 mutex_enter(&wusb_dfp->wusb_df_mutex); 880 kmem_free(wusb_dfp->wusb_df_pm, sizeof (wusb_df_power_t)); 881 wusb_dfp->wusb_df_pm = NULL; 882 mutex_exit(&wusb_dfp->wusb_df_mutex); 883 } 884 885 886 /* 887 * wusb_df_serialize_access: 888 * Get the serial synchronization object before returning. 889 * 890 * Arguments: 891 * wusb_dfp - Pointer to wusb_df state structure 892 * waitsig - Set to: 893 * WUSB_DF_SER_SIG - to wait such that a signal can interrupt 894 * WUSB_DF_SER_NOSIG - to wait such that a signal cannot interrupt 895 */ 896 static int 897 wusb_df_serialize_access(wusb_df_state_t *wusb_dfp, boolean_t waitsig) 898 { 899 int rval = 1; 900 901 ASSERT(mutex_owned(&wusb_dfp->wusb_df_mutex)); 902 903 while (wusb_dfp->wusb_df_serial_inuse) { 904 if (waitsig == WUSB_DF_SER_SIG) { 905 rval = cv_wait_sig(&wusb_dfp->wusb_df_serial_cv, 906 &wusb_dfp->wusb_df_mutex); 907 } else { 908 cv_wait(&wusb_dfp->wusb_df_serial_cv, 909 &wusb_dfp->wusb_df_mutex); 910 } 911 } 912 wusb_dfp->wusb_df_serial_inuse = B_TRUE; 913 914 return (rval); 915 } 916 917 918 /* 919 * wusb_df_release_access: 920 * Release the serial synchronization object. 921 */ 922 static void 923 wusb_df_release_access(wusb_df_state_t *wusb_dfp) 924 { 925 ASSERT(mutex_owned(&wusb_dfp->wusb_df_mutex)); 926 wusb_dfp->wusb_df_serial_inuse = B_FALSE; 927 cv_broadcast(&wusb_dfp->wusb_df_serial_cv); 928 } 929 930 /* 931 * wusb_df_info: 932 * Get minor number, soft state structure, etc. 933 */ 934 /*ARGSUSED*/ 935 static int 936 wusb_df_info(dev_info_t *dip, ddi_info_cmd_t infocmd, 937 void *arg, void **result) 938 { 939 wusb_df_state_t *wusb_dfp; 940 int error = DDI_FAILURE; 941 942 switch (infocmd) { 943 case DDI_INFO_DEVT2DEVINFO: 944 if ((wusb_dfp = ddi_get_soft_state(wusb_df_statep, 945 getminor((dev_t)arg))) != NULL) { 946 *result = wusb_dfp->wusb_df_dip; 947 if (*result != NULL) { 948 error = DDI_SUCCESS; 949 } 950 } else { 951 *result = NULL; 952 } 953 break; 954 case DDI_INFO_DEVT2INSTANCE: 955 *result = (void *)(uintptr_t)getminor((dev_t)arg); 956 error = DDI_SUCCESS; 957 break; 958 default: 959 break; 960 } 961 962 return (error); 963 } 964 965 /* Free a chain of firmware headers */ 966 static void 967 free_fw_dscs(struct fw_dsc *head) 968 { 969 struct fw_dsc *next; 970 971 while (head) { 972 next = head->next; 973 kmem_free(head, sizeof (fw_dsc_t)); 974 head = next; 975 } 976 } 977 978 static unsigned int 979 char2int32(unsigned char *input) 980 { 981 return ((*input) | 982 (*(input + 1) << 8) | 983 (*(input + 2) << 16) | 984 (*(input + 3) << 24)); 985 } 986 987 /* 988 * download firmware or command by control pipe 989 */ 990 static int 991 wusb_df_send_data(wusb_df_state_t *wusbp, 992 unsigned int address, 993 const unsigned char *buffer, 994 unsigned int size) 995 { 996 int error = DDI_FAILURE; 997 usb_ctrl_setup_t setup; 998 usb_cb_flags_t cb_flags; 999 usb_cr_t cr; 1000 mblk_t *data = NULL; /* data for USBA */ 1001 uint16_t data_len; /* # of bytes want to write */ 1002 uint_t cnt; /* # of xfered bytes */ 1003 1004 setup.bmRequestType = USB_DEV_REQ_TYPE_VENDOR | 1005 USB_DEV_REQ_HOST_TO_DEV | USB_DEV_REQ_RCPT_DEV; 1006 setup.bRequest = 0xf0; 1007 setup.attrs = 0; 1008 1009 for (cnt = 0; cnt < size; cnt += data_len) { 1010 data_len = min(size - cnt, 512); 1011 1012 /* reuse previous mblk if possible */ 1013 if ((data = reallocb(data, data_len, 0)) == NULL) { 1014 1015 return (USB_FAILURE); 1016 } 1017 bcopy(buffer + cnt, data->b_rptr, data_len); 1018 data->b_wptr += data_len; 1019 1020 setup.wValue = (address + cnt) & 0xffff; 1021 setup.wIndex = ((address + cnt) >> 16) & 0xffff; 1022 setup.wLength = data_len; 1023 error = usb_pipe_ctrl_xfer_wait( 1024 wusbp->wusb_df_reg->dev_default_ph, &setup, &data, 1025 &cr, &cb_flags, 0); 1026 if (error != USB_SUCCESS) { 1027 USB_DPRINTF_L2(PRINT_MASK_ATTA, wusbp->wusb_df_log_hdl, 1028 "wusb_df_send_data: " 1029 "send failed rval=%d, cr=%d, cb=0x%x\n", 1030 error, cr, cb_flags); 1031 1032 break; 1033 } 1034 } 1035 1036 if (data) { 1037 freemsg(data); 1038 } 1039 1040 return (error); 1041 } 1042 1043 /* 1044 * find the firmware module's "_start", "_end" symbols 1045 * and get the size of firmware. 1046 */ 1047 static int 1048 wusbdf_mod_loadsym(wusb_df_state_t *dfp, ddi_modhandle_t modp, char *mod, 1049 char *sym, char **start, size_t *len) 1050 { 1051 char start_sym[256]; 1052 char end_sym[256]; 1053 char *p, *end; 1054 int rv; 1055 size_t n; 1056 1057 (void) snprintf(start_sym, sizeof (start_sym), "%s_start", sym); 1058 (void) snprintf(end_sym, sizeof (end_sym), "%s_end", sym); 1059 1060 p = (char *)ddi_modsym(modp, start_sym, &rv); 1061 if (p == NULL || rv != 0) { 1062 USB_DPRINTF_L2(PRINT_MASK_ATTA, dfp->wusb_df_log_hdl, 1063 "mod %s: symbol %s not found\n", mod, start_sym); 1064 return (-1); 1065 } 1066 end = (char *)ddi_modsym(modp, end_sym, &rv); 1067 if (end == NULL || rv != 0) { 1068 USB_DPRINTF_L2(PRINT_MASK_ATTA, dfp->wusb_df_log_hdl, 1069 "mod %s: symbol %s not found\n", mod, end_sym); 1070 return (-1); 1071 } 1072 n = end - p; 1073 1074 *start = p; 1075 *len = n; 1076 1077 return (0); 1078 } 1079 1080 /* write firmware segments into device through control endpoint */ 1081 static int 1082 wusb_df_fw_download(wusb_df_state_t *wusb_dfp) 1083 { 1084 int error = USB_SUCCESS; 1085 size_t size = 0, record_cnt = 0; 1086 unsigned char *pdata, *data_end; 1087 unsigned char *firmware_image; 1088 fw_dsc_t *pdsc = NULL, *rcd_head = NULL, *tmpr = NULL; 1089 unsigned int remaining_size; 1090 int rv = 0; 1091 ddi_modhandle_t modp; 1092 char *firm_start; 1093 1094 USB_DPRINTF_L3(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl, 1095 "Download firmware: %s", wusb_fwmod); 1096 1097 /* allow user specify firmware in .conf? */ 1098 1099 /* see elfwrap(1) for how to turn firmware into loadable module */ 1100 modp = ddi_modopen(wusb_fwmod, KRTLD_MODE_FIRST, &rv); 1101 if (modp == NULL) { 1102 USB_DPRINTF_L2(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl, 1103 "module %s not found", wusb_fwmod); 1104 1105 error = USB_FAILURE; 1106 goto checkstatus; 1107 } 1108 1109 rv = wusbdf_mod_loadsym(wusb_dfp, modp, wusb_fwmod, wusb_fwsym1, 1110 &firm_start, &size); 1111 if (rv != 0) { 1112 USB_DPRINTF_L2(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl, 1113 "module(%s) loadsym error", wusb_fwmod); 1114 1115 error = USB_FAILURE; 1116 goto checkstatus; 1117 } 1118 1119 if (size >= MAX_DAT_FILE_SIZE) { 1120 USB_DPRINTF_L2(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl, 1121 "file size too big"); 1122 1123 error = USB_FAILURE; 1124 goto checkstatus; 1125 } else { 1126 firmware_image = (unsigned char *)kmem_alloc(size, KM_SLEEP); 1127 1128 if (!firmware_image) { 1129 USB_DPRINTF_L2(PRINT_MASK_ATTA, 1130 wusb_dfp->wusb_df_log_hdl, "malloc failed"); 1131 1132 error = USB_FAILURE; 1133 goto checkstatus; 1134 } 1135 1136 (void) memcpy(firmware_image, firm_start, size); 1137 } 1138 1139 USB_DPRINTF_L3(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl, 1140 "file size = %d", (int)size); 1141 1142 /* 1143 * close the module, return if 1) fail to close or 2) encounter error 1144 * when getting above symbol 1145 */ 1146 checkstatus: 1147 if (modp != NULL) 1148 rv = ddi_modclose(modp); 1149 1150 if ((rv != 0) || (error != USB_SUCCESS)) { 1151 USB_DPRINTF_L2(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl, 1152 "modclose(%s) error", wusb_fwmod); 1153 1154 return (USB_FAILURE); 1155 } 1156 1157 /* 1158 * BIN firmware has this format: 1159 * address(4B) + length(4B) + data(Length Bytes) ... repeat 1160 */ 1161 pdata = firmware_image; 1162 data_end = firmware_image + size; 1163 while (pdata < data_end) { 1164 error = USB_FAILURE; 1165 pdsc = (fw_dsc_t *)kmem_zalloc(sizeof (fw_dsc_t), KM_SLEEP); 1166 1167 /* hdr_offset = pdata - firmware_image; */ 1168 remaining_size = data_end - pdata; 1169 1170 if ((pdata + 8) > data_end) { 1171 kmem_free(pdsc, sizeof (fw_dsc_t)); 1172 free_fw_dscs(rcd_head); 1173 break; 1174 } 1175 1176 pdsc->next = NULL; 1177 pdsc->addr = char2int32(pdata); 1178 pdsc->size = 4 * char2int32(pdata + 4); 1179 pdsc->data = pdata + 8; 1180 if (pdsc->size > remaining_size) { 1181 kmem_free(pdsc, sizeof (fw_dsc_t)); 1182 free_fw_dscs(rcd_head); 1183 break; 1184 } 1185 USB_DPRINTF_L3(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl, 1186 "address = 0x%x, length = 0x%x, " 1187 "first 4 byte is : 0x%02x 0x%02x 0x%02x 0x%02x", 1188 pdsc->addr, (int)pdsc->size, pdsc->data[0], pdsc->data[1], 1189 pdsc->data[2], pdsc->data[3]); 1190 1191 pdata += 8 + pdsc->size; 1192 if (rcd_head == NULL) { 1193 rcd_head = pdsc; 1194 } else { 1195 tmpr->next = pdsc; 1196 } 1197 1198 tmpr = pdsc; /* tmp record */ 1199 record_cnt ++; 1200 error = USB_SUCCESS; 1201 } 1202 1203 USB_DPRINTF_L3(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl, 1204 "Start download firmware ..."); 1205 for (pdsc = rcd_head; pdsc != NULL; pdsc = pdsc->next) { 1206 error = wusb_df_send_data(wusb_dfp, pdsc->addr, 1207 pdsc->data, pdsc->size); 1208 if (error != USB_SUCCESS) { 1209 1210 USB_DPRINTF_L2(PRINT_MASK_ATTA, 1211 wusb_dfp->wusb_df_log_hdl, "Download failure!"); 1212 break; 1213 } 1214 1215 delay(drv_usectohz(1000)); 1216 } 1217 1218 USB_DPRINTF_L2(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl, 1219 "Download firmware end."); 1220 1221 free_fw_dscs(rcd_head); 1222 kmem_free(firmware_image, size); 1223 1224 return (error); 1225 } 1226 1227 1228 /* 1229 * Firmware download. Program device special registers and then call 1230 * wusb_df_fw_download() to download the true data. 1231 */ 1232 static int 1233 wusb_df_firmware_download(wusb_df_state_t *wusbp) 1234 { 1235 int error = USB_FAILURE; 1236 unsigned char buf[4]; 1237 1238 (void) memset(buf, 0, 4); 1239 /* program the device register to make it ready to accept fw */ 1240 error = wusb_df_send_data(wusbp, 0x800000c0, buf, 4); 1241 if (error != USB_SUCCESS) { 1242 USB_DPRINTF_L2(PRINT_MASK_ATTA, wusbp->wusb_df_log_hdl, 1243 "Fail init"); 1244 return (error); 1245 } 1246 1247 error = wusb_df_fw_download(wusbp); 1248 if (error != USB_SUCCESS) { 1249 USB_DPRINTF_L2(PRINT_MASK_ATTA, wusbp->wusb_df_log_hdl, 1250 "Fail to download firmware"); 1251 return (error); 1252 } 1253 1254 buf[0] = 0x48; 1255 buf[1] = 0x56; 1256 buf[2] = 0x2c; 1257 buf[3] = 0x00; 1258 error = wusb_df_send_data(wusbp, 0x80008060, buf, 4); 1259 if (error != USB_SUCCESS) { 1260 return (error); 1261 } 1262 1263 (void) memset(buf, 0, 4); 1264 buf[0] = 0x18; 1265 /* firmware download finished, program the device to lock fw */ 1266 error = wusb_df_send_data(wusbp, 0x800000c0, buf, 4); 1267 1268 return (error); 1269 }