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  * WUSB cable association driver
  28  *
  29  * This driver implements the cable association mechanism defined in
  30  * "Association Models Supplement to the Certified Wireless Universal
  31  * Serial Bus Specification 1.0". Cable association compliant devices,
  32  * i.e. with bInterfaceClass=0xEF, bInterfaceSubClass=0x03 and
  33  * bInterfaceProtocol=0x01(compatible names: "usbif,classef.3.1") will
  34  * be supported by this driver.
  35  *
  36  * The Cable Association Model uses the USB Cable-Based Association
  37  * Framework (CBAF). The basic operation under this framework is:
  38  *
  39  * - The user connects the device to the host using a USB cable.
  40  *
  41  * - The host detects that the device supports the CBAF and it is capable
  42  *   of configuring WUSB CC(Connection Context).
  43  *
  44  * - The host sends its CHID to the device, along with other information
  45  *
  46  * - If the device has a valid CC with a matching CHID, the device will
  47  *   respond to the host with the CDID from the CC.
  48  *
  49  * - As of this driver implementation, no matter if the CDID returned
  50  *   from the device matches the CDID in the host's copy of CC, we choose
  51  *   to skip further explicit user conditioning, generate a new CC and send
  52  *   it to the device.
  53  *
  54  * - Upon receiving the CC, the device must store the CC in non-volatile
  55  *   memory, replacing any existing CC with a matching CHID if it exists.
  56  *
  57  * - First time association is complete: Host has securely transferred the CC
  58  *   to the device
  59  *
  60  * CBAF requires device to use the default control endpoint to exchange
  61  * requests and data with host. Three control requests are defined by spec
  62  * and supported by this driver:
  63  *      - GET_ASSOCIATION_INFORMATION
  64  *      - GET_ASSOCIATION_REQUEST
  65  *      - SET_ASSOCIATION_RESPONSE
  66  *
  67  */
  68 
  69 #if defined(lint) && !defined(DEBUG)
  70 #define DEBUG
  71 #endif
  72 
  73 #define USBDRV_MAJOR_VER        2
  74 #define USBDRV_MINOR_VER        0
  75 
  76 #include <sys/usb/usba.h>
  77 #include <sys/stream.h>
  78 #include <sys/strsun.h>
  79 #include <sys/usb/clients/wusb_ca/wusb_ca_priv.h>
  80 #include <sys/usb/clients/wusb_ca/wusb_ca.h>
  81 
  82 
  83 uint_t  wusb_ca_errlevel = USB_LOG_L4;
  84 uint_t  wusb_ca_errmask   = (uint_t)PRINT_MASK_ALL;
  85 uint_t  wusb_ca_instance_debug = (uint_t)-1;
  86 
  87 /*
  88  * Function Prototypes
  89  */
  90 static int      wusb_ca_attach(dev_info_t *, ddi_attach_cmd_t);
  91 static int      wusb_ca_detach(dev_info_t *, ddi_detach_cmd_t);
  92 static int      wusb_ca_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
  93 static int      wusb_ca_cleanup(dev_info_t *, wusb_ca_state_t *);
  94 static int      wusb_ca_open(dev_t *, int, int, cred_t *);
  95 static int      wusb_ca_close(dev_t, int, int, cred_t *);
  96 static int      wusb_ca_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
  97 static int      wusb_ca_disconnect_callback(dev_info_t *);
  98 static int      wusb_ca_reconnect_callback(dev_info_t *);
  99 static void     wusb_ca_restore_device_state(dev_info_t *, wusb_ca_state_t *);
 100 
 101 static int      wusb_ca_cpr_suspend(dev_info_t *);
 102 static void     wusb_ca_cpr_resume(dev_info_t *);
 103 static int      wusb_ca_pm_busy_component(wusb_ca_state_t *);
 104 static void     wusb_ca_pm_idle_component(wusb_ca_state_t *);
 105 static int      wusb_ca_power(dev_info_t *, int, int);
 106 static void     wusb_ca_init_power_mgmt(wusb_ca_state_t *);
 107 static void     wusb_ca_destroy_power_mgmt(wusb_ca_state_t *);
 108 
 109 static int      wusb_ca_serialize_access(wusb_ca_state_t *, boolean_t);
 110 static void     wusb_ca_release_access(wusb_ca_state_t *);
 111 static int      wusb_ca_check_same_device(wusb_ca_state_t *);
 112 
 113 static mblk_t   *trans_from_host_info(wusb_cbaf_host_info_t *);
 114 static mblk_t   *trans_from_cc_data(wusb_cbaf_cc_data_t *);
 115 static mblk_t   *trans_from_cc_fail(wusb_cbaf_cc_fail_t *);
 116 static int      trans_to_device_info(wusb_ca_state_t *, mblk_t *,
 117                 wusb_cbaf_device_info_t *);
 118 
 119 /* _NOTE is an advice for locklint.  Locklint checks lock use for deadlocks. */
 120 _NOTE(SCHEME_PROTECTS_DATA("unique per call", usb_ctrl_req))
 121 _NOTE(SCHEME_PROTECTS_DATA("unique per call", buf))
 122 _NOTE(SCHEME_PROTECTS_DATA("unique per call", msgb))
 123 /* module loading stuff */
 124 struct cb_ops wusb_ca_cb_ops = {
 125         wusb_ca_open,           /* open  */
 126         wusb_ca_close,          /* close */
 127         nulldev,                /* strategy */
 128         nulldev,                /* print */
 129         nulldev,                /* dump */
 130         nodev,                  /* read */
 131         nodev,                  /* write */
 132         wusb_ca_ioctl,          /* ioctl */
 133         nulldev,                /* devmap */
 134         nodev,                  /* mmap */
 135         nodev,                  /* segmap */
 136         nochpoll,               /* poll */
 137         ddi_prop_op,            /* cb_prop_op */
 138         NULL,                   /* streamtab  */
 139         D_MP
 140 };
 141 
 142 static struct dev_ops wusb_ca_ops = {
 143         DEVO_REV,               /* devo_rev, */
 144         0,                      /* refcnt  */
 145         wusb_ca_info,           /* info */
 146         nulldev,                /* identify */
 147         nulldev,                /* probe */
 148         wusb_ca_attach,         /* attach */
 149         wusb_ca_detach,         /* detach */
 150         nodev,                  /* reset */
 151         &wusb_ca_cb_ops,    /* driver operations */
 152         NULL,                   /* bus operations */
 153         wusb_ca_power,          /* power */
 154         ddi_quiesce_not_needed, /* quiesce */
 155 };
 156 
 157 static struct modldrv wusb_ca_modldrv = {
 158         &mod_driverops,
 159         "WUSB Cable Association driver",
 160         &wusb_ca_ops
 161 };
 162 
 163 static struct modlinkage modlinkage = {
 164         MODREV_1,
 165         &wusb_ca_modldrv,
 166         NULL
 167 };
 168 
 169 /* local variables */
 170 
 171 /* Soft state structures */
 172 #define WUSB_CA_INITIAL_SOFT_SPACE      1
 173 static void *wusb_ca_statep;
 174 
 175 
 176 /*
 177  * Module-wide initialization routine.
 178  */
 179 int
 180 _init(void)
 181 {
 182         int rval;
 183 
 184         if ((rval = ddi_soft_state_init(&wusb_ca_statep,
 185             sizeof (wusb_ca_state_t), WUSB_CA_INITIAL_SOFT_SPACE)) != 0) {
 186 
 187                 return (rval);
 188         }
 189 
 190         if ((rval = mod_install(&modlinkage)) != 0) {
 191                 ddi_soft_state_fini(&wusb_ca_statep);
 192         }
 193 
 194         return (rval);
 195 }
 196 
 197 
 198 /*
 199  * Module-wide tear-down routine.
 200  */
 201 int
 202 _fini(void)
 203 {
 204         int rval;
 205 
 206         if ((rval = mod_remove(&modlinkage)) != 0) {
 207 
 208                 return (rval);
 209         }
 210 
 211         ddi_soft_state_fini(&wusb_ca_statep);
 212 
 213         return (rval);
 214 }
 215 
 216 
 217 int
 218 _info(struct modinfo *modinfop)
 219 {
 220         return (mod_info(&modlinkage, modinfop));
 221 }
 222 
 223 
 224 /*
 225  * wusb_ca_info:
 226  *      Get minor number, soft state structure, etc.
 227  */
 228 /*ARGSUSED*/
 229 static int
 230 wusb_ca_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
 231                         void *arg, void **result)
 232 {
 233         wusb_ca_state_t *wusb_cap;
 234         int error = DDI_FAILURE;
 235 
 236         switch (infocmd) {
 237         case DDI_INFO_DEVT2DEVINFO:
 238                 if ((wusb_cap = ddi_get_soft_state(wusb_ca_statep,
 239                     getminor((dev_t)arg))) != NULL) {
 240                         *result = wusb_cap->wusb_ca_dip;
 241                         if (*result != NULL) {
 242                                 error = DDI_SUCCESS;
 243                         }
 244                 } else {
 245                         *result = NULL;
 246                 }
 247                 break;
 248         case DDI_INFO_DEVT2INSTANCE:
 249                 *result = (void *)(uintptr_t)getminor((dev_t)arg);
 250                 error = DDI_SUCCESS;
 251                 break;
 252         default:
 253                 break;
 254         }
 255 
 256         return (error);
 257 }
 258 
 259 
 260 /*
 261  * wusb_ca_attach:
 262  *      Attach or resume.
 263  *
 264  *      For attach, initialize state and device, including:
 265  *              state variables, locks, device node
 266  *              device registration with system
 267  *              power management, hotplugging
 268  *      For resume, restore device and state
 269  */
 270 static int
 271 wusb_ca_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 272 {
 273         int                     instance = ddi_get_instance(dip);
 274         char                    *devinst;
 275         int                     devinstlen;
 276         wusb_ca_state_t         *wusb_cap = NULL;
 277         int                     status;
 278 
 279         switch (cmd) {
 280         case DDI_ATTACH:
 281                 break;
 282 
 283         case DDI_RESUME:
 284                 wusb_ca_cpr_resume(dip);
 285 
 286                 /*
 287                  * Always return success to work around enumeration failures.
 288                  * This works around an issue where devices which are present
 289                  * before a suspend and absent upon resume could cause a system
 290                  * panic on resume.
 291                  */
 292                 return (DDI_SUCCESS);
 293         default:
 294                 return (DDI_FAILURE);
 295         }
 296 
 297         if (ddi_soft_state_zalloc(wusb_ca_statep, instance) == DDI_SUCCESS) {
 298                 wusb_cap = ddi_get_soft_state(wusb_ca_statep, instance);
 299         }
 300         if (wusb_cap == NULL)  {
 301 
 302                 return (DDI_FAILURE);
 303         }
 304 
 305         wusb_cap->wusb_ca_dip = dip;
 306 
 307         devinst = kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP);
 308         devinstlen = snprintf(devinst, USB_MAXSTRINGLEN, "%s%d: ",
 309             ddi_driver_name(dip), instance);
 310 
 311         wusb_cap->wusb_ca_devinst = kmem_zalloc(devinstlen + 1, KM_SLEEP);
 312         (void) strncpy(wusb_cap->wusb_ca_devinst, devinst, devinstlen);
 313         kmem_free(devinst, USB_MAXSTRINGLEN);
 314 
 315         wusb_cap->wusb_ca_log_hdl = usb_alloc_log_hdl(dip, "wusb_ca",
 316             &wusb_ca_errlevel, &wusb_ca_errmask, &wusb_ca_instance_debug, 0);
 317 
 318         USB_DPRINTF_L4(PRINT_MASK_ATTA, wusb_cap->wusb_ca_log_hdl,
 319             "Attach: enter for attach");
 320 
 321 
 322 
 323         if ((status = usb_client_attach(dip, USBDRV_VERSION, 0)) !=
 324             USB_SUCCESS) {
 325                 USB_DPRINTF_L2(PRINT_MASK_ATTA, wusb_cap->wusb_ca_log_hdl,
 326                     "attach: usb_client_attach failed, error code:%d", status);
 327                 goto fail;
 328         }
 329 
 330         if ((status = usb_get_dev_data(dip, &wusb_cap->wusb_ca_reg,
 331             USB_PARSE_LVL_ALL, 0)) != USB_SUCCESS) {
 332                 USB_DPRINTF_L2(PRINT_MASK_ATTA, wusb_cap->wusb_ca_log_hdl,
 333                     "attach: usb_get_dev_data failed, error code:%d", status);
 334                 goto fail;
 335         }
 336 
 337         usb_free_descr_tree(dip, wusb_cap->wusb_ca_reg);
 338 
 339         mutex_init(&wusb_cap->wusb_ca_mutex, NULL, MUTEX_DRIVER,
 340             wusb_cap->wusb_ca_reg->dev_iblock_cookie);
 341 
 342         cv_init(&wusb_cap->wusb_ca_serial_cv, NULL, CV_DRIVER, NULL);
 343         wusb_cap->wusb_ca_serial_inuse = B_FALSE;
 344 
 345         wusb_cap->wusb_ca_locks_initialized = B_TRUE;
 346 
 347         /* create minor node */
 348         if (ddi_create_minor_node(dip, "wusb_ca", S_IFCHR, instance,
 349             "wusb_ca", 0) != DDI_SUCCESS) {
 350                 USB_DPRINTF_L2(PRINT_MASK_ATTA, wusb_cap->wusb_ca_log_hdl,
 351                     "attach: Error creating minor node");
 352 
 353                 goto fail;
 354         }
 355 
 356         /* Put online before PM init as can get power managed afterward. */
 357         wusb_cap->wusb_ca_dev_state = USB_DEV_ONLINE;
 358 
 359         /* initialize power management */
 360         wusb_ca_init_power_mgmt(wusb_cap);
 361 
 362         if (usb_register_hotplug_cbs(dip, wusb_ca_disconnect_callback,
 363             wusb_ca_reconnect_callback) != USB_SUCCESS) {
 364 
 365                 goto fail;
 366         }
 367 
 368         /* Report device */
 369         ddi_report_dev(dip);
 370 
 371         return (DDI_SUCCESS);
 372 
 373 fail:
 374         if (wusb_cap) {
 375                 (void) wusb_ca_cleanup(dip, wusb_cap);
 376         }
 377 
 378         return (DDI_FAILURE);
 379 }
 380 
 381 
 382 /*
 383  * wusb_ca_detach:
 384  *      detach or suspend driver instance
 385  *
 386  * Note: in detach, only contention threads is from pm and disconnnect.
 387  */
 388 static int
 389 wusb_ca_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
 390 {
 391         int             instance = ddi_get_instance(dip);
 392         int             rval = DDI_FAILURE;
 393         wusb_ca_state_t *wusb_cap;
 394 
 395         wusb_cap = ddi_get_soft_state(wusb_ca_statep, instance);
 396         switch (cmd) {
 397         case DDI_DETACH:
 398                 mutex_enter(&wusb_cap->wusb_ca_mutex);
 399                 ASSERT((wusb_cap->wusb_ca_drv_state & WUSB_CA_OPEN) == 0);
 400                 mutex_exit(&wusb_cap->wusb_ca_mutex);
 401 
 402                 USB_DPRINTF_L4(PRINT_MASK_ATTA, wusb_cap->wusb_ca_log_hdl,
 403                     "Detach: enter for detach");
 404 
 405                 rval = wusb_ca_cleanup(dip, wusb_cap);
 406 
 407                 break;
 408         case DDI_SUSPEND:
 409                 USB_DPRINTF_L4(PRINT_MASK_ATTA, wusb_cap->wusb_ca_log_hdl,
 410                     "Detach: enter for suspend");
 411 
 412                 rval = wusb_ca_cpr_suspend(dip);
 413         default:
 414 
 415                 break;
 416         }
 417 
 418         return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
 419 }
 420 
 421 
 422 /*
 423  * wusb_ca_cleanup:
 424  *      clean up the driver state for detach
 425  */
 426 static int
 427 wusb_ca_cleanup(dev_info_t *dip, wusb_ca_state_t *wusb_cap)
 428 {
 429         USB_DPRINTF_L4(PRINT_MASK_ATTA, wusb_cap->wusb_ca_log_hdl,
 430             "Cleanup: enter");
 431 
 432         if (wusb_cap->wusb_ca_locks_initialized) {
 433 
 434                 /* This must be done 1st to prevent more events from coming. */
 435                 usb_unregister_hotplug_cbs(dip);
 436 
 437                 /*
 438                  * At this point, no new activity can be initiated. The driver
 439                  * has disabled hotplug callbacks. The Solaris framework has
 440                  * disabled new opens on a device being detached, and does not
 441                  * allow detaching an open device.
 442                  *
 443                  * The following ensures that all driver activity has drained.
 444                  */
 445                 mutex_enter(&wusb_cap->wusb_ca_mutex);
 446                 (void) wusb_ca_serialize_access(wusb_cap, WUSB_CA_SER_NOSIG);
 447                 wusb_ca_release_access(wusb_cap);
 448                 mutex_exit(&wusb_cap->wusb_ca_mutex);
 449 
 450                 /* All device activity has died down. */
 451                 wusb_ca_destroy_power_mgmt(wusb_cap);
 452 
 453                 /* start dismantling */
 454                 ddi_remove_minor_node(dip, NULL);
 455 
 456                 cv_destroy(&wusb_cap->wusb_ca_serial_cv);
 457                 mutex_destroy(&wusb_cap->wusb_ca_mutex);
 458         }
 459 
 460         usb_client_detach(dip, wusb_cap->wusb_ca_reg);
 461 
 462         usb_free_log_hdl(wusb_cap->wusb_ca_log_hdl);
 463 
 464         if (wusb_cap->wusb_ca_devinst != NULL) {
 465                 kmem_free(wusb_cap->wusb_ca_devinst,
 466                     strlen(wusb_cap->wusb_ca_devinst) + 1);
 467         }
 468 
 469         ddi_soft_state_free(wusb_ca_statep, ddi_get_instance(dip));
 470         ddi_prop_remove_all(dip);
 471 
 472         return (USB_SUCCESS);
 473 }
 474 
 475 
 476 /*ARGSUSED*/
 477 static int
 478 wusb_ca_open(dev_t *devp, int flag, int otyp, cred_t *cred_p)
 479 {
 480         wusb_ca_state_t *wusb_cap =
 481             ddi_get_soft_state(wusb_ca_statep, getminor(*devp));
 482         int rval = 0;
 483 
 484         if (wusb_cap == NULL) {
 485 
 486                 return (ENXIO);
 487         }
 488 
 489         USB_DPRINTF_L4(PRINT_MASK_OPEN, wusb_cap->wusb_ca_log_hdl,
 490             "open: enter");
 491 
 492         /*
 493          * Keep it simple: one client at a time.
 494          * Exclusive open only
 495          */
 496         mutex_enter(&wusb_cap->wusb_ca_mutex);
 497         if ((wusb_cap->wusb_ca_drv_state & WUSB_CA_OPEN) != 0) {
 498                 mutex_exit(&wusb_cap->wusb_ca_mutex);
 499 
 500                 return (EBUSY);
 501         }
 502         wusb_cap->wusb_ca_drv_state |= WUSB_CA_OPEN;
 503 
 504         /*
 505          * This is in place so that a disconnect or CPR doesn't interfere with
 506          * pipe opens.
 507          */
 508         if (wusb_ca_serialize_access(wusb_cap, WUSB_CA_SER_SIG) == 0) {
 509                 wusb_cap->wusb_ca_drv_state &= ~WUSB_CA_OPEN;
 510                 mutex_exit(&wusb_cap->wusb_ca_mutex);
 511 
 512                 return (EINTR);
 513         }
 514 
 515         mutex_exit(&wusb_cap->wusb_ca_mutex);
 516         if (wusb_ca_pm_busy_component(wusb_cap) != DDI_SUCCESS) {
 517                 USB_DPRINTF_L2(PRINT_MASK_OPEN, wusb_cap->wusb_ca_log_hdl,
 518                     "open: Error raising power");
 519                 rval = EIO;
 520                 goto done;
 521         }
 522         mutex_enter(&wusb_cap->wusb_ca_mutex);
 523 
 524         /* Fail if device is no longer ready. */
 525         if (wusb_cap->wusb_ca_dev_state != USB_DEV_ONLINE) {
 526                 mutex_exit(&wusb_cap->wusb_ca_mutex);
 527                 rval = EIO;
 528                 goto done;
 529         }
 530 
 531         mutex_exit(&wusb_cap->wusb_ca_mutex);
 532 
 533 done:
 534         if (rval != 0) {
 535                 mutex_enter(&wusb_cap->wusb_ca_mutex);
 536                 wusb_cap->wusb_ca_drv_state &= ~WUSB_CA_OPEN;
 537 
 538                 wusb_ca_release_access(wusb_cap);
 539                 mutex_exit(&wusb_cap->wusb_ca_mutex);
 540 
 541                 wusb_ca_pm_idle_component(wusb_cap);
 542         } else {
 543 
 544                 /* Device is idle until it is used. */
 545                 mutex_enter(&wusb_cap->wusb_ca_mutex);
 546                 wusb_ca_release_access(wusb_cap);
 547                 mutex_exit(&wusb_cap->wusb_ca_mutex);
 548         }
 549 
 550         return (rval);
 551 }
 552 
 553 
 554 /*ARGSUSED*/
 555 static int
 556 wusb_ca_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
 557 {
 558         wusb_ca_state_t *wusb_cap =
 559             ddi_get_soft_state(wusb_ca_statep, getminor(dev));
 560 
 561         USB_DPRINTF_L4(PRINT_MASK_CLOSE, wusb_cap->wusb_ca_log_hdl,
 562             "close: enter");
 563 
 564         mutex_enter(&wusb_cap->wusb_ca_mutex);
 565         (void) wusb_ca_serialize_access(wusb_cap, WUSB_CA_SER_NOSIG);
 566         mutex_exit(&wusb_cap->wusb_ca_mutex);
 567 
 568         /* Perform device session cleanup here. */
 569 
 570         USB_DPRINTF_L4(PRINT_MASK_CLOSE, wusb_cap->wusb_ca_log_hdl,
 571             "close: cleaning up...");
 572 
 573         /*
 574          * USBA automatically flushes/resets active non-default pipes
 575          * when they are closed.  We can't reset default pipe, but we
 576          * can wait for all requests on it from this dip to drain.
 577          */
 578         (void) usb_pipe_drain_reqs(wusb_cap->wusb_ca_dip,
 579             wusb_cap->wusb_ca_reg->dev_default_ph, 0,
 580             USB_FLAGS_SLEEP, NULL, 0);
 581 
 582         mutex_enter(&wusb_cap->wusb_ca_mutex);
 583 
 584         wusb_cap->wusb_ca_drv_state &= ~WUSB_CA_OPEN;
 585 
 586         wusb_ca_release_access(wusb_cap);
 587         mutex_exit(&wusb_cap->wusb_ca_mutex);
 588 
 589         wusb_ca_pm_idle_component(wusb_cap);
 590 
 591         return (0);
 592 }
 593 
 594 
 595 /*
 596  * ioctl for cable association operations.
 597  */
 598 /*ARGSUSED*/
 599 static int
 600 wusb_ca_ioctl(dev_t dev, int cmd, intptr_t arg,
 601                 int mode, cred_t *cred_p, int *rval_p)
 602 {
 603         wusb_ca_state_t *wusb_cap =
 604             ddi_get_soft_state(wusb_ca_statep, getminor(dev));
 605 
 606         USB_DPRINTF_L4(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
 607             "ioctl enter");
 608 
 609         mutex_enter(&wusb_cap->wusb_ca_mutex);
 610 
 611         switch (cmd) {
 612         case CBAF_IOCTL_GET_ASSO_INFO:
 613                 *rval_p = wusb_cbaf_get_asso_info(wusb_cap, arg, mode);
 614 
 615                 break;
 616         case CBAF_IOCTL_GET_ASSO_REQS:
 617                 *rval_p = wusb_cbaf_get_asso_reqs(wusb_cap, arg, mode);
 618 
 619                 break;
 620         case CBAF_IOCTL_SET_HOST_INFO:
 621                 *rval_p = wusb_cbaf_set_host_info(wusb_cap, arg, mode);
 622 
 623                 break;
 624         case CBAF_IOCTL_GET_DEVICE_INFO:
 625                 *rval_p = wusb_cbaf_get_device_info(wusb_cap, arg, mode);
 626 
 627                 break;
 628         case CBAF_IOCTL_SET_CONNECTION:
 629                 *rval_p = wusb_cbaf_set_connection(wusb_cap, arg, mode);
 630 
 631                 break;
 632         case CBAF_IOCTL_SET_FAILURE:
 633                 *rval_p = wusb_cbaf_set_failure(wusb_cap, arg, mode);
 634 
 635                 break;
 636         default:
 637 
 638                 *rval_p = EINVAL;
 639         }
 640 
 641         mutex_exit(&wusb_cap->wusb_ca_mutex);
 642 
 643         return (*rval_p);
 644 }
 645 
 646 
 647 /*
 648  * wusb_ca_disconnect_callback:
 649  *      Called when device hotplug-removed.
 650  *              Close pipes. (This does not attempt to contact device.)
 651  *              Set state to DISCONNECTED
 652  */
 653 static int
 654 wusb_ca_disconnect_callback(dev_info_t *dip)
 655 {
 656         int instance = ddi_get_instance(dip);
 657         wusb_ca_state_t *wusb_cap;
 658 
 659         wusb_cap = ddi_get_soft_state(wusb_ca_statep, instance);
 660 
 661         USB_DPRINTF_L4(PRINT_MASK_CB, wusb_cap->wusb_ca_log_hdl,
 662             "disconnect: enter");
 663 
 664         mutex_enter(&wusb_cap->wusb_ca_mutex);
 665         (void) wusb_ca_serialize_access(wusb_cap, WUSB_CA_SER_NOSIG);
 666 
 667         /*
 668          * Save any state of device or IO in progress required by
 669          * wusb_ca_restore_device_state for proper device "thawing" later.
 670          */
 671         wusb_cap->wusb_ca_dev_state = USB_DEV_DISCONNECTED;
 672 
 673         wusb_ca_release_access(wusb_cap);
 674         mutex_exit(&wusb_cap->wusb_ca_mutex);
 675 
 676         return (USB_SUCCESS);
 677 }
 678 
 679 
 680 /*
 681  * wusb_ca_reconnect_callback:
 682  *      Called with device hotplug-inserted
 683  *              Restore state
 684  */
 685 static int
 686 wusb_ca_reconnect_callback(dev_info_t *dip)
 687 {
 688         int instance = ddi_get_instance(dip);
 689         wusb_ca_state_t *wusb_cap;
 690 
 691         wusb_cap = ddi_get_soft_state(wusb_ca_statep, instance);
 692 
 693         USB_DPRINTF_L4(PRINT_MASK_CB, wusb_cap->wusb_ca_log_hdl,
 694             "reconnect: enter");
 695 
 696         mutex_enter(&wusb_cap->wusb_ca_mutex);
 697         (void) wusb_ca_serialize_access(wusb_cap, WUSB_CA_SER_NOSIG);
 698         wusb_ca_restore_device_state(dip, wusb_cap);
 699         wusb_ca_release_access(wusb_cap);
 700         mutex_exit(&wusb_cap->wusb_ca_mutex);
 701 
 702         return (USB_SUCCESS);
 703 }
 704 
 705 
 706 /*
 707  * wusb_ca_restore_device_state:
 708  *      Called during hotplug-reconnect and resume.
 709  *              reenable power management
 710  *              Verify the device is the same as before the disconnect/suspend.
 711  *              Restore device state
 712  *              Thaw any IO which was frozen.
 713  *              Quiesce device.  (Other routines will activate if thawed IO.)
 714  *              Set device online.
 715  *              Leave device disconnected if there are problems.
 716  */
 717 static void
 718 wusb_ca_restore_device_state(dev_info_t *dip, wusb_ca_state_t *wusb_cap)
 719 {
 720         USB_DPRINTF_L4(PRINT_MASK_CPR, wusb_cap->wusb_ca_log_hdl,
 721             "wusb_ca_restore_device_state: enter");
 722 
 723         ASSERT(mutex_owned(&wusb_cap->wusb_ca_mutex));
 724 
 725         ASSERT((wusb_cap->wusb_ca_dev_state == USB_DEV_DISCONNECTED) ||
 726             (wusb_cap->wusb_ca_dev_state == USB_DEV_SUSPENDED));
 727 
 728         mutex_exit(&wusb_cap->wusb_ca_mutex);
 729 
 730         if (wusb_ca_pm_busy_component(wusb_cap) != DDI_SUCCESS) {
 731                 USB_DPRINTF_L2(PRINT_MASK_CPR, wusb_cap->wusb_ca_log_hdl,
 732                     "wusb_ca_restore_device_state: Error raising power");
 733 
 734                 goto fail;
 735         }
 736 
 737         /* Check if we are talking to the same device */
 738         if (wusb_ca_check_same_device(wusb_cap) != USB_SUCCESS) {
 739                 wusb_ca_pm_idle_component(wusb_cap);
 740 
 741                 goto fail;
 742         }
 743 
 744         mutex_enter(&wusb_cap->wusb_ca_mutex);
 745         wusb_cap->wusb_ca_dev_state = USB_DEV_ONLINE;
 746 
 747         if ((wusb_cap->wusb_ca_pm) &&
 748             (wusb_cap->wusb_ca_pm->wusb_ca_remote_wakeup)) {
 749                 mutex_exit(&wusb_cap->wusb_ca_mutex);
 750 
 751                 /* Failure here means device disappeared again. */
 752                 if (usb_handle_remote_wakeup(dip, USB_REMOTE_WAKEUP_ENABLE) !=
 753                     USB_SUCCESS) {
 754                         USB_DPRINTF_L2(PRINT_MASK_CPR,
 755                             wusb_cap->wusb_ca_log_hdl,
 756                             "device may or may not be accessible. "
 757                             "Please verify reconnection");
 758                 }
 759 
 760                 mutex_enter(&wusb_cap->wusb_ca_mutex);
 761         }
 762 
 763         mutex_exit(&wusb_cap->wusb_ca_mutex);
 764         wusb_ca_pm_idle_component(wusb_cap);
 765         mutex_enter(&wusb_cap->wusb_ca_mutex);
 766 
 767         USB_DPRINTF_L4(PRINT_MASK_CPR, wusb_cap->wusb_ca_log_hdl,
 768             "wusb_ca_restore_device_state: end");
 769 
 770         return;
 771 
 772 fail:
 773         /* change the device state from suspended to disconnected */
 774         mutex_enter(&wusb_cap->wusb_ca_mutex);
 775         wusb_cap->wusb_ca_dev_state = USB_DEV_DISCONNECTED;
 776 }
 777 
 778 
 779 /*
 780  * wusb_ca_cpr_suspend:
 781  *      Clean up device.
 782  *      Wait for any IO to finish, then close pipes.
 783  *      Quiesce device.
 784  */
 785 static int
 786 wusb_ca_cpr_suspend(dev_info_t *dip)
 787 {
 788         int             instance = ddi_get_instance(dip);
 789         wusb_ca_state_t *wusb_cap;
 790 
 791         wusb_cap = ddi_get_soft_state(wusb_ca_statep, instance);
 792 
 793         USB_DPRINTF_L4(PRINT_MASK_CPR, wusb_cap->wusb_ca_log_hdl,
 794             "suspend enter");
 795 
 796         /* Serialize to prevent races with detach, open, device access. */
 797         mutex_enter(&wusb_cap->wusb_ca_mutex);
 798         (void) wusb_ca_serialize_access(wusb_cap, WUSB_CA_SER_NOSIG);
 799         mutex_exit(&wusb_cap->wusb_ca_mutex);
 800 
 801         if (wusb_ca_pm_busy_component(wusb_cap) != DDI_SUCCESS) {
 802                 USB_DPRINTF_L2(PRINT_MASK_CPR, wusb_cap->wusb_ca_log_hdl,
 803                     "suspend: Error raising power");
 804                 wusb_ca_pm_idle_component(wusb_cap);
 805 
 806                 return (USB_FAILURE);
 807         }
 808 
 809         mutex_enter(&wusb_cap->wusb_ca_mutex);
 810 
 811         /*
 812          * Set dev_state to suspended so other driver threads don't start any
 813          * new I/O.
 814          */
 815 
 816         /* Don't suspend if the device is open. */
 817         if ((wusb_cap->wusb_ca_drv_state & WUSB_CA_OPEN) != 0) {
 818                 USB_DPRINTF_L2(PRINT_MASK_CPR, wusb_cap->wusb_ca_log_hdl,
 819                     "suspend: Device is open.  Can't suspend");
 820 
 821                 wusb_ca_release_access(wusb_cap);
 822                 mutex_exit(&wusb_cap->wusb_ca_mutex);
 823 
 824                 wusb_ca_pm_idle_component(wusb_cap);
 825 
 826                 return (USB_FAILURE);
 827         }
 828 
 829         wusb_cap->wusb_ca_dev_state = USB_DEV_SUSPENDED;
 830 
 831         wusb_ca_release_access(wusb_cap);
 832         mutex_exit(&wusb_cap->wusb_ca_mutex);
 833 
 834         wusb_ca_pm_idle_component(wusb_cap);
 835 
 836         USB_DPRINTF_L4(PRINT_MASK_CPR, wusb_cap->wusb_ca_log_hdl,
 837             "suspend: success");
 838 
 839         return (USB_SUCCESS);
 840 }
 841 
 842 
 843 /*
 844  * wusb_ca_cpr_resume:
 845  *
 846  *      wusb_ca_restore_device_state marks success by putting device back online
 847  */
 848 static void
 849 wusb_ca_cpr_resume(dev_info_t *dip)
 850 {
 851         int             instance = ddi_get_instance(dip);
 852         wusb_ca_state_t *wusb_cap;
 853 
 854         wusb_cap = ddi_get_soft_state(wusb_ca_statep, instance);
 855 
 856         USB_DPRINTF_L4(PRINT_MASK_CPR, wusb_cap->wusb_ca_log_hdl,
 857             "resume: enter");
 858 
 859         /*
 860          * A pm_raise_power in wusb_ca_restore_device_state will bring
 861          * the power-up state of device into synch with the system.
 862          */
 863         mutex_enter(&wusb_cap->wusb_ca_mutex);
 864         wusb_ca_restore_device_state(dip, wusb_cap);
 865         mutex_exit(&wusb_cap->wusb_ca_mutex);
 866 }
 867 
 868 
 869 static int
 870 wusb_ca_pm_busy_component(wusb_ca_state_t *wusb_cap)
 871 {
 872         int rval = DDI_SUCCESS;
 873 
 874         mutex_enter(&wusb_cap->wusb_ca_mutex);
 875         if (wusb_cap->wusb_ca_pm != NULL) {
 876                 wusb_cap->wusb_ca_pm->wusb_ca_pm_busy++;
 877                 mutex_exit(&wusb_cap->wusb_ca_mutex);
 878                 if (pm_busy_component(wusb_cap->wusb_ca_dip, 0) ==
 879                     DDI_SUCCESS) {
 880                         (void) pm_raise_power(
 881                             wusb_cap->wusb_ca_dip, 0, USB_DEV_OS_FULL_PWR);
 882                         mutex_enter(&wusb_cap->wusb_ca_mutex);
 883                 } else {
 884                         mutex_enter(&wusb_cap->wusb_ca_mutex);
 885                         wusb_cap->wusb_ca_pm->wusb_ca_pm_busy--;
 886                 }
 887         }
 888         mutex_exit(&wusb_cap->wusb_ca_mutex);
 889 
 890         return (rval);
 891 }
 892 
 893 static void
 894 wusb_ca_pm_idle_component(wusb_ca_state_t *wusb_cap)
 895 {
 896         mutex_enter(&wusb_cap->wusb_ca_mutex);
 897         if (wusb_cap->wusb_ca_pm != NULL) {
 898                 mutex_exit(&wusb_cap->wusb_ca_mutex);
 899                 if (pm_idle_component(wusb_cap->wusb_ca_dip, 0) ==
 900                     DDI_SUCCESS) {
 901                         mutex_enter(&wusb_cap->wusb_ca_mutex);
 902                         ASSERT(wusb_cap->wusb_ca_pm->wusb_ca_pm_busy > 0);
 903                         wusb_cap->wusb_ca_pm->wusb_ca_pm_busy--;
 904                         mutex_exit(&wusb_cap->wusb_ca_mutex);
 905                 }
 906                 mutex_enter(&wusb_cap->wusb_ca_mutex);
 907                 USB_DPRINTF_L3(PRINT_MASK_PM, wusb_cap->wusb_ca_log_hdl,
 908                     "wusb_ca_pm_idle_component: %d",
 909                     wusb_cap->wusb_ca_pm->wusb_ca_pm_busy);
 910         }
 911         mutex_exit(&wusb_cap->wusb_ca_mutex);
 912 }
 913 
 914 /*
 915  * wusb_ca_power :
 916  *      Power entry point, the workhorse behind pm_raise_power, pm_lower_power,
 917  *      usb_req_raise_power and usb_req_lower_power.
 918  */
 919 /* ARGSUSED */
 920 static int
 921 wusb_ca_power(dev_info_t *dip, int comp, int level)
 922 {
 923         wusb_ca_state_t *wusb_cap;
 924         wusb_ca_power_t *pm;
 925         int     rval = USB_SUCCESS;
 926 
 927         wusb_cap = ddi_get_soft_state(wusb_ca_statep, ddi_get_instance(dip));
 928 
 929         USB_DPRINTF_L4(PRINT_MASK_PM, wusb_cap->wusb_ca_log_hdl,
 930             "wusb_ca_power: enter: level = %d", level);
 931 
 932         mutex_enter(&wusb_cap->wusb_ca_mutex);
 933         (void) wusb_ca_serialize_access(wusb_cap, WUSB_CA_SER_NOSIG);
 934 
 935         /*
 936          * If we are disconnected/suspended, return success. Note that if we
 937          * return failure, bringing down the system will hang when PM tries
 938          * to power up all devices
 939          */
 940         if ((wusb_cap->wusb_ca_dev_state == USB_DEV_DISCONNECTED) ||
 941             (wusb_cap->wusb_ca_dev_state == USB_DEV_SUSPENDED)) {
 942 
 943                 USB_DPRINTF_L3(PRINT_MASK_PM, wusb_cap->wusb_ca_log_hdl,
 944                     "wusb_ca_power: disconnected/suspended "
 945                     "dev_state=%d", wusb_cap->wusb_ca_dev_state);
 946                 rval = USB_SUCCESS;
 947 
 948                 goto done;
 949         }
 950 
 951         if (wusb_cap->wusb_ca_pm == NULL) {
 952 
 953                 goto done;
 954         }
 955 
 956         pm = wusb_cap->wusb_ca_pm;
 957 
 958         /* Check if we are transitioning to a legal power level */
 959         if (USB_DEV_PWRSTATE_OK(pm->wusb_ca_pwr_states, level)) {
 960                 USB_DPRINTF_L3(PRINT_MASK_PM, wusb_cap->wusb_ca_log_hdl,
 961                     "wusb_ca_power: illegal power level = %d "
 962                     "pwr_states: %x", level, pm->wusb_ca_pwr_states);
 963 
 964                 goto done;
 965         }
 966 
 967         switch (level) {
 968         case USB_DEV_OS_PWR_OFF :
 969                 /* fail attempt to go to low power if busy */
 970                 if (pm->wusb_ca_pm_busy) {
 971 
 972                         goto done;
 973                 }
 974                 if (wusb_cap->wusb_ca_dev_state == USB_DEV_ONLINE) {
 975                         (void) usb_set_device_pwrlvl3(wusb_cap->wusb_ca_dip);
 976 
 977                         wusb_cap->wusb_ca_dev_state = USB_DEV_PWRED_DOWN;
 978                         wusb_cap->wusb_ca_pm->wusb_ca_current_power =
 979                             USB_DEV_OS_PWR_OFF;
 980                 }
 981 
 982                 break;
 983 
 984         case USB_DEV_OS_FULL_PWR :
 985                 /*
 986                  * PM framework tries to put us in full power during system
 987                  * shutdown. Handle USB_DEV_PWRED_DOWN only.
 988                  */
 989                 if (wusb_cap->wusb_ca_dev_state == USB_DEV_PWRED_DOWN) {
 990                         (void) usb_set_device_pwrlvl0(wusb_cap->wusb_ca_dip);
 991                         wusb_cap->wusb_ca_dev_state = USB_DEV_ONLINE;
 992                         wusb_cap->wusb_ca_pm->wusb_ca_current_power =
 993                             USB_DEV_OS_FULL_PWR;
 994                 }
 995 
 996                 break;
 997 
 998         /* Levels 1 and 2 are not supported by this driver to keep it simple. */
 999         default:
1000                 USB_DPRINTF_L3(PRINT_MASK_PM, wusb_cap->wusb_ca_log_hdl,
1001                     "wusb_ca_power: power level %d not supported", level);
1002                 break;
1003         }
1004 done:
1005         wusb_ca_release_access(wusb_cap);
1006         mutex_exit(&wusb_cap->wusb_ca_mutex);
1007 
1008         /* Generally return success to make PM succeed */
1009         return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
1010 }
1011 
1012 
1013 /*
1014  * wusb_ca_init_power_mgmt:
1015  *      Initialize power management and remote wakeup functionality.
1016  *      No mutex is necessary in this function as it's called only by attach.
1017  */
1018 static void
1019 wusb_ca_init_power_mgmt(wusb_ca_state_t *wusb_cap)
1020 {
1021         wusb_ca_power_t *wusb_capm;
1022         uint_t          pwr_states;
1023 
1024         USB_DPRINTF_L4(PRINT_MASK_PM, wusb_cap->wusb_ca_log_hdl,
1025             "init_power_mgmt enter");
1026 
1027         /* Allocate the state structure */
1028         wusb_capm = kmem_zalloc(sizeof (wusb_ca_power_t), KM_SLEEP);
1029         wusb_cap->wusb_ca_pm = wusb_capm;
1030         wusb_capm->wusb_ca_state = wusb_cap;
1031         wusb_capm->wusb_ca_pm_capabilities = 0;
1032         wusb_capm->wusb_ca_current_power = USB_DEV_OS_FULL_PWR;
1033 
1034         if (usb_create_pm_components(wusb_cap->wusb_ca_dip,
1035             &pwr_states) == USB_SUCCESS) {
1036                 USB_DPRINTF_L3(PRINT_MASK_PM, wusb_cap->wusb_ca_log_hdl,
1037                     "wusb_ca_init_power_mgmt: created PM components");
1038 
1039                 wusb_capm->wusb_ca_pwr_states = (uint8_t)pwr_states;
1040                 (void) pm_raise_power(wusb_cap->wusb_ca_dip, 0,
1041                     USB_DEV_OS_FULL_PWR);
1042         } else {
1043                 USB_DPRINTF_L3(PRINT_MASK_PM, wusb_cap->wusb_ca_log_hdl,
1044                     "wusb_ca_init_power_mgmt: create_pm_compts failed");
1045         }
1046 
1047         /*
1048          * If remote wakeup is not available you may not want to do
1049          * power management.
1050          */
1051         if (usb_handle_remote_wakeup(wusb_cap->wusb_ca_dip,
1052             USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS) {
1053                 wusb_capm->wusb_ca_remote_wakeup = 1;
1054         } else {
1055                 USB_DPRINTF_L3(PRINT_MASK_PM, wusb_cap->wusb_ca_log_hdl,
1056                     "wusb_ca_init_power_mgmt: failure enabling remote wakeup");
1057         }
1058 
1059         USB_DPRINTF_L4(PRINT_MASK_PM, wusb_cap->wusb_ca_log_hdl,
1060             "wusb_ca_init_power_mgmt: end");
1061 }
1062 
1063 
1064 /*
1065  * wusb_ca_destroy_power_mgmt:
1066  *      Shut down and destroy power management and remote wakeup functionality.
1067  */
1068 static void
1069 wusb_ca_destroy_power_mgmt(wusb_ca_state_t *wusb_cap)
1070 {
1071         wusb_ca_power_t *wusb_capm;
1072 
1073         USB_DPRINTF_L4(PRINT_MASK_PM, wusb_cap->wusb_ca_log_hdl,
1074             "destroy_power_mgmt enter");
1075 
1076         ASSERT(!mutex_owned(&wusb_cap->wusb_ca_mutex));
1077 
1078         mutex_enter(&wusb_cap->wusb_ca_mutex);
1079 
1080         wusb_capm = wusb_cap->wusb_ca_pm;
1081         if (!wusb_capm) {
1082                 mutex_exit(&wusb_cap->wusb_ca_mutex);
1083 
1084                 return;
1085         }
1086 
1087         mutex_exit(&wusb_cap->wusb_ca_mutex);
1088 
1089         (void) wusb_ca_pm_busy_component(wusb_cap);
1090 
1091         mutex_enter(&wusb_cap->wusb_ca_mutex);
1092         if (wusb_cap->wusb_ca_dev_state != USB_DEV_DISCONNECTED) {
1093                 int rval;
1094 
1095                 if (wusb_capm->wusb_ca_remote_wakeup) {
1096                         mutex_exit(&wusb_cap->wusb_ca_mutex);
1097 
1098                         (void) pm_raise_power(wusb_cap->wusb_ca_dip, 0,
1099                             USB_DEV_OS_FULL_PWR);
1100 
1101                         rval = usb_handle_remote_wakeup(
1102                             wusb_cap->wusb_ca_dip,
1103                             USB_REMOTE_WAKEUP_DISABLE);
1104 
1105                         USB_DPRINTF_L2(PRINT_MASK_PM,
1106                             wusb_cap->wusb_ca_log_hdl,
1107                             "wusb_ca_destroy_power_mgmt: "
1108                             "Error disabling rmt wakeup: rval = %d",
1109                             rval);
1110 
1111                         mutex_enter(&wusb_cap->wusb_ca_mutex);
1112                 }
1113         }
1114 
1115         mutex_exit(&wusb_cap->wusb_ca_mutex);
1116 
1117         /*
1118          * Since remote wakeup is disabled now,
1119          * no one can raise power
1120          * and get to device once power is lowered here.
1121          */
1122         (void) pm_lower_power(wusb_cap->wusb_ca_dip, 0, USB_DEV_OS_PWR_OFF);
1123         wusb_ca_pm_idle_component(wusb_cap);
1124 
1125         mutex_enter(&wusb_cap->wusb_ca_mutex);
1126         kmem_free(wusb_cap->wusb_ca_pm, sizeof (wusb_ca_power_t));
1127         wusb_cap->wusb_ca_pm = NULL;
1128         mutex_exit(&wusb_cap->wusb_ca_mutex);
1129 }
1130 
1131 
1132 /*
1133  * wusb_ca_serialize_access:
1134  *    Get the serial synchronization object before returning.
1135  *
1136  * Arguments:
1137  *    wusb_cap - Pointer to wusb_ca state structure
1138  *    waitsig - Set to:
1139  *      WUSB_CA_SER_SIG - to wait such that a signal can interrupt
1140  *      WUSB_CA_SER_NOSIG - to wait such that a signal cannot interrupt
1141  */
1142 static int
1143 wusb_ca_serialize_access(wusb_ca_state_t *wusb_cap, boolean_t waitsig)
1144 {
1145         int rval = 1;
1146 
1147         ASSERT(mutex_owned(&wusb_cap->wusb_ca_mutex));
1148 
1149         while (wusb_cap->wusb_ca_serial_inuse) {
1150                 if (waitsig == WUSB_CA_SER_SIG) {
1151                         rval = cv_wait_sig(&wusb_cap->wusb_ca_serial_cv,
1152                             &wusb_cap->wusb_ca_mutex);
1153                 } else {
1154                         cv_wait(&wusb_cap->wusb_ca_serial_cv,
1155                             &wusb_cap->wusb_ca_mutex);
1156                 }
1157         }
1158         wusb_cap->wusb_ca_serial_inuse = B_TRUE;
1159 
1160         return (rval);
1161 }
1162 
1163 
1164 /*
1165  * wusb_ca_release_access:
1166  *    Release the serial synchronization object.
1167  */
1168 static void
1169 wusb_ca_release_access(wusb_ca_state_t *wusb_cap)
1170 {
1171         ASSERT(mutex_owned(&wusb_cap->wusb_ca_mutex));
1172         wusb_cap->wusb_ca_serial_inuse = B_FALSE;
1173         cv_broadcast(&wusb_cap->wusb_ca_serial_cv);
1174 }
1175 
1176 
1177 /*
1178  * wusb_ca_check_same_device:
1179  *      Check if the device connected to the port is the same as
1180  *      the previous device that was in the port.  The previous device is
1181  *      represented by the dip on record for the port.  Print a message
1182  *      if the device is different.  Can block.
1183  *
1184  * return values:
1185  *      USB_SUCCESS:            same device
1186  *      USB_INVALID_VERSION     not same device
1187  *      USB_FAILURE:            Failure processing request
1188  */
1189 static int
1190 wusb_ca_check_same_device(wusb_ca_state_t *wusb_cap)
1191 {
1192         usb_dev_descr_t         *orig_usb_dev_descr;
1193         usb_dev_descr_t         usb_dev_descr;
1194         mblk_t                  *pdata = NULL;
1195         int                     rval;
1196         char                    *buf;
1197         usb_cr_t                completion_reason;
1198         usb_cb_flags_t          cb_flags;
1199         boolean_t               match = B_TRUE;
1200 
1201         usb_ctrl_setup_t        setup = {
1202             USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD |
1203                 USB_DEV_REQ_RCPT_DEV,
1204             USB_REQ_GET_DESCR,          /* bRequest */
1205             USB_DESCR_TYPE_SETUP_DEV,   /* wValue */
1206             0,                          /* wIndex */
1207             USB_DEV_DESCR_SIZE,         /* wLength */
1208             0                           /* request attributes */
1209         };
1210 
1211         ASSERT(!mutex_owned(&wusb_cap->wusb_ca_mutex));
1212 
1213         orig_usb_dev_descr = wusb_cap->wusb_ca_reg->dev_descr;
1214 
1215         /* get the "new" device descriptor */
1216         rval = usb_pipe_ctrl_xfer_wait(wusb_cap->wusb_ca_reg->dev_default_ph,
1217             &setup, &pdata, &completion_reason, &cb_flags, USB_FLAGS_SLEEP);
1218 
1219         if (rval != USB_SUCCESS) {
1220                 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1221                     "wusb_ca_check_same_device: "
1222                     "getting device descriptor failed "
1223                     "rval=%d, cr=%d, cb=0x%x\n",
1224                     rval, completion_reason, cb_flags);
1225                 freemsg(pdata);
1226 
1227                 return (USB_FAILURE);
1228         }
1229 
1230         ASSERT(pdata != NULL);
1231 
1232         (void) usb_parse_data("2cs4c3s4c", pdata->b_rptr,
1233             (intptr_t)pdata->b_wptr - (intptr_t)pdata->b_rptr, &usb_dev_descr,
1234             sizeof (usb_dev_descr_t));
1235 
1236         freemsg(pdata);
1237         pdata = NULL;
1238 
1239         /* Always check the device descriptor length. */
1240         if (usb_dev_descr.bLength != USB_DEV_DESCR_SIZE) {
1241                 match = B_FALSE;
1242 
1243         /* Always check the device descriptor. */
1244         } else if (bcmp(orig_usb_dev_descr,
1245             (char *)&usb_dev_descr, USB_DEV_DESCR_SIZE) != 0) {
1246                 match = B_FALSE;
1247         }
1248 
1249         /* if requested & this device has a serial number check and compare */
1250         if ((match == B_TRUE) &&
1251             (wusb_cap->wusb_ca_reg->dev_serial != NULL)) {
1252                 buf = kmem_alloc(USB_MAXSTRINGLEN, KM_SLEEP);
1253                 if (usb_get_string_descr(wusb_cap->wusb_ca_dip, USB_LANG_ID,
1254                     usb_dev_descr.iSerialNumber, buf,
1255                     USB_MAXSTRINGLEN) == USB_SUCCESS) {
1256                         match =
1257                             (strcmp(buf,
1258                             wusb_cap->wusb_ca_reg->dev_serial) == 0);
1259                 }
1260                 kmem_free(buf, USB_MAXSTRINGLEN);
1261         }
1262 
1263         if (match == B_FALSE) {
1264                 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1265                     "Device is not identical to the "
1266                     "previous one this port.\n"
1267                     "Please disconnect and reconnect");
1268 
1269                 return (USB_INVALID_VERSION);
1270         }
1271 
1272         return (USB_SUCCESS);
1273 }
1274 
1275 
1276 /* get association info */
1277 int
1278 wusb_cbaf_get_asso_info(wusb_ca_state_t *wusb_cap, intptr_t arg, int flag)
1279 {
1280         usb_pipe_handle_t       pipe = wusb_cap->wusb_ca_reg->dev_default_ph;
1281         usb_ctrl_setup_t        setup;
1282         usb_cr_t                completion_reason;
1283         usb_cb_flags_t          cb_flags;
1284         wusb_cbaf_asso_info_t   ca_info;
1285         mblk_t                  *pdata = NULL;
1286         int rval;
1287 
1288         setup.bmRequestType = USB_DEV_REQ_DEV_TO_HOST |
1289             USB_DEV_REQ_TYPE_CLASS | USB_DEV_REQ_RCPT_IF;
1290         setup.bRequest =  WUSB_CBAF_GET_ASSOCIATION_INFORMATION;
1291         setup.wValue = 0;
1292         setup.wIndex = 0;
1293         setup.wLength = WUSB_ASSO_INFO_SIZE;
1294         setup.attrs = USB_ATTRS_NONE;
1295 
1296         rval = usb_pipe_ctrl_xfer_wait(pipe, &setup, &pdata,
1297             &completion_reason, &cb_flags, USB_FLAGS_SLEEP);
1298 
1299         if (rval != USB_SUCCESS) {
1300                 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1301                 "cr = %d cb_flags = %d", completion_reason, cb_flags);
1302 
1303                 return (EIO);
1304         }
1305         if (pdata == NULL || msgsize(pdata) == 0) {
1306                 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1307                     "empty pdata");
1308 
1309                 return (EIO);
1310         }
1311 
1312         rval = usb_parse_data("scs", pdata->b_rptr, WUSB_ASSO_INFO_SIZE,
1313             &ca_info, sizeof (ca_info));
1314         if (rval <= 0) {
1315                 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1316                     "parse data");
1317 
1318                 return (EIO);
1319         }
1320 
1321         rval = ddi_copyout(&ca_info, (void *)arg, sizeof (ca_info), flag);
1322         if (rval != 0) {
1323                 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1324                     "ddi_copyout");
1325 
1326                 return (EIO);
1327         }
1328 
1329         freemsg(pdata);
1330 
1331         return (0);
1332 }
1333 
1334 /* get request array */
1335 int
1336 wusb_cbaf_get_asso_reqs(wusb_ca_state_t *wusb_cap, intptr_t arg, int flag)
1337 {
1338         usb_pipe_handle_t       pipe = wusb_cap->wusb_ca_reg->dev_default_ph;
1339         usb_ctrl_setup_t        setup;
1340         usb_cr_t                completion_reason;
1341         usb_cb_flags_t          cb_flags;
1342         wusb_cbaf_asso_info_t   ca_info;
1343         wusb_cbaf_asso_req_t    *ca_reqs;
1344         mblk_t                  *pdata = NULL;
1345         uchar_t                 *data;
1346         int rval, reqs_size, i;
1347 
1348         rval = ddi_copyin((void *)arg, &ca_info, sizeof (ca_info), flag);
1349         if (rval != 0) {
1350                 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1351                     "ddi_copyin");
1352 
1353                 return (EIO);
1354         }
1355 
1356         setup.bmRequestType = USB_DEV_REQ_DEV_TO_HOST |
1357             USB_DEV_REQ_TYPE_CLASS | USB_DEV_REQ_RCPT_IF;
1358         setup.bRequest =  WUSB_CBAF_GET_ASSOCIATION_INFORMATION;
1359         setup.wValue = 0;
1360         setup.wIndex = 0;
1361         setup.wLength = ca_info.Length;
1362         setup.attrs = USB_ATTRS_NONE;
1363 
1364         rval = usb_pipe_ctrl_xfer_wait(pipe, &setup, &pdata,
1365             &completion_reason, &cb_flags, USB_FLAGS_SLEEP);
1366 
1367         if (rval != USB_SUCCESS) {
1368                 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1369                 "cr = %d cb_flags = %d", completion_reason, cb_flags);
1370 
1371                 return (EIO);
1372         }
1373         if (pdata == NULL || msgsize(pdata) == 0) {
1374                 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1375                     "empty pdata");
1376 
1377                 return (EIO);
1378         }
1379 
1380         reqs_size = sizeof (wusb_cbaf_asso_req_t) *
1381             ca_info.NumAssociationRequests;
1382         ca_reqs = (wusb_cbaf_asso_req_t *)kmem_zalloc(reqs_size, KM_SLEEP);
1383 
1384         data = pdata->b_rptr + WUSB_ASSO_INFO_SIZE;
1385         for (i = 0; i < ca_info.NumAssociationRequests; i++) {
1386                 rval = usb_parse_data("ccssl", data, WUSB_ASSO_REQUEST_SIZE,
1387                     &(ca_reqs[i]), sizeof (wusb_cbaf_asso_req_t));
1388                 if (rval <= 0) {
1389                         USB_DPRINTF_L2(PRINT_MASK_ALL,
1390                             wusb_cap->wusb_ca_log_hdl,
1391                             "parse data");
1392 
1393                         return (EIO);
1394                 }
1395                 data += WUSB_ASSO_REQUEST_SIZE;
1396         }
1397 
1398         rval = ddi_copyout(ca_reqs, (void *)(arg + sizeof (ca_info)),
1399             reqs_size, flag);
1400         if (rval != 0) {
1401                 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1402                     "ddi_copyout");
1403 
1404                 return (EIO);
1405         }
1406 
1407         freemsg(pdata);
1408         kmem_free(ca_reqs, reqs_size);
1409 
1410         return (0);
1411 }
1412 
1413 /* set host info */
1414 int
1415 wusb_cbaf_set_host_info(wusb_ca_state_t *wusb_cap, intptr_t arg, int flag)
1416 {
1417         usb_pipe_handle_t       pipe = wusb_cap->wusb_ca_reg->dev_default_ph;
1418         usb_ctrl_setup_t        setup;
1419         usb_cr_t                completion_reason;
1420         usb_cb_flags_t          cb_flags;
1421         wusb_cbaf_host_info_t   host_info;
1422         mblk_t                  *pdata;
1423         int rval;
1424 
1425         rval = ddi_copyin((void *)arg, &host_info, sizeof (host_info), flag);
1426         if (rval != 0) {
1427                 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1428                     "ddi_copyin");
1429 
1430                 return (EIO);
1431         }
1432 
1433         if ((pdata = trans_from_host_info(&host_info)) == NULL) {
1434                 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1435                     "trans host info");
1436 
1437                 return (EIO);
1438         }
1439 
1440         setup.bmRequestType = USB_DEV_REQ_TYPE_CLASS | USB_DEV_REQ_RCPT_IF;
1441         setup.bRequest =  WUSB_CBAF_SET_ASSOCIATION_RESPONSE;
1442         setup.wValue = 0x101;
1443         setup.wIndex = 0;
1444         setup.wLength = WUSB_HOST_INFO_SIZE;
1445         setup.attrs = USB_ATTRS_NONE;
1446 
1447         rval = usb_pipe_ctrl_xfer_wait(pipe, &setup, &pdata,
1448             &completion_reason, &cb_flags, USB_FLAGS_SLEEP);
1449 
1450         freemsg(pdata);
1451 
1452         if (rval != USB_SUCCESS) {
1453                 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1454                 "cr = %d cb_flags = 0x%03x", completion_reason, cb_flags);
1455 
1456                 return (EIO);
1457         }
1458 
1459         return (0);
1460 }
1461 
1462 /* get device info */
1463 int
1464 wusb_cbaf_get_device_info(wusb_ca_state_t *wusb_cap, intptr_t arg, int flag)
1465 {
1466         usb_pipe_handle_t       pipe = wusb_cap->wusb_ca_reg->dev_default_ph;
1467         usb_ctrl_setup_t        setup;
1468         usb_cr_t                completion_reason;
1469         usb_cb_flags_t          cb_flags;
1470         wusb_cbaf_device_info_t device_info;
1471         mblk_t                  *pdata = NULL;
1472         int rval;
1473 
1474         setup.bmRequestType = USB_DEV_REQ_DEV_TO_HOST |
1475             USB_DEV_REQ_TYPE_CLASS | USB_DEV_REQ_RCPT_IF;
1476         setup.bRequest =  WUSB_CBAF_GET_ASSOCIATION_REQUEST;
1477         setup.wValue = 0x200;
1478         setup.wIndex = 0;
1479         setup.wLength = WUSB_DEVICE_INFO_SIZE;
1480         setup.attrs = USB_ATTRS_NONE;
1481 
1482         rval = usb_pipe_ctrl_xfer_wait(pipe, &setup, &pdata,
1483             &completion_reason, &cb_flags, USB_FLAGS_SLEEP);
1484 
1485         if (rval != USB_SUCCESS) {
1486                 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1487                     "cr = %d cb_flags = %d", completion_reason, cb_flags);
1488 
1489                 return (EIO);
1490         }
1491         if (pdata == NULL || msgsize(pdata) == 0) {
1492                 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1493                     "empty pdata");
1494 
1495                 return (EIO);
1496         }
1497 
1498         if (trans_to_device_info(wusb_cap, pdata, &device_info) != 0) {
1499                 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1500                     "trans to device_info");
1501 
1502                 return (EIO);
1503         }
1504 
1505         rval = ddi_copyout(&device_info, (void *)arg,
1506             sizeof (device_info), flag);
1507         if (rval != 0) {
1508                 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1509                     "ddi_copyout");
1510 
1511                 return (EIO);
1512         }
1513 
1514         freemsg(pdata);
1515 
1516         return (0);
1517 }
1518 
1519 /* set connection to device */
1520 int
1521 wusb_cbaf_set_connection(wusb_ca_state_t *wusb_cap, intptr_t arg, int flag)
1522 {
1523         usb_pipe_handle_t       pipe = wusb_cap->wusb_ca_reg->dev_default_ph;
1524         usb_ctrl_setup_t        setup;
1525         usb_cr_t                completion_reason;
1526         usb_cb_flags_t          cb_flags;
1527         wusb_cbaf_cc_data_t     cc_data;
1528         mblk_t                  *pdata = NULL;
1529         int rval;
1530 
1531         rval = ddi_copyin((void *)arg, &cc_data, sizeof (cc_data), flag);
1532         if (rval != 0) {
1533                 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1534                     "ddi_copyin");
1535 
1536                 return (EIO);
1537         }
1538 
1539         if ((pdata = trans_from_cc_data(&cc_data)) == NULL) {
1540                 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1541                     "trans cc data");
1542 
1543                 return (EIO);
1544         }
1545 
1546         setup.bmRequestType = USB_DEV_REQ_TYPE_CLASS | USB_DEV_REQ_RCPT_IF;
1547         setup.bRequest =  WUSB_CBAF_SET_ASSOCIATION_RESPONSE;
1548         setup.wValue = 0x201;
1549         setup.wIndex = 0;
1550         setup.wLength = WUSB_CC_DATA_SIZE;
1551         setup.attrs = USB_ATTRS_NONE;
1552 
1553         rval = usb_pipe_ctrl_xfer_wait(pipe, &setup, &pdata,
1554             &completion_reason, &cb_flags, USB_FLAGS_SLEEP);
1555 
1556         freemsg(pdata);
1557 
1558         if (rval != USB_SUCCESS) {
1559                 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1560                 "cr = %d cb_flags = %d", completion_reason, cb_flags);
1561 
1562                 return (EIO);
1563         }
1564 
1565         return (0);
1566 }
1567 
1568 /* set failure */
1569 int
1570 wusb_cbaf_set_failure(wusb_ca_state_t *wusb_cap, intptr_t arg, int flag)
1571 {
1572         usb_pipe_handle_t       pipe = wusb_cap->wusb_ca_reg->dev_default_ph;
1573         usb_ctrl_setup_t        setup;
1574         usb_cr_t                completion_reason;
1575         usb_cb_flags_t          cb_flags;
1576         wusb_cbaf_cc_fail_t     cc_fail;
1577         mblk_t                  *pdata = NULL;
1578         int rval;
1579 
1580         rval = ddi_copyin((void *)arg, &cc_fail, sizeof (cc_fail), flag);
1581         if (rval != 0) {
1582                 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1583                     "ddi_copyin");
1584 
1585                 return (EIO);
1586         }
1587 
1588         if ((pdata = trans_from_cc_fail(&cc_fail)) == NULL) {
1589                 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1590                     "trans cc fail");
1591 
1592                 return (EIO);
1593         }
1594 
1595         setup.bmRequestType = USB_DEV_REQ_TYPE_CLASS | USB_DEV_REQ_RCPT_IF;
1596         setup.bRequest =  WUSB_CBAF_SET_ASSOCIATION_RESPONSE;
1597         setup.wValue = 0x201;
1598         setup.wIndex = 0;
1599         setup.wLength = WUSB_CC_DATA_SIZE;
1600         setup.attrs = USB_ATTRS_NONE;
1601 
1602         rval = usb_pipe_ctrl_xfer_wait(pipe, &setup, &pdata,
1603             &completion_reason, &cb_flags, USB_FLAGS_SLEEP);
1604 
1605         freemsg(pdata);
1606 
1607         if (rval != USB_SUCCESS) {
1608                 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1609                     "cr = %d cb_flags = %d", completion_reason, cb_flags);
1610 
1611                 return (EIO);
1612         }
1613 
1614         return (0);
1615 }
1616 
1617 #define DRAW_BYTE(x, sh)        (((x) >> (sh * 8)) & 0xff)
1618 
1619 static mblk_t *
1620 trans_from_host_info(wusb_cbaf_host_info_t *host_info)
1621 {
1622         mblk_t *pdata;
1623 
1624         if ((pdata = allocb(WUSB_HOST_INFO_SIZE, BPRI_HI)) == NULL) {
1625 
1626                 return (NULL);
1627         }
1628 
1629         bcopy(fieldAssociationTypeId, pdata->b_wptr, 4);
1630         pdata->b_wptr += 4;
1631         *pdata->b_wptr++ = DRAW_BYTE(host_info->AssociationTypeId, 0);
1632         *pdata->b_wptr++ = DRAW_BYTE(host_info->AssociationTypeId, 1);
1633 
1634         bcopy(fieldAssociationSubTypeId, pdata->b_wptr, 4);
1635         pdata->b_wptr += 4;
1636         *pdata->b_wptr++ = DRAW_BYTE(host_info->AssociationSubTypeId, 0);
1637         *pdata->b_wptr++ = DRAW_BYTE(host_info->AssociationSubTypeId, 1);
1638 
1639         bcopy(fieldCHID, pdata->b_wptr, 4);
1640         pdata->b_wptr += 4;
1641         bcopy(host_info->CHID, pdata->b_wptr, 16);
1642         pdata->b_wptr += 16;
1643 
1644         bcopy(fieldLangID, pdata->b_wptr, 4);
1645         pdata->b_wptr += 4;
1646         *pdata->b_wptr++ = DRAW_BYTE(host_info->LangID, 0);
1647         *pdata->b_wptr++ = DRAW_BYTE(host_info->LangID, 1);
1648 
1649         bcopy(fieldHostFriendlyName, pdata->b_wptr, 4);
1650         pdata->b_wptr += 4;
1651         bcopy(host_info->HostFriendlyName, pdata->b_wptr, 64);
1652         pdata->b_wptr += 64;
1653 
1654         return (pdata);
1655 }
1656 
1657 static mblk_t *
1658 trans_from_cc_data(wusb_cbaf_cc_data_t *cc_data)
1659 {
1660         mblk_t *pdata;
1661 
1662         if ((pdata = allocb(WUSB_CC_DATA_SIZE, BPRI_HI)) == NULL) {
1663 
1664                 return (NULL);
1665         }
1666 
1667         bcopy(fieldAssociationTypeId, pdata->b_wptr, 4);
1668         pdata->b_wptr += 4;
1669         *pdata->b_wptr++ = DRAW_BYTE(cc_data->AssociationTypeId, 0);
1670         *pdata->b_wptr++ = DRAW_BYTE(cc_data->AssociationTypeId, 1);
1671 
1672         bcopy(fieldAssociationSubTypeId, pdata->b_wptr, 4);
1673         pdata->b_wptr += 4;
1674         *pdata->b_wptr++ = DRAW_BYTE(cc_data->AssociationSubTypeId, 0);
1675         *pdata->b_wptr++ = DRAW_BYTE(cc_data->AssociationSubTypeId, 1);
1676 
1677         bcopy(fieldLength, pdata->b_wptr, 4);
1678         pdata->b_wptr += 4;
1679         *pdata->b_wptr++ = DRAW_BYTE(cc_data->Length, 0);
1680         *pdata->b_wptr++ = DRAW_BYTE(cc_data->Length, 1);
1681         *pdata->b_wptr++ = DRAW_BYTE(cc_data->Length, 2);
1682         *pdata->b_wptr++ = DRAW_BYTE(cc_data->Length, 3);
1683 
1684         bcopy(fieldConnectionContext, pdata->b_wptr, 4);
1685         pdata->b_wptr += 4;
1686         bcopy(&(cc_data->CC), pdata->b_wptr, 48);
1687         pdata->b_wptr += 48;
1688 
1689         bcopy(fieldBandGroups, pdata->b_wptr, 4);
1690         pdata->b_wptr += 4;
1691         *pdata->b_wptr++ = DRAW_BYTE(cc_data->BandGroups, 0);
1692         *pdata->b_wptr++ = DRAW_BYTE(cc_data->BandGroups, 1);
1693 
1694         return (pdata);
1695 }
1696 
1697 static mblk_t *
1698 trans_from_cc_fail(wusb_cbaf_cc_fail_t *cc_fail)
1699 {
1700         mblk_t *pdata;
1701 
1702         if ((pdata = allocb(WUSB_CC_FAILURE_SIZE, BPRI_HI)) == NULL) {
1703 
1704                 return (NULL);
1705         }
1706 
1707         bcopy(fieldAssociationTypeId, pdata->b_wptr, 4);
1708         pdata->b_wptr += 4;
1709         *pdata->b_wptr++ = DRAW_BYTE(cc_fail->AssociationTypeId, 0);
1710         *pdata->b_wptr++ = DRAW_BYTE(cc_fail->AssociationTypeId, 1);
1711 
1712         bcopy(fieldAssociationSubTypeId, pdata->b_wptr, 4);
1713         pdata->b_wptr += 4;
1714         *pdata->b_wptr++ = DRAW_BYTE(cc_fail->AssociationSubTypeId, 0);
1715         *pdata->b_wptr++ = DRAW_BYTE(cc_fail->AssociationSubTypeId, 1);
1716 
1717         bcopy(fieldLength, pdata->b_wptr, 4);
1718         pdata->b_wptr += 4;
1719         *pdata->b_wptr++ = DRAW_BYTE(cc_fail->Length, 0);
1720         *pdata->b_wptr++ = DRAW_BYTE(cc_fail->Length, 1);
1721         *pdata->b_wptr++ = DRAW_BYTE(cc_fail->Length, 2);
1722         *pdata->b_wptr++ = DRAW_BYTE(cc_fail->Length, 3);
1723 
1724         bcopy(fieldAssociationStatus, pdata->b_wptr, 4);
1725         pdata->b_wptr += 4;
1726         *pdata->b_wptr++ = DRAW_BYTE(cc_fail->AssociationStatus, 0);
1727         *pdata->b_wptr++ = DRAW_BYTE(cc_fail->AssociationStatus, 1);
1728         *pdata->b_wptr++ = DRAW_BYTE(cc_fail->AssociationStatus, 2);
1729         *pdata->b_wptr++ = DRAW_BYTE(cc_fail->AssociationStatus, 3);
1730 
1731         return (pdata);
1732 }
1733 
1734 static int
1735 trans_to_device_info(wusb_ca_state_t *wusb_cap,
1736     mblk_t *pdata, wusb_cbaf_device_info_t *device_info)
1737 {
1738         int i, plen;
1739         void *paddr;
1740         char *mode;
1741         uchar_t *ptr = (uchar_t *)pdata->b_rptr;
1742         wusb_cbaf_info_item_t item;
1743 
1744         for (i = 0; i < 5; i++) {
1745                 if (((int)usb_parse_data("ss", ptr, 4, &item,
1746                     sizeof (item))) <= 0) {
1747                         USB_DPRINTF_L2(PRINT_MASK_ALL,
1748                             wusb_cap->wusb_ca_log_hdl,
1749                             "parse item[%d] failed", i);
1750 
1751                         return (-1);
1752                 }
1753                 ptr += 4;
1754 
1755                 switch (item.typeID) {
1756                 case attrLength:
1757                         mode = "l";
1758                         paddr = &(device_info->Length);
1759                         plen = sizeof (uint32_t);
1760 
1761                         break;
1762                 case attrCDID:
1763                         mode = "16c";
1764                         paddr = &(device_info->CDID);
1765                         plen = 16 * sizeof (uint8_t);
1766 
1767                         break;
1768                 case attrBandGroups:
1769                         mode = "s";
1770                         paddr = &(device_info->BandGroups);
1771                         plen = sizeof (uint16_t);
1772 
1773                         break;
1774                 case attrLangID:
1775                         mode = "s";
1776                         paddr = &(device_info->LangID);
1777                         plen = sizeof (uint16_t);
1778 
1779                         break;
1780                 case attrDeviceFriendlyName:
1781                         mode = "l";
1782                         paddr = &(device_info->DeviceFriendlyName);
1783                         plen = 64 * sizeof (char);
1784 
1785                         break;
1786                 default:
1787                         USB_DPRINTF_L2(PRINT_MASK_ALL,
1788                             wusb_cap->wusb_ca_log_hdl,
1789                             "item[%d]: 0x%04x", i, item.typeID);
1790 
1791                         return (-1);
1792                 }
1793 
1794                 if (((int)usb_parse_data(mode, ptr, item.length,
1795                     paddr, plen)) <= 0) {
1796                         USB_DPRINTF_L2(PRINT_MASK_ALL,
1797                             wusb_cap->wusb_ca_log_hdl,
1798                             "item[%d]: 0x%04x", i, item.typeID);
1799 
1800                         return (-1);
1801                 }
1802                 ptr += item.length;
1803         }
1804 
1805         return (0);
1806 }