1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 27 /* 28 * EHCI Host Controller Driver (EHCI) 29 * 30 * The EHCI driver is a software driver which interfaces to the Universal 31 * Serial Bus layer (USBA) and the Host Controller (HC). The interface to 32 * the Host Controller is defined by the EHCI Host Controller Interface. 33 * 34 * This module contains the EHCI driver isochronous code, which handles all 35 * Checking of status of USB transfers, error recovery and callbacks. 36 */ 37 #include <sys/usb/hcd/ehci/ehcid.h> 38 #include <sys/usb/hcd/ehci/ehci_xfer.h> 39 #include <sys/usb/hcd/ehci/ehci_util.h> 40 #include <sys/usb/hcd/ehci/ehci_isoch.h> 41 #include <sys/usb/hcd/ehci/ehci_isoch_util.h> 42 #include <sys/strsun.h> 43 44 /* 45 * Isochronous initialization functions 46 */ 47 int ehci_isoc_init( 48 ehci_state_t *ehcip); 49 void ehci_isoc_cleanup( 50 ehci_state_t *ehcip); 51 void ehci_isoc_pipe_cleanup( 52 ehci_state_t *ehcip, 53 usba_pipe_handle_data_t *ph); 54 static void ehci_wait_for_isoc_completion( 55 ehci_state_t *ehcip, 56 ehci_pipe_private_t *pp); 57 58 /* 59 * Isochronous request functions 60 */ 61 ehci_isoc_xwrapper_t *ehci_allocate_isoc_resources( 62 ehci_state_t *ehcip, 63 usba_pipe_handle_data_t *ph, 64 usb_isoc_req_t *isoc_reqp, 65 usb_flags_t usb_flags); 66 int ehci_insert_isoc_req( 67 ehci_state_t *ehcip, 68 ehci_pipe_private_t *pp, 69 ehci_isoc_xwrapper_t *itw, 70 usb_flags_t usb_flags); 71 static int ehci_insert_itd_req( 72 ehci_state_t *ehcip, 73 ehci_pipe_private_t *pp, 74 ehci_isoc_xwrapper_t *itw, 75 usb_flags_t usb_flags); 76 static int ehci_insert_sitd_req( 77 ehci_state_t *ehcip, 78 ehci_pipe_private_t *pp, 79 ehci_isoc_xwrapper_t *itw, 80 usb_flags_t usb_flags); 81 static void ehci_remove_isoc_itds( 82 ehci_state_t *ehcip, 83 ehci_pipe_private_t *pp); 84 static void ehci_mark_reclaim_isoc( 85 ehci_state_t *ehcip, 86 ehci_pipe_private_t *pp); 87 static void ehci_reclaim_isoc( 88 ehci_state_t *ehcip, 89 ehci_isoc_xwrapper_t *itw, 90 ehci_itd_t *itd, 91 ehci_pipe_private_t *pp); 92 int ehci_start_isoc_polling( 93 ehci_state_t *ehcip, 94 usba_pipe_handle_data_t *ph, 95 usb_flags_t flags); 96 97 /* 98 * Isochronronous handling functions. 99 */ 100 void ehci_traverse_active_isoc_list( 101 ehci_state_t *ehcip); 102 static void ehci_handle_isoc( 103 ehci_state_t *ehcip, 104 ehci_isoc_xwrapper_t *itw, 105 ehci_itd_t *itd); 106 static void ehci_handle_itd( 107 ehci_state_t *ehcip, 108 ehci_pipe_private_t *pp, 109 ehci_isoc_xwrapper_t *itw, 110 ehci_itd_t *itd, 111 void *tw_handle_callback_value); 112 static void ehci_sendup_itd_message( 113 ehci_state_t *ehcip, 114 ehci_pipe_private_t *pp, 115 ehci_isoc_xwrapper_t *itw, 116 ehci_itd_t *td, 117 usb_cr_t error); 118 void ehci_hcdi_isoc_callback( 119 usba_pipe_handle_data_t *ph, 120 ehci_isoc_xwrapper_t *itw, 121 usb_cr_t completion_reason); 122 123 124 /* 125 * Isochronous initialization functions 126 */ 127 /* 128 * Initialize all the needed resources needed by isochronous pipes. 129 */ 130 int 131 ehci_isoc_init( 132 ehci_state_t *ehcip) 133 { 134 return (ehci_allocate_isoc_pools(ehcip)); 135 } 136 137 138 /* 139 * Cleanup isochronous resources. 140 */ 141 void 142 ehci_isoc_cleanup( 143 ehci_state_t *ehcip) 144 { 145 ehci_isoc_xwrapper_t *itw; 146 ehci_pipe_private_t *pp; 147 ehci_itd_t *itd; 148 int i, ctrl, rval; 149 150 /* Free all the buffers */ 151 if (ehcip->ehci_itd_pool_addr && ehcip->ehci_itd_pool_mem_handle) { 152 for (i = 0; i < ehci_get_itd_pool_size(); i ++) { 153 itd = &ehcip->ehci_itd_pool_addr[i]; 154 ctrl = Get_ITD(ehcip-> 155 ehci_itd_pool_addr[i].itd_state); 156 157 if ((ctrl != EHCI_ITD_FREE) && 158 (ctrl != EHCI_ITD_DUMMY) && 159 (itd->itd_trans_wrapper)) { 160 161 mutex_enter(&ehcip->ehci_int_mutex); 162 163 itw = (ehci_isoc_xwrapper_t *) 164 EHCI_LOOKUP_ID((uint32_t) 165 Get_ITD(itd->itd_trans_wrapper)); 166 167 /* Obtain the pipe private structure */ 168 pp = itw->itw_pipe_private; 169 170 ehci_deallocate_itd(ehcip, itw, itd); 171 ehci_deallocate_itw(ehcip, pp, itw); 172 173 mutex_exit(&ehcip->ehci_int_mutex); 174 } 175 } 176 177 /* 178 * If EHCI_ITD_POOL_BOUND flag is set, then unbind 179 * the handle for ITD pools. 180 */ 181 if ((ehcip->ehci_dma_addr_bind_flag & 182 EHCI_ITD_POOL_BOUND) == EHCI_ITD_POOL_BOUND) { 183 184 rval = ddi_dma_unbind_handle( 185 ehcip->ehci_itd_pool_dma_handle); 186 187 ASSERT(rval == DDI_SUCCESS); 188 } 189 ddi_dma_mem_free(&ehcip->ehci_itd_pool_mem_handle); 190 } 191 192 /* Free the ITD pool */ 193 if (ehcip->ehci_itd_pool_dma_handle) { 194 ddi_dma_free_handle(&ehcip->ehci_itd_pool_dma_handle); 195 } 196 } 197 198 199 /* 200 * ehci_isoc_pipe_cleanup 201 * 202 * Cleanup ehci isoc pipes. 203 */ 204 void ehci_isoc_pipe_cleanup( 205 ehci_state_t *ehcip, 206 usba_pipe_handle_data_t *ph) 207 { 208 ehci_pipe_private_t *pp = (ehci_pipe_private_t *)ph->p_hcd_private; 209 uint_t pipe_state = pp->pp_state; 210 usb_cr_t completion_reason; 211 212 USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 213 "ehci_isoc_pipe_cleanup: ph = 0x%p", (void *)ph); 214 215 ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 216 217 /* Stop all further processing */ 218 ehci_mark_reclaim_isoc(ehcip, pp); 219 220 /* 221 * Wait for processing all completed transfers 222 * and send result upstream/ 223 */ 224 ehci_wait_for_isoc_completion(ehcip, pp); 225 226 /* Go ahead and remove all remaining itds if there are any */ 227 ehci_remove_isoc_itds(ehcip, pp); 228 229 switch (pipe_state) { 230 case EHCI_PIPE_STATE_CLOSE: 231 completion_reason = USB_CR_PIPE_CLOSING; 232 break; 233 case EHCI_PIPE_STATE_RESET: 234 case EHCI_PIPE_STATE_STOP_POLLING: 235 /* Set completion reason */ 236 completion_reason = (pipe_state == 237 EHCI_PIPE_STATE_RESET) ? 238 USB_CR_PIPE_RESET: USB_CR_STOPPED_POLLING; 239 240 /* Set pipe state to idle */ 241 pp->pp_state = EHCI_PIPE_STATE_IDLE; 242 243 break; 244 } 245 246 /* 247 * Do the callback for the original client 248 * periodic IN request. 249 */ 250 if ((ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK) == 251 USB_EP_DIR_IN) { 252 253 ehci_do_client_periodic_in_req_callback( 254 ehcip, pp, completion_reason); 255 } 256 } 257 258 259 /* 260 * ehci_wait_for_transfers_completion: 261 * 262 * Wait for processing all completed transfers and to send results 263 * to upstream. 264 */ 265 static void 266 ehci_wait_for_isoc_completion( 267 ehci_state_t *ehcip, 268 ehci_pipe_private_t *pp) 269 { 270 ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 271 272 if (pp->pp_itw_head == NULL) { 273 274 return; 275 } 276 277 (void) cv_reltimedwait(&pp->pp_xfer_cmpl_cv, &ehcip->ehci_int_mutex, 278 drv_usectohz(EHCI_XFER_CMPL_TIMEWAIT * 1000000), TR_CLOCK_TICK); 279 280 if (pp->pp_itw_head) { 281 USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 282 "ehci_wait_for_isoc_completion: " 283 "No transfers completion confirmation received"); 284 } 285 } 286 287 288 /* 289 * Isochronous request functions 290 */ 291 /* 292 * ehci_allocate_isoc_resources: 293 * 294 * Calculates the number of tds necessary for a isoch transfer, and 295 * allocates all the necessary resources. 296 * 297 * Returns NULL if there is insufficient resources otherwise ITW. 298 */ 299 ehci_isoc_xwrapper_t * 300 ehci_allocate_isoc_resources( 301 ehci_state_t *ehcip, 302 usba_pipe_handle_data_t *ph, 303 usb_isoc_req_t *isoc_reqp, 304 usb_flags_t usb_flags) 305 { 306 ehci_pipe_private_t *pp = (ehci_pipe_private_t *)ph->p_hcd_private; 307 int pipe_dir, i; 308 uint_t max_ep_pkt_size, max_isoc_xfer_size; 309 usb_isoc_pkt_descr_t *isoc_pkt_descr; 310 size_t isoc_pkt_count, isoc_pkts_length; 311 size_t itw_xfer_size = 0; 312 ehci_isoc_xwrapper_t *itw; 313 314 USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 315 "ehci_allocate_isoc_resources: flags = 0x%x", usb_flags); 316 317 ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 318 319 /* 320 * Check whether pipe is in halted state. 321 */ 322 if (pp->pp_state == EHCI_PIPE_STATE_ERROR) { 323 USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 324 "ehci_allocate_isoc_resources:" 325 "Pipe is in error state, need pipe reset to continue"); 326 327 return (NULL); 328 } 329 330 /* Calculate the maximum isochronous transfer size we allow */ 331 max_ep_pkt_size = (ph->p_ep.wMaxPacketSize & 332 EHCI_ITD_CTRL_MAX_PACKET_MASK) * 333 CalculateITDMultiField(ph->p_ep.wMaxPacketSize); 334 335 max_isoc_xfer_size = EHCI_MAX_ISOC_PKTS_PER_XFER * max_ep_pkt_size; 336 337 /* Get the packet descriptor and number of packets to send */ 338 if (isoc_reqp) { 339 isoc_pkt_descr = isoc_reqp->isoc_pkt_descr; 340 isoc_pkt_count = isoc_reqp->isoc_pkts_count; 341 isoc_pkts_length = isoc_reqp->isoc_pkts_length; 342 } else { 343 isoc_pkt_descr = ((usb_isoc_req_t *) 344 pp->pp_client_periodic_in_reqp)->isoc_pkt_descr; 345 346 isoc_pkt_count = ((usb_isoc_req_t *) 347 pp->pp_client_periodic_in_reqp)->isoc_pkts_count; 348 349 isoc_pkts_length = ((usb_isoc_req_t *) 350 pp->pp_client_periodic_in_reqp)->isoc_pkts_length; 351 } 352 353 /* Calculate the size of the transfer. */ 354 pipe_dir = ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK; 355 if (pipe_dir == USB_EP_DIR_IN) { 356 for (i = 0; i < isoc_pkt_count; i++) { 357 /* 358 * isoc_pkt_length is used as Transaction Length and 359 * according to EHCI spec Table 3-3, the maximum value 360 * allowed is 3072 361 */ 362 if (isoc_pkt_descr->isoc_pkt_length > 3072) { 363 364 return (NULL); 365 } 366 367 itw_xfer_size += isoc_pkt_descr->isoc_pkt_length; 368 369 isoc_pkt_descr++; 370 } 371 372 if ((isoc_pkts_length) && 373 (isoc_pkts_length != itw_xfer_size)) { 374 375 USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 376 "ehci_allocate_isoc_resources: " 377 "isoc_pkts_length 0x%lx is not equal to the sum of " 378 "all pkt lengths 0x%lx in an isoc request", 379 isoc_pkts_length, itw_xfer_size); 380 381 return (NULL); 382 } 383 384 } else { 385 ASSERT(isoc_reqp != NULL); 386 itw_xfer_size = MBLKL(isoc_reqp->isoc_data); 387 } 388 389 /* Check the size of isochronous request */ 390 if (itw_xfer_size > max_isoc_xfer_size) { 391 392 USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 393 "ehci_allocate_isoc_resources: Maximum isoc request " 394 "size 0x%x Given isoc request size 0x%lx", 395 max_isoc_xfer_size, itw_xfer_size); 396 397 return (NULL); 398 } 399 400 USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 401 "ehci_allocate_isoc_resources: length = 0x%lx", itw_xfer_size); 402 403 /* Allocate the itw for this request */ 404 if ((itw = ehci_allocate_itw_resources(ehcip, pp, itw_xfer_size, 405 usb_flags, isoc_pkt_count)) == NULL) { 406 407 return (NULL); 408 } 409 410 itw->itw_handle_callback_value = NULL; 411 412 if (pipe_dir == USB_EP_DIR_IN) { 413 if (ehci_allocate_isoc_in_resource(ehcip, pp, itw, usb_flags) != 414 USB_SUCCESS) { 415 416 ehci_deallocate_itw(ehcip, pp, itw); 417 418 return (NULL); 419 } 420 } else { 421 if (itw->itw_length) { 422 ASSERT(isoc_reqp->isoc_data != NULL); 423 424 /* Copy the data into the buffer */ 425 bcopy(isoc_reqp->isoc_data->b_rptr, 426 itw->itw_buf, itw->itw_length); 427 428 Sync_IO_Buffer_for_device(itw->itw_dmahandle, 429 itw->itw_length); 430 } 431 itw->itw_curr_xfer_reqp = isoc_reqp; 432 } 433 434 return (itw); 435 } 436 437 438 /* 439 * ehci_insert_isoc_req: 440 * 441 * Insert an isochronous request into the Host Controller's 442 * isochronous list. 443 */ 444 int 445 ehci_insert_isoc_req( 446 ehci_state_t *ehcip, 447 ehci_pipe_private_t *pp, 448 ehci_isoc_xwrapper_t *itw, 449 usb_flags_t usb_flags) 450 { 451 int error; 452 ehci_itd_t *new_itd, *temp_itd; 453 454 USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 455 "ehci_insert_isoc_req: flags = 0x%x port status = 0x%x", 456 usb_flags, itw->itw_port_status); 457 458 ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 459 460 ASSERT(itw->itw_curr_xfer_reqp != NULL); 461 ASSERT(itw->itw_curr_xfer_reqp->isoc_pkt_descr != NULL); 462 463 /* 464 * Save address of first usb isochronous packet descriptor. 465 */ 466 itw->itw_curr_isoc_pktp = itw->itw_curr_xfer_reqp->isoc_pkt_descr; 467 468 if (itw->itw_port_status == USBA_HIGH_SPEED_DEV) { 469 error = ehci_insert_itd_req(ehcip, pp, itw, usb_flags); 470 } else { 471 error = ehci_insert_sitd_req(ehcip, pp, itw, usb_flags); 472 } 473 474 /* Either all the isocs will be added or none of them will */ 475 error = ehci_insert_isoc_to_pfl(ehcip, pp, itw); 476 477 if (error != USB_SUCCESS) { 478 /* 479 * Deallocate all the ITDs, otherwise they will be 480 * lost forever. 481 */ 482 new_itd = itw->itw_itd_head; 483 while (new_itd) { 484 temp_itd = ehci_itd_iommu_to_cpu(ehcip, 485 Get_ITD(new_itd->itd_itw_next_itd)); 486 ehci_deallocate_itd(ehcip, itw, new_itd); 487 new_itd = temp_itd; 488 } 489 if ((itw->itw_direction == USB_EP_DIR_IN)) { 490 ehci_deallocate_isoc_in_resource(ehcip, pp, itw); 491 492 if (pp->pp_cur_periodic_req_cnt) { 493 /* 494 * Set pipe state to stop polling and 495 * error to no resource. Don't insert 496 * any more isoch polling requests. 497 */ 498 pp->pp_state = 499 EHCI_PIPE_STATE_STOP_POLLING; 500 pp->pp_error = error; 501 } else { 502 /* Set periodic in pipe state to idle */ 503 pp->pp_state = EHCI_PIPE_STATE_IDLE; 504 } 505 506 return (error); 507 } 508 509 /* Save how many packets and data actually went */ 510 itw->itw_num_itds = 0; 511 itw->itw_length = 0; 512 } 513 514 /* 515 * Reset back to the address of first usb isochronous 516 * packet descriptor. 517 */ 518 itw->itw_curr_isoc_pktp = itw->itw_curr_xfer_reqp->isoc_pkt_descr; 519 520 /* Reset the CONTINUE flag */ 521 pp->pp_flag &= ~EHCI_ISOC_XFER_CONTINUE; 522 523 return (error); 524 } 525 526 527 /* 528 * ehci_insert_itd_req: 529 * 530 * Insert an ITD request into the Host Controller's isochronous list. 531 */ 532 /* ARGSUSED */ 533 static int 534 ehci_insert_itd_req( 535 ehci_state_t *ehcip, 536 ehci_pipe_private_t *pp, 537 ehci_isoc_xwrapper_t *itw, 538 usb_flags_t usb_flags) 539 { 540 usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 541 usb_isoc_req_t *curr_isoc_reqp; 542 usb_isoc_pkt_descr_t *curr_isoc_pkt_descr; 543 size_t curr_isoc_xfer_offset; 544 size_t isoc_pkt_length; 545 uint_t count, xactcount; 546 uint32_t xact_status; 547 uint32_t page, pageselected; 548 uint32_t buf[EHCI_ITD_BUFFER_LIST_SIZE]; 549 uint16_t index = 0; 550 uint16_t multi = 0; 551 ehci_itd_t *new_itd; 552 553 /* 554 * Get the current isochronous request and packet 555 * descriptor pointers. 556 */ 557 curr_isoc_reqp = (usb_isoc_req_t *)itw->itw_curr_xfer_reqp; 558 559 page = itw->itw_cookie.dmac_address; 560 ASSERT((page % EHCI_4K_ALIGN) == 0); 561 562 USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 563 "ehci_insert_itd_req: itw_curr_xfer_reqp = 0x%p page = 0x%x," 564 " pagesize = 0x%lx", (void *)itw->itw_curr_xfer_reqp, page, 565 itw->itw_cookie.dmac_size); 566 567 /* Insert all the isochronous TDs */ 568 count = 0; 569 curr_isoc_xfer_offset = 0; 570 571 while (count < curr_isoc_reqp->isoc_pkts_count) { 572 573 /* Grab a new itd */ 574 new_itd = itw->itw_itd_free_list; 575 576 ASSERT(new_itd != NULL); 577 578 itw->itw_itd_free_list = ehci_itd_iommu_to_cpu(ehcip, 579 Get_ITD(new_itd->itd_link_ptr)); 580 Set_ITD(new_itd->itd_link_ptr, 0); 581 582 bzero(buf, EHCI_ITD_BUFFER_LIST_SIZE * sizeof (uint32_t)); 583 584 multi = CalculateITDMultiField(ph->p_ep.wMaxPacketSize); 585 586 if (multi > EHCI_ITD_CTRL_MULTI_MASK) { 587 USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 588 "ehci_insert_itd_req: Wrong multi value."); 589 590 return (USB_FAILURE); 591 } 592 593 /* Fill 8 transaction for every iTD */ 594 for (xactcount = 0, pageselected = 0; 595 xactcount < EHCI_ITD_CTRL_LIST_SIZE; xactcount++) { 596 597 curr_isoc_pkt_descr = itw->itw_curr_isoc_pktp; 598 599 isoc_pkt_length = 600 curr_isoc_pkt_descr->isoc_pkt_length; 601 602 curr_isoc_pkt_descr->isoc_pkt_actual_length 603 = (ushort_t)isoc_pkt_length; 604 605 xact_status = 0; 606 607 if (pageselected < EHCI_ITD_BUFFER_LIST_SIZE) { 608 609 buf[pageselected] |= page; 610 } else { 611 USB_DPRINTF_L2(PRINT_MASK_INTR, 612 ehcip->ehci_log_hdl, 613 "ehci_insert_itd_req: " 614 "Error in buffer pointer."); 615 616 return (USB_FAILURE); 617 } 618 619 xact_status = (uint32_t)curr_isoc_xfer_offset; 620 xact_status |= (pageselected << 12); 621 xact_status |= isoc_pkt_length << 16; 622 xact_status |= EHCI_ITD_XFER_ACTIVE; 623 624 /* Set IOC on the last TD. */ 625 if (count == (curr_isoc_reqp->isoc_pkts_count - 1)) { 626 xact_status |= EHCI_ITD_XFER_IOC_ON; 627 } 628 629 USB_DPRINTF_L3(PRINT_MASK_INTR, 630 ehcip->ehci_log_hdl, 631 "ehci_insert_itd_req: count = 0x%x multi = %d" 632 "status = 0x%x page = 0x%x index = %d " 633 "pageselected = %d isoc_pkt_length = 0x%lx", 634 xactcount, multi, xact_status, page, 635 index, pageselected, isoc_pkt_length); 636 637 /* Fill in the new itd */ 638 Set_ITD_BODY(new_itd, xactcount, xact_status); 639 640 itw->itw_curr_isoc_pktp++; 641 Set_ITD_INDEX(new_itd, xactcount, index++); 642 643 curr_isoc_xfer_offset += isoc_pkt_length; 644 645 if (curr_isoc_xfer_offset >= EHCI_4K_ALIGN) { 646 pageselected ++; 647 page += EHCI_4K_ALIGN; 648 curr_isoc_xfer_offset -= EHCI_4K_ALIGN; 649 } 650 651 count ++; 652 if (count >= curr_isoc_reqp->isoc_pkts_count) { 653 654 break; 655 } 656 } 657 658 buf[0] |= (itw->itw_endpoint_num << 8); 659 buf[0] |= itw->itw_device_addr; 660 buf[1] |= ph->p_ep.wMaxPacketSize & 661 EHCI_ITD_CTRL_MAX_PACKET_MASK; 662 663 if (itw->itw_direction == USB_EP_DIR_IN) { 664 buf[1] |= EHCI_ITD_CTRL_DIR_IN; 665 } 666 buf[2] |= multi; 667 668 Set_ITD_BODY(new_itd, EHCI_ITD_BUFFER0, buf[0]); 669 Set_ITD_BODY(new_itd, EHCI_ITD_BUFFER1, buf[1]); 670 Set_ITD_BODY(new_itd, EHCI_ITD_BUFFER2, buf[2]); 671 Set_ITD_BODY(new_itd, EHCI_ITD_BUFFER3, buf[3]); 672 Set_ITD_BODY(new_itd, EHCI_ITD_BUFFER4, buf[4]); 673 Set_ITD_BODY(new_itd, EHCI_ITD_BUFFER5, buf[5]); 674 Set_ITD_BODY(new_itd, EHCI_ITD_BUFFER6, buf[6]); 675 676 Set_ITD(new_itd->itd_state, EHCI_ITD_ACTIVE); 677 ehci_print_itd(ehcip, new_itd); 678 679 /* 680 * Add this itd to the itw before we add it in the PFL 681 * If adding it to the PFL fails, we will have to cleanup. 682 */ 683 ehci_insert_itd_on_itw(ehcip, itw, new_itd); 684 685 } 686 687 return (USB_SUCCESS); 688 } 689 690 691 /* 692 * ehci_insert_sitd_req: 693 * 694 * Insert an SITD request into the Host Controller's isochronous list. 695 */ 696 /* ARGSUSED */ 697 static int 698 ehci_insert_sitd_req( 699 ehci_state_t *ehcip, 700 ehci_pipe_private_t *pp, 701 ehci_isoc_xwrapper_t *itw, 702 usb_flags_t usb_flags) 703 { 704 usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 705 usb_isoc_req_t *curr_isoc_reqp; 706 usb_isoc_pkt_descr_t *curr_isoc_pkt_descr; 707 size_t curr_isoc_xfer_offset; 708 size_t isoc_pkt_length; 709 uint_t count; 710 uint32_t ctrl, uframe_sched, xfer_state; 711 uint32_t page0, page1, prev_sitd; 712 uint32_t ssplit_count; 713 ehci_itd_t *new_sitd; 714 715 /* 716 * Get the current isochronous request and packet 717 * descriptor pointers. 718 */ 719 curr_isoc_reqp = (usb_isoc_req_t *)itw->itw_curr_xfer_reqp; 720 721 /* Set the ctrl field */ 722 ctrl = 0; 723 if (itw->itw_direction == USB_EP_DIR_IN) { 724 ctrl |= EHCI_SITD_CTRL_DIR_IN; 725 } else { 726 ctrl |= EHCI_SITD_CTRL_DIR_OUT; 727 } 728 729 ctrl |= (itw->itw_hub_port << EHCI_SITD_CTRL_PORT_SHIFT) & 730 EHCI_SITD_CTRL_PORT_MASK; 731 ctrl |= (itw->itw_hub_addr << EHCI_SITD_CTRL_HUB_SHIFT) & 732 EHCI_SITD_CTRL_HUB_MASK; 733 ctrl |= (itw->itw_endpoint_num << EHCI_SITD_CTRL_END_PT_SHIFT) & 734 EHCI_SITD_CTRL_END_PT_MASK; 735 ctrl |= (itw->itw_device_addr << EHCI_SITD_CTRL_DEVICE_SHIFT) & 736 EHCI_SITD_CTRL_DEVICE_MASK; 737 738 /* Set the micro frame schedule */ 739 uframe_sched = 0; 740 uframe_sched |= (pp->pp_smask << EHCI_SITD_UFRAME_SMASK_SHIFT) & 741 EHCI_SITD_UFRAME_SMASK_MASK; 742 uframe_sched |= (pp->pp_cmask << EHCI_SITD_UFRAME_CMASK_SHIFT) & 743 EHCI_SITD_UFRAME_CMASK_MASK; 744 745 /* Set the default page information */ 746 page0 = itw->itw_cookie.dmac_address; 747 page1 = 0; 748 749 prev_sitd = EHCI_ITD_LINK_PTR_INVALID; 750 751 /* 752 * Save the number of isochronous TDs needs 753 * to be insert to complete current isochronous request. 754 */ 755 itw->itw_num_itds = curr_isoc_reqp->isoc_pkts_count; 756 757 /* Insert all the isochronous TDs */ 758 for (count = 0, curr_isoc_xfer_offset = 0; 759 count < itw->itw_num_itds; count++) { 760 761 curr_isoc_pkt_descr = itw->itw_curr_isoc_pktp; 762 763 isoc_pkt_length = curr_isoc_pkt_descr->isoc_pkt_length; 764 curr_isoc_pkt_descr->isoc_pkt_actual_length = 765 (ushort_t)isoc_pkt_length; 766 767 /* Set the transfer state information */ 768 xfer_state = 0; 769 770 if (itw->itw_direction == USB_EP_DIR_IN) { 771 /* Set the size to the max packet size */ 772 xfer_state |= (ph->p_ep.wMaxPacketSize << 773 EHCI_SITD_XFER_TOTAL_SHIFT) & 774 EHCI_SITD_XFER_TOTAL_MASK; 775 } else { 776 /* Set the size to the packet length */ 777 xfer_state |= (isoc_pkt_length << 778 EHCI_SITD_XFER_TOTAL_SHIFT) & 779 EHCI_SITD_XFER_TOTAL_MASK; 780 } 781 xfer_state |= EHCI_SITD_XFER_ACTIVE; 782 783 /* Set IOC on the last TD. */ 784 if (count == (itw->itw_num_itds - 1)) { 785 xfer_state |= EHCI_SITD_XFER_IOC_ON; 786 } 787 788 ssplit_count = isoc_pkt_length / MAX_UFRAME_SITD_XFER; 789 if (isoc_pkt_length % MAX_UFRAME_SITD_XFER) { 790 ssplit_count++; 791 } 792 793 page1 = (ssplit_count & EHCI_SITD_XFER_TCOUNT_MASK) << 794 EHCI_SITD_XFER_TCOUNT_SHIFT; 795 if (ssplit_count > 1) { 796 page1 |= EHCI_SITD_XFER_TP_BEGIN; 797 } else { 798 page1 |= EHCI_SITD_XFER_TP_ALL; 799 } 800 801 /* Grab a new sitd */ 802 new_sitd = itw->itw_itd_free_list; 803 804 ASSERT(new_sitd != NULL); 805 806 itw->itw_itd_free_list = ehci_itd_iommu_to_cpu(ehcip, 807 Get_ITD(new_sitd->itd_link_ptr)); 808 Set_ITD(new_sitd->itd_link_ptr, 0); 809 810 /* Fill in the new sitd */ 811 Set_ITD_BODY(new_sitd, EHCI_SITD_CTRL, ctrl); 812 Set_ITD_BODY(new_sitd, EHCI_SITD_UFRAME_SCHED, uframe_sched); 813 Set_ITD_BODY(new_sitd, EHCI_SITD_XFER_STATE, xfer_state); 814 Set_ITD_BODY(new_sitd, EHCI_SITD_BUFFER0, 815 page0 + curr_isoc_xfer_offset); 816 Set_ITD_BODY(new_sitd, EHCI_SITD_BUFFER1, page1); 817 Set_ITD_BODY(new_sitd, EHCI_SITD_PREV_SITD, prev_sitd); 818 819 Set_ITD(new_sitd->itd_state, EHCI_ITD_ACTIVE); 820 821 /* 822 * Add this itd to the itw before we add it in the PFL 823 * If adding it to the PFL fails, we will have to cleanup. 824 */ 825 ehci_insert_itd_on_itw(ehcip, itw, new_sitd); 826 827 itw->itw_curr_isoc_pktp++; 828 curr_isoc_xfer_offset += isoc_pkt_length; 829 } 830 831 return (USB_SUCCESS); 832 } 833 834 835 /* 836 * ehci_remove_isoc_itds: 837 * 838 * Remove all itds from the PFL. 839 */ 840 static void 841 ehci_remove_isoc_itds( 842 ehci_state_t *ehcip, 843 ehci_pipe_private_t *pp) 844 { 845 ehci_isoc_xwrapper_t *curr_itw, *next_itw; 846 ehci_itd_t *curr_itd, *next_itd; 847 848 USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 849 "ehci_remove_isoc_itds: pp = 0x%p", (void *)pp); 850 851 ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 852 853 curr_itw = pp->pp_itw_head; 854 while (curr_itw) { 855 USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 856 "ehci_remove_isoc_itds: itw = 0x%p num itds = %d", 857 (void *)curr_itw, curr_itw->itw_num_itds); 858 859 next_itw = curr_itw->itw_next; 860 861 curr_itd = curr_itw->itw_itd_head; 862 while (curr_itd) { 863 next_itd = ehci_itd_iommu_to_cpu(ehcip, 864 Get_ITD(curr_itd->itd_itw_next_itd)); 865 866 ehci_reclaim_isoc(ehcip, curr_itw, curr_itd, pp); 867 868 curr_itd = next_itd; 869 } 870 871 ehci_deallocate_itw(ehcip, pp, curr_itw); 872 873 curr_itw = next_itw; 874 } 875 } 876 877 878 /* 879 * ehci_mark_reclaim_isoc: 880 * 881 * Set active ITDs to RECLAIM. 882 * Return number of ITD that need to be processed. 883 */ 884 static void 885 ehci_mark_reclaim_isoc( 886 ehci_state_t *ehcip, 887 ehci_pipe_private_t *pp) 888 { 889 usb_frame_number_t current_frame_number; 890 ehci_isoc_xwrapper_t *curr_itw, *next_itw; 891 ehci_itd_t *curr_itd, *next_itd; 892 uint_t ctrl; 893 uint_t isActive; 894 int i; 895 896 USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 897 "ehci_mark_reclaim_isoc: pp = 0x%p", (void *)pp); 898 899 if (pp->pp_itw_head == NULL) { 900 901 return; 902 } 903 904 /* Get the current frame number. */ 905 current_frame_number = ehci_get_current_frame_number(ehcip); 906 907 /* Traverse the list of transfer descriptors */ 908 curr_itw = pp->pp_itw_head; 909 while (curr_itw) { 910 next_itw = curr_itw->itw_next; 911 912 USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 913 "ehci_mark_reclaim_isoc: itw = 0x%p num itds = %d", 914 (void *)curr_itw, curr_itw->itw_num_itds); 915 916 curr_itd = curr_itw->itw_itd_head; 917 while (curr_itd) { 918 next_itd = ehci_itd_iommu_to_cpu(ehcip, 919 Get_ITD(curr_itd->itd_itw_next_itd)); 920 921 if (curr_itw->itw_port_status == USBA_HIGH_SPEED_DEV) { 922 923 for (i = 0; i < EHCI_ITD_CTRL_LIST_SIZE; i++) { 924 ctrl = Get_ITD_BODY(curr_itd, 925 EHCI_ITD_CTRL0 + i); 926 isActive = ctrl & EHCI_ITD_XFER_ACTIVE; 927 /* If still active, deactivate it */ 928 if (isActive) { 929 ctrl &= ~EHCI_ITD_XFER_ACTIVE; 930 Set_ITD_BODY(curr_itd, 931 EHCI_ITD_CTRL0 + i, 932 ctrl); 933 break; 934 } 935 } 936 } else { 937 ctrl = Get_ITD_BODY(curr_itd, 938 EHCI_SITD_XFER_STATE); 939 isActive = ctrl & EHCI_SITD_XFER_ACTIVE; 940 /* If it is still active deactivate it */ 941 if (isActive) { 942 ctrl &= ~EHCI_SITD_XFER_ACTIVE; 943 Set_ITD_BODY(curr_itd, 944 EHCI_SITD_XFER_STATE, 945 ctrl); 946 } 947 } 948 949 /* 950 * If the itd was active put it on the reclaim status, 951 * so the interrupt handler will know not to process it. 952 * Otherwise leave it alone and let the interrupt 953 * handler process it normally. 954 */ 955 if (isActive) { 956 Set_ITD(curr_itd->itd_state, EHCI_ITD_RECLAIM); 957 Set_ITD_FRAME(curr_itd->itd_reclaim_number, 958 current_frame_number); 959 ehci_remove_isoc_from_pfl(ehcip, curr_itd); 960 } 961 curr_itd = next_itd; 962 } 963 curr_itw = next_itw; 964 } 965 } 966 967 968 /* 969 * ehci_reclaim_isoc: 970 * 971 * "Reclaim" itds that were marked as RECLAIM. 972 */ 973 static void 974 ehci_reclaim_isoc( 975 ehci_state_t *ehcip, 976 ehci_isoc_xwrapper_t *itw, 977 ehci_itd_t *itd, 978 ehci_pipe_private_t *pp) 979 { 980 USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 981 "ehci_reclaim_isoc: itd = 0x%p", (void *)itd); 982 983 /* 984 * These are itds that were marked "RECLAIM" 985 * by the pipe cleanup. 986 * 987 * Decrement the num_itds and the periodic in 988 * request count if necessary. 989 */ 990 if ((--itw->itw_num_itds == 0) && (itw->itw_curr_xfer_reqp)) { 991 if (itw->itw_direction == USB_EP_DIR_IN) { 992 993 pp->pp_cur_periodic_req_cnt--; 994 995 ehci_deallocate_isoc_in_resource(ehcip, pp, itw); 996 } else { 997 ehci_hcdi_isoc_callback(pp->pp_pipe_handle, itw, 998 USB_CR_FLUSHED); 999 } 1000 } 1001 1002 /* Deallocate this transfer descriptor */ 1003 ehci_deallocate_itd(ehcip, itw, itd); 1004 } 1005 1006 1007 /* 1008 * ehci_start_isoc_polling: 1009 * 1010 * Insert the number of periodic requests corresponding to polling 1011 * interval as calculated during pipe open. 1012 */ 1013 int 1014 ehci_start_isoc_polling( 1015 ehci_state_t *ehcip, 1016 usba_pipe_handle_data_t *ph, 1017 usb_flags_t flags) 1018 { 1019 ehci_pipe_private_t *pp = (ehci_pipe_private_t *)ph->p_hcd_private; 1020 ehci_isoc_xwrapper_t *itw_list, *itw; 1021 int i, total_itws; 1022 int error = USB_SUCCESS; 1023 1024 USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 1025 "ehci_start_isoc_polling:"); 1026 1027 /* Allocate all the necessary resources for the IN transfer */ 1028 itw_list = NULL; 1029 total_itws = pp->pp_max_periodic_req_cnt - pp->pp_cur_periodic_req_cnt; 1030 for (i = 0; i < total_itws; i += 1) { 1031 itw = ehci_allocate_isoc_resources(ehcip, ph, NULL, flags); 1032 if (itw == NULL) { 1033 error = USB_NO_RESOURCES; 1034 /* There are not enough resources deallocate the ITWs */ 1035 itw = itw_list; 1036 while (itw != NULL) { 1037 itw_list = itw->itw_next; 1038 ehci_deallocate_isoc_in_resource( 1039 ehcip, pp, itw); 1040 ehci_deallocate_itw(ehcip, pp, itw); 1041 itw = itw_list; 1042 } 1043 1044 return (error); 1045 } else { 1046 if (itw_list == NULL) { 1047 itw_list = itw; 1048 } 1049 } 1050 } 1051 1052 i = 0; 1053 while (pp->pp_cur_periodic_req_cnt < pp->pp_max_periodic_req_cnt) { 1054 1055 USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 1056 "ehci_start_isoc_polling: max = %d curr = %d itw = %p:", 1057 pp->pp_max_periodic_req_cnt, pp->pp_cur_periodic_req_cnt, 1058 (void *)itw_list); 1059 1060 itw = itw_list; 1061 itw_list = itw->itw_next; 1062 1063 error = ehci_insert_isoc_req(ehcip, pp, itw, flags); 1064 1065 if (error == USB_SUCCESS) { 1066 pp->pp_cur_periodic_req_cnt++; 1067 } else { 1068 /* 1069 * Deallocate the remaining tw 1070 * The current tw should have already been deallocated 1071 */ 1072 itw = itw_list; 1073 while (itw != NULL) { 1074 itw_list = itw->itw_next; 1075 ehci_deallocate_isoc_in_resource( 1076 ehcip, pp, itw); 1077 ehci_deallocate_itw(ehcip, pp, itw); 1078 itw = itw_list; 1079 } 1080 /* 1081 * If this is the first req return an error. 1082 * Otherwise return success. 1083 */ 1084 if (i != 0) { 1085 error = USB_SUCCESS; 1086 } 1087 1088 break; 1089 } 1090 i++; 1091 } 1092 1093 return (error); 1094 } 1095 1096 1097 /* 1098 * Isochronronous handling functions. 1099 */ 1100 /* 1101 * ehci_traverse_active_isoc_list: 1102 */ 1103 void 1104 ehci_traverse_active_isoc_list( 1105 ehci_state_t *ehcip) 1106 { 1107 ehci_isoc_xwrapper_t *curr_itw; 1108 ehci_itd_t *curr_itd, *next_itd; 1109 uint_t state; 1110 ehci_pipe_private_t *pp; 1111 1112 USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 1113 "ehci_traverse_active_isoc_list:"); 1114 1115 ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 1116 1117 /* Sync ITD pool */ 1118 Sync_ITD_Pool(ehcip); 1119 1120 /* Traverse the list of done itds */ 1121 curr_itd = ehci_create_done_itd_list(ehcip); 1122 USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 1123 "ehci_traverse_active_isoc_list: current itd = 0x%p", 1124 (void *)curr_itd); 1125 1126 while (curr_itd) { 1127 /* Save the next_itd */ 1128 next_itd = ehci_itd_iommu_to_cpu(ehcip, 1129 Get_ITD(curr_itd->itd_next_active_itd)); 1130 1131 /* Get the transfer wrapper and the pp */ 1132 curr_itw = (ehci_isoc_xwrapper_t *)EHCI_LOOKUP_ID( 1133 (uint32_t)Get_ITD(curr_itd->itd_trans_wrapper)); 1134 pp = curr_itw->itw_pipe_private; 1135 1136 if (curr_itw->itw_port_status == USBA_HIGH_SPEED_DEV) { 1137 ehci_print_itd(ehcip, curr_itd); 1138 } else { 1139 ehci_print_sitd(ehcip, curr_itd); 1140 } 1141 1142 /* Get the ITD state */ 1143 state = Get_ITD(curr_itd->itd_state); 1144 1145 /* Only process the ITDs marked as active. */ 1146 if (state == EHCI_ITD_ACTIVE) { 1147 ehci_parse_isoc_error(ehcip, curr_itw, curr_itd); 1148 ehci_handle_isoc(ehcip, curr_itw, curr_itd); 1149 } else { 1150 ASSERT(state == EHCI_ITD_RECLAIM); 1151 ehci_reclaim_isoc(ehcip, curr_itw, curr_itd, pp); 1152 } 1153 1154 /* 1155 * Deallocate the transfer wrapper if there are no more 1156 * ITD's for the transfer wrapper. ehci_deallocate_itw() 1157 * will not deallocate the tw for a periodic in endpoint 1158 * since it will always have a ITD attached to it. 1159 */ 1160 ehci_deallocate_itw(ehcip, pp, curr_itw); 1161 1162 /* Check any ISOC is waiting for transfers completion event */ 1163 if (pp->pp_itw_head == NULL) { 1164 USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 1165 "ehci_traverse_active_isoc_list: " 1166 "Sent transfers completion event pp = 0x%p", 1167 (void *)pp); 1168 cv_signal(&pp->pp_xfer_cmpl_cv); 1169 } 1170 1171 curr_itd = next_itd; 1172 1173 USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 1174 "ehci_traverse_active_isoc_list: state = 0x%x " 1175 "pp = 0x%p itw = 0x%p itd = 0x%p next_itd = 0x%p", 1176 state, (void *)pp, (void *)curr_itw, (void *)curr_itd, 1177 (void *)next_itd); 1178 } 1179 } 1180 1181 1182 static void 1183 ehci_handle_isoc( 1184 ehci_state_t *ehcip, 1185 ehci_isoc_xwrapper_t *itw, 1186 ehci_itd_t *itd) 1187 { 1188 ehci_pipe_private_t *pp; /* Pipe private field */ 1189 1190 ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 1191 1192 USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 1193 "ehci_handle_isoc:"); 1194 1195 /* Obtain the pipe private structure */ 1196 pp = itw->itw_pipe_private; 1197 1198 ehci_handle_itd(ehcip, pp, itw, itd, itw->itw_handle_callback_value); 1199 } 1200 1201 1202 /* 1203 * ehci_handle_itd: 1204 * 1205 * Handle an (split) isochronous transfer descriptor. 1206 * This function will deallocate the itd from the list as well. 1207 */ 1208 /* ARGSUSED */ 1209 static void 1210 ehci_handle_itd( 1211 ehci_state_t *ehcip, 1212 ehci_pipe_private_t *pp, 1213 ehci_isoc_xwrapper_t *itw, 1214 ehci_itd_t *itd, 1215 void *tw_handle_callback_value) 1216 { 1217 usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 1218 usb_isoc_req_t *curr_isoc_reqp = 1219 (usb_isoc_req_t *)itw->itw_curr_xfer_reqp; 1220 int error = USB_SUCCESS; 1221 int i, index; 1222 1223 USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 1224 "ehci_handle_itd: pp=0x%p itw=0x%p itd=0x%p " 1225 "isoc_reqp=0%p data=0x%p", (void *)pp, (void *)itw, (void *)itd, 1226 (void *)curr_isoc_reqp, (void *)curr_isoc_reqp->isoc_data); 1227 1228 if (itw->itw_port_status == USBA_HIGH_SPEED_DEV && 1229 curr_isoc_reqp != NULL) { 1230 1231 for (i = 0; i < EHCI_ITD_CTRL_LIST_SIZE; i++) { 1232 1233 index = Get_ITD_INDEX(itd, i); 1234 if (index == EHCI_ITD_UNUSED_INDEX) { 1235 1236 continue; 1237 } 1238 curr_isoc_reqp-> 1239 isoc_pkt_descr[index].isoc_pkt_actual_length = 1240 (Get_ITD_BODY(itd, i) & EHCI_ITD_XFER_LENGTH) >> 16; 1241 } 1242 } 1243 1244 /* 1245 * Decrement the ITDs counter and check whether all the isoc 1246 * data has been send or received. If ITDs counter reaches 1247 * zero then inform client driver about completion current 1248 * isoc request. Otherwise wait for completion of other isoc 1249 * ITDs or transactions on this pipe. 1250 */ 1251 if (--itw->itw_num_itds != 0) { 1252 /* Deallocate this transfer descriptor */ 1253 ehci_deallocate_itd(ehcip, itw, itd); 1254 1255 return; 1256 } 1257 1258 /* 1259 * If this is a isoc in pipe, return the data to the client. 1260 * For a isoc out pipe, there is no need to do anything. 1261 */ 1262 if (itw->itw_direction == USB_EP_DIR_OUT) { 1263 USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 1264 "ehci_handle_itd: Isoc out pipe, isoc_reqp=0x%p, data=0x%p", 1265 (void *)curr_isoc_reqp, (void *)curr_isoc_reqp->isoc_data); 1266 1267 /* Do the callback */ 1268 ehci_hcdi_isoc_callback(ph, itw, USB_CR_OK); 1269 1270 /* Deallocate this transfer descriptor */ 1271 ehci_deallocate_itd(ehcip, itw, itd); 1272 1273 return; 1274 } 1275 1276 /* Decrement number of IN isochronous request count */ 1277 pp->pp_cur_periodic_req_cnt--; 1278 1279 USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 1280 "ehci_handle_itd: pp_cur_periodic_req_cnt = 0x%x ", 1281 pp->pp_cur_periodic_req_cnt); 1282 1283 /* Call ehci_sendup_itd_message to send message to upstream */ 1284 ehci_sendup_itd_message(ehcip, pp, itw, itd, USB_CR_OK); 1285 1286 /* Deallocate this transfer descriptor */ 1287 ehci_deallocate_itd(ehcip, itw, itd); 1288 1289 /* 1290 * If isochronous pipe state is still active, insert next isochronous 1291 * request into the Host Controller's isochronous list. 1292 */ 1293 if (pp->pp_state != EHCI_PIPE_STATE_ACTIVE) { 1294 1295 return; 1296 } 1297 1298 if ((error = ehci_allocate_isoc_in_resource(ehcip, pp, itw, 0)) == 1299 USB_SUCCESS) { 1300 curr_isoc_reqp = (usb_isoc_req_t *)itw->itw_curr_xfer_reqp; 1301 1302 ASSERT(curr_isoc_reqp != NULL); 1303 1304 itw->itw_num_itds = ehci_calc_num_itds(itw, 1305 curr_isoc_reqp->isoc_pkts_count); 1306 1307 if (ehci_allocate_itds_for_itw(ehcip, itw, itw->itw_num_itds) != 1308 USB_SUCCESS) { 1309 ehci_deallocate_isoc_in_resource(ehcip, pp, itw); 1310 itw->itw_num_itds = 0; 1311 error = USB_FAILURE; 1312 } 1313 } 1314 1315 if ((error != USB_SUCCESS) || 1316 (ehci_insert_isoc_req(ehcip, pp, itw, 0) != USB_SUCCESS)) { 1317 /* 1318 * Set pipe state to stop polling and error to no 1319 * resource. Don't insert any more isoch polling 1320 * requests. 1321 */ 1322 pp->pp_state = EHCI_PIPE_STATE_STOP_POLLING; 1323 pp->pp_error = USB_CR_NO_RESOURCES; 1324 1325 } else { 1326 /* Increment number of IN isochronous request count */ 1327 pp->pp_cur_periodic_req_cnt++; 1328 1329 ASSERT(pp->pp_cur_periodic_req_cnt == 1330 pp->pp_max_periodic_req_cnt); 1331 } 1332 } 1333 1334 1335 /* 1336 * ehci_sendup_qtd_message: 1337 * copy data, if necessary and do callback 1338 */ 1339 /* ARGSUSED */ 1340 static void 1341 ehci_sendup_itd_message( 1342 ehci_state_t *ehcip, 1343 ehci_pipe_private_t *pp, 1344 ehci_isoc_xwrapper_t *itw, 1345 ehci_itd_t *td, 1346 usb_cr_t error) 1347 { 1348 usb_isoc_req_t *isoc_reqp = itw->itw_curr_xfer_reqp; 1349 usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 1350 size_t length; 1351 uchar_t *buf; 1352 mblk_t *mp; 1353 1354 ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 1355 1356 USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 1357 "ehci_sendup_itd_message:"); 1358 1359 ASSERT(itw != NULL); 1360 1361 length = itw->itw_length; 1362 1363 /* Copy the data into the mblk_t */ 1364 buf = (uchar_t *)itw->itw_buf; 1365 1366 USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 1367 "ehci_sendup_itd_message: length %ld error %d", length, error); 1368 1369 /* Get the message block */ 1370 mp = isoc_reqp->isoc_data; 1371 1372 ASSERT(mp != NULL); 1373 1374 if (length) { 1375 /* Sync IO buffer */ 1376 Sync_IO_Buffer(itw->itw_dmahandle, length); 1377 1378 /* Copy the data into the message */ 1379 ddi_rep_get8(itw->itw_accesshandle, 1380 mp->b_rptr, buf, length, DDI_DEV_AUTOINCR); 1381 1382 /* Increment the write pointer */ 1383 mp->b_wptr = mp->b_wptr + length; 1384 } else { 1385 USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 1386 "ehci_sendup_itd_message: Zero length packet"); 1387 } 1388 1389 ehci_hcdi_isoc_callback(ph, itw, error); 1390 } 1391 1392 1393 /* 1394 * ehci_hcdi_isoc_callback: 1395 * 1396 * Convenience wrapper around usba_hcdi_cb() other than root hub. 1397 */ 1398 void 1399 ehci_hcdi_isoc_callback( 1400 usba_pipe_handle_data_t *ph, 1401 ehci_isoc_xwrapper_t *itw, 1402 usb_cr_t completion_reason) 1403 { 1404 ehci_state_t *ehcip = ehci_obtain_state( 1405 ph->p_usba_device->usb_root_hub_dip); 1406 ehci_pipe_private_t *pp = (ehci_pipe_private_t *)ph->p_hcd_private; 1407 usb_opaque_t curr_xfer_reqp; 1408 uint_t pipe_state = 0; 1409 1410 USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl, 1411 "ehci_hcdi_isoc_callback: ph = 0x%p, itw = 0x%p, cr = 0x%x", 1412 (void *)ph, (void *)itw, completion_reason); 1413 1414 ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 1415 1416 /* Set the pipe state as per completion reason */ 1417 switch (completion_reason) { 1418 case USB_CR_OK: 1419 pipe_state = pp->pp_state; 1420 break; 1421 case USB_CR_NO_RESOURCES: 1422 case USB_CR_NOT_SUPPORTED: 1423 case USB_CR_PIPE_RESET: 1424 case USB_CR_STOPPED_POLLING: 1425 pipe_state = EHCI_PIPE_STATE_IDLE; 1426 break; 1427 case USB_CR_PIPE_CLOSING: 1428 break; 1429 } 1430 1431 pp->pp_state = pipe_state; 1432 1433 if (itw && itw->itw_curr_xfer_reqp) { 1434 curr_xfer_reqp = (usb_opaque_t)itw->itw_curr_xfer_reqp; 1435 itw->itw_curr_xfer_reqp = NULL; 1436 } else { 1437 ASSERT(pp->pp_client_periodic_in_reqp != NULL); 1438 1439 curr_xfer_reqp = pp->pp_client_periodic_in_reqp; 1440 pp->pp_client_periodic_in_reqp = NULL; 1441 } 1442 1443 ASSERT(curr_xfer_reqp != NULL); 1444 1445 mutex_exit(&ehcip->ehci_int_mutex); 1446 1447 usba_hcdi_cb(ph, curr_xfer_reqp, completion_reason); 1448 1449 mutex_enter(&ehcip->ehci_int_mutex); 1450 } 1451