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