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