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 }