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 * Wire Adapter Operations 28 * Both DWA and HWA have the same kind of functional components, the 29 * Wire Adapter. Functions defined in this file are to handle WA's 30 * class specific Descriptors, Requests, Notifications and Transfers. 31 * DWA or HWA specific descriptors, requests are not handled here. 32 */ 33 34 #include <sys/usb/hwa/hwahc/hwahc.h> 35 #include <sys/usb/hwa/hwahc/hwahc_util.h> 36 #include <sys/usb/usba/wa.h> 37 #include <sys/usb/usba/wusba.h> 38 #include <sys/usb/usba/whcdi.h> 39 #include <sys/usb/usba.h> 40 #include <sys/usb/usba/usba_impl.h> 41 #include <sys/usb/usba/usba_devdb.h> /* usba_devdb_refresh */ 42 #include <sys/usb/hubd/hubdvar.h> 43 #include <sys/usb/hubd/hubd_impl.h> /* hubd_ioctl_data_t */ 44 #include <sys/strsubr.h> /* allocb_wait */ 45 #include <sys/strsun.h> /* MBLKL macro */ 46 47 extern usb_log_handle_t whcdi_log_handle; 48 49 /* default rpipe PHY transfer speed */ 50 static uint8_t rp_default_speed = WUSB_PHY_TX_RATE_106; 51 52 /* function prototypes */ 53 static void wusb_wa_remove_wr_from_timeout_list(wusb_wa_rpipe_hdl_t *hdl, 54 wusb_wa_trans_wrapper_t *tw); 55 static void wusb_wa_handle_error(wusb_wa_data_t *wa_data, 56 wusb_wa_trans_wrapper_t *wr, usb_cr_t cr); 57 58 /* 59 * Parse Wire Adapter class desriptor. 60 * - see 8.4.3.7 & 8.5.2.7 61 * 62 * wa_descr - the parsed descriptors. 63 * altif_data - the passed in raw descriptor data. 64 */ 65 int 66 wusb_parse_wa_descr(usb_wa_descr_t *wa_descr, usb_alt_if_data_t *altif_data) 67 { 68 usb_cvs_data_t *cvs_data; 69 int i; 70 size_t count; 71 72 if ((wa_descr == NULL) || (altif_data == NULL)) { 73 return (USB_INVALID_ARGS); 74 } 75 76 for (i = 0; i < altif_data->altif_n_cvs; i++) { 77 cvs_data = &altif_data->altif_cvs[i]; 78 if (cvs_data->cvs_buf == NULL) { 79 continue; 80 } 81 if (cvs_data->cvs_buf[1] == USB_DESCR_TYPE_WA) { 82 count = usb_parse_data("ccsccsscccc", 83 cvs_data->cvs_buf, cvs_data->cvs_buf_len, 84 (void *)wa_descr, 85 (size_t)USB_WA_DESCR_SIZE); 86 if (count != USB_WA_DESCR_SIZE) { 87 return (USB_FAILURE); 88 } else { 89 return (USB_SUCCESS); 90 } 91 } 92 } 93 94 return (USB_FAILURE); 95 } 96 97 /* initialize rpipe structures */ 98 void 99 wusb_wa_rpipes_init(wusb_wa_data_t *wa_data) 100 { 101 int i; 102 wusb_wa_rpipe_hdl_t *hdl; 103 104 for (i = 0; i < wa_data->wa_num_rpipes; i++) { 105 hdl = &wa_data->wa_rpipe_hdl[i]; 106 mutex_init(&hdl->rp_mutex, NULL, MUTEX_DRIVER, NULL); 107 cv_init(&hdl->rp_cv, NULL, CV_DRIVER, NULL); 108 109 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*hdl)); 110 hdl->rp_state = WA_RPIPE_STATE_FREE; 111 hdl->rp_refcnt = 0; 112 hdl->rp_timeout_list = NULL; 113 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*hdl)); 114 } 115 } 116 117 /* deinitialize rpipe structures */ 118 void 119 wusb_wa_rpipes_fini(wusb_wa_data_t *wa_data) 120 { 121 int i; 122 wusb_wa_rpipe_hdl_t *hdl; 123 124 for (i = 0; i < wa_data->wa_num_rpipes; i++) { 125 hdl = &wa_data->wa_rpipe_hdl[i]; 126 mutex_destroy(&hdl->rp_mutex); 127 cv_destroy(&hdl->rp_cv); 128 } 129 } 130 131 132 /* 133 * wusb_wa_data_init: 134 * WA interface validation 135 * Parse WA class descriptors 136 * Set up RPipes 137 * Set up callbacks 138 */ 139 int 140 wusb_wa_data_init(dev_info_t *dip, wusb_wa_data_t *wa_data, wusb_wa_cb_t *cbs, 141 usb_client_dev_data_t *dev_data, 142 uint_t mask, usb_log_handle_t handle) 143 { 144 usb_alt_if_data_t *altif_data; 145 usb_ep_data_t *ep_data; 146 int ifno; 147 int rval; 148 149 if ((wa_data == NULL) || (dev_data == NULL)) { 150 151 return (USB_INVALID_ARGS); 152 } 153 154 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*wa_data)); 155 156 /* get inf descr and ept descrs from altif data */ 157 altif_data = &dev_data->dev_curr_cfg-> 158 cfg_if[dev_data->dev_curr_if].if_alt[0]; 159 160 /* T.8-44. Wire Adapter */ 161 if (altif_data->altif_descr.bInterfaceSubClass != 162 USB_SUBCLS_WUSB_2) { 163 USB_DPRINTF_L2(mask, handle, 164 "wusb_init_wa_data: invalid interface subclass (0x%x)", 165 altif_data->altif_descr.bInterfaceSubClass); 166 167 return (USB_FAILURE); 168 } 169 170 /* at least 3 EPs, INTR IN + BULK IN + BULK OUT */ 171 if (altif_data->altif_n_ep < 3) { 172 USB_DPRINTF_L2(mask, handle, 173 "wusb_init_wa_data: invalid alt 0 for interface %d", 174 dev_data->dev_curr_if); 175 176 return (USB_FAILURE); 177 } 178 179 wa_data->wa_ifno = ifno = dev_data->dev_curr_if; 180 wa_data->wa_if_descr = altif_data->altif_descr; 181 182 if ((ep_data = usb_lookup_ep_data(dip, dev_data, ifno, 0, 0, 183 USB_EP_ATTR_BULK, USB_EP_DIR_OUT)) != NULL) { 184 wa_data->wa_bulkout_ept = ep_data->ep_descr; 185 } 186 if ((ep_data = usb_lookup_ep_data(dip, dev_data, ifno, 0, 0, 187 USB_EP_ATTR_BULK, USB_EP_DIR_IN)) != NULL) { 188 wa_data->wa_bulkin_ept = ep_data->ep_descr; 189 } 190 if ((ep_data = usb_lookup_ep_data(dip, dev_data, ifno, 0, 0, 191 USB_EP_ATTR_INTR, USB_EP_DIR_IN)) != NULL) { 192 wa_data->wa_intr_ept = ep_data->ep_descr; 193 } 194 195 if ((wa_data->wa_bulkout_ept.bLength == 0) || 196 (wa_data->wa_bulkin_ept.bLength == 0) || 197 (wa_data->wa_intr_ept.bLength == 0)) { 198 USB_DPRINTF_L2(mask, handle, 199 "wusb_init_wa_data: the minimum endpoint set is not " 200 "supported"); 201 202 return (USB_FAILURE); 203 } 204 205 /* parse the WA descriptor */ 206 if ((rval = wusb_parse_wa_descr(&wa_data->wa_descr, altif_data)) != 207 USB_SUCCESS) { 208 USB_DPRINTF_L2(mask, handle, 209 "wusb_init_wa_data: parse wire adapter class descr failed"); 210 211 return (rval); 212 } 213 wa_data->wa_avail_blocks = wa_data->wa_descr.wRPipeMaxBlock; 214 215 wa_data->wa_dip = dip; 216 217 /* initialize rpipe handlers */ 218 wa_data->wa_num_rpipes = wa_data->wa_descr.wNumRPipes; 219 220 wa_data->wa_rpipe_hdl = kmem_zalloc((wa_data->wa_num_rpipes * 221 sizeof (wusb_wa_rpipe_hdl_t)), KM_SLEEP); 222 223 /* init rpipes */ 224 wusb_wa_rpipes_init(wa_data); 225 226 /* register callbacks */ 227 wa_data->pipe_periodic_req = cbs->pipe_periodic_req; 228 wa_data->intr_cb = cbs->intr_cb; 229 wa_data->intr_exc_cb = cbs->intr_exc_cb; 230 wa_data->rpipe_xfer_cb = cbs->rpipe_xfer_cb; 231 232 mutex_init(&wa_data->wa_mutex, NULL, MUTEX_DRIVER, NULL); 233 234 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*wa_data)); 235 236 return (USB_SUCCESS); 237 } 238 239 /* deinitialize data transfer related resources */ 240 void 241 wusb_wa_data_fini(wusb_wa_data_t *wa_data) 242 { 243 mutex_enter(&wa_data->wa_mutex); 244 if (wa_data->wa_rpipe_hdl) { 245 wusb_wa_rpipes_fini(wa_data); 246 kmem_free(wa_data->wa_rpipe_hdl, wa_data->wa_num_rpipes * 247 sizeof (wusb_wa_rpipe_hdl_t)); 248 } 249 mutex_exit(&wa_data->wa_mutex); 250 mutex_destroy(&wa_data->wa_mutex); 251 } 252 253 void wusb_wa_dump_rpipe_descr(usb_wa_rpipe_descr_t *pd, uint_t mask, 254 usb_log_handle_t handle) 255 { 256 USB_DPRINTF_L4(mask, handle, "RPipe Descriptor:\n" 257 "\tWRPipeIndex=%d wRequests=%d wBlocks=%d\n" 258 "\twMaxPacketSize=%d bHSHubAddress=%d\n" 259 "\tbHSHubPort=%d bSpeed=%d bDeviceAddress=%d\n" 260 "\tbEndpointAddress=0x%02x bDataSequence=%d\n" 261 "\tdwCurrentWindow=0x%08x bMaxDataSequence=%d", 262 pd->wRPipeIndex, pd->wRequests, pd->wBlocks, pd->wMaxPacketSize, 263 pd->wa_value.hwa_value.bMaxBurst, 264 pd->wa_value.hwa_value.bDeviceInfoIndex, 265 pd->bSpeed, pd->bDeviceAddress, 266 pd->bEndpointAddress, pd->bDataSequence, pd->dwCurrentWindow, 267 pd->bMaxDataSequence); 268 269 USB_DPRINTF_L4(mask, handle, 270 "(cont'ed)bInterval=%d bOverTheAirInterval=%d\n" 271 "\tbmAttribute=0x%02x bmCharacter=0x%02x\n" 272 "\tbmRetryOptions=0x%02x wNumTransactionErrors=%d\n", 273 pd->bInterval, pd->bOverTheAirInterval, 274 pd->bmAttribute, pd->bmCharacteristics, pd->bmRetryOptions, 275 pd->wNumTransactionErrors); 276 277 } 278 279 /* get rpipe descr of a certain index, refer to WUSB 1.0/8.3.1.4 */ 280 int 281 wusb_wa_get_rpipe_descr(dev_info_t *dip, usb_pipe_handle_t ph, 282 uint16_t idx, usb_wa_rpipe_descr_t *descr, 283 uint_t mask, usb_log_handle_t handle) 284 { 285 mblk_t *data = NULL; 286 usb_cr_t completion_reason; 287 usb_cb_flags_t cb_flags; 288 size_t count; 289 int rval; 290 291 /* 292 * This descriptor is critical for later operations to succeed. 293 * So, we must wait here. 294 */ 295 rval = usb_pipe_sync_ctrl_xfer(dip, ph, 296 WA_CLASS_RPIPE_REQ_IN_TYPE, 297 USB_REQ_GET_DESCR, 298 USB_DESCR_TYPE_RPIPE << 8, 299 idx, 300 USB_RPIPE_DESCR_SIZE, 301 &data, 0, 302 &completion_reason, &cb_flags, 0); 303 304 if (rval != USB_SUCCESS) { 305 USB_DPRINTF_L2(mask, handle, 306 "wusb_wa_get_rpipe_descr: rval=%d, cr=%d, " 307 "cb=0x%x", rval, completion_reason, cb_flags); 308 309 goto done; 310 } 311 312 if (MBLKL(data) != USB_RPIPE_DESCR_SIZE) { 313 USB_DPRINTF_L2(mask, handle, 314 "wusb_wa_get_rpipe_descr: return size %d", 315 (int)MBLKL(data)); 316 rval = USB_FAILURE; 317 318 goto done; 319 } 320 321 count = usb_parse_data("2c4s6cl6cs", data->b_rptr, 322 USB_RPIPE_DESCR_SIZE, descr, sizeof (usb_wa_rpipe_descr_t)); 323 324 if (count == USB_PARSE_ERROR) { 325 USB_DPRINTF_L2(mask, handle, 326 "wusb_wa_get_rpipe_descr: parse error"); 327 rval = USB_FAILURE; 328 329 goto done; 330 } 331 332 wusb_wa_dump_rpipe_descr(descr, mask, handle); 333 334 freemsg(data); 335 data = NULL; 336 337 return (USB_SUCCESS); 338 339 done: 340 if (data) { 341 freemsg(data); 342 } 343 344 return (rval); 345 } 346 347 /* 348 * Get All the RPipes' descriptors of an HWA 349 * - WA RPipe descriptor are not returned as part of the 350 * cofiguration descriptor. We have to get it separately. 351 * - See section 8.4.3.19 and 8.5.2.11 352 */ 353 int 354 wusb_wa_get_rpipe_descrs(wusb_wa_data_t *wa_data, usb_pipe_handle_t ph, 355 uint_t mask, usb_log_handle_t handle) 356 { 357 dev_info_t *dip = wa_data->wa_dip; 358 int i, rval; 359 360 if ((dip == NULL) || (ph == NULL)) { 361 362 return (USB_INVALID_ARGS); 363 } 364 365 /* called at initialization, no other threads yet */ 366 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*wa_data)); 367 368 for (i = 0; i < wa_data->wa_num_rpipes; i++) { 369 rval = wusb_wa_get_rpipe_descr(dip, ph, i, 370 &wa_data->wa_rpipe_hdl[i].rp_descr, mask, handle); 371 372 if (rval != USB_SUCCESS) { 373 USB_DPRINTF_L2(mask, handle, 374 "wusb_wa_get_rpipe_descrs: fail to get rpipe " 375 "descr for idx %d", i); 376 377 return (rval); 378 } 379 } 380 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*wa_data)); 381 382 return (USB_SUCCESS); 383 } 384 385 /* 386 * Get Wire Adapter's Status 387 * See section 8.3.1.6 388 */ 389 int 390 wusb_get_wa_status(wusb_wa_data_t *wa_data, usb_pipe_handle_t ph, 391 uint32_t *status) 392 { 393 dev_info_t *dip = wa_data->wa_dip; 394 int rval = USB_SUCCESS; 395 mblk_t *data = NULL; 396 usb_cr_t completion_reason; 397 usb_cb_flags_t cb_flags; 398 399 if ((dip == NULL) || (ph == NULL)) { 400 401 return (USB_INVALID_ARGS); 402 } 403 404 rval = usb_pipe_sync_ctrl_xfer(dip, ph, 405 WUSB_CLASS_IF_REQ_IN_TYPE, 406 USB_REQ_GET_STATUS, 407 0, 408 wa_data->wa_ifno, 409 WA_GET_WA_STATUS_LEN, 410 &data, 0, 411 &completion_reason, &cb_flags, 0); 412 413 if (rval != USB_SUCCESS) { 414 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 415 "wusb_get_wa_status: can't retrieve status"); 416 417 goto done; 418 } 419 420 *status = (*(data->b_rptr + 3) << 24) | (*(data->b_rptr + 2) << 16) | 421 (*(data->b_rptr + 1) << 8) | *(data->b_rptr); 422 423 done: 424 if (data) { 425 freemsg(data); 426 } 427 428 return (rval); 429 } 430 431 /* 432 * Reset WA 433 * See 8.3.1.9 434 */ 435 int 436 wusb_wa_reset(wusb_wa_data_t *wa_data, usb_pipe_handle_t ph) 437 { 438 dev_info_t *dip = wa_data->wa_dip; 439 usb_cr_t completion_reason; 440 usb_cb_flags_t cb_flags; 441 int rval, i; 442 uint32_t status; 443 444 if ((dip == NULL) || (ph == NULL)) { 445 446 return (USB_INVALID_ARGS); 447 } 448 449 rval = usb_pipe_sync_ctrl_xfer(dip, ph, 450 WUSB_CLASS_IF_REQ_OUT_TYPE, 451 USB_REQ_SET_FEATURE, 452 WA_DEV_RESET, 453 wa_data->wa_ifno, 454 0, 455 NULL, 0, 456 &completion_reason, &cb_flags, 0); 457 458 if (rval != USB_SUCCESS) { 459 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 460 "wusb_wa_reset: can't reset wa, rval = %d, cr=%d", rval, 461 completion_reason); 462 463 return (rval); 464 } 465 466 for (i = 0; i < 10; i++) { 467 delay(drv_usectohz(50000)); 468 469 rval = wusb_get_wa_status(wa_data, ph, &status); 470 if (rval != USB_SUCCESS) { 471 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 472 "wusb_wa_reset: can't get status, rval = %d", 473 rval); 474 475 return (rval); 476 } 477 478 if (!(status & WA_HC_RESET_IN_PROGRESS)) { 479 480 return (USB_SUCCESS); 481 } 482 } 483 484 return (USB_FAILURE); 485 } 486 487 /* 488 * Enable wire adapter. 489 * See 8.3.1.9 490 */ 491 int 492 wusb_wa_enable(wusb_wa_data_t *wa_data, usb_pipe_handle_t ph) 493 { 494 dev_info_t *dip = wa_data->wa_dip; 495 usb_cr_t completion_reason; 496 usb_cb_flags_t cb_flags; 497 int rval, i; 498 uint32_t status; 499 500 if ((dip == NULL) || (ph == NULL)) { 501 502 return (USB_INVALID_ARGS); 503 } 504 505 rval = usb_pipe_sync_ctrl_xfer(dip, ph, 506 WUSB_CLASS_IF_REQ_OUT_TYPE, 507 USB_REQ_SET_FEATURE, 508 WA_DEV_ENABLE, 509 wa_data->wa_ifno, 510 0, 511 NULL, 0, 512 &completion_reason, &cb_flags, 0); 513 514 if (rval != USB_SUCCESS) { 515 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 516 "wusb_wa_enable: can't enable WA, rval = %d, cr=%d", 517 rval, completion_reason); 518 519 return (rval); 520 } 521 522 for (i = 0; i < 10; i++) { 523 delay(drv_usectohz(50000)); 524 525 rval = wusb_get_wa_status(wa_data, ph, &status); 526 if (rval != USB_SUCCESS) { 527 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 528 "wusb_wa_enable: can't get status, rval = %d", 529 rval); 530 531 return (rval); 532 } 533 534 if (status & WA_HC_ENABLED) { 535 536 return (USB_SUCCESS); 537 } 538 } 539 540 return (USB_FAILURE); 541 } 542 543 /* 544 * Disable WA. Clear a fearture. 545 * See Section 8.3.1.3 546 */ 547 int 548 wusb_wa_disable(wusb_wa_data_t *wa_data, usb_pipe_handle_t ph) 549 { 550 dev_info_t *dip = wa_data->wa_dip; 551 usb_cr_t completion_reason; 552 usb_cb_flags_t cb_flags; 553 int rval, i; 554 uint32_t status; 555 556 if ((dip == NULL) || (ph == NULL)) { 557 558 return (USB_INVALID_ARGS); 559 } 560 561 rval = usb_pipe_sync_ctrl_xfer(dip, ph, 562 WUSB_CLASS_IF_REQ_OUT_TYPE, 563 USB_REQ_CLEAR_FEATURE, 564 WA_DEV_ENABLE, 565 wa_data->wa_ifno, 566 0, 567 NULL, 0, 568 &completion_reason, &cb_flags, 0); 569 570 if (rval != USB_SUCCESS) { 571 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 572 "wusb_wa_disable: can't disable wa, rval = %d, cr = %d", 573 rval, completion_reason); 574 575 return (rval); 576 } 577 578 for (i = 0; i < 10; i++) { 579 delay(drv_usectohz(50000)); 580 581 rval = wusb_get_wa_status(wa_data, ph, &status); 582 if (rval != USB_SUCCESS) { 583 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 584 "wusb_wa_disable: can't get status, rval = %d", 585 rval); 586 587 return (rval); 588 } 589 590 if (!(status & WA_HC_ENABLED)) { 591 592 return (USB_SUCCESS); 593 } 594 } 595 596 return (USB_FAILURE); 597 } 598 599 /* 600 * Open the two bulk endpoints and one interrupt IN endpoint, defined in 601 * a WA's data transfer interface. See 8.1.2 602 */ 603 int 604 wusb_wa_open_pipes(wusb_wa_data_t *wa_data) 605 { 606 int rval; 607 608 mutex_enter(&wa_data->wa_mutex); 609 if (wa_data->wa_state & WA_PIPES_OPENED) { 610 mutex_exit(&wa_data->wa_mutex); 611 612 return (USB_SUCCESS); 613 } 614 wa_data->wa_pipe_policy.pp_max_async_reqs = 1; 615 mutex_exit(&wa_data->wa_mutex); 616 617 rval = usb_pipe_open(wa_data->wa_dip, &wa_data->wa_intr_ept, 618 &wa_data->wa_pipe_policy, USB_FLAGS_SLEEP, 619 &wa_data->wa_intr_ph); 620 if (rval != USB_SUCCESS) { 621 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 622 "wusb_wa_open_pipes: can't open intr pipe, rval = %d", 623 rval); 624 625 return (rval); 626 } 627 628 rval = usb_pipe_open(wa_data->wa_dip, &wa_data->wa_bulkin_ept, 629 &wa_data->wa_pipe_policy, USB_FLAGS_SLEEP, 630 &wa_data->wa_bulkin_ph); 631 if (rval != USB_SUCCESS) { 632 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 633 "wusb_wa_open_pipes: can't open bulkin pipe, rval = %d", 634 rval); 635 636 usb_pipe_close(wa_data->wa_dip, wa_data->wa_intr_ph, 637 USB_FLAGS_SLEEP, NULL, NULL); 638 mutex_enter(&wa_data->wa_mutex); 639 wa_data->wa_intr_ph = NULL; 640 mutex_exit(&wa_data->wa_mutex); 641 642 return (rval); 643 } 644 645 rval = usb_pipe_open(wa_data->wa_dip, &wa_data->wa_bulkout_ept, 646 &wa_data->wa_pipe_policy, USB_FLAGS_SLEEP, 647 &wa_data->wa_bulkout_ph); 648 649 if (rval != USB_SUCCESS) { 650 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 651 "wusb_wa_open_pipes: can't open bulkout pipe, rval = %d", 652 rval); 653 654 usb_pipe_close(wa_data->wa_dip, wa_data->wa_intr_ph, 655 USB_FLAGS_SLEEP, NULL, NULL); 656 usb_pipe_close(wa_data->wa_dip, wa_data->wa_bulkin_ph, 657 USB_FLAGS_SLEEP, NULL, NULL); 658 mutex_enter(&wa_data->wa_mutex); 659 wa_data->wa_intr_ph = NULL; 660 wa_data->wa_bulkin_ph = NULL; 661 mutex_exit(&wa_data->wa_mutex); 662 663 return (rval); 664 } 665 666 mutex_enter(&wa_data->wa_mutex); 667 /* mark the state stopped until listening is started on the pipes */ 668 wa_data->wa_intr_pipe_state = WA_PIPE_STOPPED; 669 wa_data->wa_bulkin_pipe_state = WA_PIPE_STOPPED; 670 /* no listening on this pipe, just mark it active */ 671 wa_data->wa_bulkout_pipe_state = WA_PIPE_ACTIVE; 672 wa_data->wa_state |= WA_PIPES_OPENED; 673 mutex_exit(&wa_data->wa_mutex); 674 675 return (USB_SUCCESS); 676 } 677 678 /* 679 * Close WA's pipes. 680 */ 681 void 682 wusb_wa_close_pipes(wusb_wa_data_t *wa_data) 683 { 684 mutex_enter(&wa_data->wa_mutex); 685 if ((wa_data->wa_state & WA_PIPES_OPENED) == 0) { 686 mutex_exit(&wa_data->wa_mutex); 687 688 return; 689 } 690 691 mutex_exit(&wa_data->wa_mutex); 692 693 usb_pipe_close(wa_data->wa_dip, wa_data->wa_intr_ph, 694 USB_FLAGS_SLEEP, NULL, NULL); 695 696 if (wa_data->wa_bulkin_ph != NULL) { 697 usb_pipe_close(wa_data->wa_dip, wa_data->wa_bulkin_ph, 698 USB_FLAGS_SLEEP, NULL, NULL); 699 } 700 701 usb_pipe_close(wa_data->wa_dip, wa_data->wa_bulkout_ph, 702 USB_FLAGS_SLEEP, NULL, NULL); 703 704 mutex_enter(&wa_data->wa_mutex); 705 wa_data->wa_intr_ph = NULL; 706 wa_data->wa_bulkin_ph = NULL; 707 wa_data->wa_bulkout_ph = NULL; 708 wa_data->wa_intr_pipe_state = WA_PIPE_CLOSED; 709 wa_data->wa_bulkin_pipe_state = WA_PIPE_CLOSED; 710 wa_data->wa_bulkout_pipe_state = WA_PIPE_CLOSED; 711 wa_data->wa_state &= ~WA_PIPES_OPENED; 712 mutex_exit(&wa_data->wa_mutex); 713 } 714 715 /* 716 * start listening for transfer completion notifications or device 717 * notifications on the notification ept 718 */ 719 int 720 wusb_wa_start_nep(wusb_wa_data_t *wa_data, usb_flags_t flag) 721 { 722 int rval; 723 usb_intr_req_t *reqp; 724 725 mutex_enter(&wa_data->wa_mutex); 726 if ((wa_data->wa_intr_ph == NULL) || 727 (wa_data->wa_intr_pipe_state != WA_PIPE_STOPPED)) { 728 mutex_exit(&wa_data->wa_mutex); 729 730 return (USB_INVALID_PIPE); 731 } 732 733 reqp = usb_alloc_intr_req(wa_data->wa_dip, 0, flag); 734 if (!reqp) { 735 mutex_exit(&wa_data->wa_mutex); 736 737 return (USB_NO_RESOURCES); 738 } 739 740 reqp->intr_client_private = (usb_opaque_t)wa_data; 741 reqp->intr_attributes = USB_ATTRS_SHORT_XFER_OK | 742 USB_ATTRS_AUTOCLEARING; 743 reqp->intr_len = wa_data->wa_intr_ept.wMaxPacketSize; 744 reqp->intr_cb = wa_data->intr_cb; 745 reqp->intr_exc_cb = wa_data->intr_exc_cb; 746 mutex_exit(&wa_data->wa_mutex); 747 748 if ((rval = usb_pipe_intr_xfer(wa_data->wa_intr_ph, reqp, 749 flag)) != USB_SUCCESS) { 750 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 751 "wusb_wa_start_nep: intr xfer fail, rval = %d", 752 rval); 753 754 usb_free_intr_req(reqp); 755 756 return (rval); 757 } 758 759 mutex_enter(&wa_data->wa_mutex); 760 /* pipe state is active while the listening is on */ 761 wa_data->wa_intr_pipe_state = WA_PIPE_ACTIVE; 762 mutex_exit(&wa_data->wa_mutex); 763 764 return (USB_SUCCESS); 765 } 766 767 /* 768 * stop the notification ept from listening 769 */ 770 void 771 wusb_wa_stop_nep(wusb_wa_data_t *wa_data) 772 { 773 mutex_enter(&wa_data->wa_mutex); 774 if ((wa_data->wa_intr_ph == NULL) || 775 (wa_data->wa_intr_pipe_state != WA_PIPE_ACTIVE)) { 776 mutex_exit(&wa_data->wa_mutex); 777 778 return; 779 } 780 wa_data->wa_intr_pipe_state = WA_PIPE_STOPPED; 781 mutex_exit(&wa_data->wa_mutex); 782 /* stop intr in without closing the pipe */ 783 usb_pipe_stop_intr_polling(wa_data->wa_intr_ph, USB_FLAGS_SLEEP); 784 } 785 786 /* 787 * allocate a rpipe for transfers on a pipe 788 * - Find a free RPipe 789 * 790 * For now, one rpipe is associated with only one usba pipe once 791 * the pipe is opened. In the future, the rpipe needs to be 792 * multiplexed between asynchronous endpoints 793 * input: 794 * type: 0 - ctrl, 1 - isoc, 2 - bulk, 3 - intr 795 * 796 */ 797 /* ARGSUSED */ 798 int 799 wusb_wa_get_rpipe(wusb_wa_data_t *wa_data, usb_pipe_handle_t ph, 800 uint8_t type, wusb_wa_rpipe_hdl_t **hdl, 801 uint_t mask, usb_log_handle_t handle) 802 { 803 int i; 804 wusb_wa_rpipe_hdl_t *thdl; 805 uint8_t rp_type; 806 uint8_t ep_type = 1 << type; 807 808 *hdl = NULL; 809 810 mutex_enter(&wa_data->wa_mutex); 811 for (i = 0; i < wa_data->wa_num_rpipes; i++) { 812 /* find the first unused rpipe */ 813 thdl = &wa_data->wa_rpipe_hdl[i]; 814 mutex_enter(&thdl->rp_mutex); 815 if (thdl->rp_state != WA_RPIPE_STATE_FREE) { 816 mutex_exit(&thdl->rp_mutex); 817 818 continue; 819 } 820 821 /* check if the rpipe supports the ept transfer type */ 822 rp_type = (thdl->rp_descr.bmCharacteristics & 823 USB_RPIPE_CHA_MASK); 824 if (rp_type & ep_type) { 825 thdl->rp_refcnt++; 826 thdl->rp_state = WA_RPIPE_STATE_IDLE; 827 thdl->rp_avail_reqs = thdl->rp_descr.wRequests; 828 *hdl = thdl; 829 mutex_exit(&thdl->rp_mutex); 830 mutex_exit(&wa_data->wa_mutex); 831 832 return (USB_SUCCESS); 833 } 834 mutex_exit(&thdl->rp_mutex); 835 } 836 837 USB_DPRINTF_L2(mask, handle, 838 "wusb_wa_get_rpipe: no matching rpipe is found"); 839 mutex_exit(&wa_data->wa_mutex); 840 841 return (USB_FAILURE); 842 } 843 844 /* 845 * Decrease a RPipe's reference count. 846 * - if count == 0, mark it as free RPipe. 847 */ 848 int 849 wusb_wa_release_rpipe(wusb_wa_data_t *wa, wusb_wa_rpipe_hdl_t *hdl) 850 { 851 if (hdl == NULL) { 852 853 return (USB_FAILURE); 854 } 855 856 mutex_enter(&wa->wa_mutex); 857 mutex_enter(&hdl->rp_mutex); 858 if (hdl->rp_refcnt == 0) { 859 mutex_exit(&hdl->rp_mutex); 860 mutex_exit(&wa->wa_mutex); 861 862 return (USB_FAILURE); 863 } 864 865 if (--hdl->rp_refcnt == 0) { 866 hdl->rp_state = WA_RPIPE_STATE_FREE; 867 } 868 869 if (hdl->rp_block_chg == 1) { 870 wa->wa_avail_blocks += hdl->rp_descr.wBlocks; 871 hdl->rp_descr.wBlocks = 0; /* to prevent misadd upon re-call */ 872 hdl->rp_block_chg = 0; 873 } 874 875 mutex_exit(&hdl->rp_mutex); 876 mutex_exit(&wa->wa_mutex); 877 878 return (USB_SUCCESS); 879 } 880 881 /* 882 * Set a RPipe's Descriptor and make the rpipe configured 883 * See section 8.3.1.7 884 */ 885 int 886 wusb_wa_set_rpipe_descr(dev_info_t *dip, usb_pipe_handle_t ph, 887 usb_wa_rpipe_descr_t *rp_descr) 888 { 889 mblk_t *data = NULL; 890 usb_cr_t completion_reason; 891 usb_cb_flags_t cb_flags; 892 int rval; 893 uint8_t *p; 894 895 data = allocb_wait(USB_RPIPE_DESCR_SIZE, BPRI_LO, STR_NOSIG, NULL); 896 p = data->b_wptr; 897 p[0] = rp_descr->bLength; 898 p[1] = rp_descr->bDescriptorType; 899 p[2] = rp_descr->wRPipeIndex; 900 p[3] = rp_descr->wRPipeIndex >> 8; 901 p[4] = rp_descr->wRequests; 902 p[5] = rp_descr->wRequests >> 8; 903 p[6] = rp_descr->wBlocks; 904 p[7] = rp_descr->wBlocks >> 8; 905 p[8] = rp_descr->wMaxPacketSize; 906 p[9] = rp_descr->wMaxPacketSize >> 8; 907 p[10] = rp_descr->wa_value.hwa_value.bMaxBurst; 908 p[11] = rp_descr->wa_value.hwa_value.bDeviceInfoIndex; 909 p[12] = rp_descr->bSpeed; 910 p[13] = rp_descr->bDeviceAddress; 911 p[14] = rp_descr->bEndpointAddress; 912 p[15] = rp_descr->bDataSequence; 913 p[16] = rp_descr->dwCurrentWindow; 914 p[17] = rp_descr->dwCurrentWindow >> 8; 915 p[18] = rp_descr->dwCurrentWindow >> 16; 916 p[19] = rp_descr->dwCurrentWindow >> 24; 917 p[20] = rp_descr->bMaxDataSequence; 918 p[21] = rp_descr->bInterval; 919 p[22] = rp_descr->bOverTheAirInterval; 920 p[23] = rp_descr->bmAttribute; 921 p[24] = rp_descr->bmCharacteristics; 922 p[25] = rp_descr->bmRetryOptions; 923 p[26] = rp_descr->wNumTransactionErrors; 924 p[27] = rp_descr->wNumTransactionErrors >> 8; 925 926 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 927 "wusb_wa_set_rpipe_descr: RPipe Descriptors"); 928 wusb_wa_dump_rpipe_descr(rp_descr, DPRINT_MASK_WHCDI, whcdi_log_handle); 929 930 rval = usb_pipe_sync_ctrl_xfer(dip, ph, 931 WA_CLASS_RPIPE_REQ_OUT_TYPE, 932 USB_REQ_SET_DESCR, 933 USB_DESCR_TYPE_RPIPE << 8, 934 rp_descr->wRPipeIndex, 935 USB_RPIPE_DESCR_SIZE, 936 &data, 0, 937 &completion_reason, &cb_flags, 0); 938 939 freemsg(data); 940 941 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 942 "wusb_wa_set_rpipe_descr: rval = %d", rval); 943 944 return (rval); 945 } 946 947 /* ept companion descr for the default ctrl pipe, refer to WUSB 1.0/4.8.1 */ 948 usb_ep_comp_descr_t ep_comp0 = { 949 sizeof (usb_ep_comp_descr_t), USB_DESCR_TYPE_WIRELESS_EP_COMP, 950 1, 2, 951 }; 952 953 /* 954 * Get the Endpoint Companion Descriptor for the pipe 955 * ph_data - the specified pipe 956 * ep_comp - the companion descriptor returned 957 */ 958 int 959 wusb_wa_get_ep_comp_descr(usba_pipe_handle_data_t *ph_data, 960 usb_ep_comp_descr_t *ep_comp) 961 { 962 usb_ep_descr_t *ep = &ph_data->p_ep; 963 usb_client_dev_data_t *dev_data; 964 usb_if_data_t *if_data; 965 usb_alt_if_data_t *altif_data; 966 usb_ep_data_t *ep_data; 967 int i, j; 968 969 /* default ctrl endpoint */ 970 if (ep->bEndpointAddress == 0) { 971 *ep_comp = ep_comp0; 972 973 return (USB_SUCCESS); 974 } 975 976 if (usb_get_dev_data(ph_data->p_dip, &dev_data, 977 USB_PARSE_LVL_IF, 0) != USB_SUCCESS) { 978 979 return (USB_FAILURE); 980 } 981 982 /* retrieve ept companion descr from the dev data */ 983 if_data = &dev_data->dev_curr_cfg->cfg_if[dev_data->dev_curr_if]; 984 for (i = 0; i < if_data->if_n_alt; i++) { 985 altif_data = &if_data->if_alt[i]; 986 for (j = 0; j < altif_data->altif_n_ep; j++) { 987 ep_data = &altif_data->altif_ep[j]; 988 if (memcmp(&ep_data->ep_descr, ep, 989 sizeof (usb_ep_descr_t)) == 0) { 990 *ep_comp = ep_data->ep_comp_descr; 991 usb_free_dev_data(ph_data->p_dip, dev_data); 992 993 return (USB_SUCCESS); 994 } 995 } 996 } 997 usb_free_dev_data(ph_data->p_dip, dev_data); 998 999 return (USB_FAILURE); 1000 } 1001 1002 /* to check if the specified PHY speed is supported by the device */ 1003 int 1004 wusb_wa_is_speed_valid(usba_device_t *ud, uint8_t speed) 1005 { 1006 usb_uwb_cap_descr_t *uwb_descr = ud->usb_wireless_data->uwb_descr; 1007 uint8_t valid_spd[WUSB_PHY_TX_RATE_RES] = { 1008 WUSB_DATA_RATE_BIT_53, WUSB_DATA_RATE_BIT_106, 1009 WUSB_DATA_RATE_BIT_160, WUSB_DATA_RATE_BIT_200, 1010 WUSB_DATA_RATE_BIT_320, WUSB_DATA_RATE_BIT_400, 1011 WUSB_DATA_RATE_BIT_480, 0 1012 }; 1013 1014 if (speed >= WUSB_PHY_TX_RATE_RES) { 1015 1016 return (0); 1017 } 1018 1019 /* this speed is not supported by the device */ 1020 if (valid_spd[speed] != (uwb_descr->wPHYRates & valid_spd[speed])) { 1021 1022 return (0); 1023 } 1024 1025 return (1); 1026 } 1027 1028 /* 1029 * Set up a RPipe 1030 * - Associate a RPipe and a pipe handle. Hence, an endpoint has 1031 * RPipe to transfer data. 1032 * - Set this RPipe to bDeviceAddress:bEndpointAddress 1033 * 1034 * wa - wa data 1035 * ph - wa's default control pipe 1036 * ph_data - client driver's usba pipe to be opened 1037 * hdl - RPipe handle 1038 */ 1039 int 1040 wusb_wa_set_rpipe_target(dev_info_t *dip, wusb_wa_data_t *wa, 1041 usb_pipe_handle_t ph, usba_pipe_handle_data_t *ph_data, 1042 wusb_wa_rpipe_hdl_t *hdl) 1043 { 1044 int rval; 1045 usb_ep_comp_descr_t ep_comp; 1046 usb_ep_descr_t *ep = &ph_data->p_ep; 1047 usba_device_t *usba_device; 1048 uint8_t rp_status; 1049 usb_wa_descr_t *wa_desc = &wa->wa_descr; 1050 uint16_t blockcnt; 1051 uint16_t maxsize; 1052 uint16_t seg_len; 1053 1054 1055 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 1056 "wusb_wa_set_rpipe_target: ph_data = 0x%p rp_hdl = 0x%p", 1057 (void*)ph_data, (void*)hdl); 1058 1059 /* Get client device's Endpoint companion descriptor */ 1060 if ((rval = wusb_wa_get_ep_comp_descr(ph_data, &ep_comp)) != 1061 USB_SUCCESS) { 1062 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 1063 "wusb_wa_set_rpipe_target: get companion ep descr failed," 1064 " rval = %d", rval); 1065 1066 return (rval); 1067 } 1068 1069 /* set the rpipe to unconfigured state */ 1070 if ((rval = wusb_wa_rpipe_reset(dip, ph_data, hdl, 0)) != USB_SUCCESS) { 1071 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 1072 "wusb_wa_set_rpipe_target: reset rpipe failed, rval = %d", 1073 rval); 1074 1075 return (rval); 1076 } 1077 1078 if ((rval = wusb_wa_get_rpipe_status(dip, ph, 1079 hdl->rp_descr.wRPipeIndex, &rp_status)) != USB_SUCCESS) { 1080 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 1081 "wusb_wa_set_rpipe_target: get rpipe status failed, " 1082 "rval = %d", rval); 1083 1084 return (rval); 1085 } 1086 1087 if (rp_status & WA_RPIPE_CONFIGURED) { 1088 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 1089 "wusb_wa_set_rpipe_target: reset rpipe unsuccessful"); 1090 1091 return (USB_FAILURE); 1092 } 1093 1094 mutex_enter(&wa->wa_mutex); 1095 usba_device = usba_get_usba_device(ph_data->p_dip); 1096 1097 mutex_enter(&hdl->rp_mutex); 1098 1099 /* should be 0x200 for default ctrl pipe, refer to wusb 1.0/4.8.1 */ 1100 hdl->rp_descr.wMaxPacketSize = ep->wMaxPacketSize; 1101 1102 /* 1103 * set rpipe descr values 1104 * 1105 * Try to use an average block value first. If it's too small, 1106 * then try to allocate the minimum block size to accomodate one 1107 * packet. If the required number of block is not available, return 1108 * failure. 1109 */ 1110 if (hdl->rp_descr.wBlocks == 0) { 1111 blockcnt = wa_desc->wRPipeMaxBlock/wa_desc->wNumRPipes; 1112 maxsize = 1 << (wa_desc->bRPipeBlockSize - 1); 1113 seg_len = blockcnt * maxsize; 1114 1115 /* alloc enough blocks to accomodate one packet */ 1116 if (ep->wMaxPacketSize > seg_len) { 1117 blockcnt = (ep->wMaxPacketSize + maxsize -1)/maxsize; 1118 } 1119 1120 /* WA don't have so many blocks to fulfill this reqirement */ 1121 if (wa->wa_avail_blocks < blockcnt) { 1122 mutex_exit(&hdl->rp_mutex); 1123 mutex_exit(&wa->wa_mutex); 1124 1125 return (USB_FAILURE); 1126 } 1127 1128 /* we're satisfied */ 1129 hdl->rp_descr.wBlocks = blockcnt; 1130 hdl->rp_block_chg = 1; /* the wBlocks is changed */ 1131 wa->wa_avail_blocks -= blockcnt; 1132 } 1133 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 1134 "wusb_wa_set_rpipe_target: wBlocks=%d, maxblock=%d, numR=%d, av=%d", 1135 hdl->rp_descr.wBlocks, wa_desc->wRPipeMaxBlock, wa_desc->wNumRPipes, 1136 wa->wa_avail_blocks); 1137 1138 hdl->rp_descr.wa_value.hwa_value.bMaxBurst = ep_comp.bMaxBurst; 1139 1140 /* 1141 * DEVICE INDEX 1142 * device info index should be zero based, refer 1143 * to WUSB 1.0/8.5.3.7 1144 */ 1145 hdl->rp_descr.wa_value.hwa_value.bDeviceInfoIndex = 1146 usba_device->usb_port - 1; 1147 1148 /* 1149 * default ctrl pipe uses PHY base signaling rate 1150 * refer to wusb 1.0/4.8.1 1151 */ 1152 if (ep->bEndpointAddress == 0) { 1153 hdl->rp_descr.bSpeed = WUSB_PHY_TX_RATE_53; 1154 } else { 1155 if (wusb_wa_is_speed_valid(usba_device, rp_default_speed)) { 1156 hdl->rp_descr.bSpeed = rp_default_speed; 1157 } else { 1158 /* use a must-supported speed */ 1159 hdl->rp_descr.bSpeed = WUSB_PHY_TX_RATE_106; 1160 } 1161 } 1162 hdl->rp_descr.bDeviceAddress = usba_device->usb_addr; 1163 hdl->rp_descr.bEndpointAddress = ep->bEndpointAddress; 1164 hdl->rp_descr.bDataSequence = 0; 1165 hdl->rp_descr.dwCurrentWindow = 1; 1166 hdl->rp_descr.bMaxDataSequence = ep_comp.bMaxSequence - 1; 1167 hdl->rp_descr.bInterval = ep->bInterval; 1168 hdl->rp_descr.bOverTheAirInterval = ep_comp.bOverTheAirInterval; 1169 hdl->rp_descr.bmAttribute = ep->bmAttributes & 0x03; 1170 hdl->rp_descr.bmRetryOptions = 0; /* keep retrying */ 1171 hdl->rp_descr.wNumTransactionErrors = 0; 1172 mutex_exit(&hdl->rp_mutex); 1173 1174 mutex_exit(&wa->wa_mutex); 1175 1176 /* set rpipe descr */ 1177 rval = wusb_wa_set_rpipe_descr(dip, ph, &hdl->rp_descr); 1178 if (rval != USB_SUCCESS) { 1179 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 1180 "wusb_wa_set_rpipe_target: set rpipe descr failed, " 1181 "rval = %d", rval); 1182 1183 return (rval); 1184 } 1185 1186 /* check rpipe status, must be configured and idle */ 1187 if ((rval = wusb_wa_get_rpipe_status(dip, ph, 1188 hdl->rp_descr.wRPipeIndex, &rp_status)) != USB_SUCCESS) { 1189 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 1190 "wusb_wa_set_rpipe_target: get rpipe status failed, " 1191 "rval = %d", rval); 1192 1193 return (rval); 1194 } 1195 1196 if (rp_status != (WA_RPIPE_CONFIGURED | WA_RPIPE_IDLE)) { 1197 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 1198 "wusb_wa_set_rpipe_target: set rpipe descr unsuccessful"); 1199 1200 return (USB_FAILURE); 1201 } 1202 1203 return (rval); 1204 } 1205 1206 /* 1207 * Abort a RPipe 1208 * - See Section 8.3.1.1 1209 * - Aborts all transfers pending on the given pipe 1210 */ 1211 int 1212 wusb_wa_rpipe_abort(dev_info_t *dip, usb_pipe_handle_t ph, 1213 wusb_wa_rpipe_hdl_t *hdl) 1214 { 1215 usb_cr_t completion_reason; 1216 usb_cb_flags_t cb_flags; 1217 int rval; 1218 1219 mutex_enter(&hdl->rp_mutex); 1220 1221 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 1222 "wusb_wa_rpipe_abort: rp_hdl = 0x%p", (void *)hdl); 1223 1224 /* only abort when there is active transfer */ 1225 if (hdl->rp_state != WA_RPIPE_STATE_ACTIVE) { 1226 mutex_exit(&hdl->rp_mutex); 1227 1228 return (USB_SUCCESS); 1229 } 1230 1231 mutex_exit(&hdl->rp_mutex); 1232 rval = usb_pipe_sync_ctrl_xfer(dip, ph, 1233 WA_CLASS_RPIPE_REQ_OUT_TYPE, 1234 WA_REQ_ABORT_RPIPE, 1235 0, 1236 hdl->rp_descr.wRPipeIndex, 1237 0, 1238 NULL, 0, 1239 &completion_reason, &cb_flags, 0); 1240 1241 if (rval != USB_SUCCESS) { 1242 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 1243 "wusb_wa_rpipe_abort: abort failed, rval = %d", rval); 1244 1245 return (rval); 1246 } 1247 1248 return (USB_SUCCESS); 1249 } 1250 1251 /* 1252 * Clear status on the remote device's endpoint, specifically clear the 1253 * RPipe's target endpoint sequence number. See 4.5.3, 4.6.4 and Tab.8-49 1254 * for reference of data sequence. 1255 * 1256 * NOTE AGAIN: 1257 * The device endpoint will not respond to host request if the RPipe is 1258 * reset or re-targeted, while device endpoint is not reset! 1259 */ 1260 void 1261 wusb_wa_clear_dev_ep(usba_pipe_handle_data_t *ph) 1262 { 1263 uint8_t ept_addr; 1264 1265 if (ph == NULL) { 1266 return; 1267 } 1268 1269 ept_addr = ph->p_ep.bEndpointAddress; 1270 1271 USB_DPRINTF_L4(PRINT_MASK_HCDI, whcdi_log_handle, 1272 "wusb_wa_clear_dev_ep:clear endpoint = 0x%02x", ept_addr); 1273 if (ept_addr != 0) { 1274 /* only clear non-default endpoints */ 1275 (void) usb_clr_feature(ph->p_dip, USB_DEV_REQ_RCPT_EP, 0, 1276 ept_addr, USB_FLAGS_SLEEP, NULL, NULL); 1277 } 1278 } 1279 1280 /* 1281 * Reset a RPipe 1282 * - Reset a RPipe to a known state 1283 * - Pending transfers must be drained or aborted before this 1284 * operation. 1285 * - See Section 8.3.1.10 1286 * 1287 * dip - the WA's devinfo 1288 * ph - RPipe's targeted remote device's endpoint pipe. 1289 * hdl - RPipe's handle 1290 * 1291 * flag = 1, reset the RPipe descriptor to its initial state and 1292 * also clear remote device endpoint 1293 * = 0, not reset the RPipe descriptor. Caller should use 0 flag 1294 * if it's the first time to open a pipe, because we don't have 1295 * a valid ph yet before successfully opening a pipe by using 1296 * usb_pipe_open(). 1297 */ 1298 int 1299 wusb_wa_rpipe_reset(dev_info_t *dip, usba_pipe_handle_data_t *ph, 1300 wusb_wa_rpipe_hdl_t *hdl, int flag) 1301 { 1302 int rval = 0; 1303 usb_cr_t completion_reason; 1304 usb_cb_flags_t cb_flags = 0; 1305 usb_pipe_handle_t default_ph; 1306 1307 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 1308 "wusb_wa_rpipe_reset: rp_hdl = 0x%p, ep=0x%02x, flag = %d", 1309 (void *)hdl, ph->p_ep.bEndpointAddress, flag); 1310 1311 /* get WA's default pipe */ 1312 default_ph = usba_get_dflt_pipe_handle(dip); 1313 1314 rval = usb_pipe_sync_ctrl_xfer(dip, default_ph, 1315 WA_CLASS_RPIPE_REQ_OUT_TYPE, 1316 WA_REQ_RESET_RPIPE, 1317 0, 1318 hdl->rp_descr.wRPipeIndex, 1319 0, 1320 NULL, 0, 1321 &completion_reason, &cb_flags, 0); 1322 1323 if (rval != USB_SUCCESS) { 1324 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 1325 "wusb_wa_rpipe_reset: reset failed, rval=%d" 1326 " cr=%d cb=0x%02x", 1327 rval, (int)completion_reason, (int)cb_flags); 1328 1329 return (rval); 1330 } 1331 1332 if (flag == 0) { 1333 /* do nothing else, just return, the rpipe is unconfigured */ 1334 return (USB_SUCCESS); 1335 } 1336 1337 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 1338 "wusb_wa_rpipe_reset: need to clear dev pipe and reset RP descr"); 1339 1340 /* set rpipe descr and make the rpipe configured */ 1341 rval = wusb_wa_set_rpipe_descr(dip, default_ph, &hdl->rp_descr); 1342 if (rval != USB_SUCCESS) { 1343 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 1344 "wusb_wa_rpipe_reset: set descr failed, rval = %d", rval); 1345 1346 return (rval); 1347 } 1348 1349 mutex_enter(&hdl->rp_mutex); 1350 hdl->rp_avail_reqs = hdl->rp_descr.wRequests; 1351 if (hdl->rp_state == WA_RPIPE_STATE_ERROR) { 1352 hdl->rp_state = WA_RPIPE_STATE_IDLE; 1353 } 1354 mutex_exit(&hdl->rp_mutex); 1355 1356 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 1357 "wusb_wa_rpipe_reset: end"); 1358 1359 return (USB_SUCCESS); 1360 } 1361 1362 /* get rpipe status, refer to WUSB 1.0/8.3.1.5 */ 1363 int 1364 wusb_wa_get_rpipe_status(dev_info_t *dip, usb_pipe_handle_t ph, uint16_t idx, 1365 uint8_t *status) 1366 { 1367 mblk_t *data = NULL; 1368 usb_cr_t completion_reason; 1369 usb_cb_flags_t cb_flags; 1370 int rval; 1371 1372 rval = usb_pipe_sync_ctrl_xfer(dip, ph, 1373 WA_CLASS_RPIPE_REQ_IN_TYPE, 1374 USB_REQ_GET_STATUS, 1375 0, 1376 idx, 1377 1, 1378 &data, 0, 1379 &completion_reason, &cb_flags, 0); 1380 1381 if (rval != USB_SUCCESS) { 1382 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 1383 "wusb_wa_get_rpipe_status: fail, rval=%d, cr=%d, " 1384 "cb=0x%x", rval, completion_reason, cb_flags); 1385 } else { 1386 *status = *data->b_rptr; 1387 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 1388 "wusb_wa_get_rpipe_status: status = %x", *status); 1389 freemsg(data); 1390 } 1391 1392 return (rval); 1393 } 1394 1395 /* 1396 * WA specific operations end 1397 */ 1398 1399 /* Transfer related routines */ 1400 wusb_wa_trans_wrapper_t * 1401 wusb_wa_alloc_tw(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl, 1402 usba_pipe_handle_data_t *ph, uint32_t datalen, usb_flags_t usb_flags) 1403 { 1404 uint_t seg_count; 1405 uint32_t seg_len, maxpktsize; 1406 wusb_wa_trans_wrapper_t *wr; 1407 1408 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 1409 "wusb_wa_alloc_tw: ph = 0x%p rp_hdl = 0x%p ", 1410 (void*)ph, (void*)hdl); 1411 1412 mutex_enter(&hdl->rp_mutex); 1413 1414 /* compute the rpipe buffer size */ 1415 seg_len = hdl->rp_descr.wBlocks * 1416 (1 << (wa_data->wa_descr.bRPipeBlockSize - 1)); 1417 maxpktsize = hdl->rp_descr.wMaxPacketSize; 1418 mutex_exit(&hdl->rp_mutex); 1419 1420 if (seg_len < maxpktsize) { 1421 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 1422 "wusb_wa_alloc_tw: fail, segment len(%d) " 1423 "< wMaxPacketSize(%d) ", seg_len, maxpktsize); 1424 1425 return (NULL); 1426 } 1427 1428 /* 1429 * the transfer length for each segment is a multiple of the 1430 * wMaxPacketSize except the last segment, and the length 1431 * cannot exceed the rpipe buffer size 1432 */ 1433 seg_len = (seg_len / maxpktsize) * maxpktsize; 1434 if (datalen) { 1435 seg_count = (datalen + seg_len - 1) / seg_len; 1436 } else { 1437 seg_count = 1; 1438 } 1439 1440 if (seg_count > WA_MAX_SEG_COUNT) { 1441 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 1442 "wusb_wa_alloc_tw: fail, seg count(%d)" 1443 " > Max allowed number(%d) ", seg_count, WA_MAX_SEG_COUNT); 1444 1445 return (NULL); 1446 } 1447 1448 if ((wr = kmem_zalloc(sizeof (wusb_wa_trans_wrapper_t), 1449 KM_NOSLEEP)) == NULL) { 1450 1451 return (NULL); 1452 } 1453 1454 /* allocation, not visible to other threads */ 1455 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*wr)); 1456 1457 if ((wr->wr_seg_array = kmem_zalloc(sizeof (wusb_wa_seg_t) * seg_count, 1458 KM_NOSLEEP)) == NULL) { 1459 kmem_free(wr, sizeof (wusb_wa_trans_wrapper_t)); 1460 1461 return (NULL); 1462 } 1463 1464 /* assign a unique ID for each transfer */ 1465 wr->wr_id = WA_GET_ID(wr); 1466 if (wr->wr_id == 0) { 1467 kmem_free(wr->wr_seg_array, sizeof (wusb_wa_seg_t) * 1468 seg_count); 1469 kmem_free(wr, sizeof (wusb_wa_trans_wrapper_t)); 1470 1471 return (NULL); 1472 } 1473 1474 wr->wr_ph = ph; 1475 wr->wr_rp = hdl; 1476 wr->wr_wa_data = wa_data; 1477 wr->wr_flags = usb_flags; 1478 wr->wr_nsegs = (uint8_t)seg_count; 1479 wr->wr_max_seglen = seg_len; 1480 wr->wr_has_aborted = 0; 1481 1482 cv_init(&wr->wr_cv, NULL, CV_DRIVER, NULL); 1483 1484 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 1485 "wusb_wa_alloc_tw: wr = 0x%p id = %x nseg = %d", (void*)wr, 1486 wr->wr_id, wr->wr_nsegs); 1487 1488 return (wr); 1489 } 1490 1491 /* create transfer wrapper for a ctrl request, return NULL on failure */ 1492 wusb_wa_trans_wrapper_t * 1493 wusb_wa_create_ctrl_wrapper(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl, 1494 usba_pipe_handle_data_t *ph, usb_ctrl_req_t *ctrl_reqp, 1495 usb_flags_t usb_flags) 1496 { 1497 wusb_wa_trans_wrapper_t *wr = NULL; 1498 1499 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 1500 "wusb_wa_create_ctrl_wrapper: ph = 0x%p rp_hdl = 0x%p reqp = 0x%p", 1501 (void *)ph, (void*)hdl, (void *)ctrl_reqp); 1502 1503 wr = wusb_wa_alloc_tw(wa_data, hdl, ph, ctrl_reqp->ctrl_wLength, 1504 usb_flags); 1505 if (wr == NULL) { 1506 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 1507 "wusb_wa_create_ctrl_wrapper: fail to create tw for %p", 1508 (void *)ctrl_reqp); 1509 1510 return (NULL); 1511 } 1512 1513 /* not visible to other threads yet */ 1514 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*wr)); 1515 1516 if (ctrl_reqp->ctrl_bmRequestType & USB_DEV_REQ_DEV_TO_HOST) { 1517 wr->wr_dir = WA_DIR_IN; 1518 } else { 1519 wr->wr_dir = WA_DIR_OUT; 1520 } 1521 1522 wr->wr_type = WA_XFER_REQ_TYPE_CTRL; 1523 wr->wr_reqp = (usb_opaque_t)ctrl_reqp; 1524 wr->wr_timeout = (ctrl_reqp->ctrl_timeout == 0) ? 1525 WA_RPIPE_DEFAULT_TIMEOUT : ctrl_reqp->ctrl_timeout; 1526 wr->wr_cb = wusb_wa_handle_ctrl; 1527 1528 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 1529 "wusb_wa_create_ctrl_wrapper: wr = 0x%p nseg = %d", (void *)wr, 1530 wr->wr_nsegs); 1531 1532 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*wr)); 1533 1534 return (wr); 1535 } 1536 1537 /* 1538 * create transfer wrapper for a bulk request, return NULL on failure 1539 * - split the request into multiple segments 1540 * - every segment is N * wMaxPacketSize 1541 * - segment length <= bRPipeBlockSize * wBlocks 1542 */ 1543 wusb_wa_trans_wrapper_t * 1544 wusb_wa_create_bulk_wrapper(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl, 1545 usba_pipe_handle_data_t *ph, usb_bulk_req_t *bulk_reqp, 1546 usb_flags_t usb_flags) 1547 { 1548 wusb_wa_trans_wrapper_t *wr = NULL; 1549 usb_ep_descr_t *epdt = &ph->p_ep; 1550 1551 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 1552 "wusb_wa_create_bulk_wrapper: ph = 0x%p rp_hdl = 0x%p reqp = 0x%p", 1553 (void *)ph, (void *)hdl, (void *)bulk_reqp); 1554 1555 wr = wusb_wa_alloc_tw(wa_data, hdl, ph, bulk_reqp->bulk_len, 1556 usb_flags); 1557 if (wr == NULL) { 1558 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 1559 "wusb_wa_create_bulk_wrapper: fail to create tw for %p", 1560 (void *)bulk_reqp); 1561 1562 return (NULL); 1563 } 1564 1565 /* no locking needed */ 1566 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*wr)); 1567 1568 if ((epdt->bEndpointAddress & USB_EP_DIR_MASK) == USB_EP_DIR_IN) { 1569 wr->wr_dir = WA_DIR_IN; 1570 } else { 1571 wr->wr_dir = WA_DIR_OUT; 1572 } 1573 1574 wr->wr_type = WA_XFER_REQ_TYPE_BULK_INTR; 1575 wr->wr_reqp = (usb_opaque_t)bulk_reqp; 1576 wr->wr_timeout = (bulk_reqp->bulk_timeout == 0) ? 1577 WA_RPIPE_DEFAULT_TIMEOUT : bulk_reqp->bulk_timeout; 1578 wr->wr_cb = wusb_wa_handle_bulk; 1579 1580 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 1581 "wusb_wa_create_bulk_wrapper: wr = 0x%p nseg = %d", (void *)wr, 1582 wr->wr_nsegs); 1583 1584 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*wr)); 1585 1586 return (wr); 1587 } 1588 1589 /* 1590 * create transfer wrapper for a intr request, return NULL on failure 1591 * - split the request into multiple segments 1592 * - every segment is N * wMaxPacketSize 1593 * - segment length <= bRPipeBlockSize * wBlocks 1594 */ 1595 wusb_wa_trans_wrapper_t * 1596 wusb_wa_create_intr_wrapper(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl, 1597 usba_pipe_handle_data_t *ph, usb_intr_req_t *intr_reqp, 1598 usb_flags_t usb_flags) 1599 { 1600 wusb_wa_trans_wrapper_t *wr; 1601 usb_ep_descr_t *epdt = &ph->p_ep; 1602 uint32_t tw_len; 1603 usb_intr_req_t *curr_intr_reqp; 1604 1605 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 1606 "wusb_wa_create_intr_wrapper: ph = 0x%p rp_hdl = 0x%p reqp = 0x%p", 1607 (void *)ph, (void *)hdl, (void *)intr_reqp); 1608 1609 if ((ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK) == USB_EP_DIR_IN) { 1610 tw_len = (intr_reqp->intr_len) ? intr_reqp->intr_len : 1611 ph->p_ep.wMaxPacketSize; 1612 1613 /* duplicate client's intr request */ 1614 curr_intr_reqp = usba_hcdi_dup_intr_req(ph->p_dip, 1615 (usb_intr_req_t *)intr_reqp, tw_len, usb_flags); 1616 if (curr_intr_reqp == NULL) { 1617 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 1618 "wusb_wa_create_intr_wrapper: fail to create reqp"); 1619 1620 return (NULL); 1621 } 1622 1623 } else { /* OUT */ 1624 tw_len = intr_reqp->intr_len; 1625 curr_intr_reqp = intr_reqp; 1626 } 1627 1628 wr = wusb_wa_alloc_tw(wa_data, hdl, ph, tw_len, usb_flags); 1629 if (wr == NULL) { 1630 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 1631 "wusb_wa_create_bulk_wrapper: fail to create tw for %p", 1632 (void *)intr_reqp); 1633 1634 return (NULL); 1635 } 1636 1637 /* no locking needed */ 1638 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*wr)); 1639 1640 if ((epdt->bEndpointAddress & USB_EP_DIR_MASK) == USB_EP_DIR_IN) { 1641 wr->wr_dir = WA_DIR_IN; 1642 } else { 1643 wr->wr_dir = WA_DIR_OUT; 1644 } 1645 1646 wr->wr_type = WA_XFER_REQ_TYPE_BULK_INTR; 1647 1648 wr->wr_reqp = (usb_opaque_t)curr_intr_reqp; 1649 1650 wr->wr_timeout = (intr_reqp->intr_timeout == 0) ? 1651 WA_RPIPE_DEFAULT_TIMEOUT : intr_reqp->intr_timeout; 1652 wr->wr_cb = wusb_wa_handle_intr; 1653 1654 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 1655 "wusb_wa_create_intr_wrapper: wr = 0x%p nseg = %d", (void *)wr, 1656 wr->wr_nsegs); 1657 1658 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*wr)); 1659 1660 return (wr); 1661 } 1662 1663 /* 1664 * Setup the transfer request structure for a segment 1665 * len = transfer request structure length 1666 * - see section 8.3.3.1 and 8.3.3.2 1667 */ 1668 void 1669 wusb_wa_setup_trans_req(wusb_wa_trans_wrapper_t *wr, wusb_wa_seg_t *seg, 1670 uint8_t len) 1671 { 1672 mblk_t *data = seg->seg_trans_reqp->bulk_data; 1673 uint8_t *trans_req = data->b_wptr; 1674 1675 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 1676 "wusb_wa_setup_trans_req: wr = 0x%p len = %d segnum = 0x%x", 1677 (void*)wr, len, seg->seg_num); 1678 1679 bzero(trans_req, len); 1680 trans_req[0] = len; 1681 trans_req[1] = wr->wr_type; 1682 trans_req[2] = wr->wr_rp->rp_descr.wRPipeIndex; 1683 trans_req[3] = wr->wr_rp->rp_descr.wRPipeIndex >> 8; 1684 trans_req[4] = seg->seg_id; /* dwTransferID */ 1685 trans_req[5] = seg->seg_id >> 8; 1686 trans_req[6] = seg->seg_id >> 16; 1687 trans_req[7] = seg->seg_id >> 24; 1688 trans_req[8] = seg->seg_len; 1689 trans_req[9] = seg->seg_len >> 8; 1690 trans_req[10] = seg->seg_len >> 16; 1691 trans_req[11] = seg->seg_len >> 24; 1692 trans_req[12] = seg->seg_num; 1693 1694 /* 1695 * 8-byte setupdata only for the first segment of a ctrl 1696 * transfer request 1697 */ 1698 if (wr->wr_type == WA_XFER_REQ_TYPE_CTRL) { 1699 usb_ctrl_req_t *ctrl_req = (usb_ctrl_req_t *)wr->wr_reqp; 1700 1701 /* what is the unsecured flag for ? */ 1702 trans_req[13] = wr->wr_dir | WA_CTRL_SECRT_REGULAR; 1703 if ((seg->seg_num & 0x7f) == 0) { 1704 /* only send baSetupDate on the first segment */ 1705 trans_req[16] = ctrl_req->ctrl_bmRequestType; 1706 trans_req[17] = ctrl_req->ctrl_bRequest; 1707 trans_req[18] = ctrl_req->ctrl_wValue; 1708 trans_req[19] = ctrl_req->ctrl_wValue >> 8; 1709 trans_req[20] = ctrl_req->ctrl_wIndex; 1710 trans_req[21] = ctrl_req->ctrl_wIndex >> 8; 1711 trans_req[22] = ctrl_req->ctrl_wLength; 1712 trans_req[23] = ctrl_req->ctrl_wLength >> 8; 1713 1714 } 1715 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 1716 "wusb_wa_setup_trans_req: Ctrl segment = %02x", 1717 seg->seg_num); 1718 1719 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 1720 "wusb_wa_setup_trans_req: Ctrl Setup Data: " 1721 "%02x %02x %02x %02x %02x %02x %02x %02x", 1722 trans_req[16], trans_req[17], trans_req[18], 1723 trans_req[19], trans_req[20], trans_req[21], 1724 trans_req[22], trans_req[23]); 1725 } 1726 data->b_wptr += len; 1727 } 1728 1729 /* 1730 * WA bulk pipe callbacks 1731 * wusb_wa_trans_bulk_cb: transfer request stage normal callback 1732 * wusb_wa_trans_bulk_exc_cb: transfer request stage exceptional callback 1733 * 1734 * wusb_wa_data_bulk_cb: transfer data stage normal callback 1735 * wusb_wa_data_bulk_exc_cb: transfer data stage exceptional callback 1736 * 1737 * see WUSB1.0 8.3.3 for details 1738 */ 1739 void 1740 wusb_wa_trans_bulk_cb(usb_pipe_handle_t ph, struct usb_bulk_req *req) 1741 { 1742 wusb_wa_seg_t *seg = (wusb_wa_seg_t *)req->bulk_client_private; 1743 wusb_wa_trans_wrapper_t *wr = (wusb_wa_trans_wrapper_t *)seg->seg_wr; 1744 1745 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 1746 "wusb_wa_trans_bulk_cb: ph=%p req=0x%p cr=%d", (void*)ph, 1747 (void*)req, req->bulk_completion_reason); 1748 1749 mutex_enter(&wr->wr_rp->rp_mutex); 1750 1751 /* callback returned, this seg can be freed */ 1752 seg->seg_trans_req_state = 0; 1753 1754 cv_signal(&seg->seg_trans_cv); 1755 mutex_exit(&wr->wr_rp->rp_mutex); 1756 } 1757 1758 void 1759 wusb_wa_trans_bulk_exc_cb(usb_pipe_handle_t ph, struct usb_bulk_req *req) 1760 { 1761 wusb_wa_seg_t *seg = (wusb_wa_seg_t *)req->bulk_client_private; 1762 wusb_wa_trans_wrapper_t *wr = (wusb_wa_trans_wrapper_t *)seg->seg_wr; 1763 1764 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 1765 "wusb_wa_trans_bulk_exc_cb: ph=%p req=0x%p cr=%d", (void *)ph, 1766 (void *)req, req->bulk_completion_reason); 1767 1768 mutex_enter(&wr->wr_rp->rp_mutex); 1769 1770 /* callback returned, this seg can be freed */ 1771 seg->seg_trans_req_state = 0; 1772 1773 cv_signal(&seg->seg_trans_cv); 1774 mutex_exit(&wr->wr_rp->rp_mutex); 1775 } 1776 1777 void 1778 wusb_wa_data_bulk_cb(usb_pipe_handle_t ph, struct usb_bulk_req *req) 1779 { 1780 wusb_wa_seg_t *seg = (wusb_wa_seg_t *)req->bulk_client_private; 1781 wusb_wa_trans_wrapper_t *wr = (wusb_wa_trans_wrapper_t *)seg->seg_wr; 1782 1783 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 1784 "wusb_wa_data_bulk_cb: ph=%p req=0x%p cr=%d", (void *)ph, 1785 (void *)req, req->bulk_completion_reason); 1786 1787 mutex_enter(&wr->wr_rp->rp_mutex); 1788 1789 /* callback returned, this seg can be freed */ 1790 seg->seg_data_req_state = 0; 1791 1792 cv_signal(&seg->seg_data_cv); 1793 mutex_exit(&wr->wr_rp->rp_mutex); 1794 } 1795 1796 void 1797 wusb_wa_data_bulk_exc_cb(usb_pipe_handle_t ph, struct usb_bulk_req *req) 1798 { 1799 wusb_wa_seg_t *seg = (wusb_wa_seg_t *)req->bulk_client_private; 1800 wusb_wa_trans_wrapper_t *wr = (wusb_wa_trans_wrapper_t *)seg->seg_wr; 1801 1802 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 1803 "wusb_wa_data_bulk_exc_cb: ph=%p req=0x%p cr=%d", (void *)ph, 1804 (void *)req, req->bulk_completion_reason); 1805 1806 mutex_enter(&wr->wr_rp->rp_mutex); 1807 1808 /* callback returned, this seg can be freed */ 1809 seg->seg_data_req_state = 0; 1810 1811 cv_signal(&seg->seg_data_cv); 1812 mutex_exit(&wr->wr_rp->rp_mutex); 1813 } 1814 1815 /* 1816 * Setup all the transfer request segments, including the transfer request 1817 * stage and data stage for out transfer. 1818 * len = total size of payload data to transfer 1819 * - for every segment, allocate a new bulk request for Transfer 1820 * Request. Fill the request with the segment and wrapper data. 1821 * - for every segment, allocate a new bulk request for data stage. 1822 * 1823 */ 1824 int 1825 wusb_wa_setup_segs(wusb_wa_data_t *wa_data, wusb_wa_trans_wrapper_t *wr, 1826 uint32_t len, mblk_t *data) 1827 { 1828 int i, rval; 1829 wusb_wa_seg_t *seg; 1830 usb_bulk_req_t *trans_req, *data_req; 1831 uint8_t trans_req_len; 1832 uint8_t *p; 1833 wusb_wa_rpipe_hdl_t *hdl = NULL; 1834 1835 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 1836 "wusb_wa_setup_segs: wr = 0x%p len = %d data = 0x%p", (void *)wr, 1837 len, (void *)data); 1838 1839 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*wr)); 1840 1841 if (wr == NULL) { 1842 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 1843 "wusb_wa_setup_segs: invalid wr"); 1844 1845 return (USB_INVALID_ARGS); 1846 } 1847 1848 if ((len != 0) && (data != NULL)) { 1849 p = data->b_rptr; 1850 } 1851 1852 for (i = 0; i < wr->wr_nsegs; i++) { 1853 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*seg)); 1854 1855 seg = &wr->wr_seg_array[i]; 1856 cv_init(&seg->seg_trans_cv, NULL, CV_DRIVER, NULL); 1857 cv_init(&seg->seg_data_cv, NULL, CV_DRIVER, NULL); 1858 seg->seg_wr = wr; 1859 seg->seg_num = (uint8_t)i; /* 0-based */ 1860 seg->seg_len = wr->wr_max_seglen; 1861 if (i == (wr->wr_nsegs - 1)) { 1862 seg->seg_num |= 0x80; /* last segment */ 1863 seg->seg_len = len; 1864 } else { 1865 len -= seg->seg_len; 1866 } 1867 1868 /* 1869 * set seg_id, all segs are the same or unique ?? 1870 * now make all segs share the same id 1871 */ 1872 seg->seg_id = wr->wr_id; 1873 1874 /* alloc transfer request and set values */ 1875 switch (wr->wr_type) { 1876 case WA_XFER_REQ_TYPE_CTRL: 1877 trans_req_len = WA_CTRL_REQ_LEN; 1878 break; 1879 case WA_XFER_REQ_TYPE_BULK_INTR: 1880 trans_req_len = WA_BULK_INTR_REQ_LEN; 1881 1882 break; 1883 default: 1884 trans_req_len = 0; 1885 break; 1886 } 1887 1888 if (trans_req_len == 0) { 1889 rval = USB_NOT_SUPPORTED; 1890 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 1891 "wusb_wa_setup_segs: trans len error"); 1892 1893 goto error; 1894 } 1895 1896 /* alloc transfer request for the ith seg */ 1897 trans_req = usb_alloc_bulk_req(wa_data->wa_dip, 1898 trans_req_len, USB_FLAGS_NOSLEEP); 1899 if (trans_req == NULL) { 1900 rval = USB_NO_RESOURCES; 1901 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 1902 "wusb_wa_setup_segs: can't alloc_bulk_req"); 1903 1904 goto error; 1905 } 1906 1907 /* setup the ith transfer request */ 1908 trans_req->bulk_len = trans_req_len; 1909 trans_req->bulk_timeout = WA_RPIPE_DEFAULT_TIMEOUT; 1910 trans_req->bulk_attributes = USB_ATTRS_AUTOCLEARING; 1911 trans_req->bulk_cb = wusb_wa_trans_bulk_cb; 1912 trans_req->bulk_exc_cb = wusb_wa_trans_bulk_exc_cb; 1913 trans_req->bulk_client_private = (usb_opaque_t)seg; 1914 1915 seg->seg_trans_reqp = trans_req; 1916 wusb_wa_setup_trans_req(wr, seg, trans_req_len); 1917 1918 if (seg->seg_len != 0) { 1919 /* alloc request for data stage */ 1920 data_req = usb_alloc_bulk_req(wa_data->wa_dip, 1921 seg->seg_len, USB_FLAGS_NOSLEEP); 1922 if (data_req == NULL) { 1923 rval = USB_NO_RESOURCES; 1924 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, 1925 whcdi_log_handle, 1926 "wusb_wa_setup_segs: can't alloc_bulk_req" 1927 " for data"); 1928 1929 goto error; 1930 } 1931 1932 /* setup the ith data transfer */ 1933 data_req->bulk_len = seg->seg_len; 1934 data_req->bulk_timeout = WA_RPIPE_DEFAULT_TIMEOUT; 1935 data_req->bulk_attributes = USB_ATTRS_AUTOCLEARING; 1936 1937 data_req->bulk_cb = wusb_wa_data_bulk_cb; 1938 data_req->bulk_exc_cb = wusb_wa_data_bulk_exc_cb; 1939 data_req->bulk_client_private = (usb_opaque_t)seg; 1940 1941 seg->seg_data_reqp = data_req; 1942 1943 /* 1944 * Copy data from client driver to bulk request for 1945 * an OUT endpoint. 1946 */ 1947 if (wr->wr_dir == WA_DIR_OUT) { 1948 ASSERT(data != NULL); 1949 /* 1950 * cannot increase data->b_rptr, 1951 * or scsa2usb panic at bulk out 1952 */ 1953 ASSERT((intptr_t)((uintptr_t)data->b_wptr - 1954 (uintptr_t)p) >= seg->seg_len); 1955 bcopy(p, 1956 data_req->bulk_data->b_wptr, 1957 seg->seg_len); 1958 p += seg->seg_len; 1959 1960 data_req->bulk_data->b_wptr += seg->seg_len; 1961 } 1962 } 1963 1964 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*seg)); 1965 } 1966 1967 /* zero timeout means to wait infinitely */ 1968 /* 1969 * if this is the first time this WR to be transfered, 1970 * we'll add it to its rpipe handle's timeout queue 1971 */ 1972 if (wr->wr_timeout > 0) { 1973 hdl = wr->wr_rp; 1974 1975 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 1976 "wusb_wa_setup_segs: timeout=%d", wr->wr_timeout); 1977 1978 mutex_enter(&hdl->rp_mutex); 1979 1980 /* Add this new wrapper to the head of RPipe's timeout list */ 1981 if (hdl->rp_timeout_list) { 1982 wr->wr_timeout_next = hdl->rp_timeout_list; 1983 } 1984 1985 hdl->rp_timeout_list = wr; 1986 1987 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*wr)); 1988 1989 mutex_exit(&hdl->rp_mutex); 1990 } 1991 1992 return (USB_SUCCESS); 1993 1994 error: 1995 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 1996 "wusb_wa_setup_segs: fail, rval = %d", rval); 1997 1998 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*wr)); 1999 2000 mutex_enter(&hdl->rp_mutex); 2001 wusb_wa_free_segs(wr); 2002 mutex_exit(&hdl->rp_mutex); 2003 2004 return (rval); 2005 } 2006 2007 /* allocate transfer wrapper and setup all transfer segments */ 2008 wusb_wa_trans_wrapper_t * 2009 wusb_wa_alloc_ctrl_resources(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl, 2010 usba_pipe_handle_data_t *ph, usb_ctrl_req_t *ctrl_reqp, 2011 usb_flags_t usb_flags) 2012 { 2013 wusb_wa_trans_wrapper_t *wr; 2014 2015 wr = wusb_wa_create_ctrl_wrapper(wa_data, hdl, ph, ctrl_reqp, 2016 usb_flags); 2017 2018 if (wr == NULL) { 2019 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 2020 "wusb_wa_alloc_ctrl_resources failed"); 2021 2022 return (NULL); 2023 } 2024 2025 if (wusb_wa_setup_segs(wa_data, wr, ctrl_reqp->ctrl_wLength, 2026 ctrl_reqp->ctrl_data) != USB_SUCCESS) { 2027 wusb_wa_free_trans_wrapper(wr); 2028 2029 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 2030 "wusb_wa_alloc_ctrl_resources failed to setup segs"); 2031 2032 return (NULL); 2033 } 2034 2035 return (wr); 2036 } 2037 2038 /* allocate transfer wrapper and setup all transfer segments */ 2039 wusb_wa_trans_wrapper_t * 2040 wusb_wa_alloc_bulk_resources(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl, 2041 usba_pipe_handle_data_t *ph, usb_bulk_req_t *bulk_reqp, 2042 usb_flags_t usb_flags) 2043 { 2044 wusb_wa_trans_wrapper_t *wr; 2045 2046 wr = wusb_wa_create_bulk_wrapper(wa_data, hdl, ph, bulk_reqp, 2047 usb_flags); 2048 2049 if (wr == NULL) { 2050 2051 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 2052 "wusb_wa_alloc_bulk_resources: failed to create wr"); 2053 2054 return (NULL); 2055 } 2056 2057 if (wusb_wa_setup_segs(wa_data, wr, bulk_reqp->bulk_len, 2058 bulk_reqp->bulk_data) != USB_SUCCESS) { 2059 wusb_wa_free_trans_wrapper(wr); 2060 2061 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 2062 "wusb_wa_alloc_bulk_resources:failed to setup segs"); 2063 return (NULL); 2064 } 2065 2066 return (wr); 2067 } 2068 2069 /* 2070 * allocate transfer wrapper and setup all transfer segments 2071 * if it's an IN request, duplicate it. 2072 */ 2073 wusb_wa_trans_wrapper_t * 2074 wusb_wa_alloc_intr_resources(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl, 2075 usba_pipe_handle_data_t *ph, usb_intr_req_t *intr_reqp, 2076 usb_flags_t usb_flags) 2077 { 2078 wusb_wa_trans_wrapper_t *wr; 2079 2080 wr = wusb_wa_create_intr_wrapper(wa_data, hdl, ph, intr_reqp, 2081 usb_flags); 2082 2083 if (wr == NULL) { 2084 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 2085 "wusb_wa_alloc_intr_resources: failed to create wr"); 2086 2087 return (NULL); 2088 } 2089 2090 if (wusb_wa_setup_segs(wa_data, wr, intr_reqp->intr_len, 2091 intr_reqp->intr_data) != USB_SUCCESS) { 2092 wusb_wa_free_trans_wrapper(wr); 2093 2094 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 2095 "wusb_wa_alloc_intr_resources: failed to setup segs"); 2096 2097 return (NULL); 2098 } 2099 2100 return (wr); 2101 } 2102 2103 /* free the bulk request structures for all segments */ 2104 void 2105 wusb_wa_free_segs(wusb_wa_trans_wrapper_t *wr) 2106 { 2107 int i; 2108 wusb_wa_seg_t *seg; 2109 2110 ASSERT(mutex_owned(&wr->wr_rp->rp_mutex)); 2111 2112 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 2113 "wusb_wa_free_segs: wr = 0x%p, segs=%p", (void *)wr, 2114 (void *)wr->wr_seg_array); 2115 2116 if (wr->wr_seg_array == NULL) { 2117 return; 2118 } 2119 2120 2121 for (i = 0; i < wr->wr_nsegs; i++) { 2122 seg = &wr->wr_seg_array[i]; 2123 2124 if (seg->seg_trans_reqp != NULL) { 2125 while (seg->seg_trans_req_state == 1) { 2126 cv_wait(&seg->seg_trans_cv, 2127 &wr->wr_rp->rp_mutex); 2128 } 2129 /* free the bulk req for transfer request */ 2130 usb_free_bulk_req(seg->seg_trans_reqp); 2131 seg->seg_trans_reqp = NULL; 2132 } 2133 2134 if (seg->seg_data_reqp != NULL) { 2135 while (seg->seg_data_req_state == 1) { 2136 cv_wait(&seg->seg_data_cv, 2137 &wr->wr_rp->rp_mutex); 2138 } 2139 /* free the bulk req for data transfer */ 2140 usb_free_bulk_req(seg->seg_data_reqp); 2141 seg->seg_data_reqp = NULL; 2142 } 2143 2144 cv_destroy(&seg->seg_trans_cv); 2145 cv_destroy(&seg->seg_data_cv); 2146 } 2147 2148 kmem_free(wr->wr_seg_array, sizeof (wusb_wa_seg_t) * wr->wr_nsegs); 2149 2150 wr->wr_seg_array = NULL; 2151 wr->wr_nsegs = 0; 2152 } 2153 2154 /* free transfer wrapper */ 2155 void 2156 wusb_wa_free_trans_wrapper(wusb_wa_trans_wrapper_t *wr) 2157 { 2158 wusb_wa_rpipe_hdl_t *hdl = NULL; 2159 2160 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 2161 "wusb_wa_free_trans_wrapper: wr = 0x%p", (void *)wr); 2162 2163 if (wr == NULL) { 2164 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 2165 "wusb_wa_free_trans_wrapper: NULL wrapper"); 2166 return; 2167 } 2168 2169 hdl = wr->wr_rp; 2170 2171 mutex_enter(&hdl->rp_mutex); 2172 2173 wusb_wa_remove_wr_from_timeout_list(hdl, wr); 2174 2175 if (wr->wr_seg_array != NULL) { 2176 wusb_wa_free_segs(wr); 2177 kmem_free(wr->wr_seg_array, 2178 sizeof (wusb_wa_seg_t) * wr->wr_nsegs); 2179 } 2180 2181 if (wr->wr_id != 0) { 2182 WA_FREE_ID(wr->wr_id); 2183 } 2184 2185 cv_destroy(&wr->wr_cv); 2186 2187 kmem_free(wr, sizeof (wusb_wa_trans_wrapper_t)); 2188 2189 mutex_exit(&hdl->rp_mutex); 2190 } 2191 2192 /* abort a transfer, refer to WUSB 1.0/8.3.3.5 */ 2193 void 2194 wusb_wa_abort_req(wusb_wa_data_t *wa_data, wusb_wa_trans_wrapper_t *wr, 2195 uint32_t id) 2196 { 2197 usb_bulk_req_t *req; 2198 uint8_t *p; 2199 int rval; 2200 2201 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 2202 "wusb_wa_abort_req: wr = 0x%p", (void *)wr); 2203 2204 req = usb_alloc_bulk_req(wa_data->wa_dip, WA_ABORT_REQ_LEN, 2205 USB_FLAGS_NOSLEEP); 2206 if (req == NULL) { 2207 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 2208 "wusb_wa_abort_req: alloc bulk req failed"); 2209 2210 return; 2211 } 2212 2213 req->bulk_len = WA_ABORT_REQ_LEN; 2214 req->bulk_timeout = WA_RPIPE_DEFAULT_TIMEOUT; 2215 req->bulk_attributes = USB_ATTRS_AUTOCLEARING; 2216 p = req->bulk_data->b_wptr; 2217 p[0] = WA_ABORT_REQ_LEN; 2218 p[1] = WA_XFER_REQ_TYPE_ABORT; 2219 p[2] = wr->wr_rp->rp_descr.wRPipeIndex; 2220 p[3] = wr->wr_rp->rp_descr.wRPipeIndex >> 8; 2221 p[4] = (uint8_t)id; 2222 p[5] = (uint8_t)(id >> 8); 2223 p[6] = (uint8_t)(id >> 16); 2224 p[7] = (uint8_t)(id >> 24); 2225 req->bulk_data->b_wptr += WA_ABORT_REQ_LEN; 2226 2227 mutex_exit(&wr->wr_rp->rp_mutex); 2228 rval = usb_pipe_bulk_xfer(wa_data->wa_bulkout_ph, req, 2229 USB_FLAGS_SLEEP); 2230 mutex_enter(&wr->wr_rp->rp_mutex); 2231 if (rval != USB_SUCCESS) { 2232 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 2233 "wusb_wa_abort_req: send abort req failed, rval = %d", 2234 rval); 2235 } 2236 usb_free_bulk_req(req); 2237 } 2238 2239 static void 2240 wusb_wa_remove_wr_from_timeout_list(wusb_wa_rpipe_hdl_t *hdl, 2241 wusb_wa_trans_wrapper_t *tw) 2242 { 2243 wusb_wa_trans_wrapper_t *prev, *next; 2244 int ret = 0; /* debug only */ 2245 2246 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 2247 "remove_wr_from_timeout_list: %p", (void *)tw); 2248 2249 if (hdl->rp_timeout_list) { 2250 if (hdl->rp_timeout_list == tw) { 2251 hdl->rp_timeout_list = tw->wr_timeout_next; 2252 tw->wr_timeout_next = NULL; 2253 ret = 1; 2254 } else { 2255 prev = hdl->rp_timeout_list; 2256 next = prev->wr_timeout_next; 2257 2258 while (next && (next != tw)) { 2259 prev = next; 2260 next = next->wr_timeout_next; 2261 } 2262 2263 if (next == tw) { 2264 prev->wr_timeout_next = next->wr_timeout_next; 2265 tw->wr_timeout_next = NULL; 2266 ret = 1; 2267 } 2268 } 2269 } 2270 2271 /* debug only */ 2272 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 2273 "remove_wr_from_timeout_list: %p, on the list:%d", 2274 (void *)tw, ret); 2275 } 2276 2277 /* start timer on a rpipe */ 2278 void 2279 wusb_wa_start_xfer_timer(wusb_wa_rpipe_hdl_t *hdl) 2280 { 2281 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 2282 "wusb_wa_start_xfer_timer: rpipe hdl = 0x%p", (void *)hdl); 2283 2284 ASSERT(mutex_owned(&hdl->rp_mutex)); 2285 2286 /* 2287 * wr_timeout is in Seconds 2288 */ 2289 /* 2290 * Start the rpipe's timer only if currently timer is not 2291 * running and if there are transfers on the rpipe. 2292 * The timer will be per rpipe. 2293 * 2294 * The RPipe's timer expires every 1s. When this timer expires, the 2295 * handler gets called and will decrease every pending transfer 2296 * wrapper's timeout value. 2297 */ 2298 if ((!hdl->rp_timer_id) && (hdl->rp_timeout_list)) { 2299 hdl->rp_timer_id = timeout(wusb_wa_xfer_timeout_handler, 2300 (void *)hdl, drv_usectohz(1000000)); 2301 } 2302 } 2303 2304 /* transfer timeout handler */ 2305 void 2306 wusb_wa_xfer_timeout_handler(void *arg) 2307 { 2308 wusb_wa_rpipe_hdl_t *hdl = (wusb_wa_rpipe_hdl_t *)arg; 2309 wusb_wa_trans_wrapper_t *wr = NULL; 2310 wusb_wa_trans_wrapper_t *next = NULL; 2311 wusb_wa_data_t *wa_data = NULL; 2312 int rval; 2313 uint8_t rp_status; 2314 wusb_wa_trans_wrapper_t *expire_list = NULL; 2315 2316 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 2317 "wusb_wa_xfer_timeout_handler: rphdl = 0x%p ", (void *)hdl); 2318 2319 mutex_enter(&hdl->rp_mutex); 2320 2321 /* 2322 * Check whether still timeout handler is valid. 2323 */ 2324 if (hdl->rp_timer_id != 0) { 2325 2326 /* Reset the timer id to zero */ 2327 hdl->rp_timer_id = 0; 2328 } else { 2329 mutex_exit(&hdl->rp_mutex); 2330 2331 return; 2332 } 2333 2334 /* 2335 * Check each transfer wrapper on this RPipe's timeout queue 2336 * Actually, due to USBA's limitation and queueing, there's only one 2337 * usba_request submitted to HCD at a specific pipe. Hence, only one 2338 * WR can be on this RPipe's list at any moment. 2339 */ 2340 wr = hdl->rp_timeout_list; 2341 while (wr) { 2342 next = wr->wr_timeout_next; 2343 2344 USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle, 2345 "wusb_wa_xfer_timeout_handler: rhdl=0x%p" 2346 " wr=0x%p(to=%d) nxt=0x%p", (void *)hdl, (void *)wr, 2347 wr->wr_timeout, (void *)next); 2348 2349 /* 2350 * 1 second passed. Decrease every transfer wrapper's 2351 * timeout value. If the timeout < 0 (expired), remove this 2352 * wrapper from the timeout list and put it on the 2353 * expire_list. 2354 */ 2355 wr->wr_timeout--; 2356 if (wr->wr_timeout <= 0) { 2357 USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle, 2358 "wusb_wa_xfer_timeout_handler: 0x%p time out", 2359 (void *)wr); 2360 2361 /* remove it from the rpipe's timeout list */ 2362 wusb_wa_remove_wr_from_timeout_list(hdl, wr); 2363 2364 /* put it on the expired list */ 2365 wr->wr_timeout_next = expire_list; 2366 expire_list = wr; 2367 2368 } 2369 2370 wr = next; 2371 } 2372 2373 /* Restart this RPipe's timer */ 2374 wusb_wa_start_xfer_timer(hdl); 2375 2376 /* timeout handling */ 2377 wr = expire_list; 2378 while (wr) { 2379 next = wr->wr_timeout_next; 2380 2381 /* other thread shouldn't continue processing it */ 2382 wr->wr_state = WR_TIMEOUT; 2383 2384 wa_data = wr->wr_wa_data; 2385 2386 mutex_exit(&hdl->rp_mutex); 2387 rval = wusb_wa_get_rpipe_status(wa_data->wa_dip, 2388 wa_data->wa_default_pipe, hdl->rp_descr.wRPipeIndex, 2389 &rp_status); 2390 mutex_enter(&hdl->rp_mutex); 2391 2392 if (rval != USB_SUCCESS) { 2393 /* reset WA perhaps? */ 2394 hdl->rp_state = WA_RPIPE_STATE_ERROR; 2395 hdl->rp_curr_wr = NULL; 2396 mutex_exit(&hdl->rp_mutex); 2397 wr->wr_cb(wa_data, wr, USB_CR_TIMEOUT, 1); 2398 mutex_enter(&hdl->rp_mutex); 2399 2400 USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle, 2401 "wusb_wa_xfer_timeout_handler: fail to get" 2402 " rpipe status, rval = %d", rval); 2403 2404 goto continuing; 2405 } 2406 USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle, 2407 "wusb_wa_xfer_timeout_handler: rpstat=0x%02x, wr=0x%p," 2408 " wr_state=%d", rp_status, (void *)wr, wr->wr_state); 2409 2410 if (!(rp_status & WA_RPIPE_IDLE)) { 2411 /* 2412 * If RP is not idle, then it must be processing this WR. 2413 * Abort this request to make the RPipe idle. 2414 */ 2415 USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle, 2416 "wusb_wa_xfer_timeout_handler: rp not idle"); 2417 2418 mutex_exit(&hdl->rp_mutex); 2419 rval = wusb_wa_rpipe_abort(wa_data->wa_dip, 2420 wa_data->wa_default_pipe, hdl); 2421 mutex_enter(&hdl->rp_mutex); 2422 2423 USB_DPRINTF_L3(DPRINT_MASK_WHCDI, 2424 whcdi_log_handle, 2425 "wusb_wa_xfer_timeout_handler: abort rpipe" 2426 " fail rval = %d", rval); 2427 2428 if (rval == 0) { 2429 /* 2430 * wait for the result thread to get 2431 * Aborted result. If this wr hasn't been 2432 * aborted, wait it. 2433 */ 2434 if ((wr->wr_has_aborted == 0) && 2435 (cv_reltimedwait(&wr->wr_cv, &hdl->rp_mutex, 2436 drv_usectohz(100 * 1000), TR_CLOCK_TICK) 2437 >= 0)) { 2438 /* 100ms, random number, long enough? */ 2439 2440 /* the result thread has processed it */ 2441 goto continuing; 2442 } 2443 2444 USB_DPRINTF_L3(DPRINT_MASK_WHCDI, 2445 whcdi_log_handle, 2446 "wusb_wa_xfer_timeout_handler: result" 2447 " thread can't get the aborted request"); 2448 } 2449 } 2450 2451 /* 2452 * 1)The Rpipe is idle, OR, 2453 * 2)rpipe_abort fails, OR, 2454 * 3)The result thread hasn't got an aborted result in 100ms, 2455 * most likely the result is lost. We can not depend on WA to 2456 * return result for this aborted request. The WA seems not 2457 * always returning such result. This will cause some hcdi 2458 * ops hang. 2459 */ 2460 hdl->rp_state = WA_RPIPE_STATE_IDLE; 2461 hdl->rp_curr_wr = NULL; 2462 2463 /* release this WR's occupied req */ 2464 hdl->rp_avail_reqs += (wr->wr_curr_seg - wr->wr_seg_done); 2465 cv_signal(&hdl->rp_cv); 2466 2467 mutex_exit(&hdl->rp_mutex); 2468 2469 wr->wr_cb(wa_data, wr, USB_CR_TIMEOUT, 0); 2470 mutex_enter(&hdl->rp_mutex); 2471 2472 continuing: 2473 wr = next; 2474 } 2475 2476 mutex_exit(&hdl->rp_mutex); 2477 } 2478 2479 /* stop timer */ 2480 void 2481 wusb_wa_stop_xfer_timer(wusb_wa_trans_wrapper_t *wr) 2482 { 2483 wusb_wa_rpipe_hdl_t *hdl = wr->wr_rp; 2484 timeout_id_t timer_id; 2485 2486 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 2487 "wusb_wa_stop_xfer_timer: wr = 0x%p", (void *)wr); 2488 2489 ASSERT(mutex_owned(&hdl->rp_mutex)); 2490 2491 if (hdl->rp_timer_id == 0) { 2492 2493 return; 2494 } 2495 2496 timer_id = hdl->rp_timer_id; 2497 hdl->rp_timer_id = 0; 2498 mutex_exit(&hdl->rp_mutex); 2499 2500 (void) untimeout(timer_id); 2501 2502 mutex_enter(&hdl->rp_mutex); 2503 } 2504 2505 2506 /* 2507 * send transfer request and data to the bulk out pipe 2508 * 2509 * General transfer function for WA transfer, see Section 8.3.3. 2510 */ 2511 /* ARGSUSED */ 2512 int 2513 wusb_wa_wr_xfer(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl, 2514 wusb_wa_trans_wrapper_t *wr, usb_flags_t usb_flags) 2515 { 2516 int i, rval; 2517 uint8_t curr_seg; 2518 usb_bulk_req_t *req; 2519 2520 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 2521 "wusb_wa_wr_xfer: wr = 0x%p", (void *)wr); 2522 2523 ASSERT(wr->wr_seg_array != NULL); 2524 2525 ASSERT(mutex_owned(&hdl->rp_mutex)); 2526 2527 if (hdl->rp_state == WA_RPIPE_STATE_IDLE) { 2528 hdl->rp_state = WA_RPIPE_STATE_ACTIVE; 2529 hdl->rp_curr_wr = wr; 2530 } 2531 curr_seg = wr->wr_curr_seg; 2532 2533 USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle, 2534 "wusb_wa_wr_xfer: curr_seg = %d, avail_req = %d", curr_seg, 2535 hdl->rp_avail_reqs); 2536 2537 /* 2538 * For every segment, 2539 * Step 1: contruct a bulk req containing Transfer 2540 * Request(T8-12 and T8-10) 2541 * Step 2: alloc another bulk req if there's any data 2542 * for OUT endpoints. 2543 * 2544 * For IN endpoints, the data is returned in the 2545 * GetResult thread. 2546 * Just throw as many as maximum available requests to the RPipe. 2547 * If the avail_req is zero, wait! 2548 * 2549 * When a request is finished, the avail_req will be increased 2550 * in the result thread. 2551 */ 2552 for (i = curr_seg; i < wr->wr_nsegs; i++) { 2553 USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle, 2554 "wusb_wa_wr_xfer: wr=%p curr_seg = %d, avail_req = %d," 2555 " dir=%s", (void *)wr, curr_seg, hdl->rp_avail_reqs, 2556 (wr->wr_dir == WA_DIR_IN)?"IN":"OUT"); 2557 2558 /* waiting for available requests if wr is still good */ 2559 while ((hdl->rp_avail_reqs == 0) && (wr->wr_state == 0)) { 2560 rval = cv_wait_sig(&hdl->rp_cv, &hdl->rp_mutex); 2561 } 2562 2563 if ((wr->wr_curr_seg - wr->wr_seg_done) >= 1) { 2564 /* send only one segment */ 2565 2566 break; 2567 } 2568 2569 if (wr->wr_state != 0) { 2570 /* wr transfer error, don't continue */ 2571 USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle, 2572 "wusb_wa_wr_xfer: wr_state!=0(%d)", wr->wr_state); 2573 2574 break; 2575 } 2576 2577 req = wr->wr_seg_array[i].seg_trans_reqp; 2578 ASSERT(req != NULL); 2579 2580 mutex_exit(&hdl->rp_mutex); 2581 /* send ith transfer request */ 2582 rval = usb_pipe_bulk_xfer(wa_data->wa_bulkout_ph, req, 0); 2583 mutex_enter(&hdl->rp_mutex); 2584 if (rval != USB_SUCCESS) { 2585 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 2586 "wusb_wa_wr_xfer: send transfer request %d failed," 2587 "rv=%d", i, rval); 2588 2589 wr->wr_seg_array[i].seg_trans_req_state = 0; /* clear */ 2590 2591 if (i == 0) { 2592 /* no xfer in processing */ 2593 hdl->rp_state = WA_RPIPE_STATE_IDLE; 2594 hdl->rp_curr_wr = NULL; 2595 2596 return (rval); 2597 } 2598 wusb_wa_abort_req(wa_data, wr, wr->wr_id); 2599 wr->wr_state = WR_SEG_REQ_ERR; /* sending tr error */ 2600 2601 break; 2602 } 2603 wr->wr_seg_array[i].seg_trans_req_state = 1; /* submitted */ 2604 2605 USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle, 2606 "wusb_wa_wr_xfer: seg(%d) request(0x%p) sent," 2607 " avail_req = %d", i, (void*)req, hdl->rp_avail_reqs); 2608 2609 hdl->rp_avail_reqs--; 2610 2611 /* Get data in the GetResult thread for IN eps */ 2612 if (wr->wr_dir == WA_DIR_IN) { 2613 wr->wr_curr_seg++; 2614 2615 /* only send data for out request */ 2616 continue; 2617 } 2618 2619 req = wr->wr_seg_array[i].seg_data_reqp; 2620 if (req == NULL) { 2621 /* no data stage */ 2622 wr->wr_curr_seg++; 2623 2624 continue; 2625 } 2626 2627 wr->wr_seg_array[i].seg_data_req_state = 1; /* submitted */ 2628 mutex_exit(&hdl->rp_mutex); 2629 /* send ith data asynchronously */ 2630 rval = usb_pipe_bulk_xfer(wa_data->wa_bulkout_ph, req, 0); 2631 mutex_enter(&hdl->rp_mutex); 2632 if (rval != USB_SUCCESS) { 2633 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 2634 "wusb_wa_wr_xfer: send transfer data %d failed", 2635 i); 2636 2637 wr->wr_seg_array[i].seg_data_req_state = 0; /* clear */ 2638 2639 wusb_wa_abort_req(wa_data, wr, wr->wr_id); 2640 wr->wr_state = WR_SEG_DAT_ERR; /* sending data error */ 2641 2642 /* not inc rp_avail_reqs until callback */ 2643 2644 break; 2645 } 2646 2647 USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle, 2648 "wusb_wa_wr_xfer: seg(%d) data(0x%p) sent, avail_req = %d", 2649 i, (void*)req, hdl->rp_avail_reqs); 2650 2651 wr->wr_curr_seg++; 2652 } 2653 2654 /* start timer */ 2655 wusb_wa_start_xfer_timer(hdl); 2656 /* 2657 * return success even if the xfer is not complete, the callback 2658 * will only continue sending segs when (wr_error_state = 0 && 2659 * wr_curr_seg < wr_nsegs) 2660 */ 2661 return (USB_SUCCESS); 2662 } 2663 2664 /* 2665 * submit wr according to rpipe status 2666 * - check RPipe state 2667 * - call general WA transfer function to do transfer 2668 * 2669 * usba only submits one transfer to the host controller per pipe at a time 2670 * and starts next when the previous one completed. So the hwahc now 2671 * assumes one transfer per rpipe at a time. This won't be necessary to 2672 * change unless the usba scheme is changed. 2673 */ 2674 int 2675 wusb_wa_submit_ctrl_wr(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl, 2676 wusb_wa_trans_wrapper_t *wr, usb_ctrl_req_t *ctrl_reqp, 2677 usb_flags_t usb_flags) 2678 { 2679 int rval; 2680 2681 mutex_enter(&hdl->rp_mutex); 2682 switch (hdl->rp_state) { 2683 case WA_RPIPE_STATE_IDLE: 2684 rval = wusb_wa_wr_xfer(wa_data, hdl, wr, usb_flags); 2685 break; 2686 case WA_RPIPE_STATE_ACTIVE: 2687 /* only allow one req at a time, this should not happen */ 2688 default: 2689 rval = USB_PIPE_ERROR; 2690 break; 2691 } 2692 mutex_exit(&hdl->rp_mutex); 2693 2694 if (rval != USB_SUCCESS) { 2695 if (ctrl_reqp->ctrl_completion_reason == USB_CR_OK) { 2696 ctrl_reqp->ctrl_completion_reason = usba_rval2cr(rval); 2697 } 2698 mutex_enter(&hdl->rp_mutex); 2699 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 2700 "wusb_wa_submit_ctrl_wr:fail, reqp=0x%p, rpstat=%d, rv=%d", 2701 (void*)ctrl_reqp, hdl->rp_state, rval); 2702 2703 mutex_exit(&hdl->rp_mutex); 2704 2705 wusb_wa_free_trans_wrapper(wr); 2706 } 2707 2708 /* In other cases, wr will be freed in callback */ 2709 return (rval); 2710 } 2711 2712 /* 2713 * Transfer a control request: 2714 * - allocate a transfer wrapper(TW) for this request 2715 * - submit this TW 2716 */ 2717 int 2718 wusb_wa_ctrl_xfer(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl, 2719 usba_pipe_handle_data_t *ph, usb_ctrl_req_t *ctrl_reqp, 2720 usb_flags_t usb_flags) 2721 { 2722 int rval; 2723 wusb_wa_trans_wrapper_t *wr; 2724 2725 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 2726 "wusb_wa_ctrl_xfer: ph = 0x%p reqp = 0x%p", 2727 (void*)ph, (void*)ctrl_reqp); 2728 2729 wr = wusb_wa_alloc_ctrl_resources(wa_data, hdl, ph, ctrl_reqp, 2730 usb_flags); 2731 if (wr == NULL) { 2732 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 2733 "wusb_wa_ctrl_req: alloc ctrl resource failed"); 2734 2735 return (USB_NO_RESOURCES); 2736 } 2737 2738 rval = wusb_wa_submit_ctrl_wr(wa_data, hdl, wr, ctrl_reqp, usb_flags); 2739 if (rval != USB_SUCCESS) { 2740 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 2741 "wusb_wa_submit_ctrl_wr: submit ctrl req failed, rval = %d", 2742 rval); 2743 } 2744 2745 return (rval); 2746 } 2747 2748 /* 2749 * submit wr according to rpipe status 2750 * 2751 * usba only submits one transfer to the host controller per pipe at a time 2752 * and starts next when the previous one completed. So the hwahc now 2753 * assumes one transfer per rpipe at a time. This won't be necessary to 2754 * change unless the usba scheme is changed. 2755 */ 2756 int 2757 wusb_wa_submit_bulk_wr(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl, 2758 wusb_wa_trans_wrapper_t *wr, usb_bulk_req_t *bulk_reqp, 2759 usb_flags_t usb_flags) 2760 { 2761 int rval; 2762 2763 mutex_enter(&hdl->rp_mutex); 2764 switch (hdl->rp_state) { 2765 case WA_RPIPE_STATE_IDLE: 2766 rval = wusb_wa_wr_xfer(wa_data, hdl, wr, usb_flags); 2767 break; 2768 case WA_RPIPE_STATE_ACTIVE: 2769 /* only allow one req at a time, this should not happen */ 2770 default: 2771 rval = USB_PIPE_ERROR; 2772 break; 2773 } 2774 mutex_exit(&hdl->rp_mutex); 2775 2776 if (rval != USB_SUCCESS) { 2777 if (bulk_reqp->bulk_completion_reason == USB_CR_OK) { 2778 bulk_reqp->bulk_completion_reason = usba_rval2cr(rval); 2779 } 2780 wusb_wa_free_trans_wrapper(wr); 2781 } 2782 2783 /* In other cases, wr will be freed in callback */ 2784 return (rval); 2785 } 2786 2787 /* 2788 * WA general bulk transfer 2789 * - allocate bulk resources 2790 * - submit the bulk request 2791 */ 2792 int 2793 wusb_wa_bulk_xfer(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl, 2794 usba_pipe_handle_data_t *ph, usb_bulk_req_t *bulk_reqp, 2795 usb_flags_t usb_flags) 2796 { 2797 int rval; 2798 wusb_wa_trans_wrapper_t *wr; 2799 2800 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 2801 "wusb_wa_bulk_xfer: ph = 0x%p reqp = 0x%p", 2802 (void *)ph, (void *)bulk_reqp); 2803 2804 wr = wusb_wa_alloc_bulk_resources(wa_data, hdl, ph, bulk_reqp, 2805 usb_flags); 2806 if (wr == NULL) { 2807 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 2808 "wusb_wa_bulk_xfer: alloc bulk resource failed"); 2809 2810 return (USB_NO_RESOURCES); 2811 } 2812 2813 rval = wusb_wa_submit_bulk_wr(wa_data, hdl, wr, bulk_reqp, 2814 usb_flags); 2815 if (rval != USB_SUCCESS) { 2816 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 2817 "wusb_wa_bulk_req: submit bulk req failed, rval = %d", 2818 rval); 2819 } 2820 2821 return (rval); 2822 } 2823 2824 /* 2825 * submit wr according to rpipe status 2826 * 2827 * usba only submits one transfer to the host controller per pipe at a time 2828 * and starts next when the previous one completed. So the hwahc now 2829 * assumes one transfer per rpipe at a time. This won't be necessary to 2830 * change unless the usba scheme is changed. 2831 */ 2832 int 2833 wusb_wa_submit_intr_wr(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl, 2834 wusb_wa_trans_wrapper_t *wr, usb_intr_req_t *intr_reqp, 2835 usb_flags_t usb_flags) 2836 { 2837 int rval; 2838 2839 mutex_enter(&hdl->rp_mutex); 2840 switch (hdl->rp_state) { 2841 case WA_RPIPE_STATE_IDLE: 2842 rval = wusb_wa_wr_xfer(wa_data, hdl, wr, usb_flags); 2843 break; 2844 case WA_RPIPE_STATE_ACTIVE: 2845 /* only allow one req at a time, this should not happen */ 2846 default: 2847 rval = USB_PIPE_ERROR; 2848 break; 2849 } 2850 mutex_exit(&hdl->rp_mutex); 2851 2852 if (rval != USB_SUCCESS) { 2853 if (intr_reqp->intr_completion_reason == USB_CR_OK) { 2854 intr_reqp->intr_completion_reason = usba_rval2cr(rval); 2855 } 2856 wusb_wa_free_trans_wrapper(wr); 2857 } 2858 2859 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 2860 "wusb_wa_submit_intr_wr: submit intr req, rval = %d", rval); 2861 2862 /* In other cases, wr will be freed in callback */ 2863 return (rval); 2864 } 2865 2866 /* 2867 * do intr xfer 2868 * 2869 * Now only one time intr transfer is supported. intr polling is not 2870 * supported. 2871 */ 2872 int 2873 wusb_wa_intr_xfer(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl, 2874 usba_pipe_handle_data_t *ph, usb_intr_req_t *intr_reqp, 2875 usb_flags_t usb_flags) 2876 { 2877 int rval; 2878 wusb_wa_trans_wrapper_t *wr; 2879 2880 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 2881 "wusb_wa_intr_xfer: ph = 0x%p reqp = 0x%p", 2882 (void *)ph, (void *)intr_reqp); 2883 2884 wr = wusb_wa_alloc_intr_resources(wa_data, hdl, ph, intr_reqp, 2885 usb_flags); 2886 if (wr == NULL) { 2887 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 2888 "wusb_wa_intr_req: alloc intr resource failed"); 2889 2890 return (USB_NO_RESOURCES); 2891 } 2892 2893 rval = wusb_wa_submit_intr_wr(wa_data, hdl, wr, intr_reqp, 2894 usb_flags); 2895 if (rval != USB_SUCCESS) { 2896 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 2897 "wusb_wa_intr_req: submit intr req failed, rval = %d", 2898 rval); 2899 2900 return (rval); 2901 } 2902 2903 /* 2904 * have successfully duplicate and queue one more request on 2905 * the pipe. Increase the pipe request count. 2906 */ 2907 if ((ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK) == USB_EP_DIR_IN) { 2908 mutex_enter(&ph->p_mutex); 2909 2910 /* 2911 * this count will be decremented by usba_req_normal_cb 2912 * or usba_req_exc_cb (called by hcdi_do_cb <-- usba_hcdi_cb) 2913 */ 2914 ph->p_req_count++; 2915 2916 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 2917 "wusb_wa_intr_req: p_req_cnt = %d", ph->p_req_count); 2918 2919 mutex_exit(&ph->p_mutex); 2920 } 2921 2922 return (rval); 2923 } 2924 2925 /* 2926 * For an IN transfer request, receive transfer data on bulk-in ept 2927 * The bulk_req has been allocated when allocating transfer resources 2928 */ 2929 int 2930 wusb_wa_get_data(wusb_wa_data_t *wa_data, wusb_wa_seg_t *seg, uint32_t len) 2931 { 2932 usb_bulk_req_t *req; 2933 int rval; 2934 2935 if (len == 0) { 2936 2937 return (USB_SUCCESS); 2938 } 2939 2940 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 2941 "wusb_wa_get_data: get data for wr: 0x%p", (void *)seg->seg_wr); 2942 2943 req = seg->seg_data_reqp; 2944 ASSERT(req != NULL); 2945 2946 /* adjust bulk in length to actual length */ 2947 req->bulk_len = len; 2948 rval = usb_pipe_bulk_xfer(wa_data->wa_bulkin_ph, req, 2949 USB_FLAGS_SLEEP); 2950 2951 return (rval); 2952 } 2953 2954 /* 2955 * to retrieve a transfer_wrapper by dwTransferID 2956 * 2957 * Though to search a list looks not so efficient, we have to give up 2958 * id32_lookup(). When a transfer segment is throwed to HWA device, we 2959 * can't anticipate when the result will be returned, even if we try to 2960 * abort it. If we have freed the transfer wrapper due to timeout, then 2961 * after a moment, that TW's segment is accomplished by hardware. If 2962 * id32_lookup() is used to look up corresponding TW, we'll get an invalid 2963 * address. Unfortunately, id32_lookup() can't judge validity of its 2964 * returned address. 2965 */ 2966 wusb_wa_trans_wrapper_t * 2967 wusb_wa_retrieve_wr(wusb_wa_data_t *wa_data, uint32_t id) 2968 { 2969 wusb_wa_rpipe_hdl_t *rph; 2970 uint16_t i; 2971 wusb_wa_trans_wrapper_t *tw; 2972 2973 for (i = 0; i < wa_data->wa_num_rpipes; i++) { 2974 rph = &wa_data->wa_rpipe_hdl[i]; 2975 2976 mutex_enter(&rph->rp_mutex); 2977 /* all outstanding TWs are put on the timeout list */ 2978 tw = rph->rp_timeout_list; 2979 2980 while (tw) { 2981 if (tw->wr_id == id) { 2982 mutex_exit(&rph->rp_mutex); 2983 return (tw); 2984 } 2985 tw = tw->wr_timeout_next; 2986 } 2987 mutex_exit(&rph->rp_mutex); 2988 } 2989 2990 return (NULL); 2991 } 2992 2993 /* endlessly wait for transfer result on bulk-in ept and handle the result */ 2994 int 2995 wusb_wa_get_xfer_result(wusb_wa_data_t *wa_data) 2996 { 2997 usb_bulk_req_t *req; 2998 int rval; 2999 mblk_t *data; 3000 uint8_t *p; 3001 wa_xfer_result_t result; 3002 wusb_wa_trans_wrapper_t *wr; 3003 wusb_wa_seg_t *seg; 3004 uint8_t status; 3005 uint_t len; 3006 uint8_t lastseg = 0; 3007 usb_cr_t cr; 3008 uint32_t act_len; 3009 wusb_wa_rpipe_hdl_t *hdl; 3010 3011 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 3012 "wusb_wa_get_xfer_result: started, wa=0x%p", (void*)wa_data); 3013 3014 /* grab lock before accessing wa_data */ 3015 mutex_enter(&wa_data->wa_mutex); 3016 3017 len = wa_data->wa_bulkin_ept.wMaxPacketSize; 3018 3019 req = usb_alloc_bulk_req(wa_data->wa_dip, len, 3020 USB_FLAGS_NOSLEEP); 3021 if (req == NULL) { 3022 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 3023 "wusb_wa_get_xfer_result: alloc bulk req failed"); 3024 3025 mutex_exit(&wa_data->wa_mutex); 3026 3027 return (USB_NO_RESOURCES); 3028 } 3029 3030 req->bulk_len = len; 3031 req->bulk_timeout = 0; 3032 req->bulk_attributes = USB_ATTRS_SHORT_XFER_OK | 3033 USB_ATTRS_AUTOCLEARING; 3034 3035 mutex_exit(&wa_data->wa_mutex); 3036 3037 /* Get the Transfer Result head, see Table 8-14 */ 3038 rval = usb_pipe_bulk_xfer(wa_data->wa_bulkin_ph, req, 3039 USB_FLAGS_SLEEP); 3040 if ((rval != USB_SUCCESS) || (req->bulk_data == NULL)) { 3041 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 3042 "wusb_wa_get_xfer_result: bulk xfer failed or " 3043 "null data returned, rval=%d, req->bulk_data = %p", 3044 rval, (void*)req->bulk_data); 3045 usb_free_bulk_req(req); 3046 3047 return (rval); 3048 } 3049 3050 data = req->bulk_data; 3051 p = data->b_rptr; 3052 3053 USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle, 3054 "wusb_wa_get_xfer_result: received data len = %d", 3055 (int)MBLKL(data)); 3056 3057 if ((MBLKL(data) != WA_XFER_RESULT_LEN) || 3058 (p[1] != WA_RESULT_TYPE_TRANSFER)) { 3059 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 3060 "wusb_wa_get_xfer_result: invalid xfer result, " 3061 "len = %d, p0 = 0x%x, p1 = 0x%x, p6 = 0x%x", 3062 (int)MBLKL(data), p[0], p[1], p[6]); 3063 3064 usb_free_bulk_req(req); 3065 3066 return (USB_SUCCESS); /* don't stop this thread */ 3067 } 3068 3069 /* Transfer result. Section 8.3.3.4 */ 3070 (void) usb_parse_data("ccllccl", p, WA_XFER_RESULT_LEN, &result, 3071 sizeof (wa_xfer_result_t)); 3072 3073 3074 USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle, 3075 "wusb_wa_get_xfer_result: id = 0x%x len = 0x%x nseg = 0x%02x" 3076 " status = 0x%02x(0x%02x)", result.dwTransferID, 3077 result.dwTransferLength, result.bTransferSegment, 3078 result.bTransferStatus, p[11]&0x0f); 3079 3080 req->bulk_data = NULL; /* don't free it. we still need it */ 3081 usb_free_bulk_req(req); 3082 3083 status = result.bTransferStatus; 3084 if ((status & 0x3f) == WA_STS_NOT_FOUND) { 3085 freemsg(data); 3086 /* 3087 * The result is just ignored since the transfer request 3088 * has completed 3089 */ 3090 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 3091 "wusb_wa_get_xfer_result: TransferID not found"); 3092 3093 return (USB_SUCCESS); 3094 } 3095 3096 mutex_enter(&wa_data->wa_mutex); 3097 wr = wusb_wa_retrieve_wr(wa_data, result.dwTransferID); 3098 if ((wr == NULL)) { 3099 /* this id's corresponding WR may have been freed by timeout handler */ 3100 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 3101 "wusb_wa_get_xfer_result: wr == deadbeef or NULL"); 3102 3103 mutex_exit(&wa_data->wa_mutex); 3104 freemsg(data); 3105 3106 return (USB_SUCCESS); 3107 } 3108 3109 /* bit 7 is last segment flag */ 3110 if ((result.bTransferSegment & 0x7f) >= wr->wr_nsegs) { 3111 USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle, 3112 "wusb_wa_get_xfer_result: error - " 3113 " bTransferSegment(%d) > segment coutnts(%d)", 3114 (result.bTransferSegment & 0x7f), wr->wr_nsegs); 3115 3116 goto err; 3117 } 3118 3119 lastseg = result.bTransferSegment & 0x80; 3120 hdl = wr->wr_rp; 3121 3122 mutex_enter(&hdl->rp_mutex); 3123 seg = &wr->wr_seg_array[result.bTransferSegment & 0x7f]; 3124 seg->seg_status = result.bTransferStatus; 3125 act_len = seg->seg_actual_len = result.dwTransferLength; 3126 3127 /* 3128 * if this is the last segment, we should not continue. 3129 * IMPT: we expect the WA deliver result sequentially. 3130 */ 3131 seg->seg_done = (result.bTransferSegment) & 0x80; 3132 3133 wr->wr_seg_done++; 3134 hdl->rp_avail_reqs++; 3135 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle, 3136 "wusb_wa_get_xfer_result: wr = %p, rp=%p, avail_req=%d", (void*)wr, 3137 (void*)wr->wr_rp, hdl->rp_avail_reqs); 3138 3139 cv_broadcast(&hdl->rp_cv); 3140 3141 if (status & 0x40) { 3142 status = 0; /* ignore warning, see Tab8-15 */ 3143 } 3144 seg->seg_status = status; 3145 3146 /* Error bit set */ 3147 if (status & 0x80) { 3148 /* don't change timeout error */ 3149 if (wr->wr_state != WR_TIMEOUT) { 3150 wr->wr_state = WR_XFER_ERR; 3151 } 3152 3153 /* 3154 * The timeout handler is waiting, but the result thread will 3155 * process this wr. 3156 */ 3157 if ((wr->wr_state == WR_TIMEOUT) && 3158 (status & 0x3F) == WA_STS_ABORTED) { 3159 wr->wr_has_aborted = 1; 3160 cv_signal(&wr->wr_cv); /* to inform timeout hdler */ 3161 } 3162 3163 mutex_exit(&hdl->rp_mutex); 3164 /* seg error, don't proceed with this WR */ 3165 goto err; 3166 } 3167 3168 USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle, 3169 "wusb_wa_get_xfer_result: status = 0x%02x dir=%s", 3170 status, (wr->wr_dir == WA_DIR_IN)?"IN":"OUT"); 3171 3172 /* 3173 * for an IN endpoint and data length > 0 and no error, read in 3174 * the real data. Otherwise, for OUT EP, or data length = 0, or 3175 * segment error, don't read. 3176 */ 3177 if ((wr->wr_dir == WA_DIR_IN) && 3178 (act_len > 0) && 3179 ((status & 0x3F) == 0)) { /* if segment error, don't read */ 3180 /* receive data */ 3181 mutex_exit(&hdl->rp_mutex); 3182 mutex_exit(&wa_data->wa_mutex); 3183 rval = wusb_wa_get_data(wa_data, seg, act_len); 3184 mutex_enter(&wa_data->wa_mutex); 3185 mutex_enter(&hdl->rp_mutex); 3186 if (rval != USB_SUCCESS) { 3187 USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle, 3188 "wusb_wa_get_xfer_result: can't get seg data:%d", 3189 rval); 3190 3191 mutex_exit(&hdl->rp_mutex); 3192 3193 goto err; 3194 } 3195 3196 USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle, 3197 "wusb_wa_get_xfer_result: get (%dB) data for IN ep", 3198 act_len); 3199 } 3200 3201 mutex_exit(&hdl->rp_mutex); 3202 3203 mutex_exit(&wa_data->wa_mutex); 3204 3205 /* check if the whole transfer has completed */ 3206 wusb_wa_check_req_done(wa_data, wr, lastseg); 3207 3208 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 3209 "wusb_wa_get_xfer_result: ended"); 3210 3211 freemsg(data); 3212 3213 return (USB_SUCCESS); 3214 3215 err: 3216 mutex_exit(&wa_data->wa_mutex); 3217 3218 mutex_enter(&hdl->rp_mutex); 3219 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 3220 "wusb_wa_get_xfer_result: segment(%02x) error, abort wr 0x%p," 3221 "wr_state=%d", result.bTransferSegment, (void*)wr, wr->wr_state); 3222 3223 /* if it's timeout, just return the TIMEOUT error */ 3224 if (wr->wr_state == WR_TIMEOUT) { 3225 cr = USB_CR_TIMEOUT; 3226 } else { 3227 cr = wusb_wa_sts2cr(status); 3228 } 3229 3230 mutex_exit(&hdl->rp_mutex); 3231 3232 wusb_wa_handle_error(wa_data, wr, cr); 3233 3234 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 3235 "wusb_wa_get_xfer_result: error end, cr=%d", 3236 cr); 3237 3238 freemsg(data); 3239 3240 return (USB_SUCCESS); 3241 } 3242 3243 3244 static void 3245 wusb_wa_handle_error(wusb_wa_data_t *wa_data, wusb_wa_trans_wrapper_t *wr, 3246 usb_cr_t cr) 3247 { 3248 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 3249 "wusb_wa_handle_error: start"); 3250 3251 mutex_enter(&wr->wr_rp->rp_mutex); 3252 if (wr->wr_seg_done != wr->wr_curr_seg) { 3253 /* still segments pending, abort them */ 3254 USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle, 3255 "wusb_wa_handle_error: segment err, abort other segs"); 3256 3257 wusb_wa_abort_req(wa_data, wr, wr->wr_id); 3258 } 3259 3260 wusb_wa_stop_xfer_timer(wr); 3261 wr->wr_rp->rp_state = WA_RPIPE_STATE_IDLE; 3262 wr->wr_rp->rp_curr_wr = NULL; 3263 mutex_exit(&wr->wr_rp->rp_mutex); 3264 3265 wr->wr_cb(wa_data, wr, cr, 1); 3266 3267 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 3268 "wusb_wa_handle_error: error end, cr=%d", 3269 cr); 3270 } 3271 3272 /* 3273 * Check if current request is done, if yes, do callback and move on to 3274 * next request; if there is any uncleared error, do callback to cleanup 3275 * the pipe 3276 */ 3277 void 3278 wusb_wa_check_req_done(wusb_wa_data_t *wa_data, 3279 wusb_wa_trans_wrapper_t *wr, uint8_t lastseg) 3280 { 3281 wusb_wa_rpipe_hdl_t *hdl = wr->wr_rp; 3282 wusb_wa_seg_t *seg; 3283 int i, rval; 3284 usb_cr_t cr; 3285 3286 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 3287 "wusb_wa_check_req_done: wr = 0x%p, lastseg=%02x", 3288 (void*)wr, lastseg); 3289 3290 mutex_enter(&hdl->rp_mutex); 3291 /* not done: submitted segs not finished and lastseg not set */ 3292 if ((wr->wr_seg_done != wr->wr_curr_seg) && (!lastseg)) { 3293 mutex_exit(&hdl->rp_mutex); 3294 3295 return; 3296 } 3297 3298 if (wr->wr_state != 0) { /* abort somewhere */ 3299 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 3300 "wusb_wa_check_req_done: tw(%p) aborted somewhere", 3301 (void*)wr); 3302 cr = USB_CR_UNSPECIFIED_ERR; 3303 3304 goto reset; 3305 } 3306 3307 /* check if there is any error */ 3308 for (i = 0; i < wr->wr_curr_seg; i++) { 3309 seg = &wr->wr_seg_array[i]; 3310 if (seg->seg_status != WA_STS_SUCCESS) { 3311 /* what about short xfer? need to fix */ 3312 cr = wusb_wa_sts2cr(seg->seg_status); 3313 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 3314 "wusb_wa_check_req_done: seg fail, status=%02x", 3315 seg->seg_status); 3316 3317 goto reset; 3318 } 3319 3320 if (seg->seg_done == 0x80) { 3321 /* device has told this is the last segment, we're done */ 3322 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 3323 "wusb_wa_check_req_done: last seg"); 3324 3325 goto done; 3326 } 3327 } 3328 3329 /* check if current request has completed */ 3330 /* 3331 * Transfer another segment. 3332 * 3333 */ 3334 if (wr->wr_curr_seg < wr->wr_nsegs) { 3335 /* send the remained segments */ 3336 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 3337 "wusb_wa_check_req_done: req not completed, restart"); 3338 3339 rval = wusb_wa_wr_xfer(wa_data, hdl, wr, wr->wr_flags); 3340 if (rval != USB_SUCCESS) { 3341 cr = usba_rval2cr(rval); 3342 3343 goto reset; 3344 } 3345 3346 mutex_exit(&hdl->rp_mutex); 3347 3348 return; 3349 } 3350 3351 done: 3352 wusb_wa_stop_xfer_timer(wr); 3353 3354 /* release the occupied requests */ 3355 hdl->rp_avail_reqs += (wr->wr_curr_seg - wr->wr_seg_done); 3356 cv_signal(&hdl->rp_cv); 3357 3358 hdl->rp_state = WA_RPIPE_STATE_IDLE; 3359 hdl->rp_curr_wr = NULL; 3360 wr->wr_state = WR_FINISHED; 3361 mutex_exit(&hdl->rp_mutex); 3362 3363 wr->wr_cb(wa_data, wr, USB_CR_OK, 0); 3364 3365 /* Need to move on to next request? usba will do this */ 3366 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 3367 "wusb_wa_check_req_done: ended"); 3368 3369 return; 3370 3371 reset: 3372 wusb_wa_stop_xfer_timer(wr); 3373 3374 /* not necessary to reset the RPipe */ 3375 hdl->rp_state = WA_RPIPE_STATE_IDLE; 3376 hdl->rp_curr_wr = NULL; 3377 3378 hdl->rp_avail_reqs += (wr->wr_curr_seg - wr->wr_seg_done); 3379 cv_signal(&hdl->rp_cv); 3380 3381 /* if it's timeout, just return the TIMEOUT error */ 3382 if (wr->wr_state == WR_TIMEOUT) 3383 cr = USB_CR_TIMEOUT; 3384 3385 mutex_exit(&hdl->rp_mutex); 3386 3387 wr->wr_cb(wa_data, wr, cr, 1); 3388 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 3389 "wusb_wa_check_req_done: reset end"); 3390 } 3391 3392 /* 3393 * callback for ctrl transfer 3394 * 3395 * reset_flag: not support yet 3396 */ 3397 void 3398 wusb_wa_handle_ctrl(wusb_wa_data_t *wa_data, wusb_wa_trans_wrapper_t *wr, 3399 usb_cr_t cr, uint_t reset_flag) 3400 { 3401 usb_ctrl_req_t *req; 3402 usb_bulk_req_t *bulk_req; 3403 mblk_t *data, *bulk_data; 3404 int i; 3405 size_t len; 3406 wusb_wa_seg_t *seg; 3407 3408 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 3409 "wusb_wa_handle_ctrl: wr = 0x%p, cr = 0x%x, flag=%d", 3410 (void*)wr, cr, reset_flag); 3411 3412 req = (usb_ctrl_req_t *)wr->wr_reqp; 3413 3414 if ((wr->wr_dir == WA_DIR_OUT) || (cr != USB_CR_OK)) { 3415 3416 /* do callback */ 3417 wusb_wa_callback(wa_data, wr->wr_ph, wr, cr); 3418 3419 return; 3420 } 3421 3422 mutex_enter(&wr->wr_rp->rp_mutex); 3423 data = req->ctrl_data; 3424 for (i = 0; i < wr->wr_nsegs; i++) { 3425 seg = &wr->wr_seg_array[i]; 3426 /* copy received data to original req buffer */ 3427 bulk_req = (usb_bulk_req_t *) 3428 wr->wr_seg_array[i].seg_data_reqp; 3429 bulk_data = bulk_req->bulk_data; 3430 len = MBLKL(bulk_data); 3431 bcopy(bulk_data->b_rptr, data->b_wptr, len); 3432 data->b_wptr += len; 3433 if (len < wr->wr_seg_array[i].seg_len) { 3434 /* short xfer */ 3435 break; 3436 } 3437 3438 if (seg->seg_done == 0x80) { 3439 /* last segment, finish */ 3440 break; 3441 } 3442 } 3443 3444 mutex_exit(&wr->wr_rp->rp_mutex); 3445 /* do callback */ 3446 wusb_wa_callback(wa_data, wr->wr_ph, wr, cr); 3447 } 3448 3449 /* 3450 * callback for bulk transfer 3451 * 3452 * reset_flag: not support yet 3453 */ 3454 void 3455 wusb_wa_handle_bulk(wusb_wa_data_t *wa_data, wusb_wa_trans_wrapper_t *wr, 3456 usb_cr_t cr, uint_t reset_flag) 3457 { 3458 usb_bulk_req_t *req; 3459 usb_bulk_req_t *bulk_req; 3460 mblk_t *data, *bulk_data; 3461 int i; 3462 size_t len; 3463 wusb_wa_seg_t *seg; 3464 3465 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 3466 "wusb_wa_handle_bulk: wr = 0x%p, cr = 0x%x, flag=%d", 3467 (void*)wr, cr, reset_flag); 3468 3469 req = (usb_bulk_req_t *)wr->wr_reqp; 3470 3471 if ((wr->wr_dir == WA_DIR_OUT) || (cr != USB_CR_OK)) { 3472 /* do callback */ 3473 wusb_wa_callback(wa_data, wr->wr_ph, wr, cr); 3474 3475 return; 3476 } 3477 3478 mutex_enter(&wr->wr_rp->rp_mutex); 3479 data = req->bulk_data; 3480 for (i = 0; i < wr->wr_nsegs; i++) { 3481 seg = &wr->wr_seg_array[i]; 3482 /* copy received data to original req buffer */ 3483 bulk_req = (usb_bulk_req_t *) 3484 wr->wr_seg_array[i].seg_data_reqp; 3485 bulk_data = bulk_req->bulk_data; 3486 len = MBLKL(bulk_data); 3487 bcopy(bulk_data->b_rptr, data->b_wptr, len); 3488 data->b_wptr += len; 3489 if (len < wr->wr_seg_array[i].seg_len) { 3490 /* short xfer */ 3491 break; 3492 } 3493 3494 if (seg->seg_done == 0x80) { 3495 /* last segment, finish */ 3496 break; 3497 } 3498 } 3499 3500 mutex_exit(&wr->wr_rp->rp_mutex); 3501 /* do callback */ 3502 wusb_wa_callback(wa_data, wr->wr_ph, wr, cr); 3503 } 3504 3505 int 3506 wa_submit_periodic_req(wusb_wa_data_t *wa_data, usba_pipe_handle_data_t *ph) 3507 { 3508 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 3509 "wa_submit_periodic_req: wa_data=0x%p, ph=0x%p", 3510 (void*)wa_data, (void*)ph); 3511 3512 return (wa_data->pipe_periodic_req(wa_data, ph)); 3513 } 3514 3515 /* 3516 * callback for intr transfer 3517 * 3518 * reset_flag: not support yet 3519 */ 3520 void 3521 wusb_wa_handle_intr(wusb_wa_data_t *wa_data, wusb_wa_trans_wrapper_t *wr, 3522 usb_cr_t cr, uint_t reset_flag) 3523 { 3524 usb_intr_req_t *req; 3525 usb_req_attrs_t attrs; 3526 usba_pipe_handle_data_t *ph = wr->wr_ph; 3527 usb_bulk_req_t *bulk_req; 3528 mblk_t *data, *bulk_data; 3529 int i; 3530 size_t len; 3531 int rval; 3532 wusb_wa_seg_t *seg; 3533 3534 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 3535 "wusb_wa_handle_intr: wr = 0x%p, cr = 0x%x, flag=%d", 3536 (void*)wr, cr, reset_flag); 3537 3538 req = (usb_intr_req_t *)wr->wr_reqp; 3539 attrs = req->intr_attributes; 3540 3541 if ((wr->wr_dir == WA_DIR_OUT) || (cr != USB_CR_OK)) { 3542 /* do callback */ 3543 wusb_wa_callback(wa_data, wr->wr_ph, wr, cr); 3544 3545 return; 3546 } 3547 3548 mutex_enter(&wr->wr_rp->rp_mutex); 3549 /* copy data to client's buffer */ 3550 data = req->intr_data; 3551 for (i = 0; i < wr->wr_nsegs; i++) { 3552 seg = &wr->wr_seg_array[i]; 3553 /* copy received data to original req buffer */ 3554 bulk_req = (usb_bulk_req_t *) 3555 wr->wr_seg_array[i].seg_data_reqp; 3556 bulk_data = bulk_req->bulk_data; 3557 len = MBLKL(bulk_data); 3558 bcopy(bulk_data->b_rptr, data->b_wptr, len); 3559 data->b_wptr += len; 3560 if (len < wr->wr_seg_array[i].seg_len) { 3561 /* short xfer */ 3562 break; 3563 } 3564 3565 if (seg->seg_done & 0x80) { 3566 3567 break; 3568 } 3569 } 3570 3571 if (attrs & USB_ATTRS_ONE_XFER) { 3572 /* client requires ONE_XFER request, return */ 3573 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 3574 "wusb_wa_handle_intr: ONE_XFER set"); 3575 3576 mutex_exit(&wr->wr_rp->rp_mutex); 3577 goto finish; 3578 } 3579 3580 /* polling mode */ 3581 mutex_exit(&wr->wr_rp->rp_mutex); 3582 rval = wa_submit_periodic_req(wa_data, ph); 3583 if (rval != USB_SUCCESS) { 3584 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 3585 "wusb_wa_handle_intr: polling, fail to resubmit req"); 3586 3587 goto finish; 3588 } 3589 3590 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 3591 "wusb_wa_handle_intr: polling, resubmit request, rv=%d", rval); 3592 3593 finish: 3594 /* do callback */ 3595 wusb_wa_callback(wa_data, wr->wr_ph, wr, cr); 3596 3597 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 3598 "wusb_wa_handle_intr: end"); 3599 } 3600 3601 /* 3602 * free transfer wrapper 3603 * call host controller driver callback for completion handling 3604 * 3605 * This callback will call WA's specific callback function. 3606 * The callback functions should call usba_hcdi_cb() to pass request 3607 * back to client driver. 3608 */ 3609 void 3610 wusb_wa_callback(wusb_wa_data_t *wa_data, usba_pipe_handle_data_t *ph, 3611 wusb_wa_trans_wrapper_t *wr, usb_cr_t cr) 3612 { 3613 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 3614 "wusb_wa_callback: wr=0x%p, cr=0x%x, ph=0x%p, req = 0x%p", 3615 (void*)wr, cr, (void*)ph, (void*)((wr == NULL)?0:wr->wr_reqp)); 3616 3617 if (cr == USB_CR_FLUSHED) { 3618 /* 3619 * the wr is aborted. mark the rpipe as error, 3620 * so that the periodic xfer callbacks will not submit 3621 * further requests. 3622 */ 3623 mutex_enter(&wr->wr_rp->rp_mutex); 3624 wr->wr_rp->rp_state = WA_RPIPE_STATE_ERROR; 3625 mutex_exit(&wr->wr_rp->rp_mutex); 3626 } 3627 3628 wa_data->rpipe_xfer_cb(wa_data->wa_dip, ph, wr, cr); 3629 3630 /* 3631 * need to consider carefully when to free wrapper 3632 * if the rpipe is reset, what to do with current wr in processing? 3633 */ 3634 USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle, 3635 "wusb_wa_callback: hwahc callback finish for wr= 0x%p, free it", 3636 (void*)wr); 3637 3638 wusb_wa_free_trans_wrapper(wr); 3639 } 3640 3641 static struct { 3642 uint8_t status; 3643 usb_cr_t cr; 3644 } sts2cr[] = { 3645 {WA_STS_SUCCESS, USB_CR_OK}, 3646 {WA_STS_HALTED, USB_CR_STALL}, 3647 {WA_STS_DATA_BUFFER_ERROR, USB_CR_DATA_OVERRUN}, 3648 {WA_STS_BABBLE, USB_CR_DATA_UNDERRUN}, 3649 {WA_STS_NOT_FOUND, USB_CR_NOT_ACCESSED}, 3650 {WA_STS_INSUFFICIENT_RESOURCE, USB_CR_NO_RESOURCES}, 3651 {0x80 | WA_STS_TRANSACTION_ERROR, USB_CR_STALL}, 3652 {0x40 | WA_STS_TRANSACTION_ERROR, USB_CR_OK}, 3653 {WA_STS_ABORTED, USB_CR_FLUSHED}, 3654 {WA_STS_RPIPE_NOT_READY, USB_CR_DEV_NOT_RESP}, 3655 {WA_STS_INVALID_REQ_FORMAT, USB_CR_CRC}, 3656 {WA_STS_UNEXPECTED_SEGMENT_NUM, USB_CR_UNEXP_PID}, 3657 {WA_STS_RPIPE_TYPE_MISMATCH, USB_CR_NOT_SUPPORTED}, 3658 {WA_STS_PACKET_DISCARDED, USB_CR_PID_CHECKFAILURE}, 3659 {0xff, 0} /* end */ 3660 }; 3661 3662 /* translate transfer status to USB completion reason */ 3663 usb_cr_t 3664 wusb_wa_sts2cr(uint8_t rawstatus) 3665 { 3666 int i; 3667 uint8_t status; 3668 3669 /* cares about bits5:0 in WUSB 1.0 */ 3670 if ((rawstatus & 0x1f) == WA_STS_TRANSACTION_ERROR) { 3671 status = rawstatus; 3672 } else { 3673 status = rawstatus & 0x1f; 3674 } 3675 3676 for (i = 0; sts2cr[i].status != 0xff; i++) { 3677 if (sts2cr[i].status == status) { 3678 3679 return (sts2cr[i].cr); 3680 } 3681 } 3682 3683 return (USB_CR_UNSPECIFIED_ERR); 3684 }