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 */ 25 26 27 /* 28 * USBA: Solaris USB Architecture support 29 * 30 * functions that deal with allocation/free/data_xfers 31 * for the control/bulk/interrupt/isoch pipes: 32 * usb_alloc_ctrl_req() 33 * usb_free_ctrl_req() 34 * usb_pipe_ctrl_xfer() 35 * usb_pipe_sync_ctrl_xfer() 36 * usb_pipe_ctrl_xfer_wait() 37 * 38 * usb_alloc_bulk_req() 39 * usb_free_bulk_req() 40 * usb_pipe_bulk_xfer() 41 * usb_pipe_bulk_transfer_size() 42 * 43 * usb_alloc_intr_req() 44 * usb_free_intr_req() 45 * usb_pipe_intr_xfer() 46 * usb_pipe_stop_intr_polling() 47 * 48 * usb_alloc_isoc_req() 49 * usb_free_isoc_req() 50 * usb_get_current_frame_number() 51 * usb_get_max_isoc_pkts() 52 * usb_pipe_isoc_xfer() 53 * usb_pipe_stop_isoc_polling() 54 * 55 * XXX to do: 56 * update return values where needed 57 * keep track of requests not freed 58 * 59 */ 60 #define USBA_FRAMEWORK 61 #include <sys/usb/usba/usba_impl.h> 62 #include <sys/usb/usba/hcdi_impl.h> 63 #include <sys/strsubr.h> 64 65 /* prototypes */ 66 static int usba_flags_attr_check(usba_pipe_handle_data_t *, 67 usb_req_attrs_t attrs, usb_flags_t); 68 static int _usba_check_req(usba_pipe_handle_data_t *, usb_opaque_t, 69 usb_flags_t, uchar_t); 70 71 /* 72 * usba_check_req: 73 * check pipe, request structure for validity 74 * 75 * Arguments: 76 * ph - pipe handle pointer 77 * req - opaque request pointer 78 * flags - usb flags 79 * 80 * Returns: 81 * USB_SUCCESS - valid request 82 * USB_INVALID_REQUEST - request contains some invalid values 83 * USB_PIPE_ERROR - pipe is in error state 84 * USB_INVALID_CONTEXT - sleep in interrupt context 85 * USB_INVALID_PIPE - zero pipe or wrong pipe 86 */ 87 static int 88 usba_check_req(usba_pipe_handle_data_t *ph_data, usb_opaque_t req, 89 usb_flags_t flags, uchar_t pipe_type) 90 { 91 int rval = _usba_check_req(ph_data, req, flags, pipe_type); 92 93 if (rval != USB_SUCCESS) { 94 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 95 "usba_check_req: ph_data=0x%p req=0x%p flags=0%x rval=%d", 96 (void *)ph_data, (void *)req, flags, rval); 97 } 98 99 return (rval); 100 } 101 102 103 static int 104 _usba_check_req(usba_pipe_handle_data_t *ph_data, usb_opaque_t req, 105 usb_flags_t flags, uchar_t pipe_type) 106 { 107 usb_ctrl_req_t *ctrl_req = (usb_ctrl_req_t *)req; 108 usb_bulk_req_t *bulk_req = (usb_bulk_req_t *)req; 109 usb_intr_req_t *intr_req = (usb_intr_req_t *)req; 110 usb_isoc_req_t *isoc_req = (usb_isoc_req_t *)req; 111 usba_req_wrapper_t *wrp = USBA_REQ2WRP(req); 112 mblk_t *data; 113 usb_cr_t *cr; 114 usb_req_attrs_t attrs; 115 usb_opaque_t cb, exc_cb; 116 uint_t timeout = 0; 117 uchar_t direction = ph_data->p_ep.bEndpointAddress & 118 USB_EP_DIR_MASK; 119 uchar_t ep_attrs = ph_data->p_ep.bmAttributes & 120 USB_EP_ATTR_MASK; 121 int n; 122 123 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 124 "usba_check_req: ph_data=0x%p req=0x%p flags=0x%x", 125 (void *)ph_data, (void *)req, flags); 126 127 if (req == NULL) { 128 129 return (USB_INVALID_ARGS); 130 } 131 132 /* set completion reason first so it specifies an error */ 133 switch (ep_attrs) { 134 case USB_EP_ATTR_CONTROL: 135 cr = &ctrl_req->ctrl_completion_reason; 136 break; 137 case USB_EP_ATTR_BULK: 138 cr = &bulk_req->bulk_completion_reason; 139 break; 140 case USB_EP_ATTR_INTR: 141 cr = &intr_req->intr_completion_reason; 142 break; 143 case USB_EP_ATTR_ISOCH: 144 cr = &isoc_req->isoc_completion_reason; 145 break; 146 } 147 148 *cr = USB_CR_UNSPECIFIED_ERR; 149 150 if (servicing_interrupt() && (flags & USB_FLAGS_SLEEP)) { 151 152 return (USB_INVALID_CONTEXT); 153 } 154 155 if (pipe_type != ep_attrs) { 156 157 return (USB_INVALID_PIPE); 158 } 159 160 /* we must have usba_device and default ph to do autoclearing */ 161 ASSERT(ph_data->p_usba_device); 162 163 if (ph_data->p_usba_device->usb_ph_list[0].usba_ph_data == NULL) { 164 165 return (USB_INVALID_PIPE); 166 } 167 168 /* check if this is a valid request packet, ie. not freed */ 169 if (usba_check_in_list(&(ph_data->p_usba_device->usb_allocated), 170 &wrp->wr_allocated_list) != USB_SUCCESS) { 171 172 return (USB_INVALID_REQUEST); 173 } 174 175 /* copy over some members for easy checking later */ 176 switch (ep_attrs) { 177 case USB_EP_ATTR_CONTROL: 178 ctrl_req->ctrl_cb_flags = USB_CB_NO_INFO; 179 data = ctrl_req->ctrl_data; 180 attrs = ctrl_req->ctrl_attributes; 181 timeout = ctrl_req->ctrl_timeout; 182 cb = (usb_opaque_t)ctrl_req->ctrl_cb; 183 exc_cb = (usb_opaque_t)ctrl_req->ctrl_exc_cb; 184 if (flags & USB_FLAGS_SLEEP) { 185 flags |= USBA_WRP_FLAGS_WAIT; 186 } 187 /* force auto clearing on the default pipe */ 188 if (USBA_IS_DEFAULT_PIPE(ph_data)) { 189 attrs |= USB_ATTRS_AUTOCLEARING; 190 } 191 break; 192 case USB_EP_ATTR_BULK: 193 bulk_req->bulk_cb_flags = USB_CB_NO_INFO; 194 data = bulk_req->bulk_data; 195 attrs = bulk_req->bulk_attributes; 196 timeout = bulk_req->bulk_timeout; 197 cb = (usb_opaque_t)bulk_req->bulk_cb; 198 exc_cb = (usb_opaque_t)bulk_req->bulk_exc_cb; 199 if (flags & USB_FLAGS_SLEEP) { 200 flags |= USBA_WRP_FLAGS_WAIT; 201 } 202 break; 203 case USB_EP_ATTR_INTR: 204 intr_req->intr_cb_flags = USB_CB_NO_INFO; 205 data = intr_req->intr_data; 206 attrs = intr_req->intr_attributes; 207 timeout = intr_req->intr_timeout; 208 cb = (usb_opaque_t)intr_req->intr_cb; 209 exc_cb = (usb_opaque_t)intr_req->intr_exc_cb; 210 if ((flags & USB_FLAGS_SLEEP) && 211 (attrs & USB_ATTRS_ONE_XFER)) { 212 flags |= USBA_WRP_FLAGS_WAIT; 213 } 214 break; 215 case USB_EP_ATTR_ISOCH: 216 isoc_req->isoc_cb_flags = USB_CB_NO_INFO; 217 data = isoc_req->isoc_data; 218 attrs = isoc_req->isoc_attributes; 219 cb = (usb_opaque_t)isoc_req->isoc_cb; 220 exc_cb = (usb_opaque_t)isoc_req->isoc_exc_cb; 221 break; 222 } 223 224 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 225 "usba_check_req: attrs = 0x%x flags=0x%x", attrs, flags); 226 227 /* check flags and attr combinations */ 228 if (usba_flags_attr_check(ph_data, attrs, flags) != 229 USB_SUCCESS) { 230 231 return (USB_INVALID_REQUEST); 232 } 233 234 /* if no sleep, there must be callback ptrs */ 235 if ((flags & USB_FLAGS_SLEEP) == 0) { 236 if (cb == NULL || exc_cb == NULL) { 237 238 return (USB_INVALID_REQUEST); 239 } 240 } 241 242 switch (ep_attrs) { 243 case USB_EP_ATTR_CONTROL: 244 if (ctrl_req->ctrl_wLength && (data == NULL)) { 245 246 return (USB_INVALID_REQUEST); 247 } 248 break; 249 case USB_EP_ATTR_BULK: 250 if ((bulk_req->bulk_len) && (data == NULL)) { 251 252 return (USB_INVALID_REQUEST); 253 } 254 break; 255 case USB_EP_ATTR_INTR: 256 if (direction == USB_EP_DIR_OUT) { 257 if (intr_req->intr_len && data == NULL) { 258 259 return (USB_INVALID_REQUEST); 260 } 261 } 262 263 if (direction == USB_EP_DIR_IN) { 264 if (!(intr_req->intr_attributes & USB_ATTRS_ONE_XFER)) { 265 if (cb == NULL || exc_cb == NULL) { 266 267 return (USB_INVALID_REQUEST); 268 } 269 } 270 if (data != NULL) { 271 272 return (USB_INVALID_REQUEST); 273 } 274 if (!(intr_req->intr_attributes & USB_ATTRS_ONE_XFER) && 275 (timeout > 0)) { 276 277 return (USB_INVALID_REQUEST); 278 } 279 } 280 break; 281 case USB_EP_ATTR_ISOCH: 282 if (direction == USB_EP_DIR_IN) { 283 if (cb == NULL || exc_cb == NULL) { 284 285 return (USB_INVALID_REQUEST); 286 } 287 } 288 289 if (data == NULL) { 290 291 return (USB_INVALID_REQUEST); 292 } 293 294 /* 295 * Since ehci/ohci/uhci use (data->b_wptr - data->b_rptr) as 296 * real isoc_pkts_length, it should be checked. 297 */ 298 if (direction == USB_EP_DIR_OUT) { 299 if ((data->b_wptr - data->b_rptr) <= 0) { 300 301 return (USB_INVALID_REQUEST); 302 } 303 } 304 305 /* special isoc checks */ 306 if ((isoc_req->isoc_pkts_count == 0) || 307 (isoc_req->isoc_pkt_descr == NULL)) { 308 309 return (USB_INVALID_REQUEST); 310 } 311 312 /* check attributes for conflicts, one must be specified */ 313 if (!((isoc_req->isoc_attributes & 314 USB_ATTRS_ISOC_START_FRAME) || 315 (isoc_req->isoc_attributes & USB_ATTRS_ISOC_XFER_ASAP))) { 316 317 return (USB_NO_FRAME_NUMBER); 318 } 319 320 /* both may not be specified */ 321 if ((isoc_req->isoc_attributes & 322 (USB_ATTRS_ISOC_START_FRAME | USB_ATTRS_ISOC_XFER_ASAP)) == 323 (USB_ATTRS_ISOC_START_FRAME | USB_ATTRS_ISOC_XFER_ASAP)) { 324 325 return (USB_NO_FRAME_NUMBER); 326 } 327 328 /* no start frame may be specified for ASAP attribute */ 329 if (((isoc_req->isoc_attributes & USB_ATTRS_ISOC_XFER_ASAP)) && 330 isoc_req->isoc_frame_no) { 331 332 return (USB_INVALID_REQUEST); 333 } 334 335 /* start frame must be specified for START FRAME attribute */ 336 if (((isoc_req->isoc_attributes & 337 USB_ATTRS_ISOC_START_FRAME)) && 338 (isoc_req->isoc_frame_no == 0)) { 339 340 return (USB_NO_FRAME_NUMBER); 341 } 342 343 /* each packet must have initialized pkt length */ 344 for (n = 0; n < isoc_req->isoc_pkts_count; n++) { 345 if (isoc_req->isoc_pkt_descr[n].isoc_pkt_length == 0) { 346 347 return (USB_INVALID_REQUEST); 348 } 349 } 350 break; 351 } 352 353 /* save pipe_handle/attrs/timeout/usb_flags */ 354 wrp->wr_ph_data = ph_data; 355 wrp->wr_usb_flags = flags; 356 wrp->wr_attrs = attrs; 357 358 /* zero some fields in case the request is reused */ 359 wrp->wr_done = B_FALSE; 360 wrp->wr_cr = USB_CR_OK; 361 362 /* this request looks good */ 363 *cr = USB_CR_OK; 364 365 return (USB_SUCCESS); 366 } 367 368 369 /* 370 * Table of invalid flags and attributes values. See "usbai.h" 371 * for a complete table on valid usb_req_attrs_t 372 */ 373 #define X ((uint_t)(-1)) 374 #define OUT USB_EP_DIR_OUT 375 #define IN USB_EP_DIR_IN 376 377 struct flags_attr { 378 uint_t ep_dir; 379 uint_t ep_attr; 380 uint_t usb_flags; /* usb_flags SLEEP or none */ 381 uint_t attrs; 382 } usb_invalid_flags_attrs[] = { 383 { OUT, USB_EP_ATTR_BULK, X, USB_ATTRS_SHORT_XFER_OK }, 384 { OUT, USB_EP_ATTR_INTR, X, USB_ATTRS_SHORT_XFER_OK }, 385 { OUT, USB_EP_ATTR_ISOCH, X, USB_ATTRS_SHORT_XFER_OK }, 386 387 { X, USB_EP_ATTR_CONTROL, X, USB_ATTRS_ISOC_START_FRAME }, 388 { X, USB_EP_ATTR_BULK, X, USB_ATTRS_ISOC_START_FRAME }, 389 { X, USB_EP_ATTR_INTR, X, USB_ATTRS_ISOC_START_FRAME }, 390 391 { X, USB_EP_ATTR_CONTROL, X, USB_ATTRS_ISOC_XFER_ASAP }, 392 { X, USB_EP_ATTR_INTR, X, USB_ATTRS_ISOC_XFER_ASAP }, 393 { OUT, USB_EP_ATTR_INTR, X, USB_ATTRS_ONE_XFER }, 394 { X, USB_EP_ATTR_BULK, X, USB_ATTRS_ISOC_XFER_ASAP }, 395 396 { X, USB_EP_ATTR_CONTROL, X, USB_ATTRS_ONE_XFER }, 397 { X, USB_EP_ATTR_BULK, X, USB_ATTRS_ONE_XFER }, 398 { X, USB_EP_ATTR_ISOCH, X, USB_ATTRS_ONE_XFER }, 399 }; 400 401 #define N_INVALID_FLAGS_ATTRS (sizeof (usb_invalid_flags_attrs))/ \ 402 sizeof (struct flags_attr) 403 404 /* 405 * function to check flags and attribute combinations for a particular pipe 406 * Arguments: 407 * ph - pipe handle pointer 408 * attrs - attributes of the request 409 * flags - usb_flags 410 */ 411 static int 412 usba_flags_attr_check(usba_pipe_handle_data_t *ph_data, 413 usb_req_attrs_t attrs, 414 usb_flags_t flags) 415 { 416 uchar_t i; 417 uchar_t ep_dir = ph_data->p_ep.bEndpointAddress & USB_EP_DIR_MASK; 418 uchar_t ep_attr = ph_data->p_ep.bmAttributes & USB_EP_ATTR_MASK; 419 420 flags &= USB_FLAGS_SLEEP; /* ignore other flags */ 421 422 /* 423 * Do some attributes validation checks here. 424 */ 425 for (i = 0; i < N_INVALID_FLAGS_ATTRS; i++) { 426 if (((ep_dir == usb_invalid_flags_attrs[i].ep_dir) || 427 (usb_invalid_flags_attrs[i].ep_dir == X)) && 428 ((ep_attr == usb_invalid_flags_attrs[i].ep_attr) || 429 (usb_invalid_flags_attrs[i].ep_attr == X)) && 430 ((flags & usb_invalid_flags_attrs[i].usb_flags) || 431 (usb_invalid_flags_attrs[i].usb_flags == X)) && 432 ((attrs & usb_invalid_flags_attrs[i].attrs) || 433 (usb_invalid_flags_attrs[i].attrs == X))) { 434 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 435 "invalid (%d) : flags = 0x%x, attrs = 0x%x", 436 i, flags, attrs); 437 438 return (USB_INVALID_REQUEST); 439 } 440 } 441 442 return (USB_SUCCESS); 443 } 444 445 446 /* 447 * usba_rval2cr: 448 * convert rval to meaningful completion reason 449 * XXX extend completion reasons to get better mapping 450 */ 451 static struct { 452 int rval; 453 usb_cr_t cr; 454 } rval2cr[] = { 455 {USB_SUCCESS, USB_CR_OK}, 456 {USB_FAILURE, USB_CR_UNSPECIFIED_ERR}, 457 {USB_NO_RESOURCES, USB_CR_NO_RESOURCES}, 458 {USB_NO_BANDWIDTH, USB_CR_NO_RESOURCES}, 459 {USB_NOT_SUPPORTED, USB_CR_UNSPECIFIED_ERR}, 460 {USB_PIPE_ERROR, USB_CR_UNSPECIFIED_ERR}, 461 {USB_INVALID_PIPE, USB_CR_UNSPECIFIED_ERR}, 462 {USB_NO_FRAME_NUMBER, USB_CR_UNSPECIFIED_ERR}, 463 {USB_INVALID_START_FRAME, USB_CR_UNSPECIFIED_ERR}, 464 {USB_HC_HARDWARE_ERROR, USB_CR_UNSPECIFIED_ERR}, 465 {USB_INVALID_REQUEST, USB_CR_UNSPECIFIED_ERR}, 466 {USB_INVALID_CONTEXT, USB_CR_UNSPECIFIED_ERR}, 467 {USB_INVALID_VERSION, USB_CR_UNSPECIFIED_ERR}, 468 {USB_INVALID_ARGS, USB_CR_UNSPECIFIED_ERR}, 469 {USB_INVALID_PERM, USB_CR_UNSPECIFIED_ERR}, 470 {USB_BUSY, USB_CR_UNSPECIFIED_ERR}, 471 {0xffff, 0} 472 }; 473 474 usb_cr_t 475 usba_rval2cr(int rval) 476 { 477 int i; 478 479 for (i = 0; rval2cr[i].rval != 0xffff; i++) { 480 if (rval2cr[i].rval == rval) { 481 482 return (rval2cr[i].cr); 483 } 484 } 485 486 return (USB_CR_UNSPECIFIED_ERR); 487 } 488 489 490 /* 491 * usba_start_next_req: 492 * Arguments: 493 * ph_data - pointer to pipe handle 494 * 495 * Currently, only ctrl/bulk requests can be queued 496 */ 497 void 498 usba_start_next_req(usba_pipe_handle_data_t *ph_data) 499 { 500 usb_ctrl_req_t *ctrl_req; 501 usb_bulk_req_t *bulk_req; 502 usba_req_wrapper_t *wrp; 503 uchar_t ep_attrs = ph_data->p_ep.bmAttributes & 504 USB_EP_ATTR_MASK; 505 int rval; 506 usb_pipe_state_t state; 507 508 mutex_enter(&ph_data->p_mutex); 509 switch (ep_attrs) { 510 case USB_EP_ATTR_CONTROL: 511 case USB_EP_ATTR_BULK: 512 switch (usba_get_ph_state(ph_data)) { 513 case USB_PIPE_STATE_IDLE: 514 case USB_PIPE_STATE_CLOSING: 515 516 break; 517 518 default: 519 mutex_exit(&ph_data->p_mutex); 520 521 return; 522 } 523 524 break; 525 case USB_EP_ATTR_ISOCH: 526 case USB_EP_ATTR_INTR: 527 default: 528 mutex_exit(&ph_data->p_mutex); 529 530 return; 531 } 532 533 while ((wrp = (usba_req_wrapper_t *) 534 usba_rm_first_pvt_from_list(&ph_data->p_queue)) != NULL) { 535 536 /* only submit to HCD when idle/active */ 537 538 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 539 "usba_start_next_req: ph_data=0x%p state=%d", 540 (void *)ph_data, usba_get_ph_state(ph_data)); 541 542 if (ep_attrs == USB_EP_ATTR_CONTROL) { 543 ph_data->p_active_cntrl_req_wrp = (usb_opaque_t)wrp; 544 } 545 546 if ((state = usba_get_ph_state(ph_data)) == 547 USB_PIPE_STATE_IDLE) { 548 usba_pipe_new_state(ph_data, USB_PIPE_STATE_ACTIVE); 549 550 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 551 "starting req = 0x%p", 552 (void *)USBA_WRP2CTRL_REQ(wrp)); 553 554 switch (ep_attrs) { 555 case USB_EP_ATTR_CONTROL: 556 mutex_exit(&ph_data->p_mutex); 557 ctrl_req = USBA_WRP2CTRL_REQ(wrp); 558 /* submit to hcd */ 559 rval = ph_data->p_usba_device->usb_hcdi_ops-> 560 usba_hcdi_pipe_ctrl_xfer(ph_data, 561 ctrl_req, wrp->wr_usb_flags); 562 mutex_enter(&ph_data->p_mutex); 563 break; 564 case USB_EP_ATTR_BULK: 565 mutex_exit(&ph_data->p_mutex); 566 bulk_req = USBA_WRP2BULK_REQ(wrp); 567 /* submit to hcd */ 568 rval = ph_data->p_usba_device->usb_hcdi_ops-> 569 usba_hcdi_pipe_bulk_xfer(ph_data, 570 bulk_req, wrp->wr_usb_flags); 571 mutex_enter(&ph_data->p_mutex); 572 break; 573 default: 574 /* there shouldn't be any requests */ 575 rval = USB_FAILURE; 576 break; 577 } 578 579 if (rval != USB_SUCCESS) { 580 mutex_exit(&ph_data->p_mutex); 581 usba_do_req_exc_cb(wrp, 582 usba_rval2cr(rval), 583 USB_CB_SUBMIT_FAILED); 584 mutex_enter(&ph_data->p_mutex); 585 } 586 /* we are done */ 587 break; 588 589 } else { 590 mutex_exit(&ph_data->p_mutex); 591 switch (state) { 592 case USB_PIPE_STATE_CLOSING: 593 usba_do_req_exc_cb(wrp, USB_CR_PIPE_CLOSING, 0); 594 break; 595 case USB_PIPE_STATE_ERROR: 596 default: 597 usba_do_req_exc_cb(wrp, USB_CR_FLUSHED, 0); 598 break; 599 } 600 mutex_enter(&ph_data->p_mutex); 601 } 602 } 603 604 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 605 "usba_start_next_req done: ph_data=0x%p state=%d", (void *)ph_data, 606 usba_get_ph_state(ph_data)); 607 608 mutex_exit(&ph_data->p_mutex); 609 } 610 611 612 /* 613 * usba_req_wrapper_alloc: 614 * Allocate + Initialize a usba_req_wrapper_t 615 * 616 * Arguments: 617 * dip - dev_info_t of the client driver 618 * req_len - sizeof request 619 * flags - 620 * USB_FLAGS_SLEEP - Sleep if resources are not available 621 * no USB_FLAGS_SLEEP - Don't Sleep if resources are not available 622 * 623 * Return Values: 624 * pointer to usba_req_wrapper_t on success; NULL on failure. 625 * 626 */ 627 static usba_req_wrapper_t * 628 usba_req_wrapper_alloc(dev_info_t *dip, 629 size_t req_len, 630 usb_flags_t flags) 631 { 632 int kmflag; 633 usba_device_t *usba_device = usba_get_usba_device(dip); 634 usba_req_wrapper_t *wrp; 635 size_t wr_length = sizeof (usba_req_wrapper_t) + req_len; 636 ddi_iblock_cookie_t iblock_cookie = 637 usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip)-> 638 hcdi_iblock_cookie; 639 640 if (servicing_interrupt() && (flags & USB_FLAGS_SLEEP)) { 641 642 return (NULL); 643 } 644 645 kmflag = (flags & USB_FLAGS_SLEEP) ? KM_SLEEP : KM_NOSLEEP; 646 647 /* Allocate the usb_{c/b/i/i}_req + usba_req_wrapper_t structure */ 648 if ((wrp = kmem_zalloc(wr_length, kmflag)) != NULL) { 649 wrp->wr_length = wr_length; 650 wrp->wr_dip = dip; 651 wrp->wr_req = (usb_opaque_t)USBA_SETREQ_ADDR(wrp); 652 cv_init(&wrp->wr_cv, NULL, CV_DRIVER, NULL); 653 654 /* initialize mutex for the queue */ 655 usba_init_list(&wrp->wr_queue, (usb_opaque_t)wrp, 656 iblock_cookie); 657 usba_init_list(&wrp->wr_allocated_list, (usb_opaque_t)wrp, 658 iblock_cookie); 659 660 usba_add_to_list(&usba_device->usb_allocated, 661 &wrp->wr_allocated_list); 662 663 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 664 "usba_req_wrapper_alloc: wrp = 0x%p", (void *)wrp); 665 } 666 667 return (wrp); 668 } 669 670 671 /* 672 * usba_req_wrapper_free: 673 * Frees a usba_req_wrapper_t. Get rid of lists if any. 674 * 675 * Arguments: 676 * wrp: request wrapper structure 677 */ 678 void 679 usba_req_wrapper_free(usba_req_wrapper_t *wrp) 680 { 681 usba_device_t *usba_device; 682 usba_pipe_handle_data_t *ph_data; 683 684 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 685 "usba_req_wrapper_free: wrp=0x%p", (void *)wrp); 686 687 if (wrp) { 688 /* remove from queues */ 689 ph_data = USBA_WRP2PH_DATA(wrp); 690 if (ph_data) { 691 (void) usba_rm_from_list(&ph_data->p_queue, 692 &wrp->wr_queue); 693 } 694 usba_device = usba_get_usba_device(wrp->wr_dip); 695 if (usba_rm_from_list(&usba_device->usb_allocated, 696 &wrp->wr_allocated_list) != USB_SUCCESS) { 697 cmn_err(CE_PANIC, 698 "usba_req_wrapper_free: data corruption"); 699 } 700 usba_destroy_list(&wrp->wr_queue); 701 usba_destroy_list(&wrp->wr_allocated_list); 702 cv_destroy(&wrp->wr_cv); 703 kmem_free(wrp, wrp->wr_length); 704 } 705 } 706 707 708 /* 709 * usba_check_intr_context 710 * Set USB_CB_INTR_CONTEXT callback flag if executing in interrupt context 711 */ 712 usb_cb_flags_t 713 usba_check_intr_context(usb_cb_flags_t cb_flags) 714 { 715 if (servicing_interrupt() != 0) { 716 cb_flags |= USB_CB_INTR_CONTEXT; 717 } 718 719 return (cb_flags); 720 } 721 722 723 /* 724 * usba_req_normal_cb: 725 * perform normal callback depending on request type 726 */ 727 void 728 usba_req_normal_cb(usba_req_wrapper_t *req_wrp) 729 { 730 usba_pipe_handle_data_t *ph_data = req_wrp->wr_ph_data; 731 usb_pipe_handle_t pipe_handle; 732 uint_t direction = ph_data->p_ep.bEndpointAddress & 733 USB_EP_DIR_MASK; 734 usb_pipe_state_t pipe_state; 735 736 pipe_handle = usba_get_pipe_handle(ph_data); 737 738 mutex_enter(&ph_data->p_mutex); 739 ASSERT(ph_data->p_req_count >= 0); 740 pipe_state = usba_get_ph_state(ph_data); 741 742 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 743 "usba_req_normal_cb: " 744 "ph_data=0x%p state=%d wrp=0x%p ref=%d req=%d", 745 (void *)ph_data, pipe_state, (void *)req_wrp, 746 usba_get_ph_ref_count(ph_data), ph_data->p_req_count); 747 748 ASSERT((pipe_state == USB_PIPE_STATE_ACTIVE) || 749 (pipe_state == USB_PIPE_STATE_CLOSING)); 750 751 /* set done to indicate that we will do callback or cv_signal */ 752 ASSERT(req_wrp->wr_done == B_FALSE); 753 req_wrp->wr_done = B_TRUE; 754 755 /* update the pipe state */ 756 switch (req_wrp->wr_ph_data->p_ep.bmAttributes & 757 USB_EP_ATTR_MASK) { 758 case USB_EP_ATTR_CONTROL: 759 case USB_EP_ATTR_BULK: 760 usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE); 761 break; 762 case USB_EP_ATTR_INTR: 763 if ((direction == USB_EP_DIR_IN) && 764 (USBA_WRP2INTR_REQ(req_wrp)->intr_attributes & 765 USB_ATTRS_ONE_XFER)) { 766 usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE); 767 } else if ((direction == USB_EP_DIR_OUT) && 768 (ph_data->p_req_count == 0)) { 769 usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE); 770 } 771 break; 772 case USB_EP_ATTR_ISOCH: 773 if ((ph_data->p_req_count == 0) && 774 (direction == USB_EP_DIR_OUT)) { 775 usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE); 776 } 777 break; 778 } 779 780 781 /* now complete the request */ 782 if (req_wrp->wr_usb_flags & USBA_WRP_FLAGS_WAIT) { 783 ph_data->p_active_cntrl_req_wrp = NULL; 784 cv_signal(&req_wrp->wr_cv); 785 mutex_exit(&ph_data->p_mutex); 786 } else { 787 mutex_exit(&ph_data->p_mutex); 788 789 /* This sets USB_CB_INTR_CONTEXT as needed. */ 790 usba_req_set_cb_flags(req_wrp, USB_CB_NO_INFO); 791 792 switch (req_wrp->wr_ph_data->p_ep.bmAttributes & 793 USB_EP_ATTR_MASK) { 794 case USB_EP_ATTR_CONTROL: 795 USBA_WRP2CTRL_REQ(req_wrp)->ctrl_cb(pipe_handle, 796 USBA_WRP2CTRL_REQ(req_wrp)); 797 mutex_enter(&ph_data->p_mutex); 798 ph_data->p_active_cntrl_req_wrp = NULL; 799 mutex_exit(&ph_data->p_mutex); 800 break; 801 case USB_EP_ATTR_INTR: 802 USBA_WRP2INTR_REQ(req_wrp)->intr_cb(pipe_handle, 803 USBA_WRP2INTR_REQ(req_wrp)); 804 break; 805 case USB_EP_ATTR_BULK: 806 USBA_WRP2BULK_REQ(req_wrp)->bulk_cb(pipe_handle, 807 USBA_WRP2BULK_REQ(req_wrp)); 808 break; 809 case USB_EP_ATTR_ISOCH: 810 USBA_WRP2ISOC_REQ(req_wrp)->isoc_cb(pipe_handle, 811 USBA_WRP2ISOC_REQ(req_wrp)); 812 break; 813 } 814 } 815 816 /* we are done with this request */ 817 mutex_enter(&ph_data->p_mutex); 818 ph_data->p_req_count--; 819 ASSERT(ph_data->p_req_count >= 0); 820 mutex_exit(&ph_data->p_mutex); 821 } 822 823 824 /* 825 * usba_req_exc_cb: 826 * perform exception cb depending on request type. 827 * ensure the completion reason is non zero 828 */ 829 void 830 usba_req_exc_cb(usba_req_wrapper_t *req_wrp, usb_cr_t cr, 831 usb_cb_flags_t cb_flags) 832 { 833 usba_pipe_handle_data_t *ph_data = req_wrp->wr_ph_data; 834 usb_pipe_handle_t pipe_handle = usba_get_pipe_handle(ph_data); 835 836 mutex_enter(&req_wrp->wr_ph_data->p_mutex); 837 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 838 "usba_req_exc_cb: %s%d: ph_data=0x%p (ep%x) state=%d wrp=0x%p " 839 "ref=%d reqcnt=%d cr=%d", 840 ddi_driver_name(req_wrp->wr_dip), 841 ddi_get_instance(req_wrp->wr_dip), 842 (void *)ph_data, ph_data->p_ep.bEndpointAddress, 843 usba_get_ph_state(ph_data), (void *)req_wrp, 844 usba_get_ph_ref_count(ph_data), ph_data->p_req_count, 845 req_wrp->wr_cr); 846 847 ASSERT(req_wrp->wr_ph_data->p_req_count >= 0); 848 849 usba_req_set_cb_flags(req_wrp, cb_flags); 850 851 /* if there was no CR set already, set it now */ 852 if (req_wrp->wr_cr == USB_CR_OK) { 853 req_wrp->wr_cr = (cr != USB_CR_OK) ? 854 cr : USB_CR_UNSPECIFIED_ERR; 855 } 856 857 ASSERT(req_wrp->wr_done == B_FALSE); 858 req_wrp->wr_done = B_TRUE; 859 860 switch (req_wrp->wr_ph_data->p_ep.bmAttributes & 861 USB_EP_ATTR_MASK) { 862 case USB_EP_ATTR_CONTROL: 863 if (USBA_WRP2CTRL_REQ(req_wrp)-> 864 ctrl_completion_reason == USB_CR_OK) { 865 USBA_WRP2CTRL_REQ(req_wrp)-> 866 ctrl_completion_reason = req_wrp->wr_cr; 867 } 868 break; 869 case USB_EP_ATTR_INTR: 870 if (USBA_WRP2INTR_REQ(req_wrp)-> 871 intr_completion_reason == USB_CR_OK) { 872 USBA_WRP2INTR_REQ(req_wrp)-> 873 intr_completion_reason = req_wrp->wr_cr; 874 } 875 break; 876 case USB_EP_ATTR_BULK: 877 if (USBA_WRP2BULK_REQ(req_wrp)-> 878 bulk_completion_reason == USB_CR_OK) { 879 USBA_WRP2BULK_REQ(req_wrp)-> 880 bulk_completion_reason = req_wrp->wr_cr; 881 } 882 break; 883 case USB_EP_ATTR_ISOCH: 884 if (USBA_WRP2ISOC_REQ(req_wrp)-> 885 isoc_completion_reason == USB_CR_OK) { 886 USBA_WRP2ISOC_REQ(req_wrp)-> 887 isoc_completion_reason = req_wrp->wr_cr; 888 } 889 break; 890 } 891 892 if (req_wrp->wr_usb_flags & USBA_WRP_FLAGS_WAIT) { 893 cv_signal(&req_wrp->wr_cv); 894 if (ph_data->p_active_cntrl_req_wrp == (usb_opaque_t)req_wrp) { 895 ph_data->p_active_cntrl_req_wrp = NULL; 896 } 897 mutex_exit(&ph_data->p_mutex); 898 } else { 899 mutex_exit(&ph_data->p_mutex); 900 switch (req_wrp->wr_ph_data->p_ep.bmAttributes & 901 USB_EP_ATTR_MASK) { 902 case USB_EP_ATTR_CONTROL: 903 USBA_WRP2CTRL_REQ(req_wrp)->ctrl_exc_cb(pipe_handle, 904 USBA_WRP2CTRL_REQ(req_wrp)); 905 mutex_enter(&ph_data->p_mutex); 906 if (ph_data->p_active_cntrl_req_wrp == 907 (usb_opaque_t)req_wrp) { 908 ph_data->p_active_cntrl_req_wrp = NULL; 909 } 910 mutex_exit(&ph_data->p_mutex); 911 break; 912 case USB_EP_ATTR_INTR: 913 USBA_WRP2INTR_REQ(req_wrp)->intr_exc_cb(pipe_handle, 914 USBA_WRP2INTR_REQ(req_wrp)); 915 break; 916 case USB_EP_ATTR_BULK: 917 USBA_WRP2BULK_REQ(req_wrp)->bulk_exc_cb(pipe_handle, 918 USBA_WRP2BULK_REQ(req_wrp)); 919 break; 920 case USB_EP_ATTR_ISOCH: 921 USBA_WRP2ISOC_REQ(req_wrp)->isoc_exc_cb(pipe_handle, 922 USBA_WRP2ISOC_REQ(req_wrp)); 923 break; 924 } 925 } 926 927 /* we are done with this request */ 928 mutex_enter(&ph_data->p_mutex); 929 ph_data->p_req_count--; 930 ASSERT(ph_data->p_req_count >= 0); 931 mutex_exit(&ph_data->p_mutex); 932 } 933 934 935 /* 936 * usba_do_req_exc_cb: 937 * called when flushing requests. rather than calling usba_req_exc_cb() 938 * directly, this function uses usba_hcdi_cb() which ensures callback 939 * order is preserved 940 */ 941 void 942 usba_do_req_exc_cb(usba_req_wrapper_t *req_wrp, usb_cr_t cr, 943 usb_cb_flags_t cb_flags) 944 { 945 req_wrp->wr_cb_flags |= cb_flags; 946 usba_hcdi_cb(req_wrp->wr_ph_data, req_wrp->wr_req, cr); 947 } 948 949 950 /* 951 * usba_req_set_cb_flags: 952 * This function sets the request's callback flags to those stored in the 953 * request wrapper ORed with those received as an argument. Additionally 954 * USB_CB_INTR_CONTEXT is set if called from interrupt context. 955 * 956 * NOTE: The xfer may have succeeded, which client driver can determine 957 * by looking at usb_cr_t 958 */ 959 void 960 usba_req_set_cb_flags(usba_req_wrapper_t *req_wrp, 961 usb_cb_flags_t cb_flags) 962 { 963 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 964 "usba_req_set_cb_flags: wrp=0x%p cb-flags=0x%x", 965 (void *)req_wrp, cb_flags); 966 967 cb_flags |= req_wrp->wr_cb_flags; 968 cb_flags = usba_check_intr_context(cb_flags); 969 970 /* do the callback under taskq context */ 971 switch (req_wrp->wr_ph_data->p_ep.bmAttributes & 972 USB_EP_ATTR_MASK) { 973 case USB_EP_ATTR_CONTROL: 974 USBA_WRP2CTRL_REQ(req_wrp)->ctrl_cb_flags |= cb_flags; 975 break; 976 case USB_EP_ATTR_INTR: 977 USBA_WRP2INTR_REQ(req_wrp)->intr_cb_flags |= cb_flags; 978 break; 979 case USB_EP_ATTR_BULK: 980 USBA_WRP2BULK_REQ(req_wrp)->bulk_cb_flags |= cb_flags; 981 break; 982 case USB_EP_ATTR_ISOCH: 983 USBA_WRP2ISOC_REQ(req_wrp)->isoc_cb_flags |= cb_flags; 984 break; 985 } 986 } 987 988 989 /* 990 * usba_pipe_sync_wait: 991 * wait for the request to finish. 992 * usba_hcdi_cb() does a cv_signal thru a soft intr 993 * 994 * Arguments: 995 * ph_data - pointer to pipe handle data 996 * wrp - pointer to usba_req_wrapper_structure. 997 * 998 * Return Values: 999 * USB_SUCCESS - request successfully executed 1000 * USB_FAILURE - request failed 1001 */ 1002 static int 1003 usba_pipe_sync_wait(usba_pipe_handle_data_t *ph_data, 1004 usba_req_wrapper_t *wrp) 1005 { 1006 ASSERT(wrp->wr_usb_flags & USB_FLAGS_SLEEP); 1007 ASSERT(ph_data == wrp->wr_ph_data); 1008 1009 mutex_enter(&ph_data->p_mutex); 1010 while (wrp->wr_done != B_TRUE) { 1011 cv_wait(&wrp->wr_cv, &ph_data->p_mutex); 1012 } 1013 1014 mutex_exit(&ph_data->p_mutex); 1015 1016 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1017 "usba_pipe_sync_wait: ph_data=0x%p cr=0x%x", (void *)ph_data, 1018 wrp->wr_cr); 1019 1020 /* XXX return something better than USB_FAILURE?? */ 1021 1022 return (wrp->wr_cr == USB_CR_OK ? USB_SUCCESS : USB_FAILURE); 1023 } 1024 1025 1026 /* 1027 * Allocate usb control request and a USB request wrapper 1028 * 1029 * Arguments: 1030 * dip - dev_info_t of the client driver 1031 * len - length of "data" for this control request 1032 * flags: 1033 * USB_FLAGS_SLEEP - Sleep if resources are not available 1034 * no USB_FLAGS_SLEEP - Don't Sleep if resources are not available 1035 * 1036 * Return Values: usb_ctrl_req_t on success, NULL on failure 1037 */ 1038 usb_ctrl_req_t * 1039 usb_alloc_ctrl_req(dev_info_t *dip, 1040 size_t len, 1041 usb_flags_t flags) 1042 { 1043 usb_ctrl_req_t *ctrl_req = NULL; 1044 usba_req_wrapper_t *wrp; 1045 1046 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1047 "usb_alloc_ctrl_req: dip=0x%p, wlen=0x%lx, flags=0x%x", 1048 (void *)dip, len, flags); 1049 1050 /* Allocate + Initialize the usba_req_wrapper_t structure */ 1051 if (dip && 1052 ((wrp = usba_req_wrapper_alloc(dip, sizeof (*ctrl_req), flags)) != 1053 NULL)) { 1054 ctrl_req = USBA_WRP2CTRL_REQ(wrp); 1055 1056 /* Allocate the usb_ctrl_req data mblk */ 1057 if (len) { 1058 if (flags & USB_FLAGS_SLEEP) { 1059 ctrl_req->ctrl_data = allocb_wait(len, BPRI_LO, 1060 STR_NOSIG, NULL); 1061 } else if ((ctrl_req->ctrl_data = 1062 allocb(len, BPRI_HI)) == NULL) { 1063 usba_req_wrapper_free(wrp); 1064 ctrl_req = NULL; 1065 } 1066 } 1067 } 1068 1069 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1070 "usb_alloc_ctrl_req: ctrl_req = 0x%p", (void *)ctrl_req); 1071 1072 return (ctrl_req); 1073 } 1074 1075 1076 /* 1077 * usb_free_ctrl_req: 1078 * free USB control request + wrapper 1079 * 1080 * Arguments: 1081 * req - pointer to usb_ctrl_req_t 1082 */ 1083 void 1084 usb_free_ctrl_req(usb_ctrl_req_t *req) 1085 { 1086 if (req) { 1087 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1088 "usb_free_ctrl_req: req = 0x%p", (void *)req); 1089 1090 if (req->ctrl_data) { 1091 freemsg(req->ctrl_data); 1092 } 1093 usba_req_wrapper_free(USBA_REQ2WRP(req)); 1094 } 1095 } 1096 1097 1098 /* 1099 * Client driver calls this function to issue the control 1100 * request to the USBA 1101 * 1102 * Arguments: 1103 * pipe_handle: control pipe pipehandle (obtained via usb_pipe_open() 1104 * req: control request 1105 * usb_flags: 1106 * USB_FLAGS_SLEEP - wait for the request to complete 1107 * 1108 * Return Values: 1109 * USB_SUCCESS - request successfully executed 1110 * USB_FAILURE - request failed 1111 */ 1112 int 1113 usb_pipe_ctrl_xfer(usb_pipe_handle_t pipe_handle, 1114 usb_ctrl_req_t *req, 1115 usb_flags_t usb_flags) 1116 { 1117 int rval; 1118 usba_req_wrapper_t *wrp = USBA_REQ2WRP(req); 1119 usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle); 1120 usba_device_t *usba_device; 1121 usb_flags_t wrp_usb_flags; 1122 usb_pipe_state_t pipe_state; 1123 1124 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1125 "usb_pipe_ctrl_xfer: req=0x%p, wrp=0x%p\n\t" 1126 "setup = 0x%x 0x%x 0x%x 0x%x 0x%x uf=0x%x", 1127 (void *)req, (void *)wrp, req->ctrl_bmRequestType, 1128 req->ctrl_bRequest, req->ctrl_wValue, req->ctrl_wIndex, 1129 req->ctrl_wLength, usb_flags); 1130 1131 if (ph_data == NULL) { 1132 1133 return (USB_INVALID_PIPE); 1134 } 1135 1136 mutex_enter(&ph_data->p_mutex); 1137 usba_device = ph_data->p_usba_device; 1138 1139 if ((rval = usba_check_req(ph_data, (usb_opaque_t)req, usb_flags, 1140 USB_EP_ATTR_CONTROL)) != USB_SUCCESS) { 1141 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 1142 "request rejected: rval=%d", rval); 1143 mutex_exit(&ph_data->p_mutex); 1144 1145 usba_release_ph_data(ph_data->p_ph_impl); 1146 1147 return (rval); 1148 } 1149 1150 ASSERT(ph_data == wrp->wr_ph_data); 1151 1152 /* we accepted the request, so increment the req count */ 1153 ph_data->p_req_count++; 1154 1155 wrp_usb_flags = wrp->wr_usb_flags; 1156 1157 /* Get the current bulk pipe state */ 1158 pipe_state = usba_get_ph_state(ph_data); 1159 1160 /* 1161 * if this is for the default pipe, and the pipe is in error, 1162 * just queue the request. autoclearing will start this request 1163 * 1164 * if there is already an active request in the queue 1165 * then just add this request to the queue. 1166 */ 1167 switch (pipe_state) { 1168 case USB_PIPE_STATE_IDLE: 1169 if (ph_data->p_queue.next || 1170 ph_data->p_active_cntrl_req_wrp) { 1171 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1172 "usb_pipe_ctrl_xfer: queue request 0x%p", 1173 (void *)req); 1174 1175 usba_add_to_list(&ph_data->p_queue, &wrp->wr_queue); 1176 rval = USB_SUCCESS; 1177 mutex_exit(&ph_data->p_mutex); 1178 } else { 1179 usba_pipe_new_state(ph_data, USB_PIPE_STATE_ACTIVE); 1180 ph_data->p_active_cntrl_req_wrp = (usb_opaque_t)wrp; 1181 mutex_exit(&ph_data->p_mutex); 1182 1183 /* issue the request to HCD */ 1184 rval = usba_device->usb_hcdi_ops-> 1185 usba_hcdi_pipe_ctrl_xfer(ph_data, req, usb_flags); 1186 } 1187 break; 1188 case USB_PIPE_STATE_ACTIVE: 1189 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1190 "usb_pipe_ctrl_xfer: queue request 0x%p", (void *)req); 1191 1192 usba_add_to_list(&ph_data->p_queue, &wrp->wr_queue); 1193 rval = USB_SUCCESS; 1194 mutex_exit(&ph_data->p_mutex); 1195 break; 1196 case USB_PIPE_STATE_ERROR: 1197 if (USBA_IS_DEFAULT_PIPE(ph_data)) { 1198 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1199 "usb_pipe_ctrl_xfer: queue request 0x%p on " 1200 "pending def pipe error", (void *)req); 1201 1202 usba_add_to_list(&ph_data->p_queue, &wrp->wr_queue); 1203 rval = USB_SUCCESS; 1204 } else { 1205 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1206 "usb_pipe_ctrl_xfer: pipe is in error state "); 1207 1208 rval = USB_PIPE_ERROR; 1209 } 1210 mutex_exit(&ph_data->p_mutex); 1211 break; 1212 default: 1213 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1214 "usb_pipe_ctrl_xfer: pipe state %d", pipe_state); 1215 1216 rval = USB_PIPE_ERROR; 1217 mutex_exit(&ph_data->p_mutex); 1218 break; 1219 } 1220 1221 /* if there has been a failure, decrement req count */ 1222 if (rval != USB_SUCCESS) { 1223 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 1224 "usb_pipe_ctrl_xfer: hcd failed req 0x%p", (void *)req); 1225 1226 if (req->ctrl_completion_reason == USB_CR_OK) { 1227 req->ctrl_completion_reason = usba_rval2cr(rval); 1228 } 1229 mutex_enter(&ph_data->p_mutex); 1230 ASSERT(wrp->wr_done == B_FALSE); 1231 ph_data->p_req_count--; 1232 ASSERT(ph_data->p_req_count >= 0); 1233 ph_data->p_active_cntrl_req_wrp = NULL; 1234 if ((ph_data->p_req_count == 0) && 1235 (usba_get_ph_state(ph_data) == USB_PIPE_STATE_ACTIVE)) { 1236 usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE); 1237 } 1238 mutex_exit(&ph_data->p_mutex); 1239 1240 /* if success and sleep specified, wait for completion */ 1241 } else if (wrp_usb_flags & USBA_WRP_FLAGS_WAIT) { 1242 rval = usba_pipe_sync_wait(ph_data, wrp); 1243 } 1244 1245 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1246 "usb_pipe_ctrl_xfer: rval=0x%x", rval); 1247 1248 usba_release_ph_data(ph_data->p_ph_impl); 1249 1250 return (rval); 1251 } 1252 1253 1254 /* 1255 * usb_pipe_sync_ctrl_xfer(): 1256 * for simple synchronous control transactions this wrapper function 1257 * will perform the allocation, xfer, and deallocation 1258 * USB_ATTRS_AUTOCLEARING will be enabled 1259 * 1260 * Arguments: 1261 * dip - pointer to clients devinfo 1262 * pipe_handle - control pipe pipehandle (obtained via usb_pipe_open() 1263 * bmRequestType - characteristics of request 1264 * bRequest - specific request 1265 * wValue - varies according to request 1266 * wIndex - index or offset 1267 * wLength - number of bytes to xfer 1268 * data - pointer to pointer to data and may be NULL if 1269 * wLength is 0 1270 * attrs - required request attributes 1271 * completion_reason - completion status 1272 * cb_flags - request completions flags 1273 * flags - none 1274 * 1275 * Return Values: 1276 * USB_SUCCESS - request successfully executed 1277 * USB_* - request failed 1278 * 1279 * Notes: 1280 * - in the case of failure, the client should check completion_reason and 1281 * and cb_flags and determine further recovery action 1282 * - the client should check data and if non-zero, free the data on 1283 * completion 1284 */ 1285 int 1286 usb_pipe_sync_ctrl_xfer(dev_info_t *dip, 1287 usb_pipe_handle_t pipe_handle, 1288 uchar_t bmRequestType, 1289 uchar_t bRequest, 1290 uint16_t wValue, 1291 uint16_t wIndex, 1292 uint16_t wLength, 1293 mblk_t **data, 1294 usb_req_attrs_t attributes, 1295 usb_cr_t *completion_reason, 1296 usb_cb_flags_t *cb_flags, 1297 usb_flags_t flags) 1298 { 1299 usba_pipe_handle_data_t *ph_data; 1300 int rval; 1301 usb_ctrl_req_t *ctrl_req; 1302 size_t length; 1303 #ifdef DEBUG 1304 #define BUFSIZE 256 1305 char *buf = kmem_alloc(BUFSIZE, KM_SLEEP); 1306 #endif 1307 1308 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1309 "usb_pipe_sync_ctrl_xfer: ph=0x%p\n\t" 1310 "setup = 0x%x 0x%x 0x%x 0x%x 0x%x uf = 0x%x", (void *)pipe_handle, 1311 bmRequestType, bRequest, wValue, wIndex, wLength, flags); 1312 1313 if ((ph_data = usba_hold_ph_data(pipe_handle)) == NULL) { 1314 rval = USB_INVALID_PIPE; 1315 1316 goto done; 1317 } 1318 if (servicing_interrupt()) { 1319 rval = USB_INVALID_CONTEXT; 1320 1321 goto done; 1322 } 1323 if (dip == NULL) { 1324 rval = USB_INVALID_ARGS; 1325 1326 goto done; 1327 } 1328 1329 length = ((data) && (*data)) ? 0: wLength; 1330 1331 ctrl_req = usb_alloc_ctrl_req(dip, 1332 length, flags | USB_FLAGS_SLEEP); 1333 1334 /* Initialize the ctrl_req structure */ 1335 ctrl_req->ctrl_bmRequestType = bmRequestType; 1336 ctrl_req->ctrl_bRequest = bRequest; 1337 ctrl_req->ctrl_wValue = wValue; 1338 ctrl_req->ctrl_wIndex = wIndex; 1339 ctrl_req->ctrl_wLength = wLength; 1340 ctrl_req->ctrl_data = ctrl_req->ctrl_data ? 1341 ctrl_req->ctrl_data : ((data) ? *data : NULL); 1342 ctrl_req->ctrl_timeout = USB_PIPE_TIMEOUT; 1343 ctrl_req->ctrl_attributes = attributes | USB_ATTRS_AUTOCLEARING; 1344 1345 /* Issue control xfer to the HCD */ 1346 rval = usb_pipe_ctrl_xfer(pipe_handle, ctrl_req, 1347 flags | USB_FLAGS_SLEEP); 1348 1349 #ifdef DEBUG 1350 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1351 "req=0x%p, cr=%s cb_flags=%s data=0x%p rval=%s", 1352 (void *)ctrl_req, usb_str_cr(ctrl_req->ctrl_completion_reason), 1353 usb_str_cb_flags(ctrl_req->ctrl_cb_flags, buf, BUFSIZE), 1354 (void *)ctrl_req->ctrl_data, usb_str_rval(rval)); 1355 #endif 1356 1357 /* copy back ctrl_req values */ 1358 if (data) { 1359 *data = ctrl_req->ctrl_data; 1360 } 1361 if (completion_reason) { 1362 *completion_reason = ctrl_req->ctrl_completion_reason; 1363 } 1364 if (cb_flags) { 1365 *cb_flags = ctrl_req->ctrl_cb_flags; 1366 } 1367 1368 /* Free up the control request now */ 1369 ctrl_req->ctrl_data = NULL; /* leave to client to free */ 1370 usb_free_ctrl_req(ctrl_req); 1371 1372 done: 1373 #ifdef DEBUG 1374 kmem_free(buf, BUFSIZE); 1375 #endif 1376 if (ph_data) { 1377 usba_release_ph_data(ph_data->p_ph_impl); 1378 } 1379 1380 return (rval); 1381 } 1382 1383 1384 /* 1385 * usb_pipe_ctrl_xfer_wait(): 1386 * Easy-to-use wrapper around usb_pipe_sync_ctrl_xfer. 1387 * 1388 * ARGUMENTS: 1389 * pipe_handle - control pipe pipehandle (obtained via usb_pipe_open()) 1390 * setup - setup descriptor params, attributes 1391 * data - pointer to pointer to data and may be NULL when 1392 * wLength is 0 1393 * completion_reason - completion status. 1394 * cb_flags - request completions flags. 1395 * flags - none. 1396 * 1397 * RETURN VALUES: 1398 * USB_SUCCESS - request successfully executed. 1399 * USB_* - failure 1400 */ 1401 int 1402 usb_pipe_ctrl_xfer_wait( 1403 usb_pipe_handle_t pipe_handle, 1404 usb_ctrl_setup_t *setup, 1405 mblk_t **data, 1406 usb_cr_t *completion_reason, 1407 usb_cb_flags_t *cb_flags, 1408 usb_flags_t flags) 1409 { 1410 return (usb_pipe_sync_ctrl_xfer( 1411 usba_get_dip(pipe_handle), 1412 pipe_handle, 1413 setup->bmRequestType, 1414 setup->bRequest, 1415 setup->wValue, 1416 setup->wIndex, 1417 setup->wLength, 1418 data, 1419 setup->attrs, 1420 completion_reason, 1421 cb_flags, 1422 flags)); 1423 } 1424 1425 1426 /* 1427 * usb_alloc_bulk_req: 1428 * Allocate a usb bulk request + usba_req_wrapper_t 1429 * 1430 * Arguments: 1431 * dip - dev_info_t of the client driver 1432 * len - length of "data" for this bulk request 1433 * flags: 1434 * USB_FLAGS_SLEEP - Sleep if resources are not available 1435 * 1436 * Return Values: 1437 * usb_bulk_req_t on success, NULL on failure 1438 */ 1439 usb_bulk_req_t * 1440 usb_alloc_bulk_req(dev_info_t *dip, 1441 size_t len, 1442 usb_flags_t flags) 1443 { 1444 usb_bulk_req_t *bulk_req = NULL; 1445 usba_req_wrapper_t *wrp; 1446 1447 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1448 "usb_alloc_bulk_req: dip=0x%p wlen=0x%lx flags=0x%x", 1449 (void *)dip, len, flags); 1450 1451 /* Allocate + Initialize the usba_req_wrapper_t structure */ 1452 if (dip && 1453 ((wrp = usba_req_wrapper_alloc(dip, sizeof (*bulk_req), flags)) != 1454 NULL)) { 1455 bulk_req = USBA_WRP2BULK_REQ(wrp); 1456 1457 /* Allocate the usb_bulk_req data mblk */ 1458 if (len) { 1459 if (flags & USB_FLAGS_SLEEP) { 1460 bulk_req->bulk_data = allocb_wait(len, 1461 BPRI_LO, STR_NOSIG, NULL); 1462 } else if ((bulk_req->bulk_data = 1463 allocb(len, BPRI_HI)) == NULL) { 1464 usba_req_wrapper_free(wrp); 1465 bulk_req = NULL; 1466 } 1467 } 1468 1469 } 1470 1471 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1472 "usb_alloc_bulk_req: bulk_req = 0x%p", (void *)bulk_req); 1473 1474 return (bulk_req); 1475 } 1476 1477 1478 /* 1479 * usb_free_bulk_req: 1480 * free USB bulk request + wrapper 1481 * 1482 * Arguments: 1483 * req - pointer to usb_bulk_req_t 1484 */ 1485 void 1486 usb_free_bulk_req(usb_bulk_req_t *req) 1487 { 1488 if (req) { 1489 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1490 "usb_free_bulk_req: req=0x%p", (void *)req); 1491 1492 if (req->bulk_data) { 1493 freemsg(req->bulk_data); 1494 } 1495 usba_req_wrapper_free(USBA_REQ2WRP(req)); 1496 } 1497 } 1498 1499 1500 /* 1501 * Client driver calls this function to issue the bulk xfer to the USBA 1502 * 1503 * Arguments:- 1504 * pipe_handle - bulk pipe handle (obtained via usb_pipe_open() 1505 * req - bulk data xfer request (IN or OUT) 1506 * usb_flags - USB_FLAGS_SLEEP - wait for the request to complete 1507 * 1508 * Return Values: 1509 * USB_SUCCESS - success 1510 * USB_FAILURE - unspecified failure 1511 */ 1512 int 1513 usb_pipe_bulk_xfer(usb_pipe_handle_t pipe_handle, 1514 usb_bulk_req_t *req, 1515 usb_flags_t usb_flags) 1516 { 1517 int rval; 1518 usba_req_wrapper_t *wrp = USBA_REQ2WRP(req); 1519 usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle); 1520 usba_device_t *usba_device; 1521 usb_flags_t wrp_usb_flags; 1522 usb_pipe_state_t pipe_state; 1523 1524 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1525 "usb_pipe_bulk_xfer: req=0x%p uf=0x%x", (void *)req, usb_flags); 1526 1527 if (ph_data == NULL) { 1528 1529 return (USB_INVALID_PIPE); 1530 } 1531 1532 mutex_enter(&ph_data->p_mutex); 1533 usba_device = ph_data->p_usba_device; 1534 1535 if ((rval = usba_check_req(ph_data, (usb_opaque_t)req, usb_flags, 1536 USB_EP_ATTR_BULK)) != USB_SUCCESS) { 1537 mutex_exit(&ph_data->p_mutex); 1538 1539 usba_release_ph_data(ph_data->p_ph_impl); 1540 1541 return (rval); 1542 } 1543 1544 /* we accepted the request */ 1545 ph_data->p_req_count++; 1546 wrp_usb_flags = wrp->wr_usb_flags; 1547 1548 /* Get the current bulk pipe state */ 1549 pipe_state = usba_get_ph_state(ph_data); 1550 1551 /* 1552 * if there is already an active request in the queue 1553 * then just add this request to the queue. 1554 */ 1555 switch (pipe_state) { 1556 case USB_PIPE_STATE_IDLE: 1557 if (ph_data->p_queue.next) { 1558 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1559 "usb_pipe_bulk_xfer: queue request 0x%p", 1560 (void *)req); 1561 1562 usba_add_to_list(&ph_data->p_queue, &wrp->wr_queue); 1563 rval = USB_SUCCESS; 1564 mutex_exit(&ph_data->p_mutex); 1565 } else { 1566 usba_pipe_new_state(ph_data, USB_PIPE_STATE_ACTIVE); 1567 mutex_exit(&ph_data->p_mutex); 1568 1569 /* issue the request to HCD */ 1570 rval = usba_device->usb_hcdi_ops-> 1571 usba_hcdi_pipe_bulk_xfer(ph_data, req, usb_flags); 1572 } 1573 break; 1574 case USB_PIPE_STATE_ACTIVE: 1575 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1576 "usb_pipe_bulk_xfer: queue request 0x%p", (void *)req); 1577 1578 usba_add_to_list(&ph_data->p_queue, &wrp->wr_queue); 1579 rval = USB_SUCCESS; 1580 mutex_exit(&ph_data->p_mutex); 1581 break; 1582 default: 1583 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1584 "usb_pipe_bulk_xfer: pipe state %d", pipe_state); 1585 1586 rval = USB_PIPE_ERROR; 1587 mutex_exit(&ph_data->p_mutex); 1588 break; 1589 } 1590 1591 if (rval != USB_SUCCESS) { 1592 if (req->bulk_completion_reason == USB_CR_OK) { 1593 req->bulk_completion_reason = usba_rval2cr(rval); 1594 } 1595 mutex_enter(&ph_data->p_mutex); 1596 ASSERT(wrp->wr_done == B_FALSE); 1597 ph_data->p_req_count--; 1598 ASSERT(ph_data->p_req_count >= 0); 1599 if ((ph_data->p_req_count == 0) && 1600 (usba_get_ph_state(ph_data) == USB_PIPE_STATE_ACTIVE)) { 1601 usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE); 1602 } 1603 mutex_exit(&ph_data->p_mutex); 1604 } else if (wrp_usb_flags & USBA_WRP_FLAGS_WAIT) { 1605 rval = usba_pipe_sync_wait(ph_data, wrp); 1606 } 1607 1608 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1609 "usb_pipe_bulk_xfer: rval=%d", rval); 1610 1611 usba_release_ph_data(ph_data->p_ph_impl); 1612 1613 return (rval); 1614 } 1615 1616 1617 /* 1618 * usb_pipe_bulk_transfer_size: 1619 * - request HCD to return bulk max transfer data size 1620 * 1621 * Arguments: 1622 * dip - pointer to dev_info_t 1623 * size - pointer to bulk_transfer_size 1624 * 1625 * Return Values: 1626 * USB_SUCCESS - request successfully executed 1627 * USB_FAILURE - request failed 1628 */ 1629 int 1630 usb_pipe_bulk_transfer_size(dev_info_t *dip, 1631 size_t *size) 1632 { 1633 return (usb_pipe_get_max_bulk_transfer_size(dip, size)); 1634 } 1635 1636 1637 int 1638 usb_pipe_get_max_bulk_transfer_size(dev_info_t *dip, 1639 size_t *size) 1640 { 1641 usba_device_t *usba_device; 1642 1643 if ((dip == NULL) || (size == NULL)) { 1644 1645 return (USB_INVALID_ARGS); 1646 } 1647 usba_device = usba_get_usba_device(dip); 1648 1649 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1650 "usb_pipe_bulk_transfer_size: usba_device=0x%p", 1651 (void *)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 (void *)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", (void *)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", (void *)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 (void *)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 (void *)ph, rval, flags, (void *)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 (void *)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", (void *)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", (void *)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", (void *)dip); 2281 2282 if (dip) { 2283 usba_device_t *usba_device = usba_get_usba_device(dip); 2284 usb_frame_number_t frame_number; 2285 2286 if (usba_device->usb_hcdi_ops-> 2287 usba_hcdi_get_current_frame_number) { 2288 2289 if (usba_device->usb_hcdi_ops-> 2290 usba_hcdi_get_current_frame_number(usba_device, 2291 &frame_number) == USB_SUCCESS) { 2292 2293 return (frame_number); 2294 } 2295 } 2296 } 2297 2298 return (0); 2299 } 2300 2301 2302 /* 2303 * usb_get_max_isoc_pkts: 2304 * - request HCD to return maximum isochronous packets per request 2305 * 2306 * Arguments: 2307 * dip - pointer to dev_info_t 2308 * 2309 * Return Values: 2310 * isoc_pkt - request successfully executed 2311 * 0 - request failed 2312 */ 2313 uint_t 2314 usb_get_max_isoc_pkts(dev_info_t *dip) 2315 { 2316 return (usb_get_max_pkts_per_isoc_request(dip)); 2317 } 2318 2319 2320 uint_t 2321 usb_get_max_pkts_per_isoc_request(dev_info_t *dip) 2322 { 2323 if (dip) { 2324 usba_device_t *usba_device = usba_get_usba_device(dip); 2325 uint_t max_isoc_pkts_per_request; 2326 2327 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 2328 "usb_get_max_isoc_pkts: usba_device=0x%p", 2329 (void *)usba_device); 2330 2331 if (usba_device->usb_hcdi_ops->usba_hcdi_get_max_isoc_pkts) { 2332 2333 if (usba_device->usb_hcdi_ops-> 2334 usba_hcdi_get_max_isoc_pkts(usba_device, 2335 &max_isoc_pkts_per_request) == USB_SUCCESS) { 2336 2337 return (max_isoc_pkts_per_request); 2338 } 2339 } 2340 } 2341 2342 return (0); 2343 } 2344 2345 2346 /* 2347 * usb_pipe_isoc_xfer: 2348 * - check for pipe stalled 2349 * - request HCD to transport isoc data asynchronously 2350 * 2351 * Arguments: 2352 * pipe_handle - isoc pipe pipehandle (obtained via usb_pipe_open()) 2353 * req - isochronous request 2354 * 2355 * Return Values: 2356 * USB_SUCCESS - request successfully executed 2357 * USB_FAILURE - request failed 2358 */ 2359 int 2360 usb_pipe_isoc_xfer(usb_pipe_handle_t pipe_handle, 2361 usb_isoc_req_t *req, 2362 usb_flags_t flags) 2363 { 2364 int rval; 2365 usba_req_wrapper_t *wrp = USBA_REQ2WRP(req); 2366 usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle); 2367 usba_device_t *usba_device; 2368 uchar_t direction; 2369 usb_pipe_state_t pipe_state; 2370 2371 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 2372 "usb_pipe_isoc_xfer: flags=0x%x", flags); 2373 2374 if (ph_data == NULL) { 2375 2376 return (USB_INVALID_PIPE); 2377 } 2378 2379 usba_device = ph_data->p_usba_device; 2380 direction = ph_data->p_ep.bEndpointAddress & USB_EP_DIR_MASK; 2381 2382 mutex_enter(&ph_data->p_mutex); 2383 if ((rval = usba_check_req(ph_data, (usb_opaque_t)req, flags, 2384 USB_EP_ATTR_ISOCH)) != USB_SUCCESS) { 2385 mutex_exit(&ph_data->p_mutex); 2386 2387 usba_release_ph_data(ph_data->p_ph_impl); 2388 2389 return (rval); 2390 } 2391 2392 req->isoc_error_count = 0; 2393 2394 /* Get the current isoch pipe state */ 2395 pipe_state = usba_get_ph_state(ph_data); 2396 2397 switch (pipe_state) { 2398 case USB_PIPE_STATE_IDLE: 2399 usba_pipe_new_state(ph_data, USB_PIPE_STATE_ACTIVE); 2400 break; 2401 case USB_PIPE_STATE_ACTIVE: 2402 if (direction == USB_EP_DIR_IN) { 2403 USB_DPRINTF_L4(DPRINT_MASK_USBAI, 2404 usbai_log_handle, 2405 "usb_pipe_isoc_req: already polling"); 2406 2407 mutex_exit(&ph_data->p_mutex); 2408 usba_release_ph_data(ph_data->p_ph_impl); 2409 2410 return (USB_FAILURE); 2411 } 2412 break; 2413 default: 2414 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 2415 "usb_pipe_isoc_req: pipe state %d", pipe_state); 2416 2417 mutex_exit(&ph_data->p_mutex); 2418 usba_release_ph_data(ph_data->p_ph_impl); 2419 2420 return (USB_PIPE_ERROR); 2421 } 2422 2423 /* we accept the request */ 2424 ph_data->p_req_count++; 2425 mutex_exit(&ph_data->p_mutex); 2426 2427 if ((rval = usba_device->usb_hcdi_ops->usba_hcdi_pipe_isoc_xfer( 2428 ph_data, req, flags)) != USB_SUCCESS) { 2429 if (req->isoc_completion_reason == USB_CR_OK) { 2430 req->isoc_completion_reason = usba_rval2cr(rval); 2431 } 2432 mutex_enter(&ph_data->p_mutex); 2433 ASSERT(wrp->wr_done == B_FALSE); 2434 ph_data->p_req_count--; 2435 if ((ph_data->p_req_count == 0) && 2436 (usba_get_ph_state(ph_data) == USB_PIPE_STATE_ACTIVE)) { 2437 usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE); 2438 } 2439 mutex_exit(&ph_data->p_mutex); 2440 } 2441 2442 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 2443 "usb_pipe_isoc_req: rval=%x", rval); 2444 2445 usba_release_ph_data(ph_data->p_ph_impl); 2446 2447 return (rval); 2448 } 2449 2450 2451 /* 2452 * usba_pipe_sync_stop_isoc_polling: 2453 * - set up for sync transport, if necessary 2454 * - request HCD to stop polling 2455 * - wait for draining of all callbacks 2456 * 2457 * Arguments: 2458 * dip - dev_info pointer 2459 * pipe_handle - pointer to pipe handle 2460 * flags - USB_FLAGS_SLEEP: wait for completion 2461 */ 2462 /*ARGSUSED*/ 2463 static int 2464 usba_pipe_sync_stop_isoc_polling(dev_info_t *dip, 2465 usba_ph_impl_t *ph_impl, 2466 usba_pipe_async_req_t *request, 2467 usb_flags_t flags) 2468 { 2469 int rval; 2470 usba_pipe_handle_data_t *ph_data = usba_get_ph_data( 2471 (usb_pipe_handle_t)ph_impl); 2472 usba_device_t *usba_device; 2473 2474 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 2475 "usba_pipe_sync_stop_isoc_polling: uf=0x%x", flags); 2476 2477 if (ph_data == NULL) { 2478 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 2479 "usba_pipe_stop_isoc_polling: pipe closed"); 2480 2481 return (USB_INVALID_PIPE); 2482 } 2483 2484 usba_device = ph_data->p_usba_device; 2485 2486 mutex_enter(&ph_data->p_mutex); 2487 2488 if (usba_get_ph_state(ph_data) == USB_PIPE_STATE_ERROR) { 2489 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 2490 "usba_pipe_sync_stop_isoc_polling: pipe error"); 2491 mutex_exit(&ph_data->p_mutex); 2492 2493 usba_release_ph_data(ph_impl); 2494 2495 return (USB_PIPE_ERROR); 2496 } 2497 2498 if (usba_get_ph_state(ph_data) == USB_PIPE_STATE_IDLE) { 2499 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 2500 "usba_pipe_sync_stop_isoc_polling: already stopped"); 2501 mutex_exit(&ph_data->p_mutex); 2502 2503 usba_release_ph_data(ph_impl); 2504 2505 return (USB_SUCCESS); 2506 } 2507 2508 2509 mutex_exit(&ph_data->p_mutex); 2510 2511 flags |= USB_FLAGS_SLEEP; 2512 2513 for (;;) { 2514 rval = usba_device->usb_hcdi_ops-> 2515 usba_hcdi_pipe_stop_isoc_polling(ph_data, flags); 2516 2517 /* 2518 * The host controller has stopped polling of the endpoint. 2519 * Now, drain the callbacks if there are any on the callback 2520 * queue. 2521 */ 2522 if (rval == USB_SUCCESS) { 2523 mutex_enter(&ph_data->p_mutex); 2524 2525 /* 2526 * there is a tiny window that the client driver 2527 * may still have restarted the polling and we 2528 * let the stop polling win 2529 */ 2530 rval = usba_drain_cbs(ph_data, 0, 2531 USB_CR_STOPPED_POLLING); 2532 mutex_exit(&ph_data->p_mutex); 2533 if (rval != USB_SUCCESS) { 2534 2535 continue; 2536 } 2537 } 2538 2539 break; 2540 } 2541 2542 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 2543 "usba_pipe_sync_stop_isoc_polling: rval=0x%x", rval); 2544 2545 usba_release_ph_data(ph_impl); 2546 2547 return (rval); 2548 } 2549 2550 2551 /* 2552 * usb_pipe_stop_isoc_polling: 2553 * stop polling for isoc IN data 2554 * 2555 * Arguments: 2556 * pipe_handle - pipe handle 2557 * flags - 2558 * USB_FLAGS_SLEEP: wait for completion 2559 */ 2560 void 2561 usb_pipe_stop_isoc_polling(usb_pipe_handle_t pipe_handle, 2562 usb_flags_t flags) 2563 { 2564 usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle); 2565 2566 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 2567 "usba_pipe_stop_isoc_polling: uf=0x%x", flags); 2568 2569 if (ph_data == NULL) { 2570 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 2571 "usba_pipe_stop_isoc_polling: pipe closed"); 2572 2573 return; 2574 } 2575 2576 if ((ph_data->p_ep.bmAttributes & USB_EP_ATTR_MASK) != 2577 USB_EP_ATTR_ISOCH) { 2578 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 2579 "usba_pipe_stop_isoc_polling: wrong pipe type"); 2580 2581 usba_release_ph_data(ph_data->p_ph_impl); 2582 2583 return; 2584 } 2585 if ((ph_data->p_ep.bEndpointAddress & USB_EP_DIR_IN) == 0) { 2586 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 2587 "usba_pipe_stop_isoc_polling: wrong pipe direction"); 2588 2589 usba_release_ph_data(ph_data->p_ph_impl); 2590 2591 return; 2592 } 2593 2594 if (servicing_interrupt() && (flags & USB_FLAGS_SLEEP)) { 2595 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 2596 "usba_pipe_stop_intr_polling: invalid context"); 2597 2598 usba_release_ph_data(ph_data->p_ph_impl); 2599 2600 return; 2601 } 2602 2603 (void) usba_pipe_setup_func_call(ph_data->p_dip, 2604 usba_pipe_sync_stop_isoc_polling, 2605 (usba_ph_impl_t *)pipe_handle, (usb_opaque_t)flags, 2606 flags, usba_dummy_callback, NULL); 2607 } 2608