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 }