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