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