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