17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5b3001defSlg * Common Development and Distribution License (the "License"). 6b3001defSlg * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*d3d50737SRafael Vanoni * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate /* 287c478bd9Sstevel@tonic-gate * EHCI Host Controller Driver (EHCI) 297c478bd9Sstevel@tonic-gate * 307c478bd9Sstevel@tonic-gate * The EHCI driver is a software driver which interfaces to the Universal 317c478bd9Sstevel@tonic-gate * Serial Bus layer (USBA) and the Host Controller (HC). The interface to 327c478bd9Sstevel@tonic-gate * the Host Controller is defined by the EHCI Host Controller Interface. 337c478bd9Sstevel@tonic-gate * 347c478bd9Sstevel@tonic-gate * This module contains the EHCI driver isochronous code, which handles all 357c478bd9Sstevel@tonic-gate * Checking of status of USB transfers, error recovery and callbacks. 367c478bd9Sstevel@tonic-gate */ 377c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehcid.h> 387c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_xfer.h> 397c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_util.h> 407c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_isoch.h> 417c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_isoch_util.h> 42d29f5a71Szhigang lu - Sun Microsystems - Beijing China #include <sys/strsun.h> 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate /* 457c478bd9Sstevel@tonic-gate * Isochronous initialization functions 467c478bd9Sstevel@tonic-gate */ 477c478bd9Sstevel@tonic-gate int ehci_isoc_init( 487c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 497c478bd9Sstevel@tonic-gate void ehci_isoc_cleanup( 507c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 517c478bd9Sstevel@tonic-gate void ehci_isoc_pipe_cleanup( 527c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 537c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph); 547c478bd9Sstevel@tonic-gate static void ehci_wait_for_isoc_completion( 557c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 567c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp); 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate /* 597c478bd9Sstevel@tonic-gate * Isochronous request functions 607c478bd9Sstevel@tonic-gate */ 617c478bd9Sstevel@tonic-gate ehci_isoc_xwrapper_t *ehci_allocate_isoc_resources( 627c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 637c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 647c478bd9Sstevel@tonic-gate usb_isoc_req_t *isoc_reqp, 657c478bd9Sstevel@tonic-gate usb_flags_t usb_flags); 667c478bd9Sstevel@tonic-gate int ehci_insert_isoc_req( 677c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 687c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 697c478bd9Sstevel@tonic-gate ehci_isoc_xwrapper_t *itw, 707c478bd9Sstevel@tonic-gate usb_flags_t usb_flags); 71b3001defSlg static int ehci_insert_itd_req( 72b3001defSlg ehci_state_t *ehcip, 73b3001defSlg ehci_pipe_private_t *pp, 74b3001defSlg ehci_isoc_xwrapper_t *itw, 75b3001defSlg usb_flags_t usb_flags); 767c478bd9Sstevel@tonic-gate static int ehci_insert_sitd_req( 777c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 787c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 797c478bd9Sstevel@tonic-gate ehci_isoc_xwrapper_t *itw, 807c478bd9Sstevel@tonic-gate usb_flags_t usb_flags); 817c478bd9Sstevel@tonic-gate static void ehci_remove_isoc_itds( 827c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 837c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp); 847c478bd9Sstevel@tonic-gate static void ehci_mark_reclaim_isoc( 857c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 867c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp); 877c478bd9Sstevel@tonic-gate static void ehci_reclaim_isoc( 887c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 897c478bd9Sstevel@tonic-gate ehci_isoc_xwrapper_t *itw, 907c478bd9Sstevel@tonic-gate ehci_itd_t *itd, 917c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp); 927c478bd9Sstevel@tonic-gate int ehci_start_isoc_polling( 937c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 947c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 957c478bd9Sstevel@tonic-gate usb_flags_t flags); 967c478bd9Sstevel@tonic-gate 977c478bd9Sstevel@tonic-gate /* 987c478bd9Sstevel@tonic-gate * Isochronronous handling functions. 997c478bd9Sstevel@tonic-gate */ 1007c478bd9Sstevel@tonic-gate void ehci_traverse_active_isoc_list( 1017c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 1027c478bd9Sstevel@tonic-gate static void ehci_handle_isoc( 1037c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1047c478bd9Sstevel@tonic-gate ehci_isoc_xwrapper_t *itw, 1057c478bd9Sstevel@tonic-gate ehci_itd_t *itd); 1067c478bd9Sstevel@tonic-gate static void ehci_handle_itd( 1077c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1087c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 1097c478bd9Sstevel@tonic-gate ehci_isoc_xwrapper_t *itw, 1107c478bd9Sstevel@tonic-gate ehci_itd_t *itd, 1117c478bd9Sstevel@tonic-gate void *tw_handle_callback_value); 1127c478bd9Sstevel@tonic-gate static void ehci_sendup_itd_message( 1137c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1147c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 1157c478bd9Sstevel@tonic-gate ehci_isoc_xwrapper_t *itw, 1167c478bd9Sstevel@tonic-gate ehci_itd_t *td, 1177c478bd9Sstevel@tonic-gate usb_cr_t error); 1187c478bd9Sstevel@tonic-gate void ehci_hcdi_isoc_callback( 1197c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 1207c478bd9Sstevel@tonic-gate ehci_isoc_xwrapper_t *itw, 1217c478bd9Sstevel@tonic-gate usb_cr_t completion_reason); 1227c478bd9Sstevel@tonic-gate 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate /* 1257c478bd9Sstevel@tonic-gate * Isochronous initialization functions 1267c478bd9Sstevel@tonic-gate */ 1277c478bd9Sstevel@tonic-gate /* 1287c478bd9Sstevel@tonic-gate * Initialize all the needed resources needed by isochronous pipes. 1297c478bd9Sstevel@tonic-gate */ 1307c478bd9Sstevel@tonic-gate int 1317c478bd9Sstevel@tonic-gate ehci_isoc_init( 1327c478bd9Sstevel@tonic-gate ehci_state_t *ehcip) 1337c478bd9Sstevel@tonic-gate { 1347c478bd9Sstevel@tonic-gate return (ehci_allocate_isoc_pools(ehcip)); 1357c478bd9Sstevel@tonic-gate } 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate 1387c478bd9Sstevel@tonic-gate /* 1397c478bd9Sstevel@tonic-gate * Cleanup isochronous resources. 1407c478bd9Sstevel@tonic-gate */ 1417c478bd9Sstevel@tonic-gate void 1427c478bd9Sstevel@tonic-gate ehci_isoc_cleanup( 1437c478bd9Sstevel@tonic-gate ehci_state_t *ehcip) 1447c478bd9Sstevel@tonic-gate { 1457c478bd9Sstevel@tonic-gate ehci_isoc_xwrapper_t *itw; 1467c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp; 1477c478bd9Sstevel@tonic-gate ehci_itd_t *itd; 1487c478bd9Sstevel@tonic-gate int i, ctrl, rval; 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate /* Free all the buffers */ 1517c478bd9Sstevel@tonic-gate if (ehcip->ehci_itd_pool_addr && ehcip->ehci_itd_pool_mem_handle) { 1527c478bd9Sstevel@tonic-gate for (i = 0; i < ehci_get_itd_pool_size(); i ++) { 1537c478bd9Sstevel@tonic-gate itd = &ehcip->ehci_itd_pool_addr[i]; 1547c478bd9Sstevel@tonic-gate ctrl = Get_ITD(ehcip-> 1557c478bd9Sstevel@tonic-gate ehci_itd_pool_addr[i].itd_state); 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate if ((ctrl != EHCI_ITD_FREE) && 1587c478bd9Sstevel@tonic-gate (ctrl != EHCI_ITD_DUMMY) && 1597c478bd9Sstevel@tonic-gate (itd->itd_trans_wrapper)) { 1607c478bd9Sstevel@tonic-gate 1617c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex); 1627c478bd9Sstevel@tonic-gate 1637c478bd9Sstevel@tonic-gate itw = (ehci_isoc_xwrapper_t *) 1640a05e705Slc EHCI_LOOKUP_ID((uint32_t) 1650a05e705Slc Get_ITD(itd->itd_trans_wrapper)); 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate /* Obtain the pipe private structure */ 1687c478bd9Sstevel@tonic-gate pp = itw->itw_pipe_private; 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate ehci_deallocate_itd(ehcip, itw, itd); 1717c478bd9Sstevel@tonic-gate ehci_deallocate_itw(ehcip, pp, itw); 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex); 1747c478bd9Sstevel@tonic-gate } 1757c478bd9Sstevel@tonic-gate } 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate /* 1787c478bd9Sstevel@tonic-gate * If EHCI_ITD_POOL_BOUND flag is set, then unbind 1797c478bd9Sstevel@tonic-gate * the handle for ITD pools. 1807c478bd9Sstevel@tonic-gate */ 1817c478bd9Sstevel@tonic-gate if ((ehcip->ehci_dma_addr_bind_flag & 1827c478bd9Sstevel@tonic-gate EHCI_ITD_POOL_BOUND) == EHCI_ITD_POOL_BOUND) { 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate rval = ddi_dma_unbind_handle( 1857c478bd9Sstevel@tonic-gate ehcip->ehci_itd_pool_dma_handle); 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate ASSERT(rval == DDI_SUCCESS); 1887c478bd9Sstevel@tonic-gate } 1897c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&ehcip->ehci_itd_pool_mem_handle); 1907c478bd9Sstevel@tonic-gate } 1917c478bd9Sstevel@tonic-gate 1927c478bd9Sstevel@tonic-gate /* Free the ITD pool */ 1937c478bd9Sstevel@tonic-gate if (ehcip->ehci_itd_pool_dma_handle) { 1947c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&ehcip->ehci_itd_pool_dma_handle); 1957c478bd9Sstevel@tonic-gate } 1967c478bd9Sstevel@tonic-gate } 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate /* 2007c478bd9Sstevel@tonic-gate * ehci_isoc_pipe_cleanup 2017c478bd9Sstevel@tonic-gate * 2027c478bd9Sstevel@tonic-gate * Cleanup ehci isoc pipes. 2037c478bd9Sstevel@tonic-gate */ 2047c478bd9Sstevel@tonic-gate void ehci_isoc_pipe_cleanup( 2057c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2067c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph) { 2077c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp = (ehci_pipe_private_t *)ph->p_hcd_private; 2087c478bd9Sstevel@tonic-gate uint_t pipe_state = pp->pp_state; 2097c478bd9Sstevel@tonic-gate usb_cr_t completion_reason; 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 2127c478bd9Sstevel@tonic-gate "ehci_isoc_pipe_cleanup: ph = 0x%p", (void *)ph); 2137c478bd9Sstevel@tonic-gate 2147c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 2157c478bd9Sstevel@tonic-gate 2167c478bd9Sstevel@tonic-gate /* Stop all further processing */ 2177c478bd9Sstevel@tonic-gate ehci_mark_reclaim_isoc(ehcip, pp); 2187c478bd9Sstevel@tonic-gate 2197c478bd9Sstevel@tonic-gate /* 2207c478bd9Sstevel@tonic-gate * Wait for processing all completed transfers 2217c478bd9Sstevel@tonic-gate * and send result upstream/ 2227c478bd9Sstevel@tonic-gate */ 2237c478bd9Sstevel@tonic-gate ehci_wait_for_isoc_completion(ehcip, pp); 2247c478bd9Sstevel@tonic-gate 2257c478bd9Sstevel@tonic-gate /* Go ahead and remove all remaining itds if there are any */ 2267c478bd9Sstevel@tonic-gate ehci_remove_isoc_itds(ehcip, pp); 2277c478bd9Sstevel@tonic-gate 2287c478bd9Sstevel@tonic-gate switch (pipe_state) { 2297c478bd9Sstevel@tonic-gate case EHCI_PIPE_STATE_CLOSE: 2307c478bd9Sstevel@tonic-gate completion_reason = USB_CR_PIPE_CLOSING; 2317c478bd9Sstevel@tonic-gate break; 2327c478bd9Sstevel@tonic-gate case EHCI_PIPE_STATE_RESET: 2337c478bd9Sstevel@tonic-gate case EHCI_PIPE_STATE_STOP_POLLING: 2347c478bd9Sstevel@tonic-gate /* Set completion reason */ 2357c478bd9Sstevel@tonic-gate completion_reason = (pipe_state == 2367c478bd9Sstevel@tonic-gate EHCI_PIPE_STATE_RESET) ? 2377c478bd9Sstevel@tonic-gate USB_CR_PIPE_RESET: USB_CR_STOPPED_POLLING; 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate /* Set pipe state to idle */ 2407c478bd9Sstevel@tonic-gate pp->pp_state = EHCI_PIPE_STATE_IDLE; 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate break; 2437c478bd9Sstevel@tonic-gate } 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate /* 2467c478bd9Sstevel@tonic-gate * Do the callback for the original client 2477c478bd9Sstevel@tonic-gate * periodic IN request. 2487c478bd9Sstevel@tonic-gate */ 2497c478bd9Sstevel@tonic-gate if ((ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK) == 2507c478bd9Sstevel@tonic-gate USB_EP_DIR_IN) { 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate ehci_do_client_periodic_in_req_callback( 2537c478bd9Sstevel@tonic-gate ehcip, pp, completion_reason); 2547c478bd9Sstevel@tonic-gate } 2557c478bd9Sstevel@tonic-gate } 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate /* 2597c478bd9Sstevel@tonic-gate * ehci_wait_for_transfers_completion: 2607c478bd9Sstevel@tonic-gate * 2617c478bd9Sstevel@tonic-gate * Wait for processing all completed transfers and to send results 2627c478bd9Sstevel@tonic-gate * to upstream. 2637c478bd9Sstevel@tonic-gate */ 2647c478bd9Sstevel@tonic-gate static void 2657c478bd9Sstevel@tonic-gate ehci_wait_for_isoc_completion( 2667c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2677c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp) 2687c478bd9Sstevel@tonic-gate { 2697c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate if (pp->pp_itw_head == NULL) { 2727c478bd9Sstevel@tonic-gate 2737c478bd9Sstevel@tonic-gate return; 2747c478bd9Sstevel@tonic-gate } 2757c478bd9Sstevel@tonic-gate 276*d3d50737SRafael Vanoni (void) cv_reltimedwait(&pp->pp_xfer_cmpl_cv, &ehcip->ehci_int_mutex, 277*d3d50737SRafael Vanoni drv_usectohz(EHCI_XFER_CMPL_TIMEWAIT * 1000000), TR_CLOCK_TICK); 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate if (pp->pp_itw_head) { 2807c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 2817c478bd9Sstevel@tonic-gate "ehci_wait_for_isoc_completion: " 2827c478bd9Sstevel@tonic-gate "No transfers completion confirmation received"); 2837c478bd9Sstevel@tonic-gate } 2847c478bd9Sstevel@tonic-gate } 2857c478bd9Sstevel@tonic-gate 2867c478bd9Sstevel@tonic-gate 2877c478bd9Sstevel@tonic-gate /* 2887c478bd9Sstevel@tonic-gate * Isochronous request functions 2897c478bd9Sstevel@tonic-gate */ 2907c478bd9Sstevel@tonic-gate /* 2917c478bd9Sstevel@tonic-gate * ehci_allocate_isoc_resources: 2927c478bd9Sstevel@tonic-gate * 2937c478bd9Sstevel@tonic-gate * Calculates the number of tds necessary for a isoch transfer, and 2947c478bd9Sstevel@tonic-gate * allocates all the necessary resources. 2957c478bd9Sstevel@tonic-gate * 2967c478bd9Sstevel@tonic-gate * Returns NULL if there is insufficient resources otherwise ITW. 2977c478bd9Sstevel@tonic-gate */ 2987c478bd9Sstevel@tonic-gate ehci_isoc_xwrapper_t * 2997c478bd9Sstevel@tonic-gate ehci_allocate_isoc_resources( 3007c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 3017c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 3027c478bd9Sstevel@tonic-gate usb_isoc_req_t *isoc_reqp, 3037c478bd9Sstevel@tonic-gate usb_flags_t usb_flags) 3047c478bd9Sstevel@tonic-gate { 3057c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp = (ehci_pipe_private_t *)ph->p_hcd_private; 306b3001defSlg int pipe_dir, i; 3077c478bd9Sstevel@tonic-gate uint_t max_ep_pkt_size, max_isoc_xfer_size; 3087c478bd9Sstevel@tonic-gate usb_isoc_pkt_descr_t *isoc_pkt_descr; 309b3001defSlg size_t isoc_pkt_count, isoc_pkts_length; 3100a05e705Slc size_t itw_xfer_size = 0; 3117c478bd9Sstevel@tonic-gate ehci_isoc_xwrapper_t *itw; 3127c478bd9Sstevel@tonic-gate 3137c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 3147c478bd9Sstevel@tonic-gate "ehci_allocate_isoc_resources: flags = 0x%x", usb_flags); 3157c478bd9Sstevel@tonic-gate 3167c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 3177c478bd9Sstevel@tonic-gate 3187c478bd9Sstevel@tonic-gate /* 3197c478bd9Sstevel@tonic-gate * Check whether pipe is in halted state. 3207c478bd9Sstevel@tonic-gate */ 3217c478bd9Sstevel@tonic-gate if (pp->pp_state == EHCI_PIPE_STATE_ERROR) { 3227c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 3237c478bd9Sstevel@tonic-gate "ehci_allocate_isoc_resources:" 3247c478bd9Sstevel@tonic-gate "Pipe is in error state, need pipe reset to continue"); 3257c478bd9Sstevel@tonic-gate 3267c478bd9Sstevel@tonic-gate return (NULL); 3277c478bd9Sstevel@tonic-gate } 3287c478bd9Sstevel@tonic-gate 3297c478bd9Sstevel@tonic-gate /* Calculate the maximum isochronous transfer size we allow */ 3300a05e705Slc max_ep_pkt_size = (ph->p_ep.wMaxPacketSize & 3310a05e705Slc EHCI_ITD_CTRL_MAX_PACKET_MASK) * 3320a05e705Slc CalculateITDMultiField(ph->p_ep.wMaxPacketSize); 3330a05e705Slc 3347c478bd9Sstevel@tonic-gate max_isoc_xfer_size = EHCI_MAX_ISOC_PKTS_PER_XFER * max_ep_pkt_size; 3357c478bd9Sstevel@tonic-gate 3367c478bd9Sstevel@tonic-gate /* Get the packet descriptor and number of packets to send */ 3377c478bd9Sstevel@tonic-gate if (isoc_reqp) { 3387c478bd9Sstevel@tonic-gate isoc_pkt_descr = isoc_reqp->isoc_pkt_descr; 3397c478bd9Sstevel@tonic-gate isoc_pkt_count = isoc_reqp->isoc_pkts_count; 340b3001defSlg isoc_pkts_length = isoc_reqp->isoc_pkts_length; 3417c478bd9Sstevel@tonic-gate } else { 3427c478bd9Sstevel@tonic-gate isoc_pkt_descr = ((usb_isoc_req_t *) 3437c478bd9Sstevel@tonic-gate pp->pp_client_periodic_in_reqp)->isoc_pkt_descr; 3447c478bd9Sstevel@tonic-gate 3457c478bd9Sstevel@tonic-gate isoc_pkt_count = ((usb_isoc_req_t *) 3467c478bd9Sstevel@tonic-gate pp->pp_client_periodic_in_reqp)->isoc_pkts_count; 347b3001defSlg 348b3001defSlg isoc_pkts_length = ((usb_isoc_req_t *) 3497c478bd9Sstevel@tonic-gate pp->pp_client_periodic_in_reqp)->isoc_pkts_length; 3507c478bd9Sstevel@tonic-gate } 3517c478bd9Sstevel@tonic-gate 3527c478bd9Sstevel@tonic-gate /* Calculate the size of the transfer. */ 3537c478bd9Sstevel@tonic-gate pipe_dir = ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK; 3547c478bd9Sstevel@tonic-gate if (pipe_dir == USB_EP_DIR_IN) { 355b3001defSlg for (i = 0; i < isoc_pkt_count; i++) { 3560a05e705Slc /* 3570a05e705Slc * isoc_pkt_length is used as Transaction Length and 3580a05e705Slc * according to EHCI spec Table 3-3, the maximum value 3590a05e705Slc * allowed is 3072 3600a05e705Slc */ 3610a05e705Slc if (isoc_pkt_descr->isoc_pkt_length > 3072) { 3620a05e705Slc 3630a05e705Slc return (NULL); 3640a05e705Slc } 3650a05e705Slc 366b3001defSlg itw_xfer_size += isoc_pkt_descr->isoc_pkt_length; 3670a05e705Slc 368b3001defSlg isoc_pkt_descr++; 369b3001defSlg } 370b3001defSlg 371b3001defSlg if ((isoc_pkts_length) && 3720a05e705Slc (isoc_pkts_length != itw_xfer_size)) { 373b3001defSlg 374b3001defSlg USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 375b3001defSlg "ehci_allocate_isoc_resources: " 376112116d8Sfb "isoc_pkts_length 0x%lx is not equal to the sum of " 377112116d8Sfb "all pkt lengths 0x%lx in an isoc request", 378b3001defSlg isoc_pkts_length, itw_xfer_size); 379b3001defSlg 380b3001defSlg return (NULL); 381b3001defSlg } 382b3001defSlg 3837c478bd9Sstevel@tonic-gate } else { 3847c478bd9Sstevel@tonic-gate ASSERT(isoc_reqp != NULL); 385d29f5a71Szhigang lu - Sun Microsystems - Beijing China itw_xfer_size = MBLKL(isoc_reqp->isoc_data); 3867c478bd9Sstevel@tonic-gate } 3877c478bd9Sstevel@tonic-gate 3887c478bd9Sstevel@tonic-gate /* Check the size of isochronous request */ 3897c478bd9Sstevel@tonic-gate if (itw_xfer_size > max_isoc_xfer_size) { 3907c478bd9Sstevel@tonic-gate 3917c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 392b3001defSlg "ehci_allocate_isoc_resources: Maximum isoc request " 393112116d8Sfb "size 0x%x Given isoc request size 0x%lx", 3947c478bd9Sstevel@tonic-gate max_isoc_xfer_size, itw_xfer_size); 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate return (NULL); 3977c478bd9Sstevel@tonic-gate } 3987c478bd9Sstevel@tonic-gate 3997c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 400112116d8Sfb "ehci_allocate_isoc_resources: length = 0x%lx", itw_xfer_size); 4017c478bd9Sstevel@tonic-gate 4027c478bd9Sstevel@tonic-gate /* Allocate the itw for this request */ 4037c478bd9Sstevel@tonic-gate if ((itw = ehci_allocate_itw_resources(ehcip, pp, itw_xfer_size, 4047c478bd9Sstevel@tonic-gate usb_flags, isoc_pkt_count)) == NULL) { 4057c478bd9Sstevel@tonic-gate 4067c478bd9Sstevel@tonic-gate return (NULL); 4077c478bd9Sstevel@tonic-gate } 4087c478bd9Sstevel@tonic-gate 4097c478bd9Sstevel@tonic-gate itw->itw_handle_callback_value = NULL; 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate if (pipe_dir == USB_EP_DIR_IN) { 4127c478bd9Sstevel@tonic-gate if (ehci_allocate_isoc_in_resource(ehcip, pp, itw, usb_flags) != 4137c478bd9Sstevel@tonic-gate USB_SUCCESS) { 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate ehci_deallocate_itw(ehcip, pp, itw); 4167c478bd9Sstevel@tonic-gate 4177c478bd9Sstevel@tonic-gate return (NULL); 4187c478bd9Sstevel@tonic-gate } 4197c478bd9Sstevel@tonic-gate } else { 4207c478bd9Sstevel@tonic-gate if (itw->itw_length) { 4217c478bd9Sstevel@tonic-gate ASSERT(isoc_reqp->isoc_data != NULL); 4227c478bd9Sstevel@tonic-gate 4237c478bd9Sstevel@tonic-gate /* Copy the data into the buffer */ 4247c478bd9Sstevel@tonic-gate bcopy(isoc_reqp->isoc_data->b_rptr, 4257c478bd9Sstevel@tonic-gate itw->itw_buf, itw->itw_length); 4267c478bd9Sstevel@tonic-gate 4277c478bd9Sstevel@tonic-gate Sync_IO_Buffer_for_device(itw->itw_dmahandle, 4287c478bd9Sstevel@tonic-gate itw->itw_length); 4297c478bd9Sstevel@tonic-gate } 4307c478bd9Sstevel@tonic-gate itw->itw_curr_xfer_reqp = isoc_reqp; 4317c478bd9Sstevel@tonic-gate } 4327c478bd9Sstevel@tonic-gate 4337c478bd9Sstevel@tonic-gate return (itw); 4347c478bd9Sstevel@tonic-gate } 4357c478bd9Sstevel@tonic-gate 4367c478bd9Sstevel@tonic-gate 4377c478bd9Sstevel@tonic-gate /* 4387c478bd9Sstevel@tonic-gate * ehci_insert_isoc_req: 4397c478bd9Sstevel@tonic-gate * 4407c478bd9Sstevel@tonic-gate * Insert an isochronous request into the Host Controller's 4417c478bd9Sstevel@tonic-gate * isochronous list. 4427c478bd9Sstevel@tonic-gate */ 4437c478bd9Sstevel@tonic-gate int 4447c478bd9Sstevel@tonic-gate ehci_insert_isoc_req( 4457c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 4467c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 4477c478bd9Sstevel@tonic-gate ehci_isoc_xwrapper_t *itw, 4487c478bd9Sstevel@tonic-gate usb_flags_t usb_flags) 4497c478bd9Sstevel@tonic-gate { 4507c478bd9Sstevel@tonic-gate int error; 451b3001defSlg ehci_itd_t *new_itd, *temp_itd; 4527c478bd9Sstevel@tonic-gate 4537c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 4547c478bd9Sstevel@tonic-gate "ehci_insert_isoc_req: flags = 0x%x port status = 0x%x", 4557c478bd9Sstevel@tonic-gate usb_flags, itw->itw_port_status); 4567c478bd9Sstevel@tonic-gate 4577c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 4587c478bd9Sstevel@tonic-gate 4597c478bd9Sstevel@tonic-gate ASSERT(itw->itw_curr_xfer_reqp != NULL); 4607c478bd9Sstevel@tonic-gate ASSERT(itw->itw_curr_xfer_reqp->isoc_pkt_descr != NULL); 4617c478bd9Sstevel@tonic-gate 4627c478bd9Sstevel@tonic-gate /* 4637c478bd9Sstevel@tonic-gate * Save address of first usb isochronous packet descriptor. 4647c478bd9Sstevel@tonic-gate */ 4657c478bd9Sstevel@tonic-gate itw->itw_curr_isoc_pktp = itw->itw_curr_xfer_reqp->isoc_pkt_descr; 4667c478bd9Sstevel@tonic-gate 4677c478bd9Sstevel@tonic-gate if (itw->itw_port_status == USBA_HIGH_SPEED_DEV) { 468b3001defSlg error = ehci_insert_itd_req(ehcip, pp, itw, usb_flags); 4697c478bd9Sstevel@tonic-gate } else { 4707c478bd9Sstevel@tonic-gate error = ehci_insert_sitd_req(ehcip, pp, itw, usb_flags); 4717c478bd9Sstevel@tonic-gate } 4727c478bd9Sstevel@tonic-gate 473b3001defSlg /* Either all the isocs will be added or none of them will */ 474b3001defSlg error = ehci_insert_isoc_to_pfl(ehcip, pp, itw); 475b3001defSlg 476b3001defSlg if (error != USB_SUCCESS) { 477b3001defSlg /* 478b3001defSlg * Deallocate all the ITDs, otherwise they will be 479b3001defSlg * lost forever. 480b3001defSlg */ 481b3001defSlg new_itd = itw->itw_itd_head; 482b3001defSlg while (new_itd) { 483b3001defSlg temp_itd = ehci_itd_iommu_to_cpu(ehcip, 484b3001defSlg Get_ITD(new_itd->itd_itw_next_itd)); 485b3001defSlg ehci_deallocate_itd(ehcip, itw, new_itd); 486b3001defSlg new_itd = temp_itd; 487b3001defSlg } 488b3001defSlg if ((itw->itw_direction == USB_EP_DIR_IN)) { 489b3001defSlg ehci_deallocate_isoc_in_resource(ehcip, pp, itw); 490b3001defSlg 491b3001defSlg if (pp->pp_cur_periodic_req_cnt) { 492b3001defSlg /* 493b3001defSlg * Set pipe state to stop polling and 494b3001defSlg * error to no resource. Don't insert 495b3001defSlg * any more isoch polling requests. 496b3001defSlg */ 497b3001defSlg pp->pp_state = 498b3001defSlg EHCI_PIPE_STATE_STOP_POLLING; 499b3001defSlg pp->pp_error = error; 500b3001defSlg } else { 501b3001defSlg /* Set periodic in pipe state to idle */ 502b3001defSlg pp->pp_state = EHCI_PIPE_STATE_IDLE; 503b3001defSlg } 504b3001defSlg 505b3001defSlg return (error); 506b3001defSlg } 507b3001defSlg 508b3001defSlg /* Save how many packets and data actually went */ 509b3001defSlg itw->itw_num_itds = 0; 510b3001defSlg itw->itw_length = 0; 511b3001defSlg } 512b3001defSlg 513b3001defSlg /* 514b3001defSlg * Reset back to the address of first usb isochronous 515b3001defSlg * packet descriptor. 516b3001defSlg */ 517b3001defSlg itw->itw_curr_isoc_pktp = itw->itw_curr_xfer_reqp->isoc_pkt_descr; 518b3001defSlg 519b3001defSlg /* Reset the CONTINUE flag */ 520b3001defSlg pp->pp_flag &= ~EHCI_ISOC_XFER_CONTINUE; 521b3001defSlg 5227c478bd9Sstevel@tonic-gate return (error); 5237c478bd9Sstevel@tonic-gate } 5247c478bd9Sstevel@tonic-gate 5257c478bd9Sstevel@tonic-gate 526b3001defSlg /* 527b3001defSlg * ehci_insert_itd_req: 528b3001defSlg * 529b3001defSlg * Insert an ITD request into the Host Controller's isochronous list. 530b3001defSlg */ 531b3001defSlg /* ARGSUSED */ 532b3001defSlg static int 533b3001defSlg ehci_insert_itd_req( 534b3001defSlg ehci_state_t *ehcip, 535b3001defSlg ehci_pipe_private_t *pp, 536b3001defSlg ehci_isoc_xwrapper_t *itw, 537b3001defSlg usb_flags_t usb_flags) 538b3001defSlg { 539b3001defSlg usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 540b3001defSlg usb_isoc_req_t *curr_isoc_reqp; 541b3001defSlg usb_isoc_pkt_descr_t *curr_isoc_pkt_descr; 542b3001defSlg size_t curr_isoc_xfer_offset; 543b3001defSlg size_t isoc_pkt_length; 544b3001defSlg uint_t count, xactcount; 545b3001defSlg uint32_t xact_status; 546b3001defSlg uint32_t page, pageselected; 547b3001defSlg uint32_t buf[EHCI_ITD_BUFFER_LIST_SIZE]; 548b3001defSlg uint16_t index = 0; 549b3001defSlg uint16_t multi = 0; 550b3001defSlg ehci_itd_t *new_itd; 551b3001defSlg 552b3001defSlg /* 553b3001defSlg * Get the current isochronous request and packet 554b3001defSlg * descriptor pointers. 555b3001defSlg */ 556b3001defSlg curr_isoc_reqp = (usb_isoc_req_t *)itw->itw_curr_xfer_reqp; 557b3001defSlg 558b3001defSlg page = itw->itw_cookie.dmac_address; 559b3001defSlg ASSERT((page % EHCI_4K_ALIGN) == 0); 560b3001defSlg 561b3001defSlg USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 562112116d8Sfb "ehci_insert_itd_req: itw_curr_xfer_reqp = 0x%p page = 0x%x," 563112116d8Sfb " pagesize = 0x%lx", (void *)itw->itw_curr_xfer_reqp, page, 5640a05e705Slc itw->itw_cookie.dmac_size); 565b3001defSlg 566b3001defSlg /* Insert all the isochronous TDs */ 567b3001defSlg count = 0; 568b3001defSlg curr_isoc_xfer_offset = 0; 569b3001defSlg 570b3001defSlg while (count < curr_isoc_reqp->isoc_pkts_count) { 571b3001defSlg 572b3001defSlg /* Grab a new itd */ 573b3001defSlg new_itd = itw->itw_itd_free_list; 574b3001defSlg 575b3001defSlg ASSERT(new_itd != NULL); 576b3001defSlg 577b3001defSlg itw->itw_itd_free_list = ehci_itd_iommu_to_cpu(ehcip, 578b3001defSlg Get_ITD(new_itd->itd_link_ptr)); 579b3001defSlg Set_ITD(new_itd->itd_link_ptr, NULL); 580b3001defSlg 581b3001defSlg bzero(buf, EHCI_ITD_BUFFER_LIST_SIZE * sizeof (uint32_t)); 582b3001defSlg 583b3001defSlg multi = CalculateITDMultiField(ph->p_ep.wMaxPacketSize); 584b3001defSlg 585b3001defSlg if (multi > EHCI_ITD_CTRL_MULTI_MASK) { 586b3001defSlg USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 587b3001defSlg "ehci_insert_itd_req: Wrong multi value."); 588b3001defSlg 589b3001defSlg return (USB_FAILURE); 590b3001defSlg } 591b3001defSlg 592b3001defSlg /* Fill 8 transaction for every iTD */ 593b3001defSlg for (xactcount = 0, pageselected = 0; 594b3001defSlg xactcount < EHCI_ITD_CTRL_LIST_SIZE; xactcount++) { 595b3001defSlg 596b3001defSlg curr_isoc_pkt_descr = itw->itw_curr_isoc_pktp; 597b3001defSlg 5980a05e705Slc isoc_pkt_length = 5990a05e705Slc curr_isoc_pkt_descr->isoc_pkt_length; 600b3001defSlg 601b3001defSlg curr_isoc_pkt_descr->isoc_pkt_actual_length 602d29f5a71Szhigang lu - Sun Microsystems - Beijing China = (ushort_t)isoc_pkt_length; 603b3001defSlg 604b3001defSlg xact_status = 0; 605b3001defSlg 606b3001defSlg if (pageselected < EHCI_ITD_BUFFER_LIST_SIZE) { 607b3001defSlg 608b3001defSlg buf[pageselected] |= page; 609b3001defSlg } else { 610b3001defSlg USB_DPRINTF_L2(PRINT_MASK_INTR, 611b3001defSlg ehcip->ehci_log_hdl, 612b3001defSlg "ehci_insert_itd_req: " 613b3001defSlg "Error in buffer pointer."); 614b3001defSlg 615b3001defSlg return (USB_FAILURE); 616b3001defSlg } 617b3001defSlg 618d29f5a71Szhigang lu - Sun Microsystems - Beijing China xact_status = (uint32_t)curr_isoc_xfer_offset; 619b3001defSlg xact_status |= (pageselected << 12); 6200a05e705Slc xact_status |= isoc_pkt_length << 16; 621b3001defSlg xact_status |= EHCI_ITD_XFER_ACTIVE; 622b3001defSlg 623b3001defSlg /* Set IOC on the last TD. */ 624b3001defSlg if (count == (curr_isoc_reqp->isoc_pkts_count - 1)) { 625b3001defSlg xact_status |= EHCI_ITD_XFER_IOC_ON; 626b3001defSlg } 627b3001defSlg 628b3001defSlg USB_DPRINTF_L3(PRINT_MASK_INTR, 629b3001defSlg ehcip->ehci_log_hdl, 630b3001defSlg "ehci_insert_itd_req: count = 0x%x multi = %d" 631b3001defSlg "status = 0x%x page = 0x%x index = %d " 632112116d8Sfb "pageselected = %d isoc_pkt_length = 0x%lx", 633b3001defSlg xactcount, multi, xact_status, page, 634b3001defSlg index, pageselected, isoc_pkt_length); 635b3001defSlg 636b3001defSlg /* Fill in the new itd */ 637b3001defSlg Set_ITD_BODY(new_itd, xactcount, xact_status); 638b3001defSlg 639b3001defSlg itw->itw_curr_isoc_pktp++; 640b3001defSlg Set_ITD_INDEX(new_itd, xactcount, index++); 641b3001defSlg 6420a05e705Slc curr_isoc_xfer_offset += isoc_pkt_length; 643b3001defSlg 644b3001defSlg if (curr_isoc_xfer_offset >= EHCI_4K_ALIGN) { 645b3001defSlg pageselected ++; 646b3001defSlg page += EHCI_4K_ALIGN; 647b3001defSlg curr_isoc_xfer_offset -= EHCI_4K_ALIGN; 648b3001defSlg } 649b3001defSlg 650b3001defSlg count ++; 651b3001defSlg if (count >= curr_isoc_reqp->isoc_pkts_count) { 652b3001defSlg 6530a05e705Slc break; 654b3001defSlg } 655b3001defSlg } 656b3001defSlg 657b3001defSlg buf[0] |= (itw->itw_endpoint_num << 8); 658b3001defSlg buf[0] |= itw->itw_device_addr; 6590a05e705Slc buf[1] |= ph->p_ep.wMaxPacketSize & 6600a05e705Slc EHCI_ITD_CTRL_MAX_PACKET_MASK; 6610a05e705Slc 662b3001defSlg if (itw->itw_direction == USB_EP_DIR_IN) { 663b3001defSlg buf[1] |= EHCI_ITD_CTRL_DIR_IN; 664b3001defSlg } 665b3001defSlg buf[2] |= multi; 666b3001defSlg 667b3001defSlg Set_ITD_BODY(new_itd, EHCI_ITD_BUFFER0, buf[0]); 668b3001defSlg Set_ITD_BODY(new_itd, EHCI_ITD_BUFFER1, buf[1]); 669b3001defSlg Set_ITD_BODY(new_itd, EHCI_ITD_BUFFER2, buf[2]); 670b3001defSlg Set_ITD_BODY(new_itd, EHCI_ITD_BUFFER3, buf[3]); 671b3001defSlg Set_ITD_BODY(new_itd, EHCI_ITD_BUFFER4, buf[4]); 672b3001defSlg Set_ITD_BODY(new_itd, EHCI_ITD_BUFFER5, buf[5]); 673b3001defSlg Set_ITD_BODY(new_itd, EHCI_ITD_BUFFER6, buf[6]); 674b3001defSlg 675b3001defSlg Set_ITD(new_itd->itd_state, EHCI_ITD_ACTIVE); 676b3001defSlg ehci_print_itd(ehcip, new_itd); 677b3001defSlg 678b3001defSlg /* 679b3001defSlg * Add this itd to the itw before we add it in the PFL 680b3001defSlg * If adding it to the PFL fails, we will have to cleanup. 681b3001defSlg */ 682b3001defSlg ehci_insert_itd_on_itw(ehcip, itw, new_itd); 683b3001defSlg 684b3001defSlg } 685b3001defSlg 686b3001defSlg return (USB_SUCCESS); 687b3001defSlg } 688b3001defSlg 689b3001defSlg 6907c478bd9Sstevel@tonic-gate /* 6917c478bd9Sstevel@tonic-gate * ehci_insert_sitd_req: 6927c478bd9Sstevel@tonic-gate * 6937c478bd9Sstevel@tonic-gate * Insert an SITD request into the Host Controller's isochronous list. 6947c478bd9Sstevel@tonic-gate */ 6957c478bd9Sstevel@tonic-gate /* ARGSUSED */ 6967c478bd9Sstevel@tonic-gate static int 6977c478bd9Sstevel@tonic-gate ehci_insert_sitd_req( 6987c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 6997c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 7007c478bd9Sstevel@tonic-gate ehci_isoc_xwrapper_t *itw, 7017c478bd9Sstevel@tonic-gate usb_flags_t usb_flags) 7027c478bd9Sstevel@tonic-gate { 7037c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 7047c478bd9Sstevel@tonic-gate usb_isoc_req_t *curr_isoc_reqp; 7057c478bd9Sstevel@tonic-gate usb_isoc_pkt_descr_t *curr_isoc_pkt_descr; 7067c478bd9Sstevel@tonic-gate size_t curr_isoc_xfer_offset; 7077c478bd9Sstevel@tonic-gate size_t isoc_pkt_length; 708b3001defSlg uint_t count; 7097c478bd9Sstevel@tonic-gate uint32_t ctrl, uframe_sched, xfer_state; 7107c478bd9Sstevel@tonic-gate uint32_t page0, page1, prev_sitd; 7117c478bd9Sstevel@tonic-gate uint32_t ssplit_count; 712b3001defSlg ehci_itd_t *new_sitd; 7137c478bd9Sstevel@tonic-gate 7147c478bd9Sstevel@tonic-gate /* 7157c478bd9Sstevel@tonic-gate * Get the current isochronous request and packet 7167c478bd9Sstevel@tonic-gate * descriptor pointers. 7177c478bd9Sstevel@tonic-gate */ 7187c478bd9Sstevel@tonic-gate curr_isoc_reqp = (usb_isoc_req_t *)itw->itw_curr_xfer_reqp; 7197c478bd9Sstevel@tonic-gate 7207c478bd9Sstevel@tonic-gate /* Set the ctrl field */ 7217c478bd9Sstevel@tonic-gate ctrl = 0; 7227c478bd9Sstevel@tonic-gate if (itw->itw_direction == USB_EP_DIR_IN) { 7237c478bd9Sstevel@tonic-gate ctrl |= EHCI_SITD_CTRL_DIR_IN; 7247c478bd9Sstevel@tonic-gate } else { 7257c478bd9Sstevel@tonic-gate ctrl |= EHCI_SITD_CTRL_DIR_OUT; 7267c478bd9Sstevel@tonic-gate } 7277c478bd9Sstevel@tonic-gate 7287c478bd9Sstevel@tonic-gate ctrl |= (itw->itw_hub_port << EHCI_SITD_CTRL_PORT_SHIFT) & 7297c478bd9Sstevel@tonic-gate EHCI_SITD_CTRL_PORT_MASK; 7307c478bd9Sstevel@tonic-gate ctrl |= (itw->itw_hub_addr << EHCI_SITD_CTRL_HUB_SHIFT) & 7317c478bd9Sstevel@tonic-gate EHCI_SITD_CTRL_HUB_MASK; 7327c478bd9Sstevel@tonic-gate ctrl |= (itw->itw_endpoint_num << EHCI_SITD_CTRL_END_PT_SHIFT) & 7337c478bd9Sstevel@tonic-gate EHCI_SITD_CTRL_END_PT_MASK; 7347c478bd9Sstevel@tonic-gate ctrl |= (itw->itw_device_addr << EHCI_SITD_CTRL_DEVICE_SHIFT) & 7357c478bd9Sstevel@tonic-gate EHCI_SITD_CTRL_DEVICE_MASK; 7367c478bd9Sstevel@tonic-gate 7377c478bd9Sstevel@tonic-gate /* Set the micro frame schedule */ 7387c478bd9Sstevel@tonic-gate uframe_sched = 0; 7397c478bd9Sstevel@tonic-gate uframe_sched |= (pp->pp_smask << EHCI_SITD_UFRAME_SMASK_SHIFT) & 7407c478bd9Sstevel@tonic-gate EHCI_SITD_UFRAME_SMASK_MASK; 7417c478bd9Sstevel@tonic-gate uframe_sched |= (pp->pp_cmask << EHCI_SITD_UFRAME_CMASK_SHIFT) & 7427c478bd9Sstevel@tonic-gate EHCI_SITD_UFRAME_CMASK_MASK; 7437c478bd9Sstevel@tonic-gate 7447c478bd9Sstevel@tonic-gate /* Set the default page information */ 7457c478bd9Sstevel@tonic-gate page0 = itw->itw_cookie.dmac_address; 7467c478bd9Sstevel@tonic-gate page1 = 0; 7477c478bd9Sstevel@tonic-gate 7487c478bd9Sstevel@tonic-gate prev_sitd = EHCI_ITD_LINK_PTR_INVALID; 7497c478bd9Sstevel@tonic-gate 7507c478bd9Sstevel@tonic-gate /* 7517c478bd9Sstevel@tonic-gate * Save the number of isochronous TDs needs 7527c478bd9Sstevel@tonic-gate * to be insert to complete current isochronous request. 7537c478bd9Sstevel@tonic-gate */ 7547c478bd9Sstevel@tonic-gate itw->itw_num_itds = curr_isoc_reqp->isoc_pkts_count; 7557c478bd9Sstevel@tonic-gate 7567c478bd9Sstevel@tonic-gate /* Insert all the isochronous TDs */ 7577c478bd9Sstevel@tonic-gate for (count = 0, curr_isoc_xfer_offset = 0; 7580a05e705Slc count < itw->itw_num_itds; count++) { 7597c478bd9Sstevel@tonic-gate 7607c478bd9Sstevel@tonic-gate curr_isoc_pkt_descr = itw->itw_curr_isoc_pktp; 7617c478bd9Sstevel@tonic-gate 7627c478bd9Sstevel@tonic-gate isoc_pkt_length = curr_isoc_pkt_descr->isoc_pkt_length; 763d29f5a71Szhigang lu - Sun Microsystems - Beijing China curr_isoc_pkt_descr->isoc_pkt_actual_length = 764d29f5a71Szhigang lu - Sun Microsystems - Beijing China (ushort_t)isoc_pkt_length; 7657c478bd9Sstevel@tonic-gate 7667c478bd9Sstevel@tonic-gate /* Set the transfer state information */ 7677c478bd9Sstevel@tonic-gate xfer_state = 0; 7687c478bd9Sstevel@tonic-gate 7697c478bd9Sstevel@tonic-gate if (itw->itw_direction == USB_EP_DIR_IN) { 7707c478bd9Sstevel@tonic-gate /* Set the size to the max packet size */ 7717c478bd9Sstevel@tonic-gate xfer_state |= (ph->p_ep.wMaxPacketSize << 7727c478bd9Sstevel@tonic-gate EHCI_SITD_XFER_TOTAL_SHIFT) & 7737c478bd9Sstevel@tonic-gate EHCI_SITD_XFER_TOTAL_MASK; 7747c478bd9Sstevel@tonic-gate } else { 7757c478bd9Sstevel@tonic-gate /* Set the size to the packet length */ 7767c478bd9Sstevel@tonic-gate xfer_state |= (isoc_pkt_length << 7777c478bd9Sstevel@tonic-gate EHCI_SITD_XFER_TOTAL_SHIFT) & 7787c478bd9Sstevel@tonic-gate EHCI_SITD_XFER_TOTAL_MASK; 7797c478bd9Sstevel@tonic-gate } 7807c478bd9Sstevel@tonic-gate xfer_state |= EHCI_SITD_XFER_ACTIVE; 7817c478bd9Sstevel@tonic-gate 7827c478bd9Sstevel@tonic-gate /* Set IOC on the last TD. */ 7837c478bd9Sstevel@tonic-gate if (count == (itw->itw_num_itds - 1)) { 7847c478bd9Sstevel@tonic-gate xfer_state |= EHCI_SITD_XFER_IOC_ON; 7857c478bd9Sstevel@tonic-gate } 7867c478bd9Sstevel@tonic-gate 7877c478bd9Sstevel@tonic-gate ssplit_count = isoc_pkt_length / MAX_UFRAME_SITD_XFER; 7887c478bd9Sstevel@tonic-gate if (isoc_pkt_length % MAX_UFRAME_SITD_XFER) { 7897c478bd9Sstevel@tonic-gate ssplit_count++; 7907c478bd9Sstevel@tonic-gate } 7917c478bd9Sstevel@tonic-gate 7927c478bd9Sstevel@tonic-gate page1 = (ssplit_count & EHCI_SITD_XFER_TCOUNT_MASK) << 7937c478bd9Sstevel@tonic-gate EHCI_SITD_XFER_TCOUNT_SHIFT; 7947c478bd9Sstevel@tonic-gate if (ssplit_count > 1) { 7957c478bd9Sstevel@tonic-gate page1 |= EHCI_SITD_XFER_TP_BEGIN; 7967c478bd9Sstevel@tonic-gate } else { 7977c478bd9Sstevel@tonic-gate page1 |= EHCI_SITD_XFER_TP_ALL; 7987c478bd9Sstevel@tonic-gate } 7997c478bd9Sstevel@tonic-gate 8007c478bd9Sstevel@tonic-gate /* Grab a new sitd */ 8017c478bd9Sstevel@tonic-gate new_sitd = itw->itw_itd_free_list; 8027c478bd9Sstevel@tonic-gate 8037c478bd9Sstevel@tonic-gate ASSERT(new_sitd != NULL); 8047c478bd9Sstevel@tonic-gate 8057c478bd9Sstevel@tonic-gate itw->itw_itd_free_list = ehci_itd_iommu_to_cpu(ehcip, 8067c478bd9Sstevel@tonic-gate Get_ITD(new_sitd->itd_link_ptr)); 8077c478bd9Sstevel@tonic-gate Set_ITD(new_sitd->itd_link_ptr, NULL); 8087c478bd9Sstevel@tonic-gate 8097c478bd9Sstevel@tonic-gate /* Fill in the new sitd */ 8107c478bd9Sstevel@tonic-gate Set_ITD_BODY(new_sitd, EHCI_SITD_CTRL, ctrl); 8117c478bd9Sstevel@tonic-gate Set_ITD_BODY(new_sitd, EHCI_SITD_UFRAME_SCHED, uframe_sched); 8127c478bd9Sstevel@tonic-gate Set_ITD_BODY(new_sitd, EHCI_SITD_XFER_STATE, xfer_state); 8137c478bd9Sstevel@tonic-gate Set_ITD_BODY(new_sitd, EHCI_SITD_BUFFER0, 8147c478bd9Sstevel@tonic-gate page0 + curr_isoc_xfer_offset); 8157c478bd9Sstevel@tonic-gate Set_ITD_BODY(new_sitd, EHCI_SITD_BUFFER1, page1); 8167c478bd9Sstevel@tonic-gate Set_ITD_BODY(new_sitd, EHCI_SITD_PREV_SITD, prev_sitd); 8177c478bd9Sstevel@tonic-gate 8187c478bd9Sstevel@tonic-gate Set_ITD(new_sitd->itd_state, EHCI_ITD_ACTIVE); 8197c478bd9Sstevel@tonic-gate 8207c478bd9Sstevel@tonic-gate /* 8217c478bd9Sstevel@tonic-gate * Add this itd to the itw before we add it in the PFL 8227c478bd9Sstevel@tonic-gate * If adding it to the PFL fails, we will have to cleanup. 8237c478bd9Sstevel@tonic-gate */ 8247c478bd9Sstevel@tonic-gate ehci_insert_itd_on_itw(ehcip, itw, new_sitd); 8257c478bd9Sstevel@tonic-gate 8267c478bd9Sstevel@tonic-gate itw->itw_curr_isoc_pktp++; 8277c478bd9Sstevel@tonic-gate curr_isoc_xfer_offset += isoc_pkt_length; 8287c478bd9Sstevel@tonic-gate } 8297c478bd9Sstevel@tonic-gate 8307c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 8317c478bd9Sstevel@tonic-gate } 8327c478bd9Sstevel@tonic-gate 8337c478bd9Sstevel@tonic-gate 8347c478bd9Sstevel@tonic-gate /* 8357c478bd9Sstevel@tonic-gate * ehci_remove_isoc_itds: 8367c478bd9Sstevel@tonic-gate * 8377c478bd9Sstevel@tonic-gate * Remove all itds from the PFL. 8387c478bd9Sstevel@tonic-gate */ 8397c478bd9Sstevel@tonic-gate static void 8407c478bd9Sstevel@tonic-gate ehci_remove_isoc_itds( 8417c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 8427c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp) 8437c478bd9Sstevel@tonic-gate { 8447c478bd9Sstevel@tonic-gate ehci_isoc_xwrapper_t *curr_itw, *next_itw; 8457c478bd9Sstevel@tonic-gate ehci_itd_t *curr_itd, *next_itd; 8467c478bd9Sstevel@tonic-gate 8477c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 848112116d8Sfb "ehci_remove_isoc_itds: pp = 0x%p", (void *)pp); 8497c478bd9Sstevel@tonic-gate 8507c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 8517c478bd9Sstevel@tonic-gate 8527c478bd9Sstevel@tonic-gate curr_itw = pp->pp_itw_head; 8537c478bd9Sstevel@tonic-gate while (curr_itw) { 8547c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 8557c478bd9Sstevel@tonic-gate "ehci_remove_isoc_itds: itw = 0x%p num itds = %d", 856112116d8Sfb (void *)curr_itw, curr_itw->itw_num_itds); 8577c478bd9Sstevel@tonic-gate 8587c478bd9Sstevel@tonic-gate next_itw = curr_itw->itw_next; 8597c478bd9Sstevel@tonic-gate 8607c478bd9Sstevel@tonic-gate curr_itd = curr_itw->itw_itd_head; 8617c478bd9Sstevel@tonic-gate while (curr_itd) { 8627c478bd9Sstevel@tonic-gate next_itd = ehci_itd_iommu_to_cpu(ehcip, 8637c478bd9Sstevel@tonic-gate Get_ITD(curr_itd->itd_itw_next_itd)); 8647c478bd9Sstevel@tonic-gate 8657c478bd9Sstevel@tonic-gate ehci_reclaim_isoc(ehcip, curr_itw, curr_itd, pp); 8667c478bd9Sstevel@tonic-gate 8677c478bd9Sstevel@tonic-gate curr_itd = next_itd; 8687c478bd9Sstevel@tonic-gate } 8697c478bd9Sstevel@tonic-gate 8707c478bd9Sstevel@tonic-gate ehci_deallocate_itw(ehcip, pp, curr_itw); 8717c478bd9Sstevel@tonic-gate 8727c478bd9Sstevel@tonic-gate curr_itw = next_itw; 8737c478bd9Sstevel@tonic-gate } 8747c478bd9Sstevel@tonic-gate } 8757c478bd9Sstevel@tonic-gate 8767c478bd9Sstevel@tonic-gate 8777c478bd9Sstevel@tonic-gate /* 8787c478bd9Sstevel@tonic-gate * ehci_mark_reclaim_isoc: 8797c478bd9Sstevel@tonic-gate * 8807c478bd9Sstevel@tonic-gate * Set active ITDs to RECLAIM. 8817c478bd9Sstevel@tonic-gate * Return number of ITD that need to be processed. 8827c478bd9Sstevel@tonic-gate */ 8837c478bd9Sstevel@tonic-gate static void 8847c478bd9Sstevel@tonic-gate ehci_mark_reclaim_isoc( 8857c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 8867c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp) 8877c478bd9Sstevel@tonic-gate { 8887c478bd9Sstevel@tonic-gate usb_frame_number_t current_frame_number; 8897c478bd9Sstevel@tonic-gate ehci_isoc_xwrapper_t *curr_itw, *next_itw; 8907c478bd9Sstevel@tonic-gate ehci_itd_t *curr_itd, *next_itd; 8917c478bd9Sstevel@tonic-gate uint_t ctrl; 8927c478bd9Sstevel@tonic-gate uint_t isActive; 893b3001defSlg int i; 8947c478bd9Sstevel@tonic-gate 8957c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 896112116d8Sfb "ehci_mark_reclaim_isoc: pp = 0x%p", (void *)pp); 8977c478bd9Sstevel@tonic-gate 8987c478bd9Sstevel@tonic-gate if (pp->pp_itw_head == NULL) { 8997c478bd9Sstevel@tonic-gate 9007c478bd9Sstevel@tonic-gate return; 9017c478bd9Sstevel@tonic-gate } 9027c478bd9Sstevel@tonic-gate 9037c478bd9Sstevel@tonic-gate /* Get the current frame number. */ 9047c478bd9Sstevel@tonic-gate current_frame_number = ehci_get_current_frame_number(ehcip); 9057c478bd9Sstevel@tonic-gate 9067c478bd9Sstevel@tonic-gate /* Traverse the list of transfer descriptors */ 9077c478bd9Sstevel@tonic-gate curr_itw = pp->pp_itw_head; 9087c478bd9Sstevel@tonic-gate while (curr_itw) { 9097c478bd9Sstevel@tonic-gate next_itw = curr_itw->itw_next; 9107c478bd9Sstevel@tonic-gate 9117c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 9127c478bd9Sstevel@tonic-gate "ehci_mark_reclaim_isoc: itw = 0x%p num itds = %d", 913112116d8Sfb (void *)curr_itw, curr_itw->itw_num_itds); 9147c478bd9Sstevel@tonic-gate 9157c478bd9Sstevel@tonic-gate curr_itd = curr_itw->itw_itd_head; 9167c478bd9Sstevel@tonic-gate while (curr_itd) { 9177c478bd9Sstevel@tonic-gate next_itd = ehci_itd_iommu_to_cpu(ehcip, 9187c478bd9Sstevel@tonic-gate Get_ITD(curr_itd->itd_itw_next_itd)); 9197c478bd9Sstevel@tonic-gate 9207c478bd9Sstevel@tonic-gate if (curr_itw->itw_port_status == USBA_HIGH_SPEED_DEV) { 9217c478bd9Sstevel@tonic-gate 922b3001defSlg for (i = 0; i < EHCI_ITD_CTRL_LIST_SIZE; i++) { 923b3001defSlg ctrl = Get_ITD_BODY(curr_itd, 924b3001defSlg EHCI_ITD_CTRL0 + i); 925b3001defSlg isActive = ctrl & EHCI_ITD_XFER_ACTIVE; 926b3001defSlg /* If still active, deactivate it */ 927b3001defSlg if (isActive) { 928b3001defSlg ctrl &= ~EHCI_ITD_XFER_ACTIVE; 929b3001defSlg Set_ITD_BODY(curr_itd, 930b3001defSlg EHCI_ITD_CTRL0 + i, 931b3001defSlg ctrl); 932b3001defSlg break; 933b3001defSlg } 934b3001defSlg } 9357c478bd9Sstevel@tonic-gate } else { 9367c478bd9Sstevel@tonic-gate ctrl = Get_ITD_BODY(curr_itd, 9377c478bd9Sstevel@tonic-gate EHCI_SITD_XFER_STATE); 9387c478bd9Sstevel@tonic-gate isActive = ctrl & EHCI_SITD_XFER_ACTIVE; 939b3001defSlg /* If it is still active deactivate it */ 9407c478bd9Sstevel@tonic-gate if (isActive) { 9417c478bd9Sstevel@tonic-gate ctrl &= ~EHCI_SITD_XFER_ACTIVE; 9427c478bd9Sstevel@tonic-gate Set_ITD_BODY(curr_itd, 9437c478bd9Sstevel@tonic-gate EHCI_SITD_XFER_STATE, 9447c478bd9Sstevel@tonic-gate ctrl); 9457c478bd9Sstevel@tonic-gate } 9467c478bd9Sstevel@tonic-gate } 9477c478bd9Sstevel@tonic-gate 9487c478bd9Sstevel@tonic-gate /* 9497c478bd9Sstevel@tonic-gate * If the itd was active put it on the reclaim status, 9507c478bd9Sstevel@tonic-gate * so the interrupt handler will know not to process it. 9517c478bd9Sstevel@tonic-gate * Otherwise leave it alone and let the interrupt 9527c478bd9Sstevel@tonic-gate * handler process it normally. 9537c478bd9Sstevel@tonic-gate */ 9547c478bd9Sstevel@tonic-gate if (isActive) { 9557c478bd9Sstevel@tonic-gate Set_ITD(curr_itd->itd_state, EHCI_ITD_RECLAIM); 9567c478bd9Sstevel@tonic-gate Set_ITD_FRAME(curr_itd->itd_reclaim_number, 9577c478bd9Sstevel@tonic-gate current_frame_number); 9587c478bd9Sstevel@tonic-gate ehci_remove_isoc_from_pfl(ehcip, curr_itd); 9597c478bd9Sstevel@tonic-gate } 9607c478bd9Sstevel@tonic-gate curr_itd = next_itd; 9617c478bd9Sstevel@tonic-gate } 9627c478bd9Sstevel@tonic-gate curr_itw = next_itw; 9637c478bd9Sstevel@tonic-gate } 9647c478bd9Sstevel@tonic-gate } 9657c478bd9Sstevel@tonic-gate 9667c478bd9Sstevel@tonic-gate 9677c478bd9Sstevel@tonic-gate /* 9687c478bd9Sstevel@tonic-gate * ehci_reclaim_isoc: 9697c478bd9Sstevel@tonic-gate * 9707c478bd9Sstevel@tonic-gate * "Reclaim" itds that were marked as RECLAIM. 9717c478bd9Sstevel@tonic-gate */ 9727c478bd9Sstevel@tonic-gate static void 9737c478bd9Sstevel@tonic-gate ehci_reclaim_isoc( 9747c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 9757c478bd9Sstevel@tonic-gate ehci_isoc_xwrapper_t *itw, 9767c478bd9Sstevel@tonic-gate ehci_itd_t *itd, 9777c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp) 9787c478bd9Sstevel@tonic-gate { 9797c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 980112116d8Sfb "ehci_reclaim_isoc: itd = 0x%p", (void *)itd); 9817c478bd9Sstevel@tonic-gate 9827c478bd9Sstevel@tonic-gate /* 9837c478bd9Sstevel@tonic-gate * These are itds that were marked "RECLAIM" 9847c478bd9Sstevel@tonic-gate * by the pipe cleanup. 9857c478bd9Sstevel@tonic-gate * 9867c478bd9Sstevel@tonic-gate * Decrement the num_itds and the periodic in 9877c478bd9Sstevel@tonic-gate * request count if necessary. 9887c478bd9Sstevel@tonic-gate */ 9897c478bd9Sstevel@tonic-gate if ((--itw->itw_num_itds == 0) && (itw->itw_curr_xfer_reqp)) { 9907c478bd9Sstevel@tonic-gate if (itw->itw_direction == USB_EP_DIR_IN) { 9917c478bd9Sstevel@tonic-gate 9927c478bd9Sstevel@tonic-gate pp->pp_cur_periodic_req_cnt--; 9937c478bd9Sstevel@tonic-gate 9947c478bd9Sstevel@tonic-gate ehci_deallocate_isoc_in_resource(ehcip, pp, itw); 9957c478bd9Sstevel@tonic-gate } else { 9967c478bd9Sstevel@tonic-gate ehci_hcdi_isoc_callback(pp->pp_pipe_handle, itw, 9977c478bd9Sstevel@tonic-gate USB_CR_FLUSHED); 9987c478bd9Sstevel@tonic-gate } 9997c478bd9Sstevel@tonic-gate } 10007c478bd9Sstevel@tonic-gate 10017c478bd9Sstevel@tonic-gate /* Deallocate this transfer descriptor */ 10027c478bd9Sstevel@tonic-gate ehci_deallocate_itd(ehcip, itw, itd); 10037c478bd9Sstevel@tonic-gate } 10047c478bd9Sstevel@tonic-gate 10057c478bd9Sstevel@tonic-gate 10067c478bd9Sstevel@tonic-gate /* 10077c478bd9Sstevel@tonic-gate * ehci_start_isoc_polling: 10087c478bd9Sstevel@tonic-gate * 10097c478bd9Sstevel@tonic-gate * Insert the number of periodic requests corresponding to polling 10107c478bd9Sstevel@tonic-gate * interval as calculated during pipe open. 10117c478bd9Sstevel@tonic-gate */ 10127c478bd9Sstevel@tonic-gate int 10137c478bd9Sstevel@tonic-gate ehci_start_isoc_polling( 10147c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 10157c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 10167c478bd9Sstevel@tonic-gate usb_flags_t flags) 10177c478bd9Sstevel@tonic-gate { 10187c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp = (ehci_pipe_private_t *)ph->p_hcd_private; 10197c478bd9Sstevel@tonic-gate ehci_isoc_xwrapper_t *itw_list, *itw; 10207c478bd9Sstevel@tonic-gate int i, total_itws; 10217c478bd9Sstevel@tonic-gate int error = USB_SUCCESS; 10227c478bd9Sstevel@tonic-gate 1023b3001defSlg USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 10240a05e705Slc "ehci_start_isoc_polling:"); 1025b3001defSlg 10267c478bd9Sstevel@tonic-gate /* Allocate all the necessary resources for the IN transfer */ 10277c478bd9Sstevel@tonic-gate itw_list = NULL; 10287c478bd9Sstevel@tonic-gate total_itws = pp->pp_max_periodic_req_cnt - pp->pp_cur_periodic_req_cnt; 10297c478bd9Sstevel@tonic-gate for (i = 0; i < total_itws; i += 1) { 10307c478bd9Sstevel@tonic-gate itw = ehci_allocate_isoc_resources(ehcip, ph, NULL, flags); 10317c478bd9Sstevel@tonic-gate if (itw == NULL) { 10327c478bd9Sstevel@tonic-gate error = USB_NO_RESOURCES; 10337c478bd9Sstevel@tonic-gate /* There are not enough resources deallocate the ITWs */ 10347c478bd9Sstevel@tonic-gate itw = itw_list; 10357c478bd9Sstevel@tonic-gate while (itw != NULL) { 10367c478bd9Sstevel@tonic-gate itw_list = itw->itw_next; 10377c478bd9Sstevel@tonic-gate ehci_deallocate_isoc_in_resource( 10380a05e705Slc ehcip, pp, itw); 10397c478bd9Sstevel@tonic-gate ehci_deallocate_itw(ehcip, pp, itw); 10407c478bd9Sstevel@tonic-gate itw = itw_list; 10417c478bd9Sstevel@tonic-gate } 10427c478bd9Sstevel@tonic-gate 10437c478bd9Sstevel@tonic-gate return (error); 10447c478bd9Sstevel@tonic-gate } else { 10457c478bd9Sstevel@tonic-gate if (itw_list == NULL) { 10467c478bd9Sstevel@tonic-gate itw_list = itw; 10477c478bd9Sstevel@tonic-gate } 10487c478bd9Sstevel@tonic-gate } 10497c478bd9Sstevel@tonic-gate } 10507c478bd9Sstevel@tonic-gate 10517c478bd9Sstevel@tonic-gate i = 0; 10527c478bd9Sstevel@tonic-gate while (pp->pp_cur_periodic_req_cnt < pp->pp_max_periodic_req_cnt) { 10537c478bd9Sstevel@tonic-gate 10547c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 10557c478bd9Sstevel@tonic-gate "ehci_start_isoc_polling: max = %d curr = %d itw = %p:", 10567c478bd9Sstevel@tonic-gate pp->pp_max_periodic_req_cnt, pp->pp_cur_periodic_req_cnt, 1057112116d8Sfb (void *)itw_list); 10587c478bd9Sstevel@tonic-gate 10597c478bd9Sstevel@tonic-gate itw = itw_list; 10607c478bd9Sstevel@tonic-gate itw_list = itw->itw_next; 10617c478bd9Sstevel@tonic-gate 10627c478bd9Sstevel@tonic-gate error = ehci_insert_isoc_req(ehcip, pp, itw, flags); 10637c478bd9Sstevel@tonic-gate 10647c478bd9Sstevel@tonic-gate if (error == USB_SUCCESS) { 10657c478bd9Sstevel@tonic-gate pp->pp_cur_periodic_req_cnt++; 10667c478bd9Sstevel@tonic-gate } else { 10677c478bd9Sstevel@tonic-gate /* 10687c478bd9Sstevel@tonic-gate * Deallocate the remaining tw 10697c478bd9Sstevel@tonic-gate * The current tw should have already been deallocated 10707c478bd9Sstevel@tonic-gate */ 10717c478bd9Sstevel@tonic-gate itw = itw_list; 10727c478bd9Sstevel@tonic-gate while (itw != NULL) { 10737c478bd9Sstevel@tonic-gate itw_list = itw->itw_next; 10747c478bd9Sstevel@tonic-gate ehci_deallocate_isoc_in_resource( 10750a05e705Slc ehcip, pp, itw); 10767c478bd9Sstevel@tonic-gate ehci_deallocate_itw(ehcip, pp, itw); 10777c478bd9Sstevel@tonic-gate itw = itw_list; 10787c478bd9Sstevel@tonic-gate } 10797c478bd9Sstevel@tonic-gate /* 10807c478bd9Sstevel@tonic-gate * If this is the first req return an error. 10817c478bd9Sstevel@tonic-gate * Otherwise return success. 10827c478bd9Sstevel@tonic-gate */ 10837c478bd9Sstevel@tonic-gate if (i != 0) { 10847c478bd9Sstevel@tonic-gate error = USB_SUCCESS; 10857c478bd9Sstevel@tonic-gate } 10867c478bd9Sstevel@tonic-gate 10877c478bd9Sstevel@tonic-gate break; 10887c478bd9Sstevel@tonic-gate } 10897c478bd9Sstevel@tonic-gate i++; 10907c478bd9Sstevel@tonic-gate } 10917c478bd9Sstevel@tonic-gate 10927c478bd9Sstevel@tonic-gate return (error); 10937c478bd9Sstevel@tonic-gate } 10947c478bd9Sstevel@tonic-gate 10957c478bd9Sstevel@tonic-gate 10967c478bd9Sstevel@tonic-gate /* 10977c478bd9Sstevel@tonic-gate * Isochronronous handling functions. 10987c478bd9Sstevel@tonic-gate */ 10997c478bd9Sstevel@tonic-gate /* 11007c478bd9Sstevel@tonic-gate * ehci_traverse_active_isoc_list: 11017c478bd9Sstevel@tonic-gate */ 11027c478bd9Sstevel@tonic-gate void 11037c478bd9Sstevel@tonic-gate ehci_traverse_active_isoc_list( 11047c478bd9Sstevel@tonic-gate ehci_state_t *ehcip) 11057c478bd9Sstevel@tonic-gate { 11067c478bd9Sstevel@tonic-gate ehci_isoc_xwrapper_t *curr_itw; 11077c478bd9Sstevel@tonic-gate ehci_itd_t *curr_itd, *next_itd; 11087c478bd9Sstevel@tonic-gate uint_t state; 11097c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp; 11107c478bd9Sstevel@tonic-gate 11117c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 11127c478bd9Sstevel@tonic-gate "ehci_traverse_active_isoc_list:"); 11137c478bd9Sstevel@tonic-gate 11147c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 11157c478bd9Sstevel@tonic-gate 11167c478bd9Sstevel@tonic-gate /* Sync ITD pool */ 11177c478bd9Sstevel@tonic-gate Sync_ITD_Pool(ehcip); 11187c478bd9Sstevel@tonic-gate 11197c478bd9Sstevel@tonic-gate /* Traverse the list of done itds */ 11207c478bd9Sstevel@tonic-gate curr_itd = ehci_create_done_itd_list(ehcip); 1121b3001defSlg USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 1122112116d8Sfb "ehci_traverse_active_isoc_list: current itd = 0x%p", 1123112116d8Sfb (void *)curr_itd); 11247c478bd9Sstevel@tonic-gate 11257c478bd9Sstevel@tonic-gate while (curr_itd) { 11267c478bd9Sstevel@tonic-gate /* Save the next_itd */ 11277c478bd9Sstevel@tonic-gate next_itd = ehci_itd_iommu_to_cpu(ehcip, 11287c478bd9Sstevel@tonic-gate Get_ITD(curr_itd->itd_next_active_itd)); 11297c478bd9Sstevel@tonic-gate 11307c478bd9Sstevel@tonic-gate /* Get the transfer wrapper and the pp */ 11317c478bd9Sstevel@tonic-gate curr_itw = (ehci_isoc_xwrapper_t *)EHCI_LOOKUP_ID( 11320a05e705Slc (uint32_t)Get_ITD(curr_itd->itd_trans_wrapper)); 11337c478bd9Sstevel@tonic-gate pp = curr_itw->itw_pipe_private; 11347c478bd9Sstevel@tonic-gate 1135b3001defSlg if (curr_itw->itw_port_status == USBA_HIGH_SPEED_DEV) { 1136b3001defSlg ehci_print_itd(ehcip, curr_itd); 1137b3001defSlg } else { 1138b3001defSlg ehci_print_sitd(ehcip, curr_itd); 1139b3001defSlg } 11407c478bd9Sstevel@tonic-gate 11417c478bd9Sstevel@tonic-gate /* Get the ITD state */ 11427c478bd9Sstevel@tonic-gate state = Get_ITD(curr_itd->itd_state); 11437c478bd9Sstevel@tonic-gate 11447c478bd9Sstevel@tonic-gate /* Only process the ITDs marked as active. */ 11457c478bd9Sstevel@tonic-gate if (state == EHCI_ITD_ACTIVE) { 11467c478bd9Sstevel@tonic-gate ehci_parse_isoc_error(ehcip, curr_itw, curr_itd); 11477c478bd9Sstevel@tonic-gate ehci_handle_isoc(ehcip, curr_itw, curr_itd); 11487c478bd9Sstevel@tonic-gate } else { 11497c478bd9Sstevel@tonic-gate ASSERT(state == EHCI_ITD_RECLAIM); 11507c478bd9Sstevel@tonic-gate ehci_reclaim_isoc(ehcip, curr_itw, curr_itd, pp); 11517c478bd9Sstevel@tonic-gate } 11527c478bd9Sstevel@tonic-gate 11537c478bd9Sstevel@tonic-gate /* 11547c478bd9Sstevel@tonic-gate * Deallocate the transfer wrapper if there are no more 11557c478bd9Sstevel@tonic-gate * ITD's for the transfer wrapper. ehci_deallocate_itw() 11567c478bd9Sstevel@tonic-gate * will not deallocate the tw for a periodic in endpoint 11577c478bd9Sstevel@tonic-gate * since it will always have a ITD attached to it. 11587c478bd9Sstevel@tonic-gate */ 11597c478bd9Sstevel@tonic-gate ehci_deallocate_itw(ehcip, pp, curr_itw); 11607c478bd9Sstevel@tonic-gate 11617c478bd9Sstevel@tonic-gate /* Check any ISOC is waiting for transfers completion event */ 11627c478bd9Sstevel@tonic-gate if (pp->pp_itw_head == NULL) { 11637c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 11647c478bd9Sstevel@tonic-gate "ehci_traverse_active_isoc_list: " 1165112116d8Sfb "Sent transfers completion event pp = 0x%p", 1166112116d8Sfb (void *)pp); 11677c478bd9Sstevel@tonic-gate cv_signal(&pp->pp_xfer_cmpl_cv); 11687c478bd9Sstevel@tonic-gate } 11697c478bd9Sstevel@tonic-gate 11707c478bd9Sstevel@tonic-gate curr_itd = next_itd; 1171b3001defSlg 1172b3001defSlg USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 1173b3001defSlg "ehci_traverse_active_isoc_list: state = 0x%x " 1174b3001defSlg "pp = 0x%p itw = 0x%p itd = 0x%p next_itd = 0x%p", 1175112116d8Sfb state, (void *)pp, (void *)curr_itw, (void *)curr_itd, 1176112116d8Sfb (void *)next_itd); 11777c478bd9Sstevel@tonic-gate } 11787c478bd9Sstevel@tonic-gate } 11797c478bd9Sstevel@tonic-gate 11807c478bd9Sstevel@tonic-gate 11817c478bd9Sstevel@tonic-gate static void 11827c478bd9Sstevel@tonic-gate ehci_handle_isoc( 11837c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 11847c478bd9Sstevel@tonic-gate ehci_isoc_xwrapper_t *itw, 11857c478bd9Sstevel@tonic-gate ehci_itd_t *itd) 11867c478bd9Sstevel@tonic-gate { 11877c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp; /* Pipe private field */ 11887c478bd9Sstevel@tonic-gate 11897c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 11907c478bd9Sstevel@tonic-gate 11917c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 11927c478bd9Sstevel@tonic-gate "ehci_handle_isoc:"); 11937c478bd9Sstevel@tonic-gate 11947c478bd9Sstevel@tonic-gate /* Obtain the pipe private structure */ 11957c478bd9Sstevel@tonic-gate pp = itw->itw_pipe_private; 11967c478bd9Sstevel@tonic-gate 1197b3001defSlg ehci_handle_itd(ehcip, pp, itw, itd, itw->itw_handle_callback_value); 11987c478bd9Sstevel@tonic-gate } 11997c478bd9Sstevel@tonic-gate 12007c478bd9Sstevel@tonic-gate 12017c478bd9Sstevel@tonic-gate /* 12027c478bd9Sstevel@tonic-gate * ehci_handle_itd: 12037c478bd9Sstevel@tonic-gate * 1204b3001defSlg * Handle an (split) isochronous transfer descriptor. 12057c478bd9Sstevel@tonic-gate * This function will deallocate the itd from the list as well. 12067c478bd9Sstevel@tonic-gate */ 12077c478bd9Sstevel@tonic-gate /* ARGSUSED */ 12087c478bd9Sstevel@tonic-gate static void 1209b3001defSlg ehci_handle_itd( 12107c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 12117c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 12127c478bd9Sstevel@tonic-gate ehci_isoc_xwrapper_t *itw, 12137c478bd9Sstevel@tonic-gate ehci_itd_t *itd, 12147c478bd9Sstevel@tonic-gate void *tw_handle_callback_value) 12157c478bd9Sstevel@tonic-gate { 12167c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 12177c478bd9Sstevel@tonic-gate usb_isoc_req_t *curr_isoc_reqp = 12180a05e705Slc (usb_isoc_req_t *)itw->itw_curr_xfer_reqp; 12197c478bd9Sstevel@tonic-gate int error = USB_SUCCESS; 1220b3001defSlg int i, index; 12217c478bd9Sstevel@tonic-gate 12227c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 1223b3001defSlg "ehci_handle_itd: pp=0x%p itw=0x%p itd=0x%p " 1224112116d8Sfb "isoc_reqp=0%p data=0x%p", (void *)pp, (void *)itw, (void *)itd, 1225112116d8Sfb (void *)curr_isoc_reqp, (void *)curr_isoc_reqp->isoc_data); 12267c478bd9Sstevel@tonic-gate 1227b3001defSlg if (itw->itw_port_status == USBA_HIGH_SPEED_DEV && 1228b3001defSlg curr_isoc_reqp != NULL) { 1229b3001defSlg 12300a05e705Slc for (i = 0; i < EHCI_ITD_CTRL_LIST_SIZE; i++) { 1231b3001defSlg 12320a05e705Slc index = Get_ITD_INDEX(itd, i); 12330a05e705Slc if (index == EHCI_ITD_UNUSED_INDEX) { 1234b3001defSlg 12350a05e705Slc continue; 12360a05e705Slc } 12370a05e705Slc curr_isoc_reqp-> 12380a05e705Slc isoc_pkt_descr[index].isoc_pkt_actual_length = 12390a05e705Slc (Get_ITD_BODY(itd, i) & EHCI_ITD_XFER_LENGTH) >> 16; 1240b3001defSlg } 1241b3001defSlg } 1242b3001defSlg 12437c478bd9Sstevel@tonic-gate /* 12447c478bd9Sstevel@tonic-gate * Decrement the ITDs counter and check whether all the isoc 12457c478bd9Sstevel@tonic-gate * data has been send or received. If ITDs counter reaches 12467c478bd9Sstevel@tonic-gate * zero then inform client driver about completion current 12477c478bd9Sstevel@tonic-gate * isoc request. Otherwise wait for completion of other isoc 12487c478bd9Sstevel@tonic-gate * ITDs or transactions on this pipe. 12497c478bd9Sstevel@tonic-gate */ 12507c478bd9Sstevel@tonic-gate if (--itw->itw_num_itds != 0) { 12517c478bd9Sstevel@tonic-gate /* Deallocate this transfer descriptor */ 12527c478bd9Sstevel@tonic-gate ehci_deallocate_itd(ehcip, itw, itd); 12537c478bd9Sstevel@tonic-gate 12547c478bd9Sstevel@tonic-gate return; 12557c478bd9Sstevel@tonic-gate } 12567c478bd9Sstevel@tonic-gate 12577c478bd9Sstevel@tonic-gate /* 12587c478bd9Sstevel@tonic-gate * If this is a isoc in pipe, return the data to the client. 12597c478bd9Sstevel@tonic-gate * For a isoc out pipe, there is no need to do anything. 12607c478bd9Sstevel@tonic-gate */ 12617c478bd9Sstevel@tonic-gate if (itw->itw_direction == USB_EP_DIR_OUT) { 12627c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 1263112116d8Sfb "ehci_handle_itd: Isoc out pipe, isoc_reqp=0x%p, data=0x%p", 1264112116d8Sfb (void *)curr_isoc_reqp, (void *)curr_isoc_reqp->isoc_data); 12657c478bd9Sstevel@tonic-gate 12667c478bd9Sstevel@tonic-gate /* Do the callback */ 12677c478bd9Sstevel@tonic-gate ehci_hcdi_isoc_callback(ph, itw, USB_CR_OK); 12687c478bd9Sstevel@tonic-gate 12697c478bd9Sstevel@tonic-gate /* Deallocate this transfer descriptor */ 12707c478bd9Sstevel@tonic-gate ehci_deallocate_itd(ehcip, itw, itd); 12717c478bd9Sstevel@tonic-gate 12727c478bd9Sstevel@tonic-gate return; 12737c478bd9Sstevel@tonic-gate } 12747c478bd9Sstevel@tonic-gate 12757c478bd9Sstevel@tonic-gate /* Decrement number of IN isochronous request count */ 12767c478bd9Sstevel@tonic-gate pp->pp_cur_periodic_req_cnt--; 12777c478bd9Sstevel@tonic-gate 1278b3001defSlg USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 1279b3001defSlg "ehci_handle_itd: pp_cur_periodic_req_cnt = 0x%x ", 1280b3001defSlg pp->pp_cur_periodic_req_cnt); 1281b3001defSlg 12827c478bd9Sstevel@tonic-gate /* Call ehci_sendup_itd_message to send message to upstream */ 12837c478bd9Sstevel@tonic-gate ehci_sendup_itd_message(ehcip, pp, itw, itd, USB_CR_OK); 12847c478bd9Sstevel@tonic-gate 12857c478bd9Sstevel@tonic-gate /* Deallocate this transfer descriptor */ 12867c478bd9Sstevel@tonic-gate ehci_deallocate_itd(ehcip, itw, itd); 12877c478bd9Sstevel@tonic-gate 12887c478bd9Sstevel@tonic-gate /* 12897c478bd9Sstevel@tonic-gate * If isochronous pipe state is still active, insert next isochronous 12907c478bd9Sstevel@tonic-gate * request into the Host Controller's isochronous list. 12917c478bd9Sstevel@tonic-gate */ 12927c478bd9Sstevel@tonic-gate if (pp->pp_state != EHCI_PIPE_STATE_ACTIVE) { 12937c478bd9Sstevel@tonic-gate 12947c478bd9Sstevel@tonic-gate return; 12957c478bd9Sstevel@tonic-gate } 12967c478bd9Sstevel@tonic-gate 12977c478bd9Sstevel@tonic-gate if ((error = ehci_allocate_isoc_in_resource(ehcip, pp, itw, 0)) == 12987c478bd9Sstevel@tonic-gate USB_SUCCESS) { 12997c478bd9Sstevel@tonic-gate curr_isoc_reqp = (usb_isoc_req_t *)itw->itw_curr_xfer_reqp; 13007c478bd9Sstevel@tonic-gate 13017c478bd9Sstevel@tonic-gate ASSERT(curr_isoc_reqp != NULL); 13027c478bd9Sstevel@tonic-gate 13037c478bd9Sstevel@tonic-gate itw->itw_num_itds = ehci_calc_num_itds(itw, 13047c478bd9Sstevel@tonic-gate curr_isoc_reqp->isoc_pkts_count); 13057c478bd9Sstevel@tonic-gate 13067c478bd9Sstevel@tonic-gate if (ehci_allocate_itds_for_itw(ehcip, itw, itw->itw_num_itds) != 13077c478bd9Sstevel@tonic-gate USB_SUCCESS) { 13087c478bd9Sstevel@tonic-gate ehci_deallocate_isoc_in_resource(ehcip, pp, itw); 13097c478bd9Sstevel@tonic-gate itw->itw_num_itds = 0; 13107c478bd9Sstevel@tonic-gate error = USB_FAILURE; 13117c478bd9Sstevel@tonic-gate } 13127c478bd9Sstevel@tonic-gate } 13137c478bd9Sstevel@tonic-gate 13147c478bd9Sstevel@tonic-gate if ((error != USB_SUCCESS) || 13157c478bd9Sstevel@tonic-gate (ehci_insert_isoc_req(ehcip, pp, itw, 0) != USB_SUCCESS)) { 13167c478bd9Sstevel@tonic-gate /* 13177c478bd9Sstevel@tonic-gate * Set pipe state to stop polling and error to no 13187c478bd9Sstevel@tonic-gate * resource. Don't insert any more isoch polling 13197c478bd9Sstevel@tonic-gate * requests. 13207c478bd9Sstevel@tonic-gate */ 13217c478bd9Sstevel@tonic-gate pp->pp_state = EHCI_PIPE_STATE_STOP_POLLING; 13227c478bd9Sstevel@tonic-gate pp->pp_error = USB_CR_NO_RESOURCES; 13237c478bd9Sstevel@tonic-gate 13247c478bd9Sstevel@tonic-gate } else { 13257c478bd9Sstevel@tonic-gate /* Increment number of IN isochronous request count */ 13267c478bd9Sstevel@tonic-gate pp->pp_cur_periodic_req_cnt++; 13277c478bd9Sstevel@tonic-gate 13287c478bd9Sstevel@tonic-gate ASSERT(pp->pp_cur_periodic_req_cnt == 13297c478bd9Sstevel@tonic-gate pp->pp_max_periodic_req_cnt); 13307c478bd9Sstevel@tonic-gate } 13317c478bd9Sstevel@tonic-gate } 13327c478bd9Sstevel@tonic-gate 13337c478bd9Sstevel@tonic-gate 13347c478bd9Sstevel@tonic-gate /* 13357c478bd9Sstevel@tonic-gate * ehci_sendup_qtd_message: 13367c478bd9Sstevel@tonic-gate * copy data, if necessary and do callback 13377c478bd9Sstevel@tonic-gate */ 13387c478bd9Sstevel@tonic-gate /* ARGSUSED */ 13397c478bd9Sstevel@tonic-gate static void 13407c478bd9Sstevel@tonic-gate ehci_sendup_itd_message( 13417c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 13427c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 13437c478bd9Sstevel@tonic-gate ehci_isoc_xwrapper_t *itw, 13447c478bd9Sstevel@tonic-gate ehci_itd_t *td, 13457c478bd9Sstevel@tonic-gate usb_cr_t error) 13467c478bd9Sstevel@tonic-gate { 13477c478bd9Sstevel@tonic-gate usb_isoc_req_t *isoc_reqp = itw->itw_curr_xfer_reqp; 13487c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 13497c478bd9Sstevel@tonic-gate size_t length; 13507c478bd9Sstevel@tonic-gate uchar_t *buf; 13517c478bd9Sstevel@tonic-gate mblk_t *mp; 13527c478bd9Sstevel@tonic-gate 13537c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 13547c478bd9Sstevel@tonic-gate 13557c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 13567c478bd9Sstevel@tonic-gate "ehci_sendup_itd_message:"); 13577c478bd9Sstevel@tonic-gate 13587c478bd9Sstevel@tonic-gate ASSERT(itw != NULL); 13597c478bd9Sstevel@tonic-gate 13607c478bd9Sstevel@tonic-gate length = itw->itw_length; 13617c478bd9Sstevel@tonic-gate 13627c478bd9Sstevel@tonic-gate /* Copy the data into the mblk_t */ 13637c478bd9Sstevel@tonic-gate buf = (uchar_t *)itw->itw_buf; 13647c478bd9Sstevel@tonic-gate 1365b3001defSlg USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 1366112116d8Sfb "ehci_sendup_itd_message: length %ld error %d", length, error); 13677c478bd9Sstevel@tonic-gate 13687c478bd9Sstevel@tonic-gate /* Get the message block */ 13697c478bd9Sstevel@tonic-gate mp = isoc_reqp->isoc_data; 13707c478bd9Sstevel@tonic-gate 13717c478bd9Sstevel@tonic-gate ASSERT(mp != NULL); 13727c478bd9Sstevel@tonic-gate 13737c478bd9Sstevel@tonic-gate if (length) { 13747c478bd9Sstevel@tonic-gate /* Sync IO buffer */ 13757c478bd9Sstevel@tonic-gate Sync_IO_Buffer(itw->itw_dmahandle, length); 13767c478bd9Sstevel@tonic-gate 13777c478bd9Sstevel@tonic-gate /* Copy the data into the message */ 1378b3001defSlg ddi_rep_get8(itw->itw_accesshandle, 1379b3001defSlg mp->b_rptr, buf, length, DDI_DEV_AUTOINCR); 13807c478bd9Sstevel@tonic-gate 13817c478bd9Sstevel@tonic-gate /* Increment the write pointer */ 13827c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_wptr + length; 13837c478bd9Sstevel@tonic-gate } else { 13847c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 13857c478bd9Sstevel@tonic-gate "ehci_sendup_itd_message: Zero length packet"); 13867c478bd9Sstevel@tonic-gate } 13877c478bd9Sstevel@tonic-gate 13887c478bd9Sstevel@tonic-gate ehci_hcdi_isoc_callback(ph, itw, error); 13897c478bd9Sstevel@tonic-gate } 13907c478bd9Sstevel@tonic-gate 13917c478bd9Sstevel@tonic-gate 13927c478bd9Sstevel@tonic-gate /* 13937c478bd9Sstevel@tonic-gate * ehci_hcdi_isoc_callback: 13947c478bd9Sstevel@tonic-gate * 13957c478bd9Sstevel@tonic-gate * Convenience wrapper around usba_hcdi_cb() other than root hub. 13967c478bd9Sstevel@tonic-gate */ 13977c478bd9Sstevel@tonic-gate void 13987c478bd9Sstevel@tonic-gate ehci_hcdi_isoc_callback( 13997c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 14007c478bd9Sstevel@tonic-gate ehci_isoc_xwrapper_t *itw, 14017c478bd9Sstevel@tonic-gate usb_cr_t completion_reason) 14027c478bd9Sstevel@tonic-gate { 14037c478bd9Sstevel@tonic-gate ehci_state_t *ehcip = ehci_obtain_state( 14040a05e705Slc ph->p_usba_device->usb_root_hub_dip); 14057c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp = (ehci_pipe_private_t *)ph->p_hcd_private; 14067c478bd9Sstevel@tonic-gate usb_opaque_t curr_xfer_reqp; 14077c478bd9Sstevel@tonic-gate uint_t pipe_state = 0; 14087c478bd9Sstevel@tonic-gate 14097c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl, 14107c478bd9Sstevel@tonic-gate "ehci_hcdi_isoc_callback: ph = 0x%p, itw = 0x%p, cr = 0x%x", 1411112116d8Sfb (void *)ph, (void *)itw, completion_reason); 14127c478bd9Sstevel@tonic-gate 14137c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 14147c478bd9Sstevel@tonic-gate 14157c478bd9Sstevel@tonic-gate /* Set the pipe state as per completion reason */ 14167c478bd9Sstevel@tonic-gate switch (completion_reason) { 14177c478bd9Sstevel@tonic-gate case USB_CR_OK: 14187c478bd9Sstevel@tonic-gate pipe_state = pp->pp_state; 14197c478bd9Sstevel@tonic-gate break; 14207c478bd9Sstevel@tonic-gate case USB_CR_NO_RESOURCES: 14217c478bd9Sstevel@tonic-gate case USB_CR_NOT_SUPPORTED: 14227c478bd9Sstevel@tonic-gate case USB_CR_PIPE_RESET: 14237c478bd9Sstevel@tonic-gate case USB_CR_STOPPED_POLLING: 14247c478bd9Sstevel@tonic-gate pipe_state = EHCI_PIPE_STATE_IDLE; 14257c478bd9Sstevel@tonic-gate break; 14267c478bd9Sstevel@tonic-gate case USB_CR_PIPE_CLOSING: 14277c478bd9Sstevel@tonic-gate break; 14287c478bd9Sstevel@tonic-gate } 14297c478bd9Sstevel@tonic-gate 14307c478bd9Sstevel@tonic-gate pp->pp_state = pipe_state; 14317c478bd9Sstevel@tonic-gate 14327c478bd9Sstevel@tonic-gate if (itw && itw->itw_curr_xfer_reqp) { 14337c478bd9Sstevel@tonic-gate curr_xfer_reqp = (usb_opaque_t)itw->itw_curr_xfer_reqp; 14347c478bd9Sstevel@tonic-gate itw->itw_curr_xfer_reqp = NULL; 14357c478bd9Sstevel@tonic-gate } else { 14367c478bd9Sstevel@tonic-gate ASSERT(pp->pp_client_periodic_in_reqp != NULL); 14377c478bd9Sstevel@tonic-gate 14387c478bd9Sstevel@tonic-gate curr_xfer_reqp = pp->pp_client_periodic_in_reqp; 14397c478bd9Sstevel@tonic-gate pp->pp_client_periodic_in_reqp = NULL; 14407c478bd9Sstevel@tonic-gate } 14417c478bd9Sstevel@tonic-gate 14427c478bd9Sstevel@tonic-gate ASSERT(curr_xfer_reqp != NULL); 14437c478bd9Sstevel@tonic-gate 14447c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex); 14457c478bd9Sstevel@tonic-gate 14467c478bd9Sstevel@tonic-gate usba_hcdi_cb(ph, curr_xfer_reqp, completion_reason); 14477c478bd9Sstevel@tonic-gate 14487c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex); 14497c478bd9Sstevel@tonic-gate } 1450