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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * Copyright 2019 Joyent, Inc. 25 */ 26 27 28 /* 29 * USBA: Solaris USB Architecture support 30 * 31 * functions that deal with allocation/free/data_xfers 32 * for the control/bulk/interrupt/isoch pipes: 33 * usb_alloc_ctrl_req() 34 * usb_free_ctrl_req() 35 * usb_pipe_ctrl_xfer() 36 * usb_pipe_sync_ctrl_xfer() 37 * usb_pipe_ctrl_xfer_wait() 38 * 39 * usb_alloc_bulk_req() 40 * usb_free_bulk_req() 41 * usb_pipe_bulk_xfer() 42 * usb_pipe_bulk_transfer_size() 43 * 44 * usb_alloc_intr_req() 45 * usb_free_intr_req() 46 * usb_pipe_intr_xfer() 47 * usb_pipe_stop_intr_polling() 48 * 49 * usb_alloc_isoc_req() 50 * usb_free_isoc_req() 51 * usb_get_current_frame_number() 52 * usb_get_max_isoc_pkts() 53 * usb_pipe_isoc_xfer() 54 * usb_pipe_stop_isoc_polling() 55 * 56 * XXX to do: 57 * update return values where needed 58 * keep track of requests not freed 59 * 60 */ 61 #define USBA_FRAMEWORK 62 #include <sys/usb/usba/usba_impl.h> 63 #include <sys/usb/usba/hcdi_impl.h> 64 #include <sys/strsubr.h> 65 #include <sys/strsun.h> 66 67 /* prototypes */ 68 static int usba_flags_attr_check(usba_pipe_handle_data_t *, 69 usb_req_attrs_t attrs, usb_flags_t); 70 static int _usba_check_req(usba_pipe_handle_data_t *, usb_opaque_t, 71 usb_flags_t, uchar_t); 72 73 /* 74 * usba_check_req: 75 * check pipe, request structure for validity 76 * 77 * Arguments: 78 * ph - pipe handle pointer 79 * req - opaque request pointer 80 * flags - usb flags 81 * 82 * Returns: 83 * USB_SUCCESS - valid request 84 * USB_INVALID_REQUEST - request contains some invalid values 85 * USB_PIPE_ERROR - pipe is in error state 86 * USB_INVALID_CONTEXT - sleep in interrupt context 87 * USB_INVALID_PIPE - zero pipe or wrong pipe 88 */ 89 static int 90 usba_check_req(usba_pipe_handle_data_t *ph_data, usb_opaque_t req, 91 usb_flags_t flags, uchar_t pipe_type) 92 { 93 int rval = _usba_check_req(ph_data, req, flags, pipe_type); 94 95 if (rval != USB_SUCCESS) { 96 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 97 "usba_check_req: ph_data=0x%p req=0x%p flags=0%x rval=%d", 98 (void *)ph_data, (void *)req, flags, rval); 99 } 100 101 return (rval); 102 } 103 104 105 static int 106 _usba_check_req(usba_pipe_handle_data_t *ph_data, usb_opaque_t req, 107 usb_flags_t flags, uchar_t pipe_type) 108 { 109 usb_ctrl_req_t *ctrl_req = (usb_ctrl_req_t *)req; 110 usb_bulk_req_t *bulk_req = (usb_bulk_req_t *)req; 111 usb_intr_req_t *intr_req = (usb_intr_req_t *)req; 112 usb_isoc_req_t *isoc_req = (usb_isoc_req_t *)req; 113 usba_req_wrapper_t *wrp = USBA_REQ2WRP(req); 114 mblk_t *data; 115 usb_cr_t *cr; 116 usb_req_attrs_t attrs; 117 usb_opaque_t cb = NULL, exc_cb = NULL; 118 uint_t timeout = 0; 119 uchar_t direction = ph_data->p_ep.bEndpointAddress & 120 USB_EP_DIR_MASK; 121 uchar_t ep_attrs = ph_data->p_ep.bmAttributes & 122 USB_EP_ATTR_MASK; 123 int n; 124 125 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 126 "usba_check_req: ph_data=0x%p req=0x%p flags=0x%x", 127 (void *)ph_data, (void *)req, flags); 128 129 if (req == NULL) { 130 131 return (USB_INVALID_ARGS); 132 } 133 134 /* set completion reason first so it specifies an error */ 135 switch (ep_attrs) { 136 case USB_EP_ATTR_CONTROL: 137 cr = &ctrl_req->ctrl_completion_reason; 138 break; 139 case USB_EP_ATTR_BULK: 140 cr = &bulk_req->bulk_completion_reason; 141 break; 142 case USB_EP_ATTR_INTR: 143 cr = &intr_req->intr_completion_reason; 144 break; 145 case USB_EP_ATTR_ISOCH: 146 cr = &isoc_req->isoc_completion_reason; 147 break; 148 default: 149 return (USB_INVALID_REQUEST); 150 } 151 152 *cr = USB_CR_UNSPECIFIED_ERR; 153 154 if (servicing_interrupt() && (flags & USB_FLAGS_SLEEP)) { 155 156 return (USB_INVALID_CONTEXT); 157 } 158 159 if (pipe_type != ep_attrs) { 160 161 return (USB_INVALID_PIPE); 162 } 163 164 /* we must have usba_device and default ph to do autoclearing */ 165 ASSERT(ph_data->p_usba_device); 166 167 if (ph_data->p_usba_device->usb_ph_list[0].usba_ph_data == NULL) { 168 169 return (USB_INVALID_PIPE); 170 } 171 172 /* check if this is a valid request packet, ie. not freed */ 173 if (usba_check_in_list(&(ph_data->p_usba_device->usb_allocated), 174 &wrp->wr_allocated_list) != USB_SUCCESS) { 175 176 return (USB_INVALID_REQUEST); 177 } 178 179 /* copy over some members for easy checking later */ 180 switch (ep_attrs) { 181 case USB_EP_ATTR_CONTROL: 182 ctrl_req->ctrl_cb_flags = USB_CB_NO_INFO; 183 data = ctrl_req->ctrl_data; 184 attrs = ctrl_req->ctrl_attributes; 185 timeout = ctrl_req->ctrl_timeout; 186 cb = (usb_opaque_t)ctrl_req->ctrl_cb; 187 exc_cb = (usb_opaque_t)ctrl_req->ctrl_exc_cb; 188 if (flags & USB_FLAGS_SLEEP) { 189 flags |= USBA_WRP_FLAGS_WAIT; 190 } 191 /* force auto clearing on the default pipe */ 192 if (USBA_IS_DEFAULT_PIPE(ph_data)) { 193 attrs |= USB_ATTRS_AUTOCLEARING; 194 } 195 break; 196 case USB_EP_ATTR_BULK: 197 bulk_req->bulk_cb_flags = USB_CB_NO_INFO; 198 data = bulk_req->bulk_data; 199 attrs = bulk_req->bulk_attributes; 200 timeout = bulk_req->bulk_timeout; 201 cb = (usb_opaque_t)bulk_req->bulk_cb; 202 exc_cb = (usb_opaque_t)bulk_req->bulk_exc_cb; 203 if (flags & USB_FLAGS_SLEEP) { 204 flags |= USBA_WRP_FLAGS_WAIT; 205 } 206 break; 207 case USB_EP_ATTR_INTR: 208 intr_req->intr_cb_flags = USB_CB_NO_INFO; 209 data = intr_req->intr_data; 210 attrs = intr_req->intr_attributes; 211 timeout = intr_req->intr_timeout; 212 cb = (usb_opaque_t)intr_req->intr_cb; 213 exc_cb = (usb_opaque_t)intr_req->intr_exc_cb; 214 if ((flags & USB_FLAGS_SLEEP) && 215 (attrs & USB_ATTRS_ONE_XFER)) { 216 flags |= USBA_WRP_FLAGS_WAIT; 217 } 218 break; 219 case USB_EP_ATTR_ISOCH: 220 isoc_req->isoc_cb_flags = USB_CB_NO_INFO; 221 data = isoc_req->isoc_data; 222 attrs = isoc_req->isoc_attributes; 223 cb = (usb_opaque_t)isoc_req->isoc_cb; 224 exc_cb = (usb_opaque_t)isoc_req->isoc_exc_cb; 225 break; 226 default: 227 return (USB_INVALID_REQUEST); 228 } 229 230 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 231 "usba_check_req: attrs = 0x%x flags=0x%x", attrs, flags); 232 233 /* check flags and attr combinations */ 234 if (usba_flags_attr_check(ph_data, attrs, flags) != 235 USB_SUCCESS) { 236 237 return (USB_INVALID_REQUEST); 238 } 239 240 /* if no sleep, there must be callback ptrs */ 241 if ((flags & USB_FLAGS_SLEEP) == 0) { 242 if (cb == NULL || exc_cb == NULL) { 243 244 return (USB_INVALID_REQUEST); 245 } 246 } 247 248 switch (ep_attrs) { 249 case USB_EP_ATTR_CONTROL: 250 if (ctrl_req->ctrl_wLength && (data == NULL)) { 251 252 return (USB_INVALID_REQUEST); 253 } 254 break; 255 case USB_EP_ATTR_BULK: 256 if ((bulk_req->bulk_len) && (data == NULL)) { 257 258 return (USB_INVALID_REQUEST); 259 } 260 break; 261 case USB_EP_ATTR_INTR: 262 if (direction == USB_EP_DIR_OUT) { 263 if (intr_req->intr_len && data == NULL) { 264 265 return (USB_INVALID_REQUEST); 266 } 267 } 268 269 if (direction == USB_EP_DIR_IN) { 270 if (!(intr_req->intr_attributes & USB_ATTRS_ONE_XFER)) { 271 if (cb == NULL || exc_cb == NULL) { 272 273 return (USB_INVALID_REQUEST); 274 } 275 } 276 if (data != NULL) { 277 278 return (USB_INVALID_REQUEST); 279 } 280 if (!(intr_req->intr_attributes & USB_ATTRS_ONE_XFER) && 281 (timeout > 0)) { 282 283 return (USB_INVALID_REQUEST); 284 } 285 } 286 break; 287 case USB_EP_ATTR_ISOCH: 288 if (direction == USB_EP_DIR_IN) { 289 if (cb == NULL || exc_cb == NULL) { 290 291 return (USB_INVALID_REQUEST); 292 } 293 } 294 295 if (data == NULL) { 296 297 return (USB_INVALID_REQUEST); 298 } 299 300 /* 301 * Since ehci/ohci/uhci use (data->b_wptr - data->b_rptr) as 302 * real isoc_pkts_length, it should be checked. 303 */ 304 if (direction == USB_EP_DIR_OUT) { 305 if (MBLKL(data) <= 0) { 306 307 return (USB_INVALID_REQUEST); 308 } 309 } 310 311 /* special isoc checks */ 312 if ((isoc_req->isoc_pkts_count == 0) || 313 (isoc_req->isoc_pkt_descr == NULL)) { 314 315 return (USB_INVALID_REQUEST); 316 } 317 318 /* check attributes for conflicts, one must be specified */ 319 if (!((isoc_req->isoc_attributes & 320 USB_ATTRS_ISOC_START_FRAME) || 321 (isoc_req->isoc_attributes & USB_ATTRS_ISOC_XFER_ASAP))) { 322 323 return (USB_NO_FRAME_NUMBER); 324 } 325 326 /* both may not be specified */ 327 if ((isoc_req->isoc_attributes & 328 (USB_ATTRS_ISOC_START_FRAME | USB_ATTRS_ISOC_XFER_ASAP)) == 329 (USB_ATTRS_ISOC_START_FRAME | USB_ATTRS_ISOC_XFER_ASAP)) { 330 331 return (USB_NO_FRAME_NUMBER); 332 } 333 334 /* no start frame may be specified for ASAP attribute */ 335 if (((isoc_req->isoc_attributes & USB_ATTRS_ISOC_XFER_ASAP)) && 336 isoc_req->isoc_frame_no) { 337 338 return (USB_INVALID_REQUEST); 339 } 340 341 /* start frame must be specified for START FRAME attribute */ 342 if (((isoc_req->isoc_attributes & 343 USB_ATTRS_ISOC_START_FRAME)) && 344 (isoc_req->isoc_frame_no == 0)) { 345 346 return (USB_NO_FRAME_NUMBER); 347 } 348 349 /* each packet must have initialized pkt length */ 350 for (n = 0; n < isoc_req->isoc_pkts_count; n++) { 351 if (isoc_req->isoc_pkt_descr[n].isoc_pkt_length == 0) { 352 353 return (USB_INVALID_REQUEST); 354 } 355 } 356 break; 357 } 358 359 /* save pipe_handle/attrs/timeout/usb_flags */ 360 wrp->wr_ph_data = ph_data; 361 wrp->wr_usb_flags = flags; 362 wrp->wr_attrs = attrs; 363 364 /* zero some fields in case the request is reused */ 365 wrp->wr_done = B_FALSE; 366 wrp->wr_cr = USB_CR_OK; 367 368 /* this request looks good */ 369 *cr = USB_CR_OK; 370 371 return (USB_SUCCESS); 372 } 373 374 375 /* 376 * Table of invalid flags and attributes values. See "usbai.h" 377 * for a complete table on valid usb_req_attrs_t 378 */ 379 #define X ((uint_t)(-1)) 380 #define OUT USB_EP_DIR_OUT 381 #define IN USB_EP_DIR_IN 382 383 struct flags_attr { 384 uint_t ep_dir; 385 uint_t ep_attr; 386 uint_t usb_flags; /* usb_flags SLEEP or none */ 387 uint_t attrs; 388 } usb_invalid_flags_attrs[] = { 389 { OUT, USB_EP_ATTR_BULK, X, USB_ATTRS_SHORT_XFER_OK }, 390 { OUT, USB_EP_ATTR_INTR, X, USB_ATTRS_SHORT_XFER_OK }, 391 { OUT, USB_EP_ATTR_ISOCH, X, USB_ATTRS_SHORT_XFER_OK }, 392 393 { X, USB_EP_ATTR_CONTROL, X, USB_ATTRS_ISOC_START_FRAME }, 394 { X, USB_EP_ATTR_BULK, X, USB_ATTRS_ISOC_START_FRAME }, 395 { X, USB_EP_ATTR_INTR, X, USB_ATTRS_ISOC_START_FRAME }, 396 397 { X, USB_EP_ATTR_CONTROL, X, USB_ATTRS_ISOC_XFER_ASAP }, 398 { X, USB_EP_ATTR_INTR, X, USB_ATTRS_ISOC_XFER_ASAP }, 399 { OUT, USB_EP_ATTR_INTR, X, USB_ATTRS_ONE_XFER }, 400 { X, USB_EP_ATTR_BULK, X, USB_ATTRS_ISOC_XFER_ASAP }, 401 402 { X, USB_EP_ATTR_CONTROL, X, USB_ATTRS_ONE_XFER }, 403 { X, USB_EP_ATTR_BULK, X, USB_ATTRS_ONE_XFER }, 404 { X, USB_EP_ATTR_ISOCH, X, USB_ATTRS_ONE_XFER }, 405 }; 406 407 #define N_INVALID_FLAGS_ATTRS (sizeof (usb_invalid_flags_attrs))/ \ 408 sizeof (struct flags_attr) 409 410 /* 411 * function to check flags and attribute combinations for a particular pipe 412 * Arguments: 413 * ph - pipe handle pointer 414 * attrs - attributes of the request 415 * flags - usb_flags 416 */ 417 static int 418 usba_flags_attr_check(usba_pipe_handle_data_t *ph_data, 419 usb_req_attrs_t attrs, 420 usb_flags_t flags) 421 { 422 uchar_t i; 423 uchar_t ep_dir = ph_data->p_ep.bEndpointAddress & USB_EP_DIR_MASK; 424 uchar_t ep_attr = ph_data->p_ep.bmAttributes & USB_EP_ATTR_MASK; 425 426 flags &= USB_FLAGS_SLEEP; /* ignore other flags */ 427 428 /* 429 * Do some attributes validation checks here. 430 */ 431 for (i = 0; i < N_INVALID_FLAGS_ATTRS; i++) { 432 if (((ep_dir == usb_invalid_flags_attrs[i].ep_dir) || 433 (usb_invalid_flags_attrs[i].ep_dir == X)) && 434 ((ep_attr == usb_invalid_flags_attrs[i].ep_attr) || 435 (usb_invalid_flags_attrs[i].ep_attr == X)) && 436 ((flags & usb_invalid_flags_attrs[i].usb_flags) || 437 (usb_invalid_flags_attrs[i].usb_flags == X)) && 438 ((attrs & usb_invalid_flags_attrs[i].attrs) || 439 (usb_invalid_flags_attrs[i].attrs == X))) { 440 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 441 "invalid (%d) : flags = 0x%x, attrs = 0x%x", 442 i, flags, attrs); 443 444 return (USB_INVALID_REQUEST); 445 } 446 } 447 448 return (USB_SUCCESS); 449 } 450 451 452 /* 453 * usba_rval2cr: 454 * convert rval to meaningful completion reason 455 * XXX extend completion reasons to get better mapping 456 */ 457 static struct { 458 int rval; 459 usb_cr_t cr; 460 } rval2cr[] = { 461 {USB_SUCCESS, USB_CR_OK}, 462 {USB_FAILURE, USB_CR_UNSPECIFIED_ERR}, 463 {USB_NO_RESOURCES, USB_CR_NO_RESOURCES}, 464 {USB_NO_BANDWIDTH, USB_CR_NO_RESOURCES}, 465 {USB_NOT_SUPPORTED, USB_CR_UNSPECIFIED_ERR}, 466 {USB_PIPE_ERROR, USB_CR_UNSPECIFIED_ERR}, 467 {USB_INVALID_PIPE, USB_CR_UNSPECIFIED_ERR}, 468 {USB_NO_FRAME_NUMBER, USB_CR_UNSPECIFIED_ERR}, 469 {USB_INVALID_START_FRAME, USB_CR_UNSPECIFIED_ERR}, 470 {USB_HC_HARDWARE_ERROR, USB_CR_UNSPECIFIED_ERR}, 471 {USB_INVALID_REQUEST, USB_CR_UNSPECIFIED_ERR}, 472 {USB_INVALID_CONTEXT, USB_CR_UNSPECIFIED_ERR}, 473 {USB_INVALID_VERSION, USB_CR_UNSPECIFIED_ERR}, 474 {USB_INVALID_ARGS, USB_CR_UNSPECIFIED_ERR}, 475 {USB_INVALID_PERM, USB_CR_UNSPECIFIED_ERR}, 476 {USB_BUSY, USB_CR_UNSPECIFIED_ERR}, 477 {0xffff, 0} 478 }; 479 480 usb_cr_t 481 usba_rval2cr(int rval) 482 { 483 int i; 484 485 for (i = 0; rval2cr[i].rval != 0xffff; i++) { 486 if (rval2cr[i].rval == rval) { 487 488 return (rval2cr[i].cr); 489 } 490 } 491 492 return (USB_CR_UNSPECIFIED_ERR); 493 } 494 495 496 /* 497 * usba_start_next_req: 498 * Arguments: 499 * ph_data - pointer to pipe handle 500 * 501 * Currently, only ctrl/bulk requests can be queued 502 */ 503 void 504 usba_start_next_req(usba_pipe_handle_data_t *ph_data) 505 { 506 usb_ctrl_req_t *ctrl_req; 507 usb_bulk_req_t *bulk_req; 508 usba_req_wrapper_t *wrp; 509 uchar_t ep_attrs = ph_data->p_ep.bmAttributes & 510 USB_EP_ATTR_MASK; 511 int rval; 512 usb_pipe_state_t state; 513 514 mutex_enter(&ph_data->p_mutex); 515 switch (ep_attrs) { 516 case USB_EP_ATTR_CONTROL: 517 case USB_EP_ATTR_BULK: 518 switch (usba_get_ph_state(ph_data)) { 519 case USB_PIPE_STATE_IDLE: 520 case USB_PIPE_STATE_CLOSING: 521 522 break; 523 524 default: 525 mutex_exit(&ph_data->p_mutex); 526 527 return; 528 } 529 530 break; 531 case USB_EP_ATTR_ISOCH: 532 case USB_EP_ATTR_INTR: 533 default: 534 mutex_exit(&ph_data->p_mutex); 535 536 return; 537 } 538 539 while ((wrp = (usba_req_wrapper_t *) 540 usba_rm_first_pvt_from_list(&ph_data->p_queue)) != NULL) { 541 542 /* only submit to HCD when idle/active */ 543 544 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 545 "usba_start_next_req: ph_data=0x%p state=%d", 546 (void *)ph_data, usba_get_ph_state(ph_data)); 547 548 if (ep_attrs == USB_EP_ATTR_CONTROL) { 549 ph_data->p_active_cntrl_req_wrp = (usb_opaque_t)wrp; 550 } 551 552 if ((state = usba_get_ph_state(ph_data)) == 553 USB_PIPE_STATE_IDLE) { 554 usba_pipe_new_state(ph_data, USB_PIPE_STATE_ACTIVE); 555 556 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 557 "starting req = 0x%p", 558 (void *)USBA_WRP2CTRL_REQ(wrp)); 559 560 switch (ep_attrs) { 561 case USB_EP_ATTR_CONTROL: 562 mutex_exit(&ph_data->p_mutex); 563 ctrl_req = USBA_WRP2CTRL_REQ(wrp); 564 /* submit to hcd */ 565 rval = ph_data->p_usba_device->usb_hcdi_ops-> 566 usba_hcdi_pipe_ctrl_xfer(ph_data, 567 ctrl_req, wrp->wr_usb_flags); 568 mutex_enter(&ph_data->p_mutex); 569 break; 570 case USB_EP_ATTR_BULK: 571 mutex_exit(&ph_data->p_mutex); 572 bulk_req = USBA_WRP2BULK_REQ(wrp); 573 /* submit to hcd */ 574 rval = ph_data->p_usba_device->usb_hcdi_ops-> 575 usba_hcdi_pipe_bulk_xfer(ph_data, 576 bulk_req, wrp->wr_usb_flags); 577 mutex_enter(&ph_data->p_mutex); 578 break; 579 default: 580 /* there shouldn't be any requests */ 581 rval = USB_FAILURE; 582 break; 583 } 584 585 if (rval != USB_SUCCESS) { 586 mutex_exit(&ph_data->p_mutex); 587 usba_do_req_exc_cb(wrp, 588 usba_rval2cr(rval), 589 USB_CB_SUBMIT_FAILED); 590 mutex_enter(&ph_data->p_mutex); 591 } 592 /* we are done */ 593 break; 594 595 } else { 596 mutex_exit(&ph_data->p_mutex); 597 switch (state) { 598 case USB_PIPE_STATE_CLOSING: 599 usba_do_req_exc_cb(wrp, USB_CR_PIPE_CLOSING, 0); 600 break; 601 case USB_PIPE_STATE_ERROR: 602 default: 603 usba_do_req_exc_cb(wrp, USB_CR_FLUSHED, 0); 604 break; 605 } 606 mutex_enter(&ph_data->p_mutex); 607 } 608 } 609 610 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 611 "usba_start_next_req done: ph_data=0x%p state=%d", (void *)ph_data, 612 usba_get_ph_state(ph_data)); 613 614 mutex_exit(&ph_data->p_mutex); 615 } 616 617 618 /* 619 * usba_req_wrapper_alloc: 620 * Allocate + Initialize a usba_req_wrapper_t 621 * 622 * Arguments: 623 * dip - dev_info_t of the client driver 624 * req_len - sizeof request 625 * flags - 626 * USB_FLAGS_SLEEP - Sleep if resources are not available 627 * no USB_FLAGS_SLEEP - Don't Sleep if resources are not available 628 * 629 * Return Values: 630 * pointer to usba_req_wrapper_t on success; NULL on failure. 631 * 632 */ 633 static usba_req_wrapper_t * 634 usba_req_wrapper_alloc(dev_info_t *dip, 635 size_t req_len, 636 usb_flags_t flags) 637 { 638 int kmflag; 639 usba_device_t *usba_device = usba_get_usba_device(dip); 640 usba_req_wrapper_t *wrp; 641 size_t wr_length = sizeof (usba_req_wrapper_t) + req_len; 642 ddi_iblock_cookie_t iblock_cookie = 643 usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip)-> 644 hcdi_iblock_cookie; 645 646 if (servicing_interrupt() && (flags & USB_FLAGS_SLEEP)) { 647 648 return (NULL); 649 } 650 651 kmflag = (flags & USB_FLAGS_SLEEP) ? KM_SLEEP : KM_NOSLEEP; 652 653 /* Allocate the usb_{c/b/i/i}_req + usba_req_wrapper_t structure */ 654 if ((wrp = kmem_zalloc(wr_length, kmflag)) != NULL) { 655 wrp->wr_length = wr_length; 656 wrp->wr_dip = dip; 657 wrp->wr_req = (usb_opaque_t)USBA_SETREQ_ADDR(wrp); 658 cv_init(&wrp->wr_cv, NULL, CV_DRIVER, NULL); 659 660 /* initialize mutex for the queue */ 661 usba_init_list(&wrp->wr_queue, (usb_opaque_t)wrp, 662 iblock_cookie); 663 usba_init_list(&wrp->wr_allocated_list, (usb_opaque_t)wrp, 664 iblock_cookie); 665 666 usba_add_to_list(&usba_device->usb_allocated, 667 &wrp->wr_allocated_list); 668 669 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 670 "usba_req_wrapper_alloc: wrp = 0x%p", (void *)wrp); 671 } 672 673 return (wrp); 674 } 675 676 677 /* 678 * usba_req_wrapper_free: 679 * Frees a usba_req_wrapper_t. Get rid of lists if any. 680 * 681 * Arguments: 682 * wrp: request wrapper structure 683 */ 684 void 685 usba_req_wrapper_free(usba_req_wrapper_t *wrp) 686 { 687 usba_device_t *usba_device; 688 usba_pipe_handle_data_t *ph_data; 689 690 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 691 "usba_req_wrapper_free: wrp=0x%p", (void *)wrp); 692 693 if (wrp) { 694 /* remove from queues */ 695 ph_data = USBA_WRP2PH_DATA(wrp); 696 if (ph_data) { 697 (void) usba_rm_from_list(&ph_data->p_queue, 698 &wrp->wr_queue); 699 } 700 usba_device = usba_get_usba_device(wrp->wr_dip); 701 if (usba_rm_from_list(&usba_device->usb_allocated, 702 &wrp->wr_allocated_list) != USB_SUCCESS) { 703 cmn_err(CE_PANIC, 704 "usba_req_wrapper_free: data corruption"); 705 } 706 usba_destroy_list(&wrp->wr_queue); 707 usba_destroy_list(&wrp->wr_allocated_list); 708 cv_destroy(&wrp->wr_cv); 709 kmem_free(wrp, wrp->wr_length); 710 } 711 } 712 713 714 /* 715 * usba_check_intr_context 716 * Set USB_CB_INTR_CONTEXT callback flag if executing in interrupt context 717 */ 718 usb_cb_flags_t 719 usba_check_intr_context(usb_cb_flags_t cb_flags) 720 { 721 if (servicing_interrupt() != 0) { 722 cb_flags |= USB_CB_INTR_CONTEXT; 723 } 724 725 return (cb_flags); 726 } 727 728 729 /* 730 * usba_req_normal_cb: 731 * perform normal callback depending on request type 732 */ 733 void 734 usba_req_normal_cb(usba_req_wrapper_t *req_wrp) 735 { 736 usba_pipe_handle_data_t *ph_data = req_wrp->wr_ph_data; 737 usb_pipe_handle_t pipe_handle; 738 uint_t direction = ph_data->p_ep.bEndpointAddress & 739 USB_EP_DIR_MASK; 740 usb_pipe_state_t pipe_state; 741 742 pipe_handle = usba_get_pipe_handle(ph_data); 743 744 mutex_enter(&ph_data->p_mutex); 745 ASSERT(ph_data->p_req_count >= 0); 746 pipe_state = usba_get_ph_state(ph_data); 747 748 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 749 "usba_req_normal_cb: " 750 "ph_data=0x%p state=%d wrp=0x%p ref=%d req=%d", 751 (void *)ph_data, pipe_state, (void *)req_wrp, 752 usba_get_ph_ref_count(ph_data), ph_data->p_req_count); 753 754 ASSERT((pipe_state == USB_PIPE_STATE_ACTIVE) || 755 (pipe_state == USB_PIPE_STATE_CLOSING)); 756 757 /* set done to indicate that we will do callback or cv_signal */ 758 ASSERT(req_wrp->wr_done == B_FALSE); 759 req_wrp->wr_done = B_TRUE; 760 761 /* update the pipe state */ 762 switch (req_wrp->wr_ph_data->p_ep.bmAttributes & 763 USB_EP_ATTR_MASK) { 764 case USB_EP_ATTR_CONTROL: 765 case USB_EP_ATTR_BULK: 766 usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE); 767 break; 768 case USB_EP_ATTR_INTR: 769 if ((direction == USB_EP_DIR_IN) && 770 (USBA_WRP2INTR_REQ(req_wrp)->intr_attributes & 771 USB_ATTRS_ONE_XFER)) { 772 usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE); 773 } else if ((direction == USB_EP_DIR_OUT) && 774 (ph_data->p_req_count == 0)) { 775 usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE); 776 } 777 break; 778 case USB_EP_ATTR_ISOCH: 779 if ((ph_data->p_req_count == 0) && 780 (direction == USB_EP_DIR_OUT)) { 781 usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE); 782 } 783 break; 784 } 785 786 787 /* now complete the request */ 788 if (req_wrp->wr_usb_flags & USBA_WRP_FLAGS_WAIT) { 789 ph_data->p_active_cntrl_req_wrp = NULL; 790 cv_signal(&req_wrp->wr_cv); 791 mutex_exit(&ph_data->p_mutex); 792 } else { 793 mutex_exit(&ph_data->p_mutex); 794 795 /* This sets USB_CB_INTR_CONTEXT as needed. */ 796 usba_req_set_cb_flags(req_wrp, USB_CB_NO_INFO); 797 798 switch (req_wrp->wr_ph_data->p_ep.bmAttributes & 799 USB_EP_ATTR_MASK) { 800 case USB_EP_ATTR_CONTROL: 801 USBA_WRP2CTRL_REQ(req_wrp)->ctrl_cb(pipe_handle, 802 USBA_WRP2CTRL_REQ(req_wrp)); 803 mutex_enter(&ph_data->p_mutex); 804 ph_data->p_active_cntrl_req_wrp = NULL; 805 mutex_exit(&ph_data->p_mutex); 806 break; 807 case USB_EP_ATTR_INTR: 808 USBA_WRP2INTR_REQ(req_wrp)->intr_cb(pipe_handle, 809 USBA_WRP2INTR_REQ(req_wrp)); 810 break; 811 case USB_EP_ATTR_BULK: 812 USBA_WRP2BULK_REQ(req_wrp)->bulk_cb(pipe_handle, 813 USBA_WRP2BULK_REQ(req_wrp)); 814 break; 815 case USB_EP_ATTR_ISOCH: 816 USBA_WRP2ISOC_REQ(req_wrp)->isoc_cb(pipe_handle, 817 USBA_WRP2ISOC_REQ(req_wrp)); 818 break; 819 } 820 } 821 822 /* we are done with this request */ 823 mutex_enter(&ph_data->p_mutex); 824 ph_data->p_req_count--; 825 ASSERT(ph_data->p_req_count >= 0); 826 mutex_exit(&ph_data->p_mutex); 827 } 828 829 830 /* 831 * usba_req_exc_cb: 832 * perform exception cb depending on request type. 833 * ensure the completion reason is non zero 834 */ 835 void 836 usba_req_exc_cb(usba_req_wrapper_t *req_wrp, usb_cr_t cr, 837 usb_cb_flags_t cb_flags) 838 { 839 usba_pipe_handle_data_t *ph_data = req_wrp->wr_ph_data; 840 usb_pipe_handle_t pipe_handle = usba_get_pipe_handle(ph_data); 841 842 mutex_enter(&req_wrp->wr_ph_data->p_mutex); 843 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 844 "usba_req_exc_cb: %s%d: ph_data=0x%p (ep%x) state=%d wrp=0x%p " 845 "ref=%d reqcnt=%d cr=%d", 846 ddi_driver_name(req_wrp->wr_dip), 847 ddi_get_instance(req_wrp->wr_dip), 848 (void *)ph_data, ph_data->p_ep.bEndpointAddress, 849 usba_get_ph_state(ph_data), (void *)req_wrp, 850 usba_get_ph_ref_count(ph_data), ph_data->p_req_count, 851 req_wrp->wr_cr); 852 853 ASSERT(req_wrp->wr_ph_data->p_req_count >= 0); 854 855 usba_req_set_cb_flags(req_wrp, cb_flags); 856 857 /* if there was no CR set already, set it now */ 858 if (req_wrp->wr_cr == USB_CR_OK) { 859 req_wrp->wr_cr = (cr != USB_CR_OK) ? 860 cr : USB_CR_UNSPECIFIED_ERR; 861 } 862 863 ASSERT(req_wrp->wr_done == B_FALSE); 864 req_wrp->wr_done = B_TRUE; 865 866 switch (req_wrp->wr_ph_data->p_ep.bmAttributes & 867 USB_EP_ATTR_MASK) { 868 case USB_EP_ATTR_CONTROL: 869 if (USBA_WRP2CTRL_REQ(req_wrp)-> 870 ctrl_completion_reason == USB_CR_OK) { 871 USBA_WRP2CTRL_REQ(req_wrp)-> 872 ctrl_completion_reason = req_wrp->wr_cr; 873 } 874 break; 875 case USB_EP_ATTR_INTR: 876 if (USBA_WRP2INTR_REQ(req_wrp)-> 877 intr_completion_reason == USB_CR_OK) { 878 USBA_WRP2INTR_REQ(req_wrp)-> 879 intr_completion_reason = req_wrp->wr_cr; 880 } 881 break; 882 case USB_EP_ATTR_BULK: 883 if (USBA_WRP2BULK_REQ(req_wrp)-> 884 bulk_completion_reason == USB_CR_OK) { 885 USBA_WRP2BULK_REQ(req_wrp)-> 886 bulk_completion_reason = req_wrp->wr_cr; 887 } 888 break; 889 case USB_EP_ATTR_ISOCH: 890 if (USBA_WRP2ISOC_REQ(req_wrp)-> 891 isoc_completion_reason == USB_CR_OK) { 892 USBA_WRP2ISOC_REQ(req_wrp)-> 893 isoc_completion_reason = req_wrp->wr_cr; 894 } 895 break; 896 } 897 898 if (req_wrp->wr_usb_flags & USBA_WRP_FLAGS_WAIT) { 899 cv_signal(&req_wrp->wr_cv); 900 if (ph_data->p_active_cntrl_req_wrp == (usb_opaque_t)req_wrp) { 901 ph_data->p_active_cntrl_req_wrp = NULL; 902 } 903 mutex_exit(&ph_data->p_mutex); 904 } else { 905 mutex_exit(&ph_data->p_mutex); 906 switch (req_wrp->wr_ph_data->p_ep.bmAttributes & 907 USB_EP_ATTR_MASK) { 908 case USB_EP_ATTR_CONTROL: 909 USBA_WRP2CTRL_REQ(req_wrp)->ctrl_exc_cb(pipe_handle, 910 USBA_WRP2CTRL_REQ(req_wrp)); 911 mutex_enter(&ph_data->p_mutex); 912 if (ph_data->p_active_cntrl_req_wrp == 913 (usb_opaque_t)req_wrp) { 914 ph_data->p_active_cntrl_req_wrp = NULL; 915 } 916 mutex_exit(&ph_data->p_mutex); 917 break; 918 case USB_EP_ATTR_INTR: 919 USBA_WRP2INTR_REQ(req_wrp)->intr_exc_cb(pipe_handle, 920 USBA_WRP2INTR_REQ(req_wrp)); 921 break; 922 case USB_EP_ATTR_BULK: 923 USBA_WRP2BULK_REQ(req_wrp)->bulk_exc_cb(pipe_handle, 924 USBA_WRP2BULK_REQ(req_wrp)); 925 break; 926 case USB_EP_ATTR_ISOCH: 927 USBA_WRP2ISOC_REQ(req_wrp)->isoc_exc_cb(pipe_handle, 928 USBA_WRP2ISOC_REQ(req_wrp)); 929 break; 930 } 931 } 932 933 /* we are done with this request */ 934 mutex_enter(&ph_data->p_mutex); 935 ph_data->p_req_count--; 936 ASSERT(ph_data->p_req_count >= 0); 937 mutex_exit(&ph_data->p_mutex); 938 } 939 940 941 /* 942 * usba_do_req_exc_cb: 943 * called when flushing requests. rather than calling usba_req_exc_cb() 944 * directly, this function uses usba_hcdi_cb() which ensures callback 945 * order is preserved 946 */ 947 void 948 usba_do_req_exc_cb(usba_req_wrapper_t *req_wrp, usb_cr_t cr, 949 usb_cb_flags_t cb_flags) 950 { 951 req_wrp->wr_cb_flags |= cb_flags; 952 usba_hcdi_cb(req_wrp->wr_ph_data, req_wrp->wr_req, cr); 953 } 954 955 956 /* 957 * usba_req_set_cb_flags: 958 * This function sets the request's callback flags to those stored in the 959 * request wrapper ORed with those received as an argument. Additionally 960 * USB_CB_INTR_CONTEXT is set if called from interrupt context. 961 * 962 * NOTE: The xfer may have succeeded, which client driver can determine 963 * by looking at usb_cr_t 964 */ 965 void 966 usba_req_set_cb_flags(usba_req_wrapper_t *req_wrp, 967 usb_cb_flags_t cb_flags) 968 { 969 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 970 "usba_req_set_cb_flags: wrp=0x%p cb-flags=0x%x", 971 (void *)req_wrp, cb_flags); 972 973 cb_flags |= req_wrp->wr_cb_flags; 974 cb_flags = usba_check_intr_context(cb_flags); 975 976 /* do the callback under taskq context */ 977 switch (req_wrp->wr_ph_data->p_ep.bmAttributes & 978 USB_EP_ATTR_MASK) { 979 case USB_EP_ATTR_CONTROL: 980 USBA_WRP2CTRL_REQ(req_wrp)->ctrl_cb_flags |= cb_flags; 981 break; 982 case USB_EP_ATTR_INTR: 983 USBA_WRP2INTR_REQ(req_wrp)->intr_cb_flags |= cb_flags; 984 break; 985 case USB_EP_ATTR_BULK: 986 USBA_WRP2BULK_REQ(req_wrp)->bulk_cb_flags |= cb_flags; 987 break; 988 case USB_EP_ATTR_ISOCH: 989 USBA_WRP2ISOC_REQ(req_wrp)->isoc_cb_flags |= cb_flags; 990 break; 991 } 992 } 993 994 995 /* 996 * usba_pipe_sync_wait: 997 * wait for the request to finish. 998 * usba_hcdi_cb() does a cv_signal thru a soft intr 999 * 1000 * Arguments: 1001 * ph_data - pointer to pipe handle data 1002 * wrp - pointer to usba_req_wrapper_structure. 1003 * 1004 * Return Values: 1005 * USB_SUCCESS - request successfully executed 1006 * USB_FAILURE - request failed 1007 */ 1008 static int 1009 usba_pipe_sync_wait(usba_pipe_handle_data_t *ph_data, 1010 usba_req_wrapper_t *wrp) 1011 { 1012 ASSERT(wrp->wr_usb_flags & USB_FLAGS_SLEEP); 1013 ASSERT(ph_data == wrp->wr_ph_data); 1014 1015 mutex_enter(&ph_data->p_mutex); 1016 while (wrp->wr_done != B_TRUE) { 1017 cv_wait(&wrp->wr_cv, &ph_data->p_mutex); 1018 } 1019 1020 mutex_exit(&ph_data->p_mutex); 1021 1022 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1023 "usba_pipe_sync_wait: ph_data=0x%p cr=0x%x", (void *)ph_data, 1024 wrp->wr_cr); 1025 1026 /* XXX return something better than USB_FAILURE?? */ 1027 1028 return (wrp->wr_cr == USB_CR_OK ? USB_SUCCESS : USB_FAILURE); 1029 } 1030 1031 1032 /* 1033 * Allocate usb control request and a USB request wrapper 1034 * 1035 * Arguments: 1036 * dip - dev_info_t of the client driver 1037 * len - length of "data" for this control request 1038 * flags: 1039 * USB_FLAGS_SLEEP - Sleep if resources are not available 1040 * no USB_FLAGS_SLEEP - Don't Sleep if resources are not available 1041 * 1042 * Return Values: usb_ctrl_req_t on success, NULL on failure 1043 */ 1044 usb_ctrl_req_t * 1045 usb_alloc_ctrl_req(dev_info_t *dip, 1046 size_t len, 1047 usb_flags_t flags) 1048 { 1049 usb_ctrl_req_t *ctrl_req = NULL; 1050 usba_req_wrapper_t *wrp; 1051 1052 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1053 "usb_alloc_ctrl_req: dip=0x%p, wlen=0x%lx, flags=0x%x", 1054 (void *)dip, len, flags); 1055 1056 /* Allocate + Initialize the usba_req_wrapper_t structure */ 1057 if (dip && 1058 ((wrp = usba_req_wrapper_alloc(dip, sizeof (*ctrl_req), flags)) != 1059 NULL)) { 1060 ctrl_req = USBA_WRP2CTRL_REQ(wrp); 1061 1062 /* Allocate the usb_ctrl_req data mblk */ 1063 if (len) { 1064 if (flags & USB_FLAGS_SLEEP) { 1065 ctrl_req->ctrl_data = allocb_wait(len, BPRI_LO, 1066 STR_NOSIG, NULL); 1067 } else if ((ctrl_req->ctrl_data = 1068 allocb(len, BPRI_HI)) == NULL) { 1069 usba_req_wrapper_free(wrp); 1070 ctrl_req = NULL; 1071 } 1072 } 1073 } 1074 1075 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1076 "usb_alloc_ctrl_req: ctrl_req = 0x%p", (void *)ctrl_req); 1077 1078 return (ctrl_req); 1079 } 1080 1081 1082 /* 1083 * usb_free_ctrl_req: 1084 * free USB control request + wrapper 1085 * 1086 * Arguments: 1087 * req - pointer to usb_ctrl_req_t 1088 */ 1089 void 1090 usb_free_ctrl_req(usb_ctrl_req_t *req) 1091 { 1092 if (req) { 1093 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1094 "usb_free_ctrl_req: req = 0x%p", (void *)req); 1095 1096 if (req->ctrl_data) { 1097 freemsg(req->ctrl_data); 1098 } 1099 usba_req_wrapper_free(USBA_REQ2WRP(req)); 1100 } 1101 } 1102 1103 1104 /* 1105 * Client driver calls this function to issue the control 1106 * request to the USBA 1107 * 1108 * Arguments: 1109 * pipe_handle: control pipe pipehandle (obtained via usb_pipe_open() 1110 * req: control request 1111 * usb_flags: 1112 * USB_FLAGS_SLEEP - wait for the request to complete 1113 * 1114 * Return Values: 1115 * USB_SUCCESS - request successfully executed 1116 * USB_FAILURE - request failed 1117 */ 1118 int 1119 usb_pipe_ctrl_xfer(usb_pipe_handle_t pipe_handle, 1120 usb_ctrl_req_t *req, 1121 usb_flags_t usb_flags) 1122 { 1123 int rval; 1124 usba_req_wrapper_t *wrp = USBA_REQ2WRP(req); 1125 usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle); 1126 usba_device_t *usba_device; 1127 usb_flags_t wrp_usb_flags; 1128 usb_pipe_state_t pipe_state; 1129 1130 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1131 "usb_pipe_ctrl_xfer: req=0x%p, wrp=0x%p\n\t" 1132 "setup = 0x%x 0x%x 0x%x 0x%x 0x%x uf=0x%x", 1133 (void *)req, (void *)wrp, req->ctrl_bmRequestType, 1134 req->ctrl_bRequest, req->ctrl_wValue, req->ctrl_wIndex, 1135 req->ctrl_wLength, usb_flags); 1136 1137 if (ph_data == NULL) { 1138 1139 return (USB_INVALID_PIPE); 1140 } 1141 1142 mutex_enter(&ph_data->p_mutex); 1143 usba_device = ph_data->p_usba_device; 1144 1145 if ((rval = usba_check_req(ph_data, (usb_opaque_t)req, usb_flags, 1146 USB_EP_ATTR_CONTROL)) != USB_SUCCESS) { 1147 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 1148 "request rejected: rval=%d", rval); 1149 mutex_exit(&ph_data->p_mutex); 1150 1151 usba_release_ph_data(ph_data->p_ph_impl); 1152 1153 return (rval); 1154 } 1155 1156 ASSERT(ph_data == wrp->wr_ph_data); 1157 1158 /* we accepted the request, so increment the req count */ 1159 ph_data->p_req_count++; 1160 1161 wrp_usb_flags = wrp->wr_usb_flags; 1162 1163 /* Get the current bulk pipe state */ 1164 pipe_state = usba_get_ph_state(ph_data); 1165 1166 /* 1167 * if this is for the default pipe, and the pipe is in error, 1168 * just queue the request. autoclearing will start this request 1169 * 1170 * if there is already an active request in the queue 1171 * then just add this request to the queue. 1172 */ 1173 switch (pipe_state) { 1174 case USB_PIPE_STATE_IDLE: 1175 if (ph_data->p_queue.next || 1176 ph_data->p_active_cntrl_req_wrp) { 1177 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1178 "usb_pipe_ctrl_xfer: queue request 0x%p", 1179 (void *)req); 1180 1181 usba_add_to_list(&ph_data->p_queue, &wrp->wr_queue); 1182 rval = USB_SUCCESS; 1183 mutex_exit(&ph_data->p_mutex); 1184 } else { 1185 usba_pipe_new_state(ph_data, USB_PIPE_STATE_ACTIVE); 1186 ph_data->p_active_cntrl_req_wrp = (usb_opaque_t)wrp; 1187 mutex_exit(&ph_data->p_mutex); 1188 1189 /* issue the request to HCD */ 1190 rval = usba_device->usb_hcdi_ops-> 1191 usba_hcdi_pipe_ctrl_xfer(ph_data, req, usb_flags); 1192 } 1193 break; 1194 case USB_PIPE_STATE_ACTIVE: 1195 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1196 "usb_pipe_ctrl_xfer: queue request 0x%p", (void *)req); 1197 1198 usba_add_to_list(&ph_data->p_queue, &wrp->wr_queue); 1199 rval = USB_SUCCESS; 1200 mutex_exit(&ph_data->p_mutex); 1201 break; 1202 case USB_PIPE_STATE_ERROR: 1203 if (USBA_IS_DEFAULT_PIPE(ph_data)) { 1204 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1205 "usb_pipe_ctrl_xfer: queue request 0x%p on " 1206 "pending def pipe error", (void *)req); 1207 1208 usba_add_to_list(&ph_data->p_queue, &wrp->wr_queue); 1209 rval = USB_SUCCESS; 1210 } else { 1211 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1212 "usb_pipe_ctrl_xfer: pipe is in error state "); 1213 1214 rval = USB_PIPE_ERROR; 1215 } 1216 mutex_exit(&ph_data->p_mutex); 1217 break; 1218 default: 1219 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1220 "usb_pipe_ctrl_xfer: pipe state %d", pipe_state); 1221 1222 rval = USB_PIPE_ERROR; 1223 mutex_exit(&ph_data->p_mutex); 1224 break; 1225 } 1226 1227 /* if there has been a failure, decrement req count */ 1228 if (rval != USB_SUCCESS) { 1229 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 1230 "usb_pipe_ctrl_xfer: hcd failed req 0x%p", (void *)req); 1231 1232 if (req->ctrl_completion_reason == USB_CR_OK) { 1233 req->ctrl_completion_reason = usba_rval2cr(rval); 1234 } 1235 mutex_enter(&ph_data->p_mutex); 1236 ASSERT(wrp->wr_done == B_FALSE); 1237 ph_data->p_req_count--; 1238 ASSERT(ph_data->p_req_count >= 0); 1239 ph_data->p_active_cntrl_req_wrp = NULL; 1240 if ((ph_data->p_req_count == 0) && 1241 (usba_get_ph_state(ph_data) == USB_PIPE_STATE_ACTIVE)) { 1242 usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE); 1243 } 1244 mutex_exit(&ph_data->p_mutex); 1245 1246 /* if success and sleep specified, wait for completion */ 1247 } else if (wrp_usb_flags & USBA_WRP_FLAGS_WAIT) { 1248 rval = usba_pipe_sync_wait(ph_data, wrp); 1249 } 1250 1251 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1252 "usb_pipe_ctrl_xfer: rval=0x%x", rval); 1253 1254 usba_release_ph_data(ph_data->p_ph_impl); 1255 1256 return (rval); 1257 } 1258 1259 1260 /* 1261 * usb_pipe_sync_ctrl_xfer(): 1262 * for simple synchronous control transactions this wrapper function 1263 * will perform the allocation, xfer, and deallocation 1264 * USB_ATTRS_AUTOCLEARING will be enabled 1265 * 1266 * Arguments: 1267 * dip - pointer to clients devinfo 1268 * pipe_handle - control pipe pipehandle (obtained via usb_pipe_open() 1269 * bmRequestType - characteristics of request 1270 * bRequest - specific request 1271 * wValue - varies according to request 1272 * wIndex - index or offset 1273 * wLength - number of bytes to xfer 1274 * data - pointer to pointer to data and may be NULL if 1275 * wLength is 0 1276 * attrs - required request attributes 1277 * completion_reason - completion status 1278 * cb_flags - request completions flags 1279 * flags - none 1280 * 1281 * Return Values: 1282 * USB_SUCCESS - request successfully executed 1283 * USB_* - request failed 1284 * 1285 * Notes: 1286 * - in the case of failure, the client should check completion_reason and 1287 * and cb_flags and determine further recovery action 1288 * - the client should check data and if non-zero, free the data on 1289 * completion 1290 */ 1291 int 1292 usb_pipe_sync_ctrl_xfer(dev_info_t *dip, 1293 usb_pipe_handle_t pipe_handle, 1294 uchar_t bmRequestType, 1295 uchar_t bRequest, 1296 uint16_t wValue, 1297 uint16_t wIndex, 1298 uint16_t wLength, 1299 mblk_t **data, 1300 usb_req_attrs_t attributes, 1301 usb_cr_t *completion_reason, 1302 usb_cb_flags_t *cb_flags, 1303 usb_flags_t flags) 1304 { 1305 usba_pipe_handle_data_t *ph_data; 1306 int rval; 1307 usb_ctrl_req_t *ctrl_req; 1308 size_t length; 1309 #ifdef DEBUG 1310 #define BUFSIZE 256 1311 char *buf = kmem_alloc(BUFSIZE, KM_SLEEP); 1312 #endif 1313 1314 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1315 "usb_pipe_sync_ctrl_xfer: ph=0x%p\n\t" 1316 "setup = 0x%x 0x%x 0x%x 0x%x 0x%x uf = 0x%x", (void *)pipe_handle, 1317 bmRequestType, bRequest, wValue, wIndex, wLength, flags); 1318 1319 if ((ph_data = usba_hold_ph_data(pipe_handle)) == NULL) { 1320 rval = USB_INVALID_PIPE; 1321 1322 goto done; 1323 } 1324 if (servicing_interrupt()) { 1325 rval = USB_INVALID_CONTEXT; 1326 1327 goto done; 1328 } 1329 if (dip == NULL) { 1330 rval = USB_INVALID_ARGS; 1331 1332 goto done; 1333 } 1334 1335 length = ((data) && (*data)) ? 0: wLength; 1336 1337 ctrl_req = usb_alloc_ctrl_req(dip, 1338 length, flags | USB_FLAGS_SLEEP); 1339 1340 /* Initialize the ctrl_req structure */ 1341 ctrl_req->ctrl_bmRequestType = bmRequestType; 1342 ctrl_req->ctrl_bRequest = bRequest; 1343 ctrl_req->ctrl_wValue = wValue; 1344 ctrl_req->ctrl_wIndex = wIndex; 1345 ctrl_req->ctrl_wLength = wLength; 1346 ctrl_req->ctrl_data = ctrl_req->ctrl_data ? 1347 ctrl_req->ctrl_data : ((data) ? *data : NULL); 1348 ctrl_req->ctrl_timeout = USB_PIPE_TIMEOUT; 1349 ctrl_req->ctrl_attributes = attributes | USB_ATTRS_AUTOCLEARING; 1350 1351 /* Issue control xfer to the HCD */ 1352 rval = usb_pipe_ctrl_xfer(pipe_handle, ctrl_req, 1353 flags | USB_FLAGS_SLEEP); 1354 1355 #ifdef DEBUG 1356 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1357 "req=0x%p, cr=%s cb_flags=%s data=0x%p rval=%s", 1358 (void *)ctrl_req, usb_str_cr(ctrl_req->ctrl_completion_reason), 1359 usb_str_cb_flags(ctrl_req->ctrl_cb_flags, buf, BUFSIZE), 1360 (void *)ctrl_req->ctrl_data, usb_str_rval(rval)); 1361 #endif 1362 1363 /* copy back ctrl_req values */ 1364 if (data) { 1365 *data = ctrl_req->ctrl_data; 1366 } 1367 if (completion_reason) { 1368 *completion_reason = ctrl_req->ctrl_completion_reason; 1369 } 1370 if (cb_flags) { 1371 *cb_flags = ctrl_req->ctrl_cb_flags; 1372 } 1373 1374 /* Free up the control request now */ 1375 ctrl_req->ctrl_data = NULL; /* leave to client to free */ 1376 usb_free_ctrl_req(ctrl_req); 1377 1378 done: 1379 #ifdef DEBUG 1380 kmem_free(buf, BUFSIZE); 1381 #endif 1382 if (ph_data) { 1383 usba_release_ph_data(ph_data->p_ph_impl); 1384 } 1385 1386 return (rval); 1387 } 1388 1389 1390 /* 1391 * usb_pipe_ctrl_xfer_wait(): 1392 * Easy-to-use wrapper around usb_pipe_sync_ctrl_xfer. 1393 * 1394 * ARGUMENTS: 1395 * pipe_handle - control pipe pipehandle (obtained via usb_pipe_open()) 1396 * setup - setup descriptor params, attributes 1397 * data - pointer to pointer to data and may be NULL when 1398 * wLength is 0 1399 * completion_reason - completion status. 1400 * cb_flags - request completions flags. 1401 * flags - none. 1402 * 1403 * RETURN VALUES: 1404 * USB_SUCCESS - request successfully executed. 1405 * USB_* - failure 1406 */ 1407 int 1408 usb_pipe_ctrl_xfer_wait( 1409 usb_pipe_handle_t pipe_handle, 1410 usb_ctrl_setup_t *setup, 1411 mblk_t **data, 1412 usb_cr_t *completion_reason, 1413 usb_cb_flags_t *cb_flags, 1414 usb_flags_t flags) 1415 { 1416 return (usb_pipe_sync_ctrl_xfer( 1417 usba_get_dip(pipe_handle), 1418 pipe_handle, 1419 setup->bmRequestType, 1420 setup->bRequest, 1421 setup->wValue, 1422 setup->wIndex, 1423 setup->wLength, 1424 data, 1425 setup->attrs, 1426 completion_reason, 1427 cb_flags, 1428 flags)); 1429 } 1430 1431 1432 /* 1433 * usb_alloc_bulk_req: 1434 * Allocate a usb bulk request + usba_req_wrapper_t 1435 * 1436 * Arguments: 1437 * dip - dev_info_t of the client driver 1438 * len - length of "data" for this bulk request 1439 * flags: 1440 * USB_FLAGS_SLEEP - Sleep if resources are not available 1441 * 1442 * Return Values: 1443 * usb_bulk_req_t on success, NULL on failure 1444 */ 1445 usb_bulk_req_t * 1446 usb_alloc_bulk_req(dev_info_t *dip, 1447 size_t len, 1448 usb_flags_t flags) 1449 { 1450 usb_bulk_req_t *bulk_req = NULL; 1451 usba_req_wrapper_t *wrp; 1452 1453 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1454 "usb_alloc_bulk_req: dip=0x%p wlen=0x%lx flags=0x%x", 1455 (void *)dip, len, flags); 1456 1457 /* Allocate + Initialize the usba_req_wrapper_t structure */ 1458 if (dip && 1459 ((wrp = usba_req_wrapper_alloc(dip, sizeof (*bulk_req), flags)) != 1460 NULL)) { 1461 bulk_req = USBA_WRP2BULK_REQ(wrp); 1462 1463 /* Allocate the usb_bulk_req data mblk */ 1464 if (len) { 1465 if (flags & USB_FLAGS_SLEEP) { 1466 bulk_req->bulk_data = allocb_wait(len, 1467 BPRI_LO, STR_NOSIG, NULL); 1468 } else if ((bulk_req->bulk_data = 1469 allocb(len, BPRI_HI)) == NULL) { 1470 usba_req_wrapper_free(wrp); 1471 bulk_req = NULL; 1472 } 1473 } 1474 1475 } 1476 1477 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1478 "usb_alloc_bulk_req: bulk_req = 0x%p", (void *)bulk_req); 1479 1480 return (bulk_req); 1481 } 1482 1483 1484 /* 1485 * usb_free_bulk_req: 1486 * free USB bulk request + wrapper 1487 * 1488 * Arguments: 1489 * req - pointer to usb_bulk_req_t 1490 */ 1491 void 1492 usb_free_bulk_req(usb_bulk_req_t *req) 1493 { 1494 if (req) { 1495 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1496 "usb_free_bulk_req: req=0x%p", (void *)req); 1497 1498 if (req->bulk_data) { 1499 freemsg(req->bulk_data); 1500 } 1501 usba_req_wrapper_free(USBA_REQ2WRP(req)); 1502 } 1503 } 1504 1505 1506 /* 1507 * Client driver calls this function to issue the bulk xfer to the USBA 1508 * 1509 * Arguments:- 1510 * pipe_handle - bulk pipe handle (obtained via usb_pipe_open() 1511 * req - bulk data xfer request (IN or OUT) 1512 * usb_flags - USB_FLAGS_SLEEP - wait for the request to complete 1513 * 1514 * Return Values: 1515 * USB_SUCCESS - success 1516 * USB_FAILURE - unspecified failure 1517 */ 1518 int 1519 usb_pipe_bulk_xfer(usb_pipe_handle_t pipe_handle, 1520 usb_bulk_req_t *req, 1521 usb_flags_t usb_flags) 1522 { 1523 int rval; 1524 usba_req_wrapper_t *wrp = USBA_REQ2WRP(req); 1525 usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle); 1526 usba_device_t *usba_device; 1527 usb_flags_t wrp_usb_flags; 1528 usb_pipe_state_t pipe_state; 1529 1530 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1531 "usb_pipe_bulk_xfer: req=0x%p uf=0x%x", (void *)req, usb_flags); 1532 1533 if (ph_data == NULL) { 1534 1535 return (USB_INVALID_PIPE); 1536 } 1537 1538 mutex_enter(&ph_data->p_mutex); 1539 usba_device = ph_data->p_usba_device; 1540 1541 if ((rval = usba_check_req(ph_data, (usb_opaque_t)req, usb_flags, 1542 USB_EP_ATTR_BULK)) != USB_SUCCESS) { 1543 mutex_exit(&ph_data->p_mutex); 1544 1545 usba_release_ph_data(ph_data->p_ph_impl); 1546 1547 return (rval); 1548 } 1549 1550 /* we accepted the request */ 1551 ph_data->p_req_count++; 1552 wrp_usb_flags = wrp->wr_usb_flags; 1553 1554 /* Get the current bulk pipe state */ 1555 pipe_state = usba_get_ph_state(ph_data); 1556 1557 /* 1558 * if there is already an active request in the queue 1559 * then just add this request to the queue. 1560 */ 1561 switch (pipe_state) { 1562 case USB_PIPE_STATE_IDLE: 1563 if (ph_data->p_queue.next) { 1564 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1565 "usb_pipe_bulk_xfer: queue request 0x%p", 1566 (void *)req); 1567 1568 usba_add_to_list(&ph_data->p_queue, &wrp->wr_queue); 1569 rval = USB_SUCCESS; 1570 mutex_exit(&ph_data->p_mutex); 1571 } else { 1572 usba_pipe_new_state(ph_data, USB_PIPE_STATE_ACTIVE); 1573 mutex_exit(&ph_data->p_mutex); 1574 1575 /* issue the request to HCD */ 1576 rval = usba_device->usb_hcdi_ops-> 1577 usba_hcdi_pipe_bulk_xfer(ph_data, req, usb_flags); 1578 } 1579 break; 1580 case USB_PIPE_STATE_ACTIVE: 1581 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1582 "usb_pipe_bulk_xfer: queue request 0x%p", (void *)req); 1583 1584 usba_add_to_list(&ph_data->p_queue, &wrp->wr_queue); 1585 rval = USB_SUCCESS; 1586 mutex_exit(&ph_data->p_mutex); 1587 break; 1588 default: 1589 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1590 "usb_pipe_bulk_xfer: pipe state %d", pipe_state); 1591 1592 rval = USB_PIPE_ERROR; 1593 mutex_exit(&ph_data->p_mutex); 1594 break; 1595 } 1596 1597 if (rval != USB_SUCCESS) { 1598 if (req->bulk_completion_reason == USB_CR_OK) { 1599 req->bulk_completion_reason = usba_rval2cr(rval); 1600 } 1601 mutex_enter(&ph_data->p_mutex); 1602 ASSERT(wrp->wr_done == B_FALSE); 1603 ph_data->p_req_count--; 1604 ASSERT(ph_data->p_req_count >= 0); 1605 if ((ph_data->p_req_count == 0) && 1606 (usba_get_ph_state(ph_data) == USB_PIPE_STATE_ACTIVE)) { 1607 usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE); 1608 } 1609 mutex_exit(&ph_data->p_mutex); 1610 } else if (wrp_usb_flags & USBA_WRP_FLAGS_WAIT) { 1611 rval = usba_pipe_sync_wait(ph_data, wrp); 1612 } 1613 1614 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1615 "usb_pipe_bulk_xfer: rval=%d", rval); 1616 1617 usba_release_ph_data(ph_data->p_ph_impl); 1618 1619 return (rval); 1620 } 1621 1622 1623 /* 1624 * usb_pipe_bulk_transfer_size: 1625 * - request HCD to return bulk max transfer data size 1626 * 1627 * Arguments: 1628 * dip - pointer to dev_info_t 1629 * size - pointer to bulk_transfer_size 1630 * 1631 * Return Values: 1632 * USB_SUCCESS - request successfully executed 1633 * USB_FAILURE - request failed 1634 */ 1635 int 1636 usb_pipe_bulk_transfer_size(dev_info_t *dip, 1637 size_t *size) 1638 { 1639 return (usb_pipe_get_max_bulk_transfer_size(dip, size)); 1640 } 1641 1642 1643 int 1644 usb_pipe_get_max_bulk_transfer_size(dev_info_t *dip, 1645 size_t *size) 1646 { 1647 usba_device_t *usba_device; 1648 1649 if ((dip == NULL) || (size == NULL)) { 1650 1651 return (USB_INVALID_ARGS); 1652 } 1653 usba_device = usba_get_usba_device(dip); 1654 1655 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1656 "usb_pipe_bulk_transfer_size: usba_device=0x%p", 1657 (void *)usba_device); 1658 1659 if ((usba_device) && 1660 (usba_device->usb_hcdi_ops->usba_hcdi_bulk_transfer_size)) { 1661 1662 return (usba_device->usb_hcdi_ops-> 1663 usba_hcdi_bulk_transfer_size(usba_device, size)); 1664 } else { 1665 *size = 0; 1666 1667 return (USB_FAILURE); 1668 } 1669 } 1670 1671 1672 /* 1673 * usb_alloc_intr_req: 1674 * Allocate usb interrupt request 1675 * 1676 * Arguments: 1677 * dip - dev_info_t of the client driver 1678 * len - length of "data" for this interrupt request 1679 * flags - 1680 * USB_FLAGS_SLEEP - Sleep if resources are not available 1681 * 1682 * Return Values: 1683 * usb_intr_req_t on success, NULL on failure 1684 */ 1685 usb_intr_req_t * 1686 usb_alloc_intr_req(dev_info_t *dip, 1687 size_t len, 1688 usb_flags_t flags) 1689 { 1690 usb_intr_req_t *intr_req = NULL; 1691 usba_req_wrapper_t *wrp; 1692 1693 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1694 "usb_alloc_intr_req: dip=0x%p, len=0x%lx, flags=0x%x", 1695 (void *)dip, len, flags); 1696 1697 /* Allocate + Initialize the usba_req_wrapper_t structure */ 1698 if ((dip && 1699 (wrp = usba_req_wrapper_alloc(dip, sizeof (*intr_req), flags)) != 1700 NULL)) { 1701 intr_req = (usb_intr_req_t *)USBA_WRP2INTR_REQ(wrp); 1702 1703 /* Allocate the usb_intr_req data mblk */ 1704 if (len) { 1705 if (flags & USB_FLAGS_SLEEP) { 1706 intr_req->intr_data = allocb_wait(len, BPRI_LO, 1707 STR_NOSIG, NULL); 1708 } else if ((intr_req->intr_data = 1709 allocb(len, BPRI_HI)) == NULL) { 1710 usba_req_wrapper_free(wrp); 1711 intr_req = NULL; 1712 } 1713 } 1714 } 1715 1716 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1717 "usb_alloc_intr_req: intr_req=0x%p", (void *)intr_req); 1718 1719 return (intr_req); 1720 } 1721 1722 1723 /* 1724 * usba_hcdi_dup_intr_req: 1725 * create duplicate of interrupt request 1726 * 1727 * Arguments: 1728 * dip - devinfo pointer 1729 * reqp - original requestp pointer 1730 * len - length of "data" for this interrupt request 1731 * flags - 1732 * USB_FLAGS_SLEEP - Sleep if resources are not available 1733 * 1734 * Return Values: 1735 * usb_intr_req_t on success, NULL on failure 1736 */ 1737 usb_intr_req_t * 1738 usba_hcdi_dup_intr_req( 1739 dev_info_t *dip, 1740 usb_intr_req_t *reqp, 1741 size_t len, 1742 usb_flags_t flags) 1743 { 1744 usb_intr_req_t *intr_reqp = NULL; 1745 usba_req_wrapper_t *intr_wrp, *req_wrp; 1746 1747 if (reqp == NULL) { 1748 1749 return (NULL); 1750 } 1751 1752 req_wrp = USBA_REQ2WRP(reqp); 1753 1754 if (((intr_reqp = usb_alloc_intr_req(dip, len, flags)) != NULL)) { 1755 intr_reqp->intr_client_private = reqp->intr_client_private; 1756 intr_reqp->intr_timeout = reqp->intr_timeout; 1757 intr_reqp->intr_attributes = reqp->intr_attributes; 1758 intr_reqp->intr_len = reqp->intr_len; 1759 intr_reqp->intr_cb = reqp->intr_cb; 1760 intr_reqp->intr_exc_cb = reqp->intr_exc_cb; 1761 1762 intr_wrp = USBA_REQ2WRP(intr_reqp); 1763 intr_wrp->wr_dip = req_wrp->wr_dip; 1764 intr_wrp->wr_ph_data = req_wrp->wr_ph_data; 1765 intr_wrp->wr_attrs = req_wrp->wr_attrs; 1766 intr_wrp->wr_usb_flags = req_wrp->wr_usb_flags; 1767 } 1768 1769 return (intr_reqp); 1770 } 1771 1772 1773 /* 1774 * usb_free_intr_req: 1775 * free USB intr request + wrapper 1776 * 1777 * Arguments: 1778 * req - pointer to usb_intr_req_t 1779 */ 1780 void 1781 usb_free_intr_req(usb_intr_req_t *req) 1782 { 1783 if (req) { 1784 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1785 "usb_free_intr_req: req = 0x%p", (void *)req); 1786 1787 if (req->intr_data) { 1788 freemsg(req->intr_data); 1789 } 1790 1791 usba_req_wrapper_free(USBA_REQ2WRP(req)); 1792 } 1793 } 1794 1795 1796 /* 1797 * Client driver calls this function to issue the intr xfer to the USBA 1798 * 1799 * Arguments:- 1800 * pipe_handle - intr pipe handle (obtained via usb_pipe_open() 1801 * req - intr data xfer request (IN or OUT) 1802 * flags - 1803 * USB_FLAGS_SLEEP - wait for the request to complete 1804 * Return Values 1805 * USB_SUCCESS - success 1806 * USB_FAILURE - unspecified failure 1807 */ 1808 int 1809 usb_pipe_intr_xfer(usb_pipe_handle_t pipe_handle, 1810 usb_intr_req_t *req, 1811 usb_flags_t usb_flags) 1812 { 1813 int rval; 1814 usba_req_wrapper_t *wrp = USBA_REQ2WRP(req); 1815 usba_ph_impl_t *ph_impl = (usba_ph_impl_t *)pipe_handle; 1816 usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle); 1817 usba_device_t *usba_device; 1818 uchar_t direction; 1819 usb_flags_t wrp_usb_flags; 1820 usb_pipe_state_t pipe_state; 1821 1822 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1823 "usb_pipe_intr_req: req=0x%p uf=0x%x", 1824 (void *)req, usb_flags); 1825 1826 if (ph_data == NULL) { 1827 1828 return (USB_INVALID_PIPE); 1829 } 1830 usba_device = ph_data->p_usba_device; 1831 direction = ph_data->p_ep.bEndpointAddress & USB_EP_DIR_MASK; 1832 1833 mutex_enter(&ph_data->p_mutex); 1834 if ((rval = usba_check_req(ph_data, (usb_opaque_t)req, usb_flags, 1835 USB_EP_ATTR_INTR)) != USB_SUCCESS) { 1836 mutex_exit(&ph_data->p_mutex); 1837 1838 usba_release_ph_data(ph_data->p_ph_impl); 1839 1840 return (rval); 1841 } 1842 1843 /* Get the current interrupt pipe state */ 1844 pipe_state = usba_get_ph_state(ph_data); 1845 1846 switch (pipe_state) { 1847 case USB_PIPE_STATE_IDLE: 1848 /* 1849 * if the pipe state is in middle of transition, 1850 * i.e. stop polling is in progress, fail any 1851 * attempt to do a start polling 1852 */ 1853 mutex_enter(&ph_impl->usba_ph_mutex); 1854 if (ph_impl->usba_ph_state_changing > 0) { 1855 mutex_exit(&ph_impl->usba_ph_mutex); 1856 1857 mutex_exit(&ph_data->p_mutex); 1858 usba_release_ph_data(ph_data->p_ph_impl); 1859 1860 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 1861 "usb_pipe_intr_req: fail request - " 1862 "stop polling in progress"); 1863 1864 return (USB_FAILURE); 1865 } else { 1866 mutex_exit(&ph_impl->usba_ph_mutex); 1867 usba_pipe_new_state(ph_data, USB_PIPE_STATE_ACTIVE); 1868 } 1869 1870 break; 1871 case USB_PIPE_STATE_ACTIVE: 1872 /* 1873 * If this is interrupt IN pipe and if we are 1874 * already polling, return failure. 1875 */ 1876 if (direction == USB_EP_DIR_IN) { 1877 USB_DPRINTF_L4(DPRINT_MASK_USBAI, 1878 usbai_log_handle, 1879 "usb_pipe_intr_req: already polling"); 1880 1881 mutex_exit(&ph_data->p_mutex); 1882 usba_release_ph_data(ph_data->p_ph_impl); 1883 1884 return (USB_FAILURE); 1885 } 1886 1887 break; 1888 default: 1889 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1890 "usb_pipe_intr_req: pipe state %d", pipe_state); 1891 1892 mutex_exit(&ph_data->p_mutex); 1893 usba_release_ph_data(ph_data->p_ph_impl); 1894 1895 return (USB_PIPE_ERROR); 1896 } 1897 1898 /* we accept the request */ 1899 wrp_usb_flags = wrp->wr_usb_flags; 1900 ph_data->p_req_count++; 1901 1902 mutex_exit(&ph_data->p_mutex); 1903 1904 /* issue the request out */ 1905 if ((rval = usba_device->usb_hcdi_ops->usba_hcdi_pipe_intr_xfer(ph_data, 1906 req, usb_flags)) != USB_SUCCESS) { 1907 1908 /* the request failed, decrement the ref_count */ 1909 if (req->intr_completion_reason == USB_CR_OK) { 1910 req->intr_completion_reason = usba_rval2cr(rval); 1911 } 1912 mutex_enter(&ph_data->p_mutex); 1913 ASSERT(wrp->wr_done == B_FALSE); 1914 ph_data->p_req_count--; 1915 ASSERT(ph_data->p_req_count >= 0); 1916 if ((ph_data->p_req_count == 0) && 1917 (usba_get_ph_state(ph_data) == USB_PIPE_STATE_ACTIVE)) { 1918 usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE); 1919 } 1920 mutex_exit(&ph_data->p_mutex); 1921 1922 /* if sleep specified, wait for completion */ 1923 } else if (wrp_usb_flags & USBA_WRP_FLAGS_WAIT) { 1924 rval = usba_pipe_sync_wait(ph_data, wrp); 1925 } 1926 1927 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1928 "usb_pipe_intr_req: rval=0x%x", rval); 1929 1930 usba_release_ph_data(ph_data->p_ph_impl); 1931 1932 return (rval); 1933 } 1934 1935 1936 /* 1937 * usba_pipe_sync_stop_intr_polling: 1938 * - set up for sync transport, if necessary 1939 * - request HCD to stop polling 1940 * - wait for draining of all callbacks 1941 */ 1942 /*ARGSUSED*/ 1943 static int 1944 usba_pipe_sync_stop_intr_polling(dev_info_t *dip, 1945 usba_ph_impl_t *ph_impl, 1946 usba_pipe_async_req_t *request, 1947 usb_flags_t flags) 1948 { 1949 int rval; 1950 usba_pipe_handle_data_t *ph_data; 1951 usba_device_t *usba_device; 1952 1953 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1954 "usba_pipe_sync_stop_intr_polling: flags=0x%x", flags); 1955 1956 ph_data = usba_get_ph_data((usb_pipe_handle_t)ph_impl); 1957 if (ph_data == NULL) { 1958 usba_release_ph_data(ph_impl); 1959 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 1960 "usba_pipe_sync_stop_intr_polling: pipe closed"); 1961 1962 return (USB_INVALID_PIPE); 1963 } 1964 1965 usba_device = ph_data->p_usba_device; 1966 1967 mutex_enter(&ph_data->p_mutex); 1968 1969 if (usba_get_ph_state(ph_data) == USB_PIPE_STATE_ERROR) { 1970 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 1971 "usba_pipe_sync_stop_intr_polling: pipe error"); 1972 mutex_exit(&ph_data->p_mutex); 1973 1974 usba_release_ph_data(ph_impl); 1975 1976 return (USB_PIPE_ERROR); 1977 } 1978 1979 if (usba_get_ph_state(ph_data) == USB_PIPE_STATE_IDLE) { 1980 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 1981 "usba_pipe_sync_stop_intr_polling: already idle"); 1982 mutex_exit(&ph_data->p_mutex); 1983 1984 usba_release_ph_data(ph_impl); 1985 1986 return (USB_SUCCESS); 1987 } 1988 mutex_exit(&ph_data->p_mutex); 1989 1990 mutex_enter(&ph_impl->usba_ph_mutex); 1991 ph_impl->usba_ph_state_changing++; 1992 mutex_exit(&ph_impl->usba_ph_mutex); 1993 1994 flags |= USB_FLAGS_SLEEP; 1995 1996 for (;;) { 1997 rval = usba_device->usb_hcdi_ops-> 1998 usba_hcdi_pipe_stop_intr_polling(ph_data, flags); 1999 2000 /* 2001 * The host controller has stopped polling of the endpoint. 2002 * Now, drain the callbacks if there are any on the callback 2003 * queue. 2004 */ 2005 if (rval == USB_SUCCESS) { 2006 mutex_enter(&ph_data->p_mutex); 2007 2008 /* 2009 * there is a tiny window that the client driver 2010 * may still have restarted the polling and we 2011 * have to let the stop polling win) 2012 */ 2013 rval = usba_drain_cbs(ph_data, 0, 2014 USB_CR_STOPPED_POLLING); 2015 mutex_exit(&ph_data->p_mutex); 2016 if (rval != USB_SUCCESS) { 2017 2018 continue; 2019 } 2020 } 2021 2022 break; 2023 } 2024 2025 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 2026 "usba_pipe_sync_stop_intr_polling: rval=0x%x", rval); 2027 2028 mutex_enter(&ph_impl->usba_ph_mutex); 2029 ph_impl->usba_ph_state_changing--; 2030 mutex_exit(&ph_impl->usba_ph_mutex); 2031 2032 usba_release_ph_data(ph_impl); 2033 2034 return (rval); 2035 } 2036 2037 2038 /* 2039 * dummy callback function for stop polling 2040 */ 2041 static void 2042 usba_dummy_callback( 2043 usb_pipe_handle_t ph, 2044 usb_opaque_t arg, 2045 int rval, 2046 usb_cb_flags_t flags) 2047 { 2048 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 2049 "usba_dummy_callback: " 2050 "ph=0x%p rval=0x%x flags=0x%x cb_arg=0x%p", 2051 (void *)ph, rval, flags, (void *)arg); 2052 } 2053 2054 2055 /* 2056 * usb_pipe_stop_intr_polling: 2057 * stop polling for interrupt pipe IN data 2058 * The HCD doesn't do a usba_hcdi_cb(). 2059 * It just returns success/failure 2060 * Arguments: 2061 * pipe_handle - pipe handle 2062 * flags - 2063 * USB_FLAGS_SLEEP: wait for completion 2064 */ 2065 void 2066 usb_pipe_stop_intr_polling(usb_pipe_handle_t pipe_handle, 2067 usb_flags_t flags) 2068 { 2069 usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle); 2070 2071 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 2072 "usba_pipe_stop_intr_polling: flags=0x%x", flags); 2073 2074 if (ph_data == NULL) { 2075 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 2076 "usba_pipe_stop_intr_polling: pipe closed"); 2077 2078 return; 2079 } 2080 2081 if ((ph_data->p_ep.bmAttributes & 2082 USB_EP_ATTR_MASK) != USB_EP_ATTR_INTR) { 2083 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 2084 "usba_pipe_stop_intr_polling: wrong pipe type"); 2085 2086 usba_release_ph_data(ph_data->p_ph_impl); 2087 2088 return; 2089 } 2090 2091 if ((ph_data->p_ep.bEndpointAddress & USB_EP_DIR_IN) == 0) { 2092 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 2093 "usba_pipe_stop_intr_polling: wrong pipe direction"); 2094 2095 usba_release_ph_data(ph_data->p_ph_impl); 2096 2097 return; 2098 } 2099 2100 if (servicing_interrupt() && (flags & USB_FLAGS_SLEEP)) { 2101 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 2102 "usba_pipe_stop_intr_polling: invalid context"); 2103 2104 usba_release_ph_data(ph_data->p_ph_impl); 2105 2106 return; 2107 } 2108 2109 (void) usba_pipe_setup_func_call(ph_data->p_dip, 2110 usba_pipe_sync_stop_intr_polling, 2111 (usba_ph_impl_t *)pipe_handle, (usb_opaque_t)flags, 2112 flags, usba_dummy_callback, NULL); 2113 } 2114 2115 2116 /* 2117 * usb_alloc_isoc_req: 2118 * - Allocate usb isochronous resources that includes usb isochronous 2119 * request and array of packet descriptor structures and wrapper. 2120 * 2121 * Arguments: 2122 * dip - dev_info_t of the client driver 2123 * isoc_pkts_count - number of isoc_pkt_descr_t's 2124 * len - length of "data" for this isochronous request 2125 * flags - 2126 * USB_FLAGS_SLEEP - Sleep if resources are not available 2127 * no USB_FLAGS_SLEEP - Don't Sleep if resources are not available 2128 * 2129 * Return Values: 2130 * usb_isoc_req_t on success, NULL on failure 2131 */ 2132 /*ARGSUSED*/ 2133 usb_isoc_req_t * 2134 usb_alloc_isoc_req(dev_info_t *dip, 2135 uint_t isoc_pkts_count, 2136 size_t len, 2137 usb_flags_t flags) 2138 { 2139 usb_isoc_req_t *isoc_req = NULL; 2140 usba_req_wrapper_t *wrp; 2141 size_t length = sizeof (*isoc_req) + 2142 (sizeof (usb_isoc_pkt_descr_t) * isoc_pkts_count); 2143 2144 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 2145 "usb_alloc_isoc_req: dip=0x%p pkt_cnt=%d len=%lu flags=0x%x", 2146 (void *)dip, isoc_pkts_count, len, flags); 2147 2148 /* client needs to set isoc_pks_count */ 2149 if (dip && isoc_pkts_count) { 2150 /* Allocate + Initialize the usba_req_wrapper_t structure */ 2151 if ((wrp = usba_req_wrapper_alloc(dip, length, flags)) != 2152 NULL) { 2153 isoc_req = (usb_isoc_req_t *)USBA_WRP2ISOC_REQ(wrp); 2154 2155 /* Allocate the usb_isoc_req data mblk */ 2156 if (len) { 2157 if ((isoc_req->isoc_data = 2158 allocb(len, BPRI_HI)) == NULL) { 2159 usba_req_wrapper_free(wrp); 2160 isoc_req = NULL; 2161 } 2162 } 2163 } 2164 } 2165 2166 if (isoc_req) { 2167 isoc_req->isoc_pkt_descr = (usb_isoc_pkt_descr_t *) 2168 (((intptr_t)isoc_req) + (sizeof (usb_isoc_req_t))); 2169 2170 /* Initialize all the fields of usb isochronous request */ 2171 isoc_req->isoc_pkts_count = (ushort_t)isoc_pkts_count; 2172 } 2173 2174 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 2175 "usb_alloc_isoc_req: isoc_req = 0x%p", (void *)isoc_req); 2176 2177 return (isoc_req); 2178 } 2179 2180 2181 /* 2182 * usba_hcdi_dup_isoc_req: 2183 * create duplicate of isoc request 2184 * 2185 * Arguments: 2186 * dip - devinfo pointer 2187 * reqp - original request pointer 2188 * len - length of "data" for this isoc request 2189 * flags - 2190 * USB_FLAGS_SLEEP - Sleep if resources are not available 2191 * 2192 * Return Values: 2193 * usb_isoc_req_t on success, NULL on failure 2194 */ 2195 usb_isoc_req_t * 2196 usba_hcdi_dup_isoc_req( 2197 dev_info_t *dip, 2198 usb_isoc_req_t *reqp, 2199 usb_flags_t flags) 2200 { 2201 usb_isoc_req_t *isoc_reqp = NULL; 2202 usba_req_wrapper_t *isoc_wrp, *req_wrp; 2203 ushort_t count; 2204 ushort_t isoc_pkts_count; 2205 size_t length; 2206 2207 if (reqp == NULL) { 2208 2209 return (isoc_reqp); 2210 } 2211 2212 isoc_pkts_count = reqp->isoc_pkts_count; 2213 2214 /* calculate total data length required in original request */ 2215 for (count = length = 0; count < isoc_pkts_count; count++) { 2216 length += reqp->isoc_pkt_descr[count].isoc_pkt_length; 2217 } 2218 2219 req_wrp = USBA_REQ2WRP(reqp); 2220 2221 if (((isoc_reqp = usb_alloc_isoc_req(dip, 2222 isoc_pkts_count, length, flags)) != NULL)) { 2223 isoc_reqp->isoc_frame_no = reqp->isoc_frame_no; 2224 isoc_reqp->isoc_pkts_count = reqp->isoc_pkts_count; 2225 isoc_reqp->isoc_pkts_length = reqp->isoc_pkts_length; 2226 isoc_reqp->isoc_attributes = reqp->isoc_attributes; 2227 isoc_reqp->isoc_client_private = reqp->isoc_client_private; 2228 isoc_reqp->isoc_cb = reqp->isoc_cb; 2229 isoc_reqp->isoc_exc_cb = reqp->isoc_exc_cb; 2230 2231 isoc_wrp = USBA_REQ2WRP(isoc_reqp); 2232 isoc_wrp->wr_dip = req_wrp->wr_dip; 2233 isoc_wrp->wr_ph_data = req_wrp->wr_ph_data; 2234 isoc_wrp->wr_attrs = req_wrp->wr_attrs; 2235 isoc_wrp->wr_usb_flags = req_wrp->wr_usb_flags; 2236 2237 for (count = 0; count < isoc_pkts_count; count++) { 2238 isoc_reqp->isoc_pkt_descr[count].isoc_pkt_length = 2239 reqp->isoc_pkt_descr[count].isoc_pkt_length; 2240 } 2241 } 2242 2243 return (isoc_reqp); 2244 } 2245 2246 2247 /* 2248 * usb_free_isoc_req: 2249 * - Deallocate usb isochronous resources that includes usb isochronous 2250 * request and array of packet descriptor strcutures. 2251 * 2252 * Arguments: 2253 * req - pointer to usb_isoc_req_t 2254 */ 2255 void 2256 usb_free_isoc_req(usb_isoc_req_t *req) 2257 { 2258 if (req) { 2259 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 2260 "usb_free_isoc_req: req=0x%p", (void *)req); 2261 2262 if (req->isoc_data) { 2263 freemsg(req->isoc_data); 2264 } 2265 2266 usba_req_wrapper_free(USBA_REQ2WRP(req)); 2267 } 2268 } 2269 2270 2271 /* 2272 * usb_get_current_frame_number: 2273 * - request HCD to return current usb frame number 2274 * 2275 * Arguments: 2276 * dip - pointer to dev_info_t 2277 * 2278 * Return Values: 2279 * current_frame_number - request successfully executed 2280 * 0 - request failed 2281 */ 2282 usb_frame_number_t 2283 usb_get_current_frame_number(dev_info_t *dip) 2284 { 2285 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 2286 "usb_get_current_frame_number: dip=0x%p", (void *)dip); 2287 2288 if (dip) { 2289 usba_device_t *usba_device = usba_get_usba_device(dip); 2290 usb_frame_number_t frame_number; 2291 2292 if (usba_device->usb_hcdi_ops-> 2293 usba_hcdi_get_current_frame_number) { 2294 2295 if (usba_device->usb_hcdi_ops-> 2296 usba_hcdi_get_current_frame_number(usba_device, 2297 &frame_number) == USB_SUCCESS) { 2298 2299 return (frame_number); 2300 } 2301 } 2302 } 2303 2304 return (0); 2305 } 2306 2307 2308 /* 2309 * usb_get_max_isoc_pkts: 2310 * - request HCD to return maximum isochronous packets per request 2311 * 2312 * Arguments: 2313 * dip - pointer to dev_info_t 2314 * 2315 * Return Values: 2316 * isoc_pkt - request successfully executed 2317 * 0 - request failed 2318 */ 2319 uint_t 2320 usb_get_max_isoc_pkts(dev_info_t *dip) 2321 { 2322 return (usb_get_max_pkts_per_isoc_request(dip)); 2323 } 2324 2325 2326 uint_t 2327 usb_get_max_pkts_per_isoc_request(dev_info_t *dip) 2328 { 2329 if (dip) { 2330 usba_device_t *usba_device = usba_get_usba_device(dip); 2331 uint_t max_isoc_pkts_per_request; 2332 2333 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 2334 "usb_get_max_isoc_pkts: usba_device=0x%p", 2335 (void *)usba_device); 2336 2337 if (usba_device->usb_hcdi_ops->usba_hcdi_get_max_isoc_pkts) { 2338 2339 if (usba_device->usb_hcdi_ops-> 2340 usba_hcdi_get_max_isoc_pkts(usba_device, 2341 &max_isoc_pkts_per_request) == USB_SUCCESS) { 2342 2343 return (max_isoc_pkts_per_request); 2344 } 2345 } 2346 } 2347 2348 return (0); 2349 } 2350 2351 2352 /* 2353 * usb_pipe_isoc_xfer: 2354 * - check for pipe stalled 2355 * - request HCD to transport isoc data asynchronously 2356 * 2357 * Arguments: 2358 * pipe_handle - isoc pipe pipehandle (obtained via usb_pipe_open()) 2359 * req - isochronous request 2360 * 2361 * Return Values: 2362 * USB_SUCCESS - request successfully executed 2363 * USB_FAILURE - request failed 2364 */ 2365 int 2366 usb_pipe_isoc_xfer(usb_pipe_handle_t pipe_handle, 2367 usb_isoc_req_t *req, 2368 usb_flags_t flags) 2369 { 2370 int rval; 2371 usba_req_wrapper_t *wrp = USBA_REQ2WRP(req); 2372 usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle); 2373 usba_device_t *usba_device; 2374 uchar_t direction; 2375 usb_pipe_state_t pipe_state; 2376 2377 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 2378 "usb_pipe_isoc_xfer: flags=0x%x", flags); 2379 2380 if (ph_data == NULL) { 2381 2382 return (USB_INVALID_PIPE); 2383 } 2384 2385 usba_device = ph_data->p_usba_device; 2386 direction = ph_data->p_ep.bEndpointAddress & USB_EP_DIR_MASK; 2387 2388 mutex_enter(&ph_data->p_mutex); 2389 if ((rval = usba_check_req(ph_data, (usb_opaque_t)req, flags, 2390 USB_EP_ATTR_ISOCH)) != USB_SUCCESS) { 2391 mutex_exit(&ph_data->p_mutex); 2392 2393 usba_release_ph_data(ph_data->p_ph_impl); 2394 2395 return (rval); 2396 } 2397 2398 req->isoc_error_count = 0; 2399 2400 /* Get the current isoch pipe state */ 2401 pipe_state = usba_get_ph_state(ph_data); 2402 2403 switch (pipe_state) { 2404 case USB_PIPE_STATE_IDLE: 2405 usba_pipe_new_state(ph_data, USB_PIPE_STATE_ACTIVE); 2406 break; 2407 case USB_PIPE_STATE_ACTIVE: 2408 if (direction == USB_EP_DIR_IN) { 2409 USB_DPRINTF_L4(DPRINT_MASK_USBAI, 2410 usbai_log_handle, 2411 "usb_pipe_isoc_req: already polling"); 2412 2413 mutex_exit(&ph_data->p_mutex); 2414 usba_release_ph_data(ph_data->p_ph_impl); 2415 2416 return (USB_FAILURE); 2417 } 2418 break; 2419 default: 2420 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 2421 "usb_pipe_isoc_req: pipe state %d", pipe_state); 2422 2423 mutex_exit(&ph_data->p_mutex); 2424 usba_release_ph_data(ph_data->p_ph_impl); 2425 2426 return (USB_PIPE_ERROR); 2427 } 2428 2429 /* we accept the request */ 2430 ph_data->p_req_count++; 2431 mutex_exit(&ph_data->p_mutex); 2432 2433 if ((rval = usba_device->usb_hcdi_ops->usba_hcdi_pipe_isoc_xfer( 2434 ph_data, req, flags)) != USB_SUCCESS) { 2435 if (req->isoc_completion_reason == USB_CR_OK) { 2436 req->isoc_completion_reason = usba_rval2cr(rval); 2437 } 2438 mutex_enter(&ph_data->p_mutex); 2439 ASSERT(wrp->wr_done == B_FALSE); 2440 ph_data->p_req_count--; 2441 if ((ph_data->p_req_count == 0) && 2442 (usba_get_ph_state(ph_data) == USB_PIPE_STATE_ACTIVE)) { 2443 usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE); 2444 } 2445 mutex_exit(&ph_data->p_mutex); 2446 } 2447 2448 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 2449 "usb_pipe_isoc_req: rval=%x", rval); 2450 2451 usba_release_ph_data(ph_data->p_ph_impl); 2452 2453 return (rval); 2454 } 2455 2456 2457 /* 2458 * usba_pipe_sync_stop_isoc_polling: 2459 * - set up for sync transport, if necessary 2460 * - request HCD to stop polling 2461 * - wait for draining of all callbacks 2462 * 2463 * Arguments: 2464 * dip - dev_info pointer 2465 * pipe_handle - pointer to pipe handle 2466 * flags - USB_FLAGS_SLEEP: wait for completion 2467 */ 2468 /*ARGSUSED*/ 2469 static int 2470 usba_pipe_sync_stop_isoc_polling(dev_info_t *dip, 2471 usba_ph_impl_t *ph_impl, 2472 usba_pipe_async_req_t *request, 2473 usb_flags_t flags) 2474 { 2475 int rval; 2476 usba_pipe_handle_data_t *ph_data = usba_get_ph_data( 2477 (usb_pipe_handle_t)ph_impl); 2478 usba_device_t *usba_device; 2479 2480 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 2481 "usba_pipe_sync_stop_isoc_polling: uf=0x%x", flags); 2482 2483 if (ph_data == NULL) { 2484 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 2485 "usba_pipe_stop_isoc_polling: pipe closed"); 2486 2487 return (USB_INVALID_PIPE); 2488 } 2489 2490 usba_device = ph_data->p_usba_device; 2491 2492 mutex_enter(&ph_data->p_mutex); 2493 2494 if (usba_get_ph_state(ph_data) == USB_PIPE_STATE_ERROR) { 2495 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 2496 "usba_pipe_sync_stop_isoc_polling: pipe error"); 2497 mutex_exit(&ph_data->p_mutex); 2498 2499 usba_release_ph_data(ph_impl); 2500 2501 return (USB_PIPE_ERROR); 2502 } 2503 2504 if (usba_get_ph_state(ph_data) == USB_PIPE_STATE_IDLE) { 2505 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 2506 "usba_pipe_sync_stop_isoc_polling: already stopped"); 2507 mutex_exit(&ph_data->p_mutex); 2508 2509 usba_release_ph_data(ph_impl); 2510 2511 return (USB_SUCCESS); 2512 } 2513 2514 2515 mutex_exit(&ph_data->p_mutex); 2516 2517 flags |= USB_FLAGS_SLEEP; 2518 2519 for (;;) { 2520 rval = usba_device->usb_hcdi_ops-> 2521 usba_hcdi_pipe_stop_isoc_polling(ph_data, flags); 2522 2523 /* 2524 * The host controller has stopped polling of the endpoint. 2525 * Now, drain the callbacks if there are any on the callback 2526 * queue. 2527 */ 2528 if (rval == USB_SUCCESS) { 2529 mutex_enter(&ph_data->p_mutex); 2530 2531 /* 2532 * there is a tiny window that the client driver 2533 * may still have restarted the polling and we 2534 * let the stop polling win 2535 */ 2536 rval = usba_drain_cbs(ph_data, 0, 2537 USB_CR_STOPPED_POLLING); 2538 mutex_exit(&ph_data->p_mutex); 2539 if (rval != USB_SUCCESS) { 2540 2541 continue; 2542 } 2543 } 2544 2545 break; 2546 } 2547 2548 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 2549 "usba_pipe_sync_stop_isoc_polling: rval=0x%x", rval); 2550 2551 usba_release_ph_data(ph_impl); 2552 2553 return (rval); 2554 } 2555 2556 2557 /* 2558 * usb_pipe_stop_isoc_polling: 2559 * stop polling for isoc IN data 2560 * 2561 * Arguments: 2562 * pipe_handle - pipe handle 2563 * flags - 2564 * USB_FLAGS_SLEEP: wait for completion 2565 */ 2566 void 2567 usb_pipe_stop_isoc_polling(usb_pipe_handle_t pipe_handle, 2568 usb_flags_t flags) 2569 { 2570 usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle); 2571 2572 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 2573 "usba_pipe_stop_isoc_polling: uf=0x%x", flags); 2574 2575 if (ph_data == NULL) { 2576 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 2577 "usba_pipe_stop_isoc_polling: pipe closed"); 2578 2579 return; 2580 } 2581 2582 if ((ph_data->p_ep.bmAttributes & USB_EP_ATTR_MASK) != 2583 USB_EP_ATTR_ISOCH) { 2584 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 2585 "usba_pipe_stop_isoc_polling: wrong pipe type"); 2586 2587 usba_release_ph_data(ph_data->p_ph_impl); 2588 2589 return; 2590 } 2591 if ((ph_data->p_ep.bEndpointAddress & USB_EP_DIR_IN) == 0) { 2592 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 2593 "usba_pipe_stop_isoc_polling: wrong pipe direction"); 2594 2595 usba_release_ph_data(ph_data->p_ph_impl); 2596 2597 return; 2598 } 2599 2600 if (servicing_interrupt() && (flags & USB_FLAGS_SLEEP)) { 2601 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 2602 "usba_pipe_stop_intr_polling: invalid context"); 2603 2604 usba_release_ph_data(ph_data->p_ph_impl); 2605 2606 return; 2607 } 2608 2609 (void) usba_pipe_setup_func_call(ph_data->p_dip, 2610 usba_pipe_sync_stop_isoc_polling, 2611 (usba_ph_impl_t *)pipe_handle, (usb_opaque_t)flags, 2612 flags, usba_dummy_callback, NULL); 2613 } 2614