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  * UWB HWA Radio Controller driver.
  29  *
  30  *
  31  * The device has four states (refer to usbai.h):
  32  *      USB_DEV_ONLINE: In action or ready for action.
  33  *      USB_DEV_DISCONNECTED: Hotplug removed, or device not present/correct on
  34  *              resume (CPR).
  35  *      USB_DEV_SUSPENDED: Device has been suspended along with the system.
  36  *      USB_DEV_PWRED_DOWN: Device has been powered down.  (Note that this
  37  *              driver supports only two power states, powered down and
  38  *              full power.)
  39  *
  40  * In order to avoid race conditions between driver entry points,
  41  * access to the device is serialized.  Race conditions are an issue in
  42  * particular between disconnect event callbacks, detach, power, open
  43  * and data transfer callbacks.  The functions hwarc_serialize/release_access
  44  * are implemented for this purpose.
  45  *
  46  * Mutexes should never be held when making calls into USBA or when
  47  * sleeping.
  48  *
  49  * pm_busy_component and pm_idle_component mark the device as busy or idle to
  50  * the system.  These functions are paired, and are called only from code
  51  * bracketed by hwarc_serialize_access and hwarc_release_access.
  52  *
  53  */
  54 
  55 #define USBDRV_MAJOR_VER        2
  56 #define USBDRV_MINOR_VER        0
  57 
  58 #include <sys/strsun.h>
  59 #include <sys/usb/usba.h>
  60 #include <sys/usb/clients/hwarc/hwarc.h>
  61 
  62 
  63 
  64 uint_t          hwarc_errlevel          = 4;
  65 static uint_t   hwarc_errmask           = (uint_t)PRINT_MASK_ALL;
  66 static uint_t   hwarc_instance_debug    = (uint_t)-1;
  67 
  68 static char     *name           = "hwarc";      /* Driver name, used all over */
  69 
  70 
  71 /* Function Prototypes */
  72 static int      hwarc_attach(dev_info_t *, ddi_attach_cmd_t);
  73 static int      hwarc_detach(dev_info_t *, ddi_detach_cmd_t);
  74 static int      hwarc_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
  75 static int      hwarc_cleanup(dev_info_t *, hwarc_state_t *);
  76 static int      hwarc_open(dev_t *, int, int, cred_t *);
  77 static int      hwarc_close(dev_t, int, int, cred_t *);
  78 static int      hwarc_send_cmd(uwb_dev_handle_t, mblk_t *, uint16_t);
  79 static int      hwarc_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
  80 static int      hwarc_disconnect_callback(dev_info_t *);
  81 static int      hwarc_reconnect_callback(dev_info_t *);
  82 static void     hwarc_restore_device_state(dev_info_t *, hwarc_state_t *);
  83 static int      hwarc_cpr_suspend(dev_info_t *);
  84 static void     hwarc_cpr_resume(dev_info_t *);
  85 static int      hwarc_open_intr_pipe(hwarc_state_t *);
  86 static void     hwarc_close_intr_pipe(hwarc_state_t *);
  87 static void     hwarc_pm_busy_component(hwarc_state_t *);
  88 static void     hwarc_pm_idle_component(hwarc_state_t *);
  89 static int      hwarc_power(dev_info_t *, int, int);
  90 static int      hwarc_serialize_access(hwarc_state_t *, boolean_t);
  91 static void     hwarc_release_access(hwarc_state_t *);
  92 static int      hwarc_reset_device(hwarc_state_t *);
  93 static int      hwarc_init_phy(hwarc_state_t *);
  94 
  95 
  96 static int      hwarc_start_polling(hwarc_state_t *, usb_pipe_handle_t);
  97 
  98 
  99 _NOTE(SCHEME_PROTECTS_DATA("unique per call", usb_ctrl_req))
 100 _NOTE(SCHEME_PROTECTS_DATA("unique per call", usb_intr_req))
 101 _NOTE(SCHEME_PROTECTS_DATA("unique per call", buf))
 102 
 103 /* module loading stuff */
 104 struct cb_ops hwarc_cb_ops = {
 105         hwarc_open,             /* open  */
 106         hwarc_close,            /* close */
 107         nodev,                  /* strategy */
 108         nulldev,                /* print */
 109         nulldev,                /* dump */
 110         nodev,                  /* read */
 111         nodev,                  /* write */
 112         hwarc_ioctl,            /* ioctl */
 113         nulldev,                /* devmap */
 114         nodev,                  /* mmap */
 115         nodev,                  /* segmap */
 116         nochpoll,               /* poll */
 117         ddi_prop_op,            /* cb_prop_op */
 118         NULL,                   /* streamtab  */
 119         D_MP
 120 };
 121 
 122 static struct dev_ops hwarc_ops = {
 123         DEVO_REV,               /* devo_rev, */
 124         0,                      /* refcnt  */
 125         hwarc_info,             /* info */
 126         nulldev,                /* identify */
 127         nulldev,                /* probe */
 128         hwarc_attach,           /* attach */
 129         hwarc_detach,           /* detach */
 130         nodev,                  /* reset */
 131         &hwarc_cb_ops,              /* driver operations */
 132         NULL,                   /* bus operations */
 133         hwarc_power,            /* power */
 134         ddi_quiesce_not_needed, /* devo_quiesce */
 135 };
 136 
 137 static struct modldrv hwarc_modldrv =   {
 138         &mod_driverops,
 139         "USB HWA Radio Controller driver",
 140         &hwarc_ops
 141 };
 142 
 143 static struct modlinkage modlinkage = {
 144         MODREV_1,
 145         &hwarc_modldrv,
 146         NULL
 147 };
 148 
 149 /* Soft state structures */
 150 #define HWARC_INITIAL_SOFT_SPACE        1
 151 static void *hwarc_statep;
 152 
 153 
 154 /* Module-wide initialization routine */
 155 int
 156 _init(void)
 157 {
 158         int rval;
 159 
 160         if ((rval = ddi_soft_state_init(&hwarc_statep,
 161             sizeof (hwarc_state_t), HWARC_INITIAL_SOFT_SPACE)) != 0) {
 162 
 163                 return (rval);
 164         }
 165 
 166         if ((rval = mod_install(&modlinkage)) != 0) {
 167                 ddi_soft_state_fini(&hwarc_statep);
 168         }
 169 
 170         return (rval);
 171 }
 172 
 173 
 174 /* Module-wide tear-down routine */
 175 int
 176 _fini(void)
 177 {
 178         int rval;
 179 
 180         if ((rval = mod_remove(&modlinkage)) != 0) {
 181 
 182                 return (rval);
 183         }
 184 
 185         ddi_soft_state_fini(&hwarc_statep);
 186 
 187         return (rval);
 188 }
 189 
 190 
 191 int
 192 _info(struct modinfo *modinfop)
 193 {
 194         return (mod_info(&modlinkage, modinfop));
 195 }
 196 
 197 
 198 /*
 199  * hwarc_info:
 200  *      Get minor number, soft state structure, etc.
 201  */
 202 /*ARGSUSED*/
 203 static int
 204 hwarc_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
 205                         void *arg, void **result)
 206 {
 207         hwarc_state_t   *hrcp;
 208         int error = DDI_FAILURE;
 209 
 210         switch (infocmd) {
 211         case DDI_INFO_DEVT2DEVINFO:
 212                 *result = NULL;
 213                 if ((hrcp = ddi_get_soft_state(hwarc_statep,
 214                     getminor((dev_t)arg))) != NULL) {
 215                         *result = hrcp->hrc_dip;
 216                 }
 217                 error = (*result)? DDI_SUCCESS:DDI_FAILURE;
 218 
 219                 break;
 220         case DDI_INFO_DEVT2INSTANCE:
 221                 *result = (void *)(uintptr_t)getminor((dev_t)arg);
 222                 error = DDI_SUCCESS;
 223                 break;
 224         default:
 225                 break;
 226         }
 227 
 228         return (error);
 229 }
 230 
 231 
 232 
 233 /*
 234  * hwarc_init_power_mgmt:
 235  *      Initialize power management and remote wakeup functionality.
 236  *      No mutex is necessary in this function as it's called only by attach.
 237  */
 238 static void
 239 hwarc_init_power_mgmt(hwarc_state_t *hrcp)
 240 {
 241         hwarc_power_t   *hrcpm = NULL;
 242         uint_t          pwr_states;
 243 
 244         USB_DPRINTF_L4(PRINT_MASK_PM, hrcp->hrc_log_hdl,
 245             "init_power_mgmt enter");
 246 
 247         /* Put online before PM init as can get power managed afterward. */
 248         hrcp->hrc_dev_state = USB_DEV_ONLINE;
 249 
 250         /* Allocate the state structure */
 251         hrcpm = kmem_zalloc(sizeof (hwarc_power_t), KM_SLEEP);
 252 
 253         hrcpm->hrc_state             = hrcp;
 254         hrcpm->hrc_pm_capabilities   = 0;
 255         hrcpm->hrc_current_power     = USB_DEV_OS_FULL_PWR;
 256 
 257 
 258         if (usb_create_pm_components(hrcp->hrc_dip, &pwr_states) ==
 259             USB_SUCCESS) {
 260                 hrcpm->hrc_pwr_states        = (uint8_t)pwr_states;
 261 
 262                 if (usb_handle_remote_wakeup(hrcp->hrc_dip,
 263                     USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS) {
 264                         hrcpm->hrc_wakeup_enabled = 1;
 265                 } else {
 266                         USB_DPRINTF_L2(PRINT_MASK_PM,
 267                             hrcp->hrc_log_hdl, "hwarc_init_power_mgmt:"
 268                             " remote wakeup not supported");
 269                 }
 270 
 271         } else {
 272                 USB_DPRINTF_L2(PRINT_MASK_PM, hrcp->hrc_log_hdl,
 273                     "hwarc_init_power_mgmt:created PM components failed");
 274         }
 275         mutex_enter(&hrcp->hrc_mutex);
 276         hrcp->hrc_pm = hrcpm;
 277         hwarc_pm_busy_component(hrcp);
 278         mutex_exit(&hrcp->hrc_mutex);
 279 
 280         (void) pm_raise_power(
 281             hrcp->hrc_dip, 0, USB_DEV_OS_FULL_PWR);
 282 
 283         USB_DPRINTF_L4(PRINT_MASK_PM, hrcp->hrc_log_hdl,
 284             "hwarc_init_power_mgmt: end");
 285 }
 286 
 287 
 288 /*
 289  * hwarc_destroy_power_mgmt:
 290  *      Shut down and destroy power management and remote wakeup functionality.
 291  */
 292 static void
 293 hwarc_destroy_power_mgmt(hwarc_state_t *hrcp)
 294 {
 295         hwarc_power_t   *pm;
 296 
 297         USB_DPRINTF_L4(PRINT_MASK_PM, hrcp->hrc_log_hdl,
 298             "destroy_power_mgmt enter");
 299 
 300         mutex_enter(&hrcp->hrc_mutex);
 301 
 302         if ((pm = hrcp->hrc_pm) == NULL) {
 303                 USB_DPRINTF_L3(PRINT_MASK_PM, hrcp->hrc_log_hdl,
 304                     "hwarc_destroy_power_mgmt:pm not supported");
 305                 goto done;
 306         }
 307 
 308         if (hrcp->hrc_dev_state == USB_DEV_DISCONNECTED) {
 309                 USB_DPRINTF_L3(PRINT_MASK_PM, hrcp->hrc_log_hdl,
 310                     "hwarc_destroy_power_mgmt:device disconnected");
 311                 goto done;
 312         }
 313 
 314         hwarc_pm_busy_component(hrcp);
 315 
 316         mutex_exit(&hrcp->hrc_mutex);
 317 
 318         if (pm->hrc_wakeup_enabled) {
 319 
 320                 /* First bring the device to full power */
 321                 (void) pm_raise_power(hrcp->hrc_dip, 0, USB_DEV_OS_FULL_PWR);
 322                 if (usb_handle_remote_wakeup(hrcp->hrc_dip,
 323                     USB_REMOTE_WAKEUP_DISABLE) != USB_SUCCESS) {
 324                         USB_DPRINTF_L2(PRINT_MASK_PM,
 325                             hrcp->hrc_log_hdl, "hwarc_destroy_power_mgmt: "
 326                             "Error disabling rmt wakeup");
 327                 }
 328 
 329         }
 330 
 331         /*
 332          * Since remote wakeup is disabled now,
 333          * no one can raise power
 334          * and get to device once power is lowered here.
 335          */
 336         (void) pm_lower_power(hrcp->hrc_dip, 0, USB_DEV_OS_PWR_OFF);
 337 
 338         mutex_enter(&hrcp->hrc_mutex);
 339 
 340         hwarc_pm_idle_component(hrcp);
 341 
 342 done:
 343         if (pm) {
 344                 kmem_free(pm, sizeof (hwarc_power_t));
 345 
 346                 hrcp->hrc_pm = NULL;
 347         }
 348         mutex_exit(&hrcp->hrc_mutex);
 349 }
 350 
 351 
 352 static void
 353 hwarc_pm_busy_component(hwarc_state_t *hrcp)
 354 {
 355         ASSERT(mutex_owned(&hrcp->hrc_mutex));
 356 
 357         USB_DPRINTF_L4(PRINT_MASK_PM, hrcp->hrc_log_hdl,
 358             "hwarc_pm_busy_component: enter");
 359         if (hrcp->hrc_pm == NULL) {
 360                 USB_DPRINTF_L4(PRINT_MASK_PM, hrcp->hrc_log_hdl,
 361                     "hwarc_pm_busy_component: pm not supported, return");
 362 
 363                 return;
 364         }
 365 
 366         hrcp->hrc_pm->hrc_pm_busy++;
 367 
 368         mutex_exit(&hrcp->hrc_mutex);
 369         if (pm_busy_component(hrcp->hrc_dip, 0) !=
 370             DDI_SUCCESS) {
 371                 mutex_enter(&hrcp->hrc_mutex);
 372                 USB_DPRINTF_L3(PRINT_MASK_PM, hrcp->hrc_log_hdl,
 373                     "hwarc_pm_busy_component: pm busy fail, hrc_pm_busy=%d",
 374                     hrcp->hrc_pm->hrc_pm_busy);
 375 
 376                 hrcp->hrc_pm->hrc_pm_busy--;
 377                 mutex_exit(&hrcp->hrc_mutex);
 378         }
 379         mutex_enter(&hrcp->hrc_mutex);
 380 
 381         USB_DPRINTF_L4(PRINT_MASK_PM, hrcp->hrc_log_hdl,
 382             "hwarc_pm_busy_component: exit");
 383 }
 384 
 385 
 386 static void
 387 hwarc_pm_idle_component(hwarc_state_t *hrcp)
 388 {
 389         ASSERT(mutex_owned(&hrcp->hrc_mutex));
 390         USB_DPRINTF_L4(PRINT_MASK_PM, hrcp->hrc_log_hdl,
 391             "hwarc_pm_idle_component: enter");
 392 
 393         if (hrcp->hrc_pm == NULL) {
 394                 USB_DPRINTF_L4(PRINT_MASK_PM, hrcp->hrc_log_hdl,
 395                     "hwarc_pm_idle_component: pm not supported");
 396 
 397                 return;
 398         }
 399 
 400         mutex_exit(&hrcp->hrc_mutex);
 401         if (pm_idle_component(hrcp->hrc_dip, 0) == DDI_SUCCESS) {
 402                 mutex_enter(&hrcp->hrc_mutex);
 403                 ASSERT(hrcp->hrc_pm->hrc_pm_busy > 0);
 404                 hrcp->hrc_pm->hrc_pm_busy--;
 405                 mutex_exit(&hrcp->hrc_mutex);
 406         }
 407         mutex_enter(&hrcp->hrc_mutex);
 408 
 409         USB_DPRINTF_L3(PRINT_MASK_PM, hrcp->hrc_log_hdl,
 410             "hwarc_pm_idle_component: %d", hrcp->hrc_pm->hrc_pm_busy);
 411 
 412 }
 413 
 414 
 415 /*
 416  * hwarc_pwrlvl0:
 417  * Functions to handle power transition for OS levels 0 -> 3
 418  */
 419 static int
 420 hwarc_pwrlvl0(hwarc_state_t *hrcp)
 421 {
 422         int rval;
 423 
 424         USB_DPRINTF_L3(PRINT_MASK_PM, hrcp->hrc_log_hdl,
 425             "hwarc_pwrlvl0, dev_state: %x", hrcp->hrc_dev_state);
 426 
 427         switch (hrcp->hrc_dev_state) {
 428                 case USB_DEV_ONLINE:
 429                         /* Deny the powerdown request if the device is busy */
 430                         if (hrcp->hrc_pm->hrc_pm_busy != 0) {
 431                                 USB_DPRINTF_L2(PRINT_MASK_PM, hrcp->hrc_log_hdl,
 432                                     "hwarc_pwrlvl0: hrc_pm_busy");
 433 
 434                                 return (USB_FAILURE);
 435                         }
 436 
 437                         /* Close the interrupt pipe */
 438                         mutex_exit(&hrcp->hrc_mutex);
 439                         hwarc_close_intr_pipe(hrcp);
 440                         mutex_enter(&hrcp->hrc_mutex);
 441 
 442                         /* Issue USB D3 command to the device here */
 443                         rval = usb_set_device_pwrlvl3(hrcp->hrc_dip);
 444                         ASSERT(rval == USB_SUCCESS);
 445 
 446                         hrcp->hrc_dev_state = USB_DEV_PWRED_DOWN;
 447                         hrcp->hrc_pm->hrc_current_power = USB_DEV_OS_PWR_OFF;
 448 
 449                 /* FALLTHRU */
 450                 case USB_DEV_DISCONNECTED:
 451                 case USB_DEV_SUSPENDED:
 452 
 453                         return (USB_SUCCESS);
 454 
 455                 case USB_DEV_PWRED_DOWN:
 456                 default:
 457                         USB_DPRINTF_L2(PRINT_MASK_PM, hrcp->hrc_log_hdl,
 458                             "hwarc_pwrlvl0: illegal dev state");
 459 
 460                         return (USB_FAILURE);
 461         }
 462 }
 463 
 464 
 465 /*
 466  * hwarc_pwrlvl1:
 467  *      Functions to handle power transition to OS levels -> 2
 468  */
 469 static int
 470 hwarc_pwrlvl1(hwarc_state_t *hrcp)
 471 {
 472         int     rval;
 473 
 474         USB_DPRINTF_L4(PRINT_MASK_PM, hrcp->hrc_log_hdl, "hwarc_pwrlvl1");
 475 
 476         /* Issue USB D2 command to the device here */
 477         rval = usb_set_device_pwrlvl2(hrcp->hrc_dip);
 478         ASSERT(rval == USB_SUCCESS);
 479 
 480         return (USB_FAILURE);
 481 }
 482 
 483 
 484 /*
 485  * hwarc_pwrlvl2:
 486  *      Functions to handle power transition to OS levels -> 1
 487  */
 488 static int
 489 hwarc_pwrlvl2(hwarc_state_t *hrcp)
 490 {
 491         int     rval;
 492 
 493         USB_DPRINTF_L3(PRINT_MASK_PM, hrcp->hrc_log_hdl,
 494             "hwarc_pwrlvl2, dev_stat=%d", hrcp->hrc_dev_state);
 495 
 496         /* Issue USB D1 command to the device here */
 497         rval = usb_set_device_pwrlvl1(hrcp->hrc_dip);
 498         ASSERT(rval == USB_SUCCESS);
 499 
 500         return (USB_FAILURE);
 501 }
 502 
 503 
 504 /*
 505  * hwarc_pwrlvl3:
 506  *      Functions to handle power transition to OS level -> 0
 507  */
 508 static int
 509 hwarc_pwrlvl3(hwarc_state_t *hrcp)
 510 {
 511 
 512         USB_DPRINTF_L3(PRINT_MASK_PM, hrcp->hrc_log_hdl,
 513             "hwarc_pwrlvl3, dev_stat=%d", hrcp->hrc_dev_state);
 514 
 515         switch (hrcp->hrc_dev_state) {
 516                 case USB_DEV_PWRED_DOWN:
 517                         /* Issue USB D0 command to the device here */
 518                         (void) usb_set_device_pwrlvl0(hrcp->hrc_dip);
 519 
 520                         mutex_exit(&hrcp->hrc_mutex);
 521                         if (hwarc_open_intr_pipe(hrcp) != USB_SUCCESS) {
 522                                 mutex_enter(&hrcp->hrc_mutex);
 523 
 524                                 return (USB_FAILURE);
 525                         }
 526                         mutex_enter(&hrcp->hrc_mutex);
 527 
 528                         /* Todo: Reset device or not */
 529                         hrcp->hrc_dev_state          = USB_DEV_ONLINE;
 530                         hrcp->hrc_pm->hrc_current_power = USB_DEV_OS_FULL_PWR;
 531 
 532                         /* FALLTHRU */
 533                 case USB_DEV_ONLINE:
 534                         /* we are already in full power */
 535                         /* FALLTHRU */
 536                 case USB_DEV_DISCONNECTED:
 537                 case USB_DEV_SUSPENDED:
 538                         /*
 539                          * PM framework tries to put us in full power
 540                          * during system shutdown. If we are disconnected/cpr'ed
 541                          * return success anyways
 542                          */
 543 
 544                         return (USB_SUCCESS);
 545 
 546                 default:
 547                         USB_DPRINTF_L2(PRINT_MASK_PM, hrcp->hrc_log_hdl,
 548                             "hwarc_pwrlvl3: illegal dev state");
 549 
 550                         return (USB_FAILURE);
 551         }
 552 }
 553 
 554 /* Init dev inst */
 555 static void
 556 hwarc_init_devinst(dev_info_t *dip, hwarc_state_t *hrcp)
 557 {
 558         char    *devinst;
 559         int     devinstlen;
 560 
 561         hrcp->hrc_dip          = dip;
 562         hrcp->hrc_log_hdl = usb_alloc_log_hdl(dip,
 563             "hwarc", &hwarc_errlevel,
 564             &hwarc_errmask, &hwarc_instance_debug, 0);
 565 
 566         devinst = kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP);
 567         devinstlen = snprintf(devinst, USB_MAXSTRINGLEN, "%s%d: ",
 568             ddi_driver_name(dip), ddi_get_instance(dip));
 569 
 570         hrcp->hrc_devinst = kmem_zalloc(devinstlen + 1, KM_SLEEP);
 571         (void) strncpy(hrcp->hrc_devinst, devinst, devinstlen);
 572 
 573         kmem_free(devinst, USB_MAXSTRINGLEN);
 574 }
 575 
 576 /* init endpoints */
 577 static int
 578 hwarc_init_ep(dev_info_t *dip, hwarc_state_t *hrcp)
 579 {
 580         int status = USB_SUCCESS;
 581         usb_ep_data_t   *ep_datap;
 582         if ((status = usb_client_attach(dip, USBDRV_VERSION, 0)) !=
 583             USB_SUCCESS) {
 584                 USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
 585                     "hwarc_init_ep: usb_client_attach failed"
 586                     " error code = %d", status);
 587                 goto done;
 588         }
 589 
 590         if ((status = usb_get_dev_data(dip, &hrcp->hrc_reg, USB_PARSE_LVL_ALL,
 591             0)) != USB_SUCCESS) {
 592                 USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
 593                     "hwarc_init_ep: usb_get_dev_data failed"
 594                     "error code = %d", status);
 595                 goto done;
 596         }
 597         hrcp->hrc_if_descr =
 598             &hrcp->hrc_reg->dev_curr_cfg->cfg_if[hrcp->hrc_reg->dev_curr_if];
 599         hrcp->hrc_default_ph = hrcp->hrc_reg->dev_default_ph;
 600 
 601         /*
 602          * Get the descriptor for an intr pipe at alt 0 of current interface.
 603          * This will be used later to open the pipe.
 604          */
 605         if ((ep_datap = usb_lookup_ep_data(dip, hrcp->hrc_reg,
 606             hrcp->hrc_reg->dev_curr_if, 0, 0,
 607             USB_EP_ATTR_INTR, USB_EP_DIR_IN)) == NULL) {
 608                 USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
 609                     "hwarc_init_ep: Error getting intr endpoint descriptor");
 610                 status = USB_FAILURE;
 611                 goto done;
 612         }
 613         hrcp->hrc_intr_ep_descr = ep_datap->ep_descr;
 614 
 615 done:
 616 
 617         return (status);
 618 }
 619 /* init mutex */
 620 static void
 621 hwarc_init_mutex(hwarc_state_t *hrcp) {
 622         mutex_init(&hrcp->hrc_mutex, NULL, MUTEX_DRIVER,
 623             hrcp->hrc_reg->dev_iblock_cookie);
 624 
 625         cv_init(&hrcp->hrc_serial_cv, NULL, CV_DRIVER, NULL);
 626         hrcp->hrc_serial_inuse = B_FALSE;
 627 
 628         hrcp->hrc_locks_initialized = B_TRUE;
 629 }
 630 /*
 631  * hwarc_attach:
 632  *      Attach or resume.
 633  *
 634  *      For attach, initialize state and device, including:
 635  *              state variables, locks, device node
 636  *              device registration with system
 637  *              power management, hotplugging
 638  *      For resume, restore device and state
 639  */
 640 static int
 641 hwarc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 642 {
 643         int                     instance = ddi_get_instance(dip);
 644         hwarc_state_t           *hrcp = NULL;
 645 
 646         switch (cmd) {
 647                 case DDI_ATTACH:
 648                         break;
 649 
 650                 case DDI_RESUME:
 651                         hwarc_cpr_resume(dip);
 652                         /*
 653                          * Always return success to work around enumeration
 654                          * failures.This works around an issue where devices
 655                          * which are present before a suspend and absent upon
 656                          * resume could cause a system panic on resume.
 657                          */
 658 
 659                         return (DDI_SUCCESS);
 660                 default:
 661                         return (DDI_FAILURE);
 662         }
 663 
 664         if (ddi_soft_state_zalloc(hwarc_statep, instance) == DDI_SUCCESS) {
 665                 hrcp = ddi_get_soft_state(hwarc_statep, instance);
 666         }
 667         if (hrcp == NULL)  {
 668                 USB_DPRINTF_L2(PRINT_MASK_ATTA, NULL,
 669                     "hwarc_attach: get soft state failed for instance %d",
 670                     instance);
 671 
 672                 return (DDI_FAILURE);
 673         }
 674 
 675         (void) hwarc_init_devinst(dip, hrcp);
 676 
 677         if (hwarc_init_ep(dip, hrcp) != USB_SUCCESS) {
 678                 USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
 679                     "attach: Error init usb data");
 680                 goto fail;
 681         }
 682         hwarc_init_mutex(hrcp);
 683 
 684         /* create minor node */
 685         if (ddi_create_minor_node(dip, name, S_IFCHR, instance,
 686             NULL, 0) != DDI_SUCCESS) {
 687                 USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
 688                     "attach: Error creating minor node");
 689                 goto fail;
 690         }
 691 
 692         /* initialize power management */
 693         hwarc_init_power_mgmt(hrcp);
 694 
 695         if (usb_register_hotplug_cbs(dip, hwarc_disconnect_callback,
 696             hwarc_reconnect_callback) != USB_SUCCESS) {
 697                 USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
 698                     "attach: Error register hotplug cbs");
 699 
 700                 goto fail;
 701         }
 702 
 703         /* register this device to uwba */
 704         uwb_dev_attach(dip, &hrcp->hrc_dev_hdl, 0, hwarc_send_cmd);
 705 
 706         if (hwarc_open_intr_pipe(hrcp) != USB_SUCCESS) {
 707                 USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
 708                     "attach: Error open intr pipe");
 709 
 710                 goto fail;
 711         }
 712 
 713         /* reset device */
 714         if (hwarc_reset_device(hrcp) != USB_SUCCESS) {
 715                 USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
 716                     "attach: Error reset deivce");
 717                 goto fail;
 718         }
 719         /* init phy capabilities */
 720         if (hwarc_init_phy(hrcp) != USB_SUCCESS) {
 721                 USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
 722                     "attach: Error get phy ie");
 723 
 724                 goto fail;
 725         }
 726         /* Report device */
 727         ddi_report_dev(dip);
 728 
 729         mutex_enter(&hrcp->hrc_mutex);
 730         hwarc_pm_idle_component(hrcp);
 731         mutex_exit(&hrcp->hrc_mutex);
 732 
 733         return (DDI_SUCCESS);
 734 
 735 fail:
 736         (void) hwarc_cleanup(dip, hrcp);
 737 
 738         return (DDI_FAILURE);
 739 }
 740 
 741 
 742 /*
 743  * hwarc_detach:
 744  *      detach or suspend driver instance
 745  *
 746  * Note: in detach, only contention threads is from pm and disconnnect.
 747  */
 748 static int
 749 hwarc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
 750 {
 751         int             rval    = USB_SUCCESS;
 752         hwarc_state_t   *hrcp   =
 753             ddi_get_soft_state(hwarc_statep, ddi_get_instance(dip));
 754 
 755         USB_DPRINTF_L3(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
 756             "hwarc_detach: enter for detach, cmd = %d", cmd);
 757 
 758 
 759         switch (cmd) {
 760                 case DDI_DETACH:
 761 
 762                         rval = hwarc_cleanup(dip, hrcp);
 763 
 764                         break;
 765                 case DDI_SUSPEND:
 766 
 767                         rval = hwarc_cpr_suspend(dip);
 768                 default:
 769 
 770                         break;
 771         }
 772 
 773         return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
 774 }
 775 
 776 
 777 /*
 778  * hwarc_cleanup:
 779  *      clean up the driver state for detach
 780  */
 781 static int
 782 hwarc_cleanup(dev_info_t *dip, hwarc_state_t *hrcp)
 783 {
 784         USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl, "Cleanup: enter");
 785 
 786         if (hrcp->hrc_locks_initialized) {
 787 
 788                 (void) uwb_stop_beacon(dip);
 789                 /* This must be done 1st to prevent more events from coming. */
 790                 usb_unregister_hotplug_cbs(dip);
 791 
 792                 hwarc_close_intr_pipe(hrcp);
 793 
 794                 /*
 795                  * At this point, no new activity can be initiated. The driver
 796                  * has disabled hotplug callbacks. The Solaris framework has
 797                  * disabled new opens on a device being detached, and does not
 798                  * allow detaching an open device.
 799                  *
 800                  * The following ensures that all driver activity has drained.
 801                  */
 802                 mutex_enter(&hrcp->hrc_mutex);
 803                 (void) hwarc_serialize_access(hrcp, HWARC_SER_NOSIG);
 804                 hwarc_release_access(hrcp);
 805                 mutex_exit(&hrcp->hrc_mutex);
 806 
 807                 /* All device activity has died down. */
 808                 hwarc_destroy_power_mgmt(hrcp);
 809 
 810                 /* start dismantling */
 811                 ddi_remove_minor_node(dip, NULL);
 812                 cv_destroy(&hrcp->hrc_serial_cv);
 813                 mutex_destroy(&hrcp->hrc_mutex);
 814         }
 815 
 816         usb_client_detach(dip, hrcp->hrc_reg);
 817 
 818         USB_DPRINTF_L4(PRINT_MASK_ATTA, hrcp->hrc_log_hdl, "Cleanup: end");
 819 
 820         usb_free_log_hdl(hrcp->hrc_log_hdl);
 821 
 822         uwb_dev_detach(hrcp->hrc_dev_hdl);
 823 
 824         kmem_free(hrcp->hrc_devinst, strlen(hrcp->hrc_devinst) + 1);
 825 
 826         ddi_soft_state_free(hwarc_statep, ddi_get_instance(dip));
 827         ddi_prop_remove_all(dip);
 828 
 829         return (USB_SUCCESS);
 830 }
 831 
 832 
 833 
 834 /*ARGSUSED*/
 835 static int
 836 hwarc_open(dev_t *devp, int flag, int otyp, cred_t *cred_p)
 837 {
 838         hwarc_state_t   *hrcp = NULL;
 839         int rval = 0;
 840 
 841         hrcp = ddi_get_soft_state(hwarc_statep, getminor(*devp));
 842 
 843         ASSERT(hrcp != NULL);
 844 
 845         USB_DPRINTF_L4(PRINT_MASK_OPEN, hrcp->hrc_log_hdl, "hwarc_open: enter");
 846 
 847         /*
 848          * Keep it simple: one client at a time.
 849          * Exclusive open only
 850          */
 851         mutex_enter(&hrcp->hrc_mutex);
 852         /* exclusive open */
 853         if ((flag & FEXCL) && (hrcp->hrc_open_count > 0)) {
 854                 USB_DPRINTF_L2(PRINT_MASK_OPEN, hrcp->hrc_log_hdl,
 855                     "hwarc_open failed, open count=%d", hrcp->hrc_open_count);
 856                 mutex_exit(&hrcp->hrc_mutex);
 857 
 858                 return (EBUSY);
 859         }
 860 
 861         if ((hrcp->hrc_dev_state == USB_DEV_DISCONNECTED) ||
 862             (hrcp->hrc_dev_state == USB_DEV_SUSPENDED)) {
 863 
 864                 USB_DPRINTF_L2(PRINT_MASK_OPEN, hrcp->hrc_log_hdl,
 865                     "hwarc_open failed, dev_stat=%d", hrcp->hrc_dev_state);
 866                 mutex_exit(&hrcp->hrc_mutex);
 867 
 868                 return (EIO);
 869         }
 870 
 871         hrcp->hrc_open_count++;
 872 
 873         USB_DPRINTF_L3(PRINT_MASK_OPEN, hrcp->hrc_log_hdl,
 874             "hwarc_open, open count=%d", hrcp->hrc_open_count);
 875         if (hwarc_serialize_access(hrcp, HWARC_SER_SIG) == 0) {
 876                 hrcp->hrc_open_count--;
 877                 hwarc_release_access(hrcp);
 878                 mutex_exit(&hrcp->hrc_mutex);
 879 
 880                 return (EINTR);
 881         }
 882 
 883         hwarc_pm_busy_component(hrcp);
 884 
 885         mutex_exit(&hrcp->hrc_mutex);
 886         (void) pm_raise_power(hrcp->hrc_dip, 0, USB_DEV_OS_FULL_PWR);
 887 
 888         mutex_enter(&hrcp->hrc_mutex);
 889         /* Fail if device is no longer ready. */
 890         if (hrcp->hrc_dev_state != USB_DEV_ONLINE) {
 891                 USB_DPRINTF_L2(PRINT_MASK_OPEN, hrcp->hrc_log_hdl,
 892                     "hwarc_open failed, dev_stat=%d", hrcp->hrc_dev_state);
 893                 rval = EIO;
 894         }
 895         hwarc_release_access(hrcp);
 896         /* Device specific initialization goes here. */
 897         if (rval != 0) {
 898                 hrcp->hrc_open_count--;
 899                 hwarc_pm_idle_component(hrcp);
 900         }
 901         mutex_exit(&hrcp->hrc_mutex);
 902 
 903         USB_DPRINTF_L4(PRINT_MASK_OPEN, hrcp->hrc_log_hdl, "hwarc_open: leave");
 904 
 905         return (0);
 906 }
 907 
 908 
 909 /*ARGSUSED*/
 910 static int
 911 hwarc_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
 912 {
 913         hwarc_state_t   *hrcp =
 914             ddi_get_soft_state(hwarc_statep, getminor(dev));
 915 
 916         USB_DPRINTF_L4(PRINT_MASK_CLOSE, hrcp->hrc_log_hdl,
 917             "hwarc_close: enter");
 918 
 919         mutex_enter(&hrcp->hrc_mutex);
 920         (void) hwarc_serialize_access(hrcp, HWARC_SER_NOSIG);
 921 
 922         hrcp->hrc_open_count--;
 923         USB_DPRINTF_L3(PRINT_MASK_CLOSE, hrcp->hrc_log_hdl,
 924             "hwarc_close: open count=%d", hrcp->hrc_open_count);
 925 
 926         hwarc_release_access(hrcp);
 927         hwarc_pm_idle_component(hrcp);
 928 
 929         mutex_exit(&hrcp->hrc_mutex);
 930 
 931         USB_DPRINTF_L4(PRINT_MASK_CLOSE, hrcp->hrc_log_hdl,
 932             "hwarc_close: leave");
 933 
 934         return (0);
 935 }
 936 
 937 /* Send cmd to hwarc device */
 938 int
 939 hwarc_send_cmd(uwb_dev_handle_t uwb_dev_hdl, mblk_t *data, uint16_t data_len)
 940 {
 941         usb_cb_flags_t          cb_flags;
 942         usb_cr_t                cr;
 943         usb_ctrl_setup_t        setup;
 944         int                     rval;
 945         hwarc_state_t           *hrcp = NULL;
 946         dev_info_t              *dip = uwb_get_dip(uwb_dev_hdl);
 947 
 948         hrcp = ddi_get_soft_state(hwarc_statep, ddi_get_instance(dip));
 949 
 950         ASSERT((hrcp != NULL) && (data != NULL));
 951 
 952         setup.bmRequestType     = HWARC_SET_IF;
 953         setup.bRequest          = HWA_EXEC_RC_CMD;
 954 
 955         setup.wValue            = 0;
 956         setup.wIndex = hrcp->hrc_if_descr->if_alt->altif_descr.bInterfaceNumber;
 957 
 958         setup.wLength           = data_len;
 959         setup.attrs             = 0;
 960 
 961         USB_DPRINTF_L3(PRINT_MASK_DEVCTRL, hrcp->hrc_log_hdl,
 962             "hwarc_send_cmd: wLength=%d, data[0], [1], [2], [3]=%d, %d, %d, %d",
 963             setup.wLength, data->b_rptr[0], data->b_rptr[1], data->b_rptr[2],
 964             data->b_rptr[3]);
 965 
 966         if ((rval = usb_pipe_ctrl_xfer_wait(hrcp->hrc_default_ph, &setup,
 967             &data, &cr, &cb_flags, 0)) != USB_SUCCESS) {
 968                 USB_DPRINTF_L2(PRINT_MASK_DEVCTRL, hrcp->hrc_log_hdl,
 969                     "hwarc_send_cmd: fail, rval=%d, cr=%d, "
 970                     "cb_flags=%x", rval, cr, cb_flags);
 971 
 972         }
 973 
 974         freemsg(data);
 975 
 976         return (rval);
 977 }
 978 
 979 /* ioctl, call uwb ioctl  */
 980 /*ARGSUSED*/
 981 static int
 982 hwarc_ioctl(dev_t dev, int cmd, intptr_t arg,
 983                 int mode, cred_t *cred_p, int *rval_p)
 984 {
 985         int             rv = 0;
 986 
 987         hwarc_state_t   *hrcp =
 988             ddi_get_soft_state(hwarc_statep, getminor(dev));
 989         if (hrcp == NULL) {
 990 
 991                 return (ENXIO);
 992         }
 993 
 994         if (drv_priv(cred_p) != 0) {
 995                 USB_DPRINTF_L3(PRINT_MASK_ALL, hrcp->hrc_log_hdl,
 996                     "hwahc_wusb_ioctl: user must have SYS_DEVICE privilege,"
 997                     "cmd=%x", cmd);
 998 
 999                 return (EPERM);
1000         }
1001 
1002 
1003 
1004         USB_DPRINTF_L4(PRINT_MASK_ALL, hrcp->hrc_log_hdl, "hwarc_ioctl: enter");
1005 
1006         mutex_enter(&hrcp->hrc_mutex);
1007         if (hrcp->hrc_dev_state != USB_DEV_ONLINE) {
1008                 USB_DPRINTF_L2(PRINT_MASK_ALL, hrcp->hrc_log_hdl,
1009                     "ioctl: Device is not online,"
1010                     " dev_stat=%d", hrcp->hrc_dev_state);
1011                 mutex_exit(&hrcp->hrc_mutex);
1012 
1013                 return (EFAULT);
1014         }
1015         mutex_exit(&hrcp->hrc_mutex);
1016 
1017         rv = uwb_do_ioctl(hrcp->hrc_dev_hdl, cmd, arg, mode);
1018 
1019         return (rv);
1020 }
1021 
1022 
1023 /*
1024  * hwarc_disconnect_callback:
1025  *      Called when device hotplug-removed.
1026  *              Close pipes. (This does not attempt to contact device.)
1027  *              Set state to DISCONNECTED
1028  */
1029 static int
1030 hwarc_disconnect_callback(dev_info_t *dip)
1031 {
1032         hwarc_state_t   *hrcp =
1033             ddi_get_soft_state(hwarc_statep, ddi_get_instance(dip));
1034 
1035         USB_DPRINTF_L4(PRINT_MASK_CB, hrcp->hrc_log_hdl, "disconnect: enter");
1036 
1037         /* Disconnect the uwb device will stop beacon and save state */
1038         (void) uwb_dev_disconnect(dip);
1039         hwarc_close_intr_pipe(hrcp);
1040 
1041         mutex_enter(&hrcp->hrc_mutex);
1042         (void) hwarc_serialize_access(hrcp, HWARC_SER_NOSIG);
1043 
1044         /*
1045          * Save any state of device or IO in progress required by
1046          * hwarc_restore_device_state for proper device "thawing" later.
1047          */
1048         hrcp->hrc_dev_state = USB_DEV_DISCONNECTED;
1049 
1050         hwarc_release_access(hrcp);
1051         mutex_exit(&hrcp->hrc_mutex);
1052 
1053         return (USB_SUCCESS);
1054 }
1055 
1056 
1057 /*
1058  * hwarc_reconnect_callback:
1059  *      Called with device hotplug-inserted
1060  *              Restore state
1061  */
1062 static int
1063 hwarc_reconnect_callback(dev_info_t *dip)
1064 {
1065         int instance = ddi_get_instance(dip);
1066         hwarc_state_t   *hrcp =
1067             ddi_get_soft_state(hwarc_statep, instance);
1068 
1069         USB_DPRINTF_L4(PRINT_MASK_CB, hrcp->hrc_log_hdl, "reconnect: enter");
1070 
1071         mutex_enter(&hrcp->hrc_mutex);
1072         (void) hwarc_serialize_access(hrcp, HWARC_SER_NOSIG);
1073         hwarc_restore_device_state(dip, hrcp);
1074         hwarc_release_access(hrcp);
1075         mutex_exit(&hrcp->hrc_mutex);
1076 
1077         /* Reconnect the uwb device will restore uwb device state */
1078         (void) uwb_dev_reconnect(dip);
1079         return (USB_SUCCESS);
1080 }
1081 
1082 
1083 /*
1084  * hwarc_restore_device_state:
1085  *      Called during hotplug-reconnect and resume.
1086  *              reenable power management
1087  *              Verify the device is the same as before the disconnect/suspend.
1088  *              Restore device state
1089  *              Thaw any IO which was frozen.
1090  *              Quiesce device.  (Other routines will activate if thawed IO.)
1091  *              Set device online.
1092  *              Leave device disconnected if there are problems.
1093  */
1094 static void
1095 hwarc_restore_device_state(dev_info_t *dip, hwarc_state_t *hrcp)
1096 {
1097 
1098         USB_DPRINTF_L4(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
1099             "hwarc_restore_device_state: enter");
1100 
1101         ASSERT(mutex_owned(&hrcp->hrc_mutex));
1102 
1103         ASSERT((hrcp->hrc_dev_state == USB_DEV_DISCONNECTED) ||
1104             (hrcp->hrc_dev_state == USB_DEV_SUSPENDED));
1105 
1106         hwarc_pm_busy_component(hrcp);
1107 
1108         mutex_exit(&hrcp->hrc_mutex);
1109 
1110         (void) pm_raise_power(hrcp->hrc_dip, 0, USB_DEV_OS_FULL_PWR);
1111 
1112         if (usb_check_same_device(dip, hrcp->hrc_log_hdl, USB_LOG_L2,
1113             PRINT_MASK_ALL, USB_CHK_BASIC|USB_CHK_CFG, NULL) != USB_SUCCESS) {
1114                 USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
1115                     "hwarc_restore_device_state: check same device failed");
1116 
1117                 goto fail;
1118 
1119         }
1120         if (hwarc_open_intr_pipe(hrcp) != USB_SUCCESS) {
1121 
1122                 goto fail;
1123         }
1124         mutex_enter(&hrcp->hrc_mutex);
1125 
1126         hrcp->hrc_dev_state = USB_DEV_ONLINE;
1127 
1128         if (hrcp->hrc_pm && hrcp->hrc_pm->hrc_wakeup_enabled) {
1129 
1130                 mutex_exit(&hrcp->hrc_mutex);
1131                 if (usb_handle_remote_wakeup(dip, USB_REMOTE_WAKEUP_ENABLE) !=
1132                     USB_SUCCESS) {
1133                         USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
1134                             "hwarc_restore_device_state: "
1135                             "fail to enable device remote wakeup");
1136                 }
1137                 mutex_enter(&hrcp->hrc_mutex);
1138 
1139         }
1140 
1141         hwarc_pm_idle_component(hrcp);
1142 
1143         USB_DPRINTF_L3(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
1144             "hwarc_restore_device_state: end");
1145 
1146         return;
1147 
1148 fail:
1149         /* change the device state from suspended to disconnected */
1150         mutex_enter(&hrcp->hrc_mutex);
1151         hrcp->hrc_dev_state = USB_DEV_DISCONNECTED;
1152         hwarc_pm_idle_component(hrcp);
1153 }
1154 
1155 
1156 /*
1157  * hwarc_cpr_suspend:
1158  *      Clean up device.
1159  *      Wait for any IO to finish, then close pipes.
1160  *      Quiesce device.
1161  */
1162 static int
1163 hwarc_cpr_suspend(dev_info_t *dip)
1164 {
1165         hwarc_state_t   *hrcp = ddi_get_soft_state(hwarc_statep,
1166             ddi_get_instance(dip));
1167 
1168         USB_DPRINTF_L3(PRINT_MASK_PM, hrcp->hrc_log_hdl,
1169             "hwarc_cpr_suspend, dev_stat=%d", hrcp->hrc_dev_state);
1170 
1171         /* Disconnect the uwb device will stop beacon and save state */
1172         (void) uwb_dev_disconnect(dip);
1173 
1174         /* Serialize to prevent races with detach, open, device access. */
1175         mutex_enter(&hrcp->hrc_mutex);
1176         (void) hwarc_serialize_access(hrcp, HWARC_SER_NOSIG);
1177 
1178         hwarc_pm_busy_component(hrcp);
1179 
1180         /*
1181          * Set dev_state to suspended so other driver threads don't start any
1182          * new I/O.  In a real driver, there may be draining of requests done
1183          * afterwards, and we don't want the draining to compete with new
1184          * requests being queued.
1185          */
1186 
1187         /* Don't suspend if the device is open. */
1188         if (hrcp->hrc_open_count != 0) {
1189                 USB_DPRINTF_L3(PRINT_MASK_PM, hrcp->hrc_log_hdl,
1190                     "suspend: Device is open.  Can't suspend");
1191 
1192                 hwarc_release_access(hrcp);
1193                 hwarc_pm_idle_component(hrcp);
1194                 mutex_exit(&hrcp->hrc_mutex);
1195 
1196                 return (USB_FAILURE);
1197         }
1198 
1199         /* Access device here to clean it up. */
1200         mutex_exit(&hrcp->hrc_mutex);
1201         hwarc_close_intr_pipe(hrcp);
1202         mutex_enter(&hrcp->hrc_mutex);
1203 
1204         hrcp->hrc_dev_state = USB_DEV_SUSPENDED;
1205 
1206         /*
1207          * Save any state of device required by hwarc_restore_device_state
1208          * for proper device "thawing" later.
1209          */
1210         hwarc_release_access(hrcp);
1211         hwarc_pm_idle_component(hrcp);
1212         mutex_exit(&hrcp->hrc_mutex);
1213 
1214         USB_DPRINTF_L3(PRINT_MASK_PM, hrcp->hrc_log_hdl, "suspend: success");
1215 
1216         return (USB_SUCCESS);
1217 }
1218 
1219 
1220 /*
1221  * hwarc_cpr_resume:
1222  *
1223  *      hwarc_restore_device_state marks success by putting device back online
1224  */
1225 static void
1226 hwarc_cpr_resume(dev_info_t *dip)
1227 {
1228         int             instance = ddi_get_instance(dip);
1229         hwarc_state_t   *hrcp = ddi_get_soft_state(hwarc_statep,
1230             instance);
1231 
1232         USB_DPRINTF_L3(PRINT_MASK_PM, hrcp->hrc_log_hdl,
1233             "hwarc_cpr_resume, dev_stat=%d", hrcp->hrc_dev_state);
1234 
1235         /*
1236          * NOTE: A pm_raise_power in hwarc_restore_device_state will bring
1237          * the power-up state of device into synch with the system.
1238          */
1239         mutex_enter(&hrcp->hrc_mutex);
1240         hwarc_restore_device_state(dip, hrcp);
1241         mutex_exit(&hrcp->hrc_mutex);
1242 
1243         /* Reconnect the uwb device will restore uwb device state */
1244         (void) uwb_dev_reconnect(dip);
1245 }
1246 
1247 /*
1248  * pipe callbacks
1249  * --------------
1250  *
1251  * intr in callback for event receiving for hwarc device
1252  */
1253 /*ARGSUSED*/
1254 void
1255 hwarc_intr_cb(usb_pipe_handle_t pipe, usb_intr_req_t *req)
1256 {
1257         hwarc_state_t *hrcp = (hwarc_state_t *)req->intr_client_private;
1258         uwb_dev_handle_t uwb_dev_hd;
1259         mblk_t  *data = req->intr_data;
1260         int             data_len, parse_err;
1261 
1262         uwb_dev_hd = hrcp->hrc_dev_hdl;
1263         data_len = (data) ? MBLKL(data) : 0;
1264 
1265         if (data_len == 0) {
1266 
1267                 return;
1268         }
1269 
1270         /*
1271          * Parse the event/notifications from the device, and cv_signal the
1272          * waiting cmd
1273          */
1274         parse_err = uwb_parse_evt_notif((uint8_t *)data->b_rptr,
1275             data_len, uwb_dev_hd);
1276         if (parse_err != UWB_SUCCESS) {
1277                 USB_DPRINTF_L2(PRINT_MASK_CB, hrcp->hrc_log_hdl,
1278                     "hwarc_intr_cb: parse failed, no cmd result or "
1279                     "notifs delivered. parse_err= %d", parse_err);
1280                 if (data_len >= 5) {
1281                         USB_DPRINTF_L2(PRINT_MASK_CB, hrcp->hrc_log_hdl,
1282                             "hwarc_intr_cb: erro evt len=%d"
1283                             " evtcode=%d %d,evt_context=%d, result-code=%d",
1284                             data_len, data->b_rptr[1], data->b_rptr[2],
1285                             data->b_rptr[3], data->b_rptr[4]);
1286                 }
1287         }
1288 
1289         usb_free_intr_req(req);
1290 }
1291 
1292 /*
1293  * pipe callbacks
1294  * --------------
1295  *
1296  * intr in exception callback
1297  */
1298 void
1299 hwarc_intr_ex_cb(usb_pipe_handle_t pipe, usb_intr_req_t *req)
1300 {
1301         hwarc_state_t *hrcp = (hwarc_state_t *)req->intr_client_private;
1302         usb_cr_t        cr = req->intr_completion_reason;
1303 
1304         USB_DPRINTF_L4(PRINT_MASK_CB, hrcp->hrc_log_hdl,
1305             "hwarc_intr_ex_cb: ph = 0x%p req = 0x%p  cr=%d flags=%x",
1306             (void *)pipe, (void *)req, cr, req->intr_cb_flags);
1307 
1308         usb_free_intr_req(req);
1309 
1310         /* restart polling */
1311         if ((cr != USB_CR_PIPE_CLOSING) && (cr != USB_CR_STOPPED_POLLING) &&
1312             (cr != USB_CR_FLUSHED) && (cr != USB_CR_DEV_NOT_RESP) &&
1313             (cr != USB_CR_PIPE_RESET) &&
1314             (hrcp->hrc_dev_state == USB_DEV_ONLINE)) {
1315                 if (hwarc_start_polling(hrcp, hrcp->hrc_intr_ph) !=
1316                     USB_SUCCESS) {
1317                         USB_DPRINTF_L2(PRINT_MASK_CB, hrcp->hrc_log_hdl,
1318                             "hwarc_intr_ex_cb:"
1319                             "Restart pollling failed.");
1320                 }
1321         } else {
1322                 USB_DPRINTF_L2(PRINT_MASK_CB, hrcp->hrc_log_hdl,
1323                     "hwarc_intr_ex_cb:"
1324                     "get events failed: cr=%d", cr);
1325         }
1326 }
1327 
1328 /*
1329  * start polling on the interrupt pipe for events
1330  */
1331 int
1332 hwarc_start_polling(hwarc_state_t *hrcp, usb_pipe_handle_t intr_ph)
1333 {
1334         usb_intr_req_t  *br;
1335         int             rval = USB_SUCCESS;
1336 
1337         USB_DPRINTF_L3(PRINT_MASK_OPEN, hrcp->hrc_log_hdl,
1338             "hwarc_start_polling");
1339 
1340         br = usb_alloc_intr_req(hrcp->hrc_dip, 0, USB_FLAGS_SLEEP);
1341 
1342         if (!br) {
1343                 USB_DPRINTF_L2(PRINT_MASK_OPEN, hrcp->hrc_log_hdl,
1344                     "hwarc_start_polling: alloc req failed.");
1345 
1346                 return (USB_FAILURE);
1347         }
1348         br->intr_attributes = USB_ATTRS_SHORT_XFER_OK | USB_ATTRS_AUTOCLEARING;
1349         br->intr_len = hrcp->hrc_intr_ep_descr.wMaxPacketSize;
1350         br->intr_client_private = (void *)hrcp;
1351 
1352         br->intr_cb = hwarc_intr_cb;
1353         br->intr_exc_cb = hwarc_intr_ex_cb;
1354 
1355         rval = usb_pipe_intr_xfer(intr_ph, br, USB_FLAGS_SLEEP);
1356 
1357         if (rval != USB_SUCCESS) {
1358                 usb_free_intr_req(br);
1359 
1360                 USB_DPRINTF_L2(PRINT_MASK_OPEN, hrcp->hrc_log_hdl,
1361                     "hwarc_start_polling: failed (%d)", rval);
1362         }
1363 
1364         return (rval);
1365 }
1366 
1367 /*
1368  * hwarc_open_intr_pipe:
1369  *      Open any pipes other than default pipe.
1370  *      Mutex is assumed to be held.
1371  */
1372 static int
1373 hwarc_open_intr_pipe(hwarc_state_t *hrcp)
1374 {
1375 
1376         int                     rval = USB_SUCCESS;
1377         usb_pipe_policy_t       pipe_policy;
1378         usb_pipe_handle_t       pipe_handle;
1379 
1380         USB_DPRINTF_L3(PRINT_MASK_ATTA, hrcp->hrc_log_hdl, "open_pipes enter");
1381 
1382         bzero(&pipe_policy, sizeof (pipe_policy));
1383 
1384         /*
1385          * Allow that pipes can support at least two asynchronous operations
1386          * going on simultaneously.  Operations include asynchronous callbacks,
1387          * resets, closures.
1388          */
1389         pipe_policy.pp_max_async_reqs = 2;
1390 
1391         if ((rval = usb_pipe_open(hrcp->hrc_dip,
1392             &hrcp->hrc_intr_ep_descr, &pipe_policy,
1393             USB_FLAGS_SLEEP, &pipe_handle)) != USB_SUCCESS) {
1394                 USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
1395                     "hwarc_open_intr_pipe:Error opening intr pipe: status = %d",
1396                     rval);
1397                 goto done;
1398         }
1399 
1400         mutex_enter(&hrcp->hrc_mutex);
1401         hrcp->hrc_intr_ph = pipe_handle;
1402         mutex_exit(&hrcp->hrc_mutex);
1403 
1404         /*
1405          * At this point, polling could be started on the pipe by making an
1406          * asynchronous input request on the pipe.  Allocate a request by
1407          * calling usb_alloc_intr_req(9F) with a zero length, initialize
1408          * attributes with USB_ATTRS_SHORT_XFER_OK | USB_ATTRS_AUTOCLEARING,
1409          * initialize length to be packetsize of the endpoint, specify the
1410          * callbacks.  Pass this request to usb_pipe_intr_xfer to start polling.
1411          * Call usb_pipe_stop_intr_poling(9F) to stop polling.
1412          */
1413         rval = hwarc_start_polling(hrcp, hrcp->hrc_intr_ph);
1414         if (rval != USB_SUCCESS) {
1415                 hwarc_close_intr_pipe(hrcp);
1416 
1417                 USB_DPRINTF_L3(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
1418                     "hwarc_open_intr_pipe: Error start "
1419                     "polling intr pipe: rval = %d", rval);
1420         }
1421 
1422 done:
1423 
1424         return (rval);
1425 }
1426 
1427 
1428 /*
1429  * hwarc_close_intr_pipe:
1430  *      Close pipes. Mutex is assumed to be held.
1431  */
1432 static void
1433 hwarc_close_intr_pipe(hwarc_state_t *hrcp)
1434 {
1435         usb_pipe_handle_t       pipe_handle = NULL;
1436         USB_DPRINTF_L3(PRINT_MASK_ATTA, hrcp->hrc_log_hdl, "close_pipes enter");
1437 
1438         mutex_enter(&hrcp->hrc_mutex);
1439         if (!hrcp->hrc_intr_ph) {
1440                 USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
1441                     "hwarc intr pipe not exist");
1442                 mutex_exit(&hrcp->hrc_mutex);
1443                 return;
1444         }
1445 
1446         pipe_handle = hrcp->hrc_intr_ph;
1447         hrcp->hrc_intr_ph = NULL;
1448         mutex_exit(&hrcp->hrc_mutex);
1449 
1450         /* Stop polling */
1451         usb_pipe_stop_intr_polling(pipe_handle, USB_FLAGS_SLEEP);
1452 
1453         /* Close Pipe */
1454         usb_pipe_close(hrcp->hrc_dip, pipe_handle, USB_FLAGS_SLEEP, NULL, 0);
1455 }
1456 
1457 /*
1458  * hwarc_power :
1459  *      Power entry point, the workhorse behind pm_raise_power, pm_lower_power,
1460  *      usb_req_raise_power and usb_req_lower_power.
1461  */
1462 /*ARGSUSED*/
1463 static int
1464 hwarc_power(dev_info_t *dip, int comp, int level)
1465 {
1466         hwarc_state_t   *hrcp;
1467         int     rval = USB_FAILURE;
1468 
1469         hrcp = ddi_get_soft_state(hwarc_statep, ddi_get_instance(dip));
1470 
1471         USB_DPRINTF_L3(PRINT_MASK_PM, hrcp->hrc_log_hdl,
1472             "hwarc_power: level = %d", level);
1473 
1474         mutex_enter(&hrcp->hrc_mutex);
1475 
1476         ASSERT(hrcp->hrc_pm != NULL);
1477 
1478         (void) hwarc_serialize_access(hrcp, HWARC_SER_NOSIG);
1479 
1480         /*
1481          * If we are disconnected/suspended, return success. Note that if we
1482          * return failure, bringing down the system will hang when
1483          * PM tries to power up all devices
1484          */
1485         if ((hrcp->hrc_dev_state == USB_DEV_DISCONNECTED) ||
1486             (hrcp->hrc_dev_state == USB_DEV_SUSPENDED)) {
1487 
1488                 USB_DPRINTF_L3(PRINT_MASK_PM, hrcp->hrc_log_hdl,
1489                     "hwarc_power: disconnected/suspended "
1490                     "dev_state=%d", hrcp->hrc_dev_state);
1491                 rval = USB_SUCCESS;
1492 
1493                 goto done;
1494         }
1495 
1496 
1497         /* Check if we are transitioning to a legal power level */
1498         if (USB_DEV_PWRSTATE_OK(hrcp->hrc_pm->hrc_pwr_states, level)) {
1499                 USB_DPRINTF_L2(PRINT_MASK_PM, hrcp->hrc_log_hdl,
1500                     "hwarc_power: illegal power level = %d "
1501                     "pwr_states: %x", level, hrcp->hrc_pm->hrc_pwr_states);
1502 
1503                 goto done;
1504         }
1505 
1506         switch (level) {
1507         case USB_DEV_OS_PWR_OFF :
1508                 rval = hwarc_pwrlvl0(hrcp);
1509 
1510                 break;
1511         case USB_DEV_OS_PWR_1:
1512                 rval = hwarc_pwrlvl1(hrcp);
1513 
1514                 break;
1515         case USB_DEV_OS_PWR_2:
1516                 rval = hwarc_pwrlvl2(hrcp);
1517 
1518                 break;
1519         case USB_DEV_OS_FULL_PWR :
1520                 rval = hwarc_pwrlvl3(hrcp);
1521 
1522                 break;
1523         }
1524 
1525 done:
1526         hwarc_release_access(hrcp);
1527         mutex_exit(&hrcp->hrc_mutex);
1528 
1529         return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
1530 }
1531 
1532 
1533 /*
1534  * hwarc_serialize_access:
1535  *    Get the serial synchronization object before returning.
1536  *
1537  * Arguments:
1538  *    hrcp - Pointer to hwarc state structure
1539  *    waitsig - Set to:
1540  *      HWARC_SER_SIG - to wait such that a signal can interrupt
1541  *      HWARC_SER_NOSIG - to wait such that a signal cannot interrupt
1542  */
1543 static int
1544 hwarc_serialize_access(hwarc_state_t *hrcp, boolean_t waitsig)
1545 {
1546         int rval = 1;
1547 
1548         ASSERT(mutex_owned(&hrcp->hrc_mutex));
1549 
1550         while (hrcp->hrc_serial_inuse) {
1551                 if (waitsig == HWARC_SER_SIG) {
1552                         rval = cv_wait_sig(&hrcp->hrc_serial_cv,
1553                             &hrcp->hrc_mutex);
1554                 } else {
1555                         cv_wait(&hrcp->hrc_serial_cv,
1556                             &hrcp->hrc_mutex);
1557                 }
1558         }
1559         hrcp->hrc_serial_inuse = B_TRUE;
1560 
1561         return (rval);
1562 }
1563 
1564 
1565 /*
1566  * hwarc_release_access:
1567  *    Release the serial synchronization object.
1568  */
1569 static void
1570 hwarc_release_access(hwarc_state_t *hrcp)
1571 {
1572         ASSERT(mutex_owned(&hrcp->hrc_mutex));
1573         hrcp->hrc_serial_inuse = B_FALSE;
1574         cv_broadcast(&hrcp->hrc_serial_cv);
1575 }
1576 
1577 
1578 /*
1579  * hwarc_reset_device:
1580  *      Reset the readio controller with uwb interfaces.
1581  *      if the device is different.  Can block.
1582  */
1583 static int
1584 hwarc_reset_device(hwarc_state_t *hrcp)
1585 {
1586         if (uwb_reset_dev(hrcp->hrc_dip) != UWB_SUCCESS) {
1587                 USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
1588                     "hwarc_reset_device: uwb_reset_dev failed");
1589 
1590                 return (USB_FAILURE);
1591         }
1592 
1593         return (USB_SUCCESS);
1594 }
1595 
1596 /*
1597  * hwarc_init_phy
1598  *      init the physical capabilities of the radio controller.
1599  *      the band groups and phy rates will be initialized in the
1600  *      uwb devices.
1601  */
1602 static int
1603 hwarc_init_phy(hwarc_state_t *hrcp)
1604 {
1605         if (uwb_init_phy(hrcp->hrc_dip) != UWB_SUCCESS) {
1606                 USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
1607                     "hwarc_init_phy: uwb_init_phy failed");
1608 
1609                 return (USB_FAILURE);
1610         }
1611 
1612         return (USB_SUCCESS);
1613 }