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 /*
22d3d50737SRafael 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
ehci_isoc_init(ehci_state_t * ehcip)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
ehci_isoc_cleanup(ehci_state_t * ehcip)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 */
ehci_isoc_pipe_cleanup(ehci_state_t * ehcip,usba_pipe_handle_data_t * ph)2047c478bd9Sstevel@tonic-gate void ehci_isoc_pipe_cleanup(
2057c478bd9Sstevel@tonic-gate ehci_state_t *ehcip,
206*6aef9e11SToomas Soome usba_pipe_handle_data_t *ph)
207*6aef9e11SToomas Soome {
2087c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp = (ehci_pipe_private_t *)ph->p_hcd_private;
2097c478bd9Sstevel@tonic-gate uint_t pipe_state = pp->pp_state;
2107c478bd9Sstevel@tonic-gate usb_cr_t completion_reason;
2117c478bd9Sstevel@tonic-gate
2127c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
2137c478bd9Sstevel@tonic-gate "ehci_isoc_pipe_cleanup: ph = 0x%p", (void *)ph);
2147c478bd9Sstevel@tonic-gate
2157c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
2167c478bd9Sstevel@tonic-gate
2177c478bd9Sstevel@tonic-gate /* Stop all further processing */
2187c478bd9Sstevel@tonic-gate ehci_mark_reclaim_isoc(ehcip, pp);
2197c478bd9Sstevel@tonic-gate
2207c478bd9Sstevel@tonic-gate /*
2217c478bd9Sstevel@tonic-gate * Wait for processing all completed transfers
2227c478bd9Sstevel@tonic-gate * and send result upstream/
2237c478bd9Sstevel@tonic-gate */
2247c478bd9Sstevel@tonic-gate ehci_wait_for_isoc_completion(ehcip, pp);
2257c478bd9Sstevel@tonic-gate
2267c478bd9Sstevel@tonic-gate /* Go ahead and remove all remaining itds if there are any */
2277c478bd9Sstevel@tonic-gate ehci_remove_isoc_itds(ehcip, pp);
2287c478bd9Sstevel@tonic-gate
2297c478bd9Sstevel@tonic-gate switch (pipe_state) {
2307c478bd9Sstevel@tonic-gate case EHCI_PIPE_STATE_CLOSE:
2317c478bd9Sstevel@tonic-gate completion_reason = USB_CR_PIPE_CLOSING;
2327c478bd9Sstevel@tonic-gate break;
2337c478bd9Sstevel@tonic-gate case EHCI_PIPE_STATE_RESET:
2347c478bd9Sstevel@tonic-gate case EHCI_PIPE_STATE_STOP_POLLING:
2357c478bd9Sstevel@tonic-gate /* Set completion reason */
2367c478bd9Sstevel@tonic-gate completion_reason = (pipe_state ==
2377c478bd9Sstevel@tonic-gate EHCI_PIPE_STATE_RESET) ?
2387c478bd9Sstevel@tonic-gate USB_CR_PIPE_RESET: USB_CR_STOPPED_POLLING;
2397c478bd9Sstevel@tonic-gate
2407c478bd9Sstevel@tonic-gate /* Set pipe state to idle */
2417c478bd9Sstevel@tonic-gate pp->pp_state = EHCI_PIPE_STATE_IDLE;
2427c478bd9Sstevel@tonic-gate
2437c478bd9Sstevel@tonic-gate break;
2447c478bd9Sstevel@tonic-gate }
2457c478bd9Sstevel@tonic-gate
2467c478bd9Sstevel@tonic-gate /*
2477c478bd9Sstevel@tonic-gate * Do the callback for the original client
2487c478bd9Sstevel@tonic-gate * periodic IN request.
2497c478bd9Sstevel@tonic-gate */
2507c478bd9Sstevel@tonic-gate if ((ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK) ==
2517c478bd9Sstevel@tonic-gate USB_EP_DIR_IN) {
2527c478bd9Sstevel@tonic-gate
2537c478bd9Sstevel@tonic-gate ehci_do_client_periodic_in_req_callback(
2547c478bd9Sstevel@tonic-gate ehcip, pp, completion_reason);
2557c478bd9Sstevel@tonic-gate }
2567c478bd9Sstevel@tonic-gate }
2577c478bd9Sstevel@tonic-gate
2587c478bd9Sstevel@tonic-gate
2597c478bd9Sstevel@tonic-gate /*
2607c478bd9Sstevel@tonic-gate * ehci_wait_for_transfers_completion:
2617c478bd9Sstevel@tonic-gate *
2627c478bd9Sstevel@tonic-gate * Wait for processing all completed transfers and to send results
2637c478bd9Sstevel@tonic-gate * to upstream.
2647c478bd9Sstevel@tonic-gate */
2657c478bd9Sstevel@tonic-gate static void
ehci_wait_for_isoc_completion(ehci_state_t * ehcip,ehci_pipe_private_t * pp)2667c478bd9Sstevel@tonic-gate ehci_wait_for_isoc_completion(
2677c478bd9Sstevel@tonic-gate ehci_state_t *ehcip,
2687c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp)
2697c478bd9Sstevel@tonic-gate {
2707c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
2717c478bd9Sstevel@tonic-gate
2727c478bd9Sstevel@tonic-gate if (pp->pp_itw_head == NULL) {
2737c478bd9Sstevel@tonic-gate
2747c478bd9Sstevel@tonic-gate return;
2757c478bd9Sstevel@tonic-gate }
2767c478bd9Sstevel@tonic-gate
277d3d50737SRafael Vanoni (void) cv_reltimedwait(&pp->pp_xfer_cmpl_cv, &ehcip->ehci_int_mutex,
278d3d50737SRafael Vanoni drv_usectohz(EHCI_XFER_CMPL_TIMEWAIT * 1000000), TR_CLOCK_TICK);
2797c478bd9Sstevel@tonic-gate
2807c478bd9Sstevel@tonic-gate if (pp->pp_itw_head) {
2817c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
2827c478bd9Sstevel@tonic-gate "ehci_wait_for_isoc_completion: "
2837c478bd9Sstevel@tonic-gate "No transfers completion confirmation received");
2847c478bd9Sstevel@tonic-gate }
2857c478bd9Sstevel@tonic-gate }
2867c478bd9Sstevel@tonic-gate
2877c478bd9Sstevel@tonic-gate
2887c478bd9Sstevel@tonic-gate /*
2897c478bd9Sstevel@tonic-gate * Isochronous request functions
2907c478bd9Sstevel@tonic-gate */
2917c478bd9Sstevel@tonic-gate /*
2927c478bd9Sstevel@tonic-gate * ehci_allocate_isoc_resources:
2937c478bd9Sstevel@tonic-gate *
2947c478bd9Sstevel@tonic-gate * Calculates the number of tds necessary for a isoch transfer, and
2957c478bd9Sstevel@tonic-gate * allocates all the necessary resources.
2967c478bd9Sstevel@tonic-gate *
2977c478bd9Sstevel@tonic-gate * Returns NULL if there is insufficient resources otherwise ITW.
2987c478bd9Sstevel@tonic-gate */
2997c478bd9Sstevel@tonic-gate ehci_isoc_xwrapper_t *
ehci_allocate_isoc_resources(ehci_state_t * ehcip,usba_pipe_handle_data_t * ph,usb_isoc_req_t * isoc_reqp,usb_flags_t usb_flags)3007c478bd9Sstevel@tonic-gate ehci_allocate_isoc_resources(
3017c478bd9Sstevel@tonic-gate ehci_state_t *ehcip,
3027c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
3037c478bd9Sstevel@tonic-gate usb_isoc_req_t *isoc_reqp,
3047c478bd9Sstevel@tonic-gate usb_flags_t usb_flags)
3057c478bd9Sstevel@tonic-gate {
3067c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp = (ehci_pipe_private_t *)ph->p_hcd_private;
307b3001defSlg int pipe_dir, i;
3087c478bd9Sstevel@tonic-gate uint_t max_ep_pkt_size, max_isoc_xfer_size;
3097c478bd9Sstevel@tonic-gate usb_isoc_pkt_descr_t *isoc_pkt_descr;
310b3001defSlg size_t isoc_pkt_count, isoc_pkts_length;
3110a05e705Slc size_t itw_xfer_size = 0;
3127c478bd9Sstevel@tonic-gate ehci_isoc_xwrapper_t *itw;
3137c478bd9Sstevel@tonic-gate
3147c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
3157c478bd9Sstevel@tonic-gate "ehci_allocate_isoc_resources: flags = 0x%x", usb_flags);
3167c478bd9Sstevel@tonic-gate
3177c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
3187c478bd9Sstevel@tonic-gate
3197c478bd9Sstevel@tonic-gate /*
3207c478bd9Sstevel@tonic-gate * Check whether pipe is in halted state.
3217c478bd9Sstevel@tonic-gate */
3227c478bd9Sstevel@tonic-gate if (pp->pp_state == EHCI_PIPE_STATE_ERROR) {
3237c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
3247c478bd9Sstevel@tonic-gate "ehci_allocate_isoc_resources:"
3257c478bd9Sstevel@tonic-gate "Pipe is in error state, need pipe reset to continue");
3267c478bd9Sstevel@tonic-gate
3277c478bd9Sstevel@tonic-gate return (NULL);
3287c478bd9Sstevel@tonic-gate }
3297c478bd9Sstevel@tonic-gate
3307c478bd9Sstevel@tonic-gate /* Calculate the maximum isochronous transfer size we allow */
3310a05e705Slc max_ep_pkt_size = (ph->p_ep.wMaxPacketSize &
3320a05e705Slc EHCI_ITD_CTRL_MAX_PACKET_MASK) *
3330a05e705Slc CalculateITDMultiField(ph->p_ep.wMaxPacketSize);
3340a05e705Slc
3357c478bd9Sstevel@tonic-gate max_isoc_xfer_size = EHCI_MAX_ISOC_PKTS_PER_XFER * max_ep_pkt_size;
3367c478bd9Sstevel@tonic-gate
3377c478bd9Sstevel@tonic-gate /* Get the packet descriptor and number of packets to send */
3387c478bd9Sstevel@tonic-gate if (isoc_reqp) {
3397c478bd9Sstevel@tonic-gate isoc_pkt_descr = isoc_reqp->isoc_pkt_descr;
3407c478bd9Sstevel@tonic-gate isoc_pkt_count = isoc_reqp->isoc_pkts_count;
341b3001defSlg isoc_pkts_length = isoc_reqp->isoc_pkts_length;
3427c478bd9Sstevel@tonic-gate } else {
3437c478bd9Sstevel@tonic-gate isoc_pkt_descr = ((usb_isoc_req_t *)
3447c478bd9Sstevel@tonic-gate pp->pp_client_periodic_in_reqp)->isoc_pkt_descr;
3457c478bd9Sstevel@tonic-gate
3467c478bd9Sstevel@tonic-gate isoc_pkt_count = ((usb_isoc_req_t *)
3477c478bd9Sstevel@tonic-gate pp->pp_client_periodic_in_reqp)->isoc_pkts_count;
348b3001defSlg
349b3001defSlg isoc_pkts_length = ((usb_isoc_req_t *)
3507c478bd9Sstevel@tonic-gate pp->pp_client_periodic_in_reqp)->isoc_pkts_length;
3517c478bd9Sstevel@tonic-gate }
3527c478bd9Sstevel@tonic-gate
3537c478bd9Sstevel@tonic-gate /* Calculate the size of the transfer. */
3547c478bd9Sstevel@tonic-gate pipe_dir = ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK;
3557c478bd9Sstevel@tonic-gate if (pipe_dir == USB_EP_DIR_IN) {
356b3001defSlg for (i = 0; i < isoc_pkt_count; i++) {
3570a05e705Slc /*
3580a05e705Slc * isoc_pkt_length is used as Transaction Length and
3590a05e705Slc * according to EHCI spec Table 3-3, the maximum value
3600a05e705Slc * allowed is 3072
3610a05e705Slc */
3620a05e705Slc if (isoc_pkt_descr->isoc_pkt_length > 3072) {
3630a05e705Slc
3640a05e705Slc return (NULL);
3650a05e705Slc }
3660a05e705Slc
367b3001defSlg itw_xfer_size += isoc_pkt_descr->isoc_pkt_length;
3680a05e705Slc
369b3001defSlg isoc_pkt_descr++;
370b3001defSlg }
371b3001defSlg
372b3001defSlg if ((isoc_pkts_length) &&
3730a05e705Slc (isoc_pkts_length != itw_xfer_size)) {
374b3001defSlg
375b3001defSlg USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
376b3001defSlg "ehci_allocate_isoc_resources: "
377112116d8Sfb "isoc_pkts_length 0x%lx is not equal to the sum of "
378112116d8Sfb "all pkt lengths 0x%lx in an isoc request",
379b3001defSlg isoc_pkts_length, itw_xfer_size);
380b3001defSlg
381b3001defSlg return (NULL);
382b3001defSlg }
383b3001defSlg
3847c478bd9Sstevel@tonic-gate } else {
3857c478bd9Sstevel@tonic-gate ASSERT(isoc_reqp != NULL);
386d29f5a71Szhigang lu - Sun Microsystems - Beijing China itw_xfer_size = MBLKL(isoc_reqp->isoc_data);
3877c478bd9Sstevel@tonic-gate }
3887c478bd9Sstevel@tonic-gate
3897c478bd9Sstevel@tonic-gate /* Check the size of isochronous request */
3907c478bd9Sstevel@tonic-gate if (itw_xfer_size > max_isoc_xfer_size) {
3917c478bd9Sstevel@tonic-gate
3927c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
393b3001defSlg "ehci_allocate_isoc_resources: Maximum isoc request "
394112116d8Sfb "size 0x%x Given isoc request size 0x%lx",
3957c478bd9Sstevel@tonic-gate max_isoc_xfer_size, itw_xfer_size);
3967c478bd9Sstevel@tonic-gate
3977c478bd9Sstevel@tonic-gate return (NULL);
3987c478bd9Sstevel@tonic-gate }
3997c478bd9Sstevel@tonic-gate
4007c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
401112116d8Sfb "ehci_allocate_isoc_resources: length = 0x%lx", itw_xfer_size);
4027c478bd9Sstevel@tonic-gate
4037c478bd9Sstevel@tonic-gate /* Allocate the itw for this request */
4047c478bd9Sstevel@tonic-gate if ((itw = ehci_allocate_itw_resources(ehcip, pp, itw_xfer_size,
4057c478bd9Sstevel@tonic-gate usb_flags, isoc_pkt_count)) == NULL) {
4067c478bd9Sstevel@tonic-gate
4077c478bd9Sstevel@tonic-gate return (NULL);
4087c478bd9Sstevel@tonic-gate }
4097c478bd9Sstevel@tonic-gate
4107c478bd9Sstevel@tonic-gate itw->itw_handle_callback_value = NULL;
4117c478bd9Sstevel@tonic-gate
4127c478bd9Sstevel@tonic-gate if (pipe_dir == USB_EP_DIR_IN) {
4137c478bd9Sstevel@tonic-gate if (ehci_allocate_isoc_in_resource(ehcip, pp, itw, usb_flags) !=
4147c478bd9Sstevel@tonic-gate USB_SUCCESS) {
4157c478bd9Sstevel@tonic-gate
4167c478bd9Sstevel@tonic-gate ehci_deallocate_itw(ehcip, pp, itw);
4177c478bd9Sstevel@tonic-gate
4187c478bd9Sstevel@tonic-gate return (NULL);
4197c478bd9Sstevel@tonic-gate }
4207c478bd9Sstevel@tonic-gate } else {
4217c478bd9Sstevel@tonic-gate if (itw->itw_length) {
4227c478bd9Sstevel@tonic-gate ASSERT(isoc_reqp->isoc_data != NULL);
4237c478bd9Sstevel@tonic-gate
4247c478bd9Sstevel@tonic-gate /* Copy the data into the buffer */
4257c478bd9Sstevel@tonic-gate bcopy(isoc_reqp->isoc_data->b_rptr,
4267c478bd9Sstevel@tonic-gate itw->itw_buf, itw->itw_length);
4277c478bd9Sstevel@tonic-gate
4287c478bd9Sstevel@tonic-gate Sync_IO_Buffer_for_device(itw->itw_dmahandle,
4297c478bd9Sstevel@tonic-gate itw->itw_length);
4307c478bd9Sstevel@tonic-gate }
4317c478bd9Sstevel@tonic-gate itw->itw_curr_xfer_reqp = isoc_reqp;
4327c478bd9Sstevel@tonic-gate }
4337c478bd9Sstevel@tonic-gate
4347c478bd9Sstevel@tonic-gate return (itw);
4357c478bd9Sstevel@tonic-gate }
4367c478bd9Sstevel@tonic-gate
4377c478bd9Sstevel@tonic-gate
4387c478bd9Sstevel@tonic-gate /*
4397c478bd9Sstevel@tonic-gate * ehci_insert_isoc_req:
4407c478bd9Sstevel@tonic-gate *
4417c478bd9Sstevel@tonic-gate * Insert an isochronous request into the Host Controller's
4427c478bd9Sstevel@tonic-gate * isochronous list.
4437c478bd9Sstevel@tonic-gate */
4447c478bd9Sstevel@tonic-gate int
ehci_insert_isoc_req(ehci_state_t * ehcip,ehci_pipe_private_t * pp,ehci_isoc_xwrapper_t * itw,usb_flags_t usb_flags)4457c478bd9Sstevel@tonic-gate ehci_insert_isoc_req(
4467c478bd9Sstevel@tonic-gate ehci_state_t *ehcip,
4477c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp,
4487c478bd9Sstevel@tonic-gate ehci_isoc_xwrapper_t *itw,
4497c478bd9Sstevel@tonic-gate usb_flags_t usb_flags)
4507c478bd9Sstevel@tonic-gate {
4517c478bd9Sstevel@tonic-gate int error;
452b3001defSlg ehci_itd_t *new_itd, *temp_itd;
4537c478bd9Sstevel@tonic-gate
4547c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
4557c478bd9Sstevel@tonic-gate "ehci_insert_isoc_req: flags = 0x%x port status = 0x%x",
4567c478bd9Sstevel@tonic-gate usb_flags, itw->itw_port_status);
4577c478bd9Sstevel@tonic-gate
4587c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
4597c478bd9Sstevel@tonic-gate
4607c478bd9Sstevel@tonic-gate ASSERT(itw->itw_curr_xfer_reqp != NULL);
4617c478bd9Sstevel@tonic-gate ASSERT(itw->itw_curr_xfer_reqp->isoc_pkt_descr != NULL);
4627c478bd9Sstevel@tonic-gate
4637c478bd9Sstevel@tonic-gate /*
4647c478bd9Sstevel@tonic-gate * Save address of first usb isochronous packet descriptor.
4657c478bd9Sstevel@tonic-gate */
4667c478bd9Sstevel@tonic-gate itw->itw_curr_isoc_pktp = itw->itw_curr_xfer_reqp->isoc_pkt_descr;
4677c478bd9Sstevel@tonic-gate
4687c478bd9Sstevel@tonic-gate if (itw->itw_port_status == USBA_HIGH_SPEED_DEV) {
469b3001defSlg error = ehci_insert_itd_req(ehcip, pp, itw, usb_flags);
4707c478bd9Sstevel@tonic-gate } else {
4717c478bd9Sstevel@tonic-gate error = ehci_insert_sitd_req(ehcip, pp, itw, usb_flags);
4727c478bd9Sstevel@tonic-gate }
4737c478bd9Sstevel@tonic-gate
474b3001defSlg /* Either all the isocs will be added or none of them will */
475b3001defSlg error = ehci_insert_isoc_to_pfl(ehcip, pp, itw);
476b3001defSlg
477b3001defSlg if (error != USB_SUCCESS) {
478b3001defSlg /*
479b3001defSlg * Deallocate all the ITDs, otherwise they will be
480b3001defSlg * lost forever.
481b3001defSlg */
482b3001defSlg new_itd = itw->itw_itd_head;
483b3001defSlg while (new_itd) {
484b3001defSlg temp_itd = ehci_itd_iommu_to_cpu(ehcip,
485b3001defSlg Get_ITD(new_itd->itd_itw_next_itd));
486b3001defSlg ehci_deallocate_itd(ehcip, itw, new_itd);
487b3001defSlg new_itd = temp_itd;
488b3001defSlg }
489b3001defSlg if ((itw->itw_direction == USB_EP_DIR_IN)) {
490b3001defSlg ehci_deallocate_isoc_in_resource(ehcip, pp, itw);
491b3001defSlg
492b3001defSlg if (pp->pp_cur_periodic_req_cnt) {
493b3001defSlg /*
494b3001defSlg * Set pipe state to stop polling and
495b3001defSlg * error to no resource. Don't insert
496b3001defSlg * any more isoch polling requests.
497b3001defSlg */
498b3001defSlg pp->pp_state =
499b3001defSlg EHCI_PIPE_STATE_STOP_POLLING;
500b3001defSlg pp->pp_error = error;
501b3001defSlg } else {
502b3001defSlg /* Set periodic in pipe state to idle */
503b3001defSlg pp->pp_state = EHCI_PIPE_STATE_IDLE;
504b3001defSlg }
505b3001defSlg
506b3001defSlg return (error);
507b3001defSlg }
508b3001defSlg
509b3001defSlg /* Save how many packets and data actually went */
510b3001defSlg itw->itw_num_itds = 0;
511b3001defSlg itw->itw_length = 0;
512b3001defSlg }
513b3001defSlg
514b3001defSlg /*
515b3001defSlg * Reset back to the address of first usb isochronous
516b3001defSlg * packet descriptor.
517b3001defSlg */
518b3001defSlg itw->itw_curr_isoc_pktp = itw->itw_curr_xfer_reqp->isoc_pkt_descr;
519b3001defSlg
520b3001defSlg /* Reset the CONTINUE flag */
521b3001defSlg pp->pp_flag &= ~EHCI_ISOC_XFER_CONTINUE;
522b3001defSlg
5237c478bd9Sstevel@tonic-gate return (error);
5247c478bd9Sstevel@tonic-gate }
5257c478bd9Sstevel@tonic-gate
5267c478bd9Sstevel@tonic-gate
527b3001defSlg /*
528b3001defSlg * ehci_insert_itd_req:
529b3001defSlg *
530b3001defSlg * Insert an ITD request into the Host Controller's isochronous list.
531b3001defSlg */
532b3001defSlg /* ARGSUSED */
533b3001defSlg static int
ehci_insert_itd_req(ehci_state_t * ehcip,ehci_pipe_private_t * pp,ehci_isoc_xwrapper_t * itw,usb_flags_t usb_flags)534b3001defSlg ehci_insert_itd_req(
535b3001defSlg ehci_state_t *ehcip,
536b3001defSlg ehci_pipe_private_t *pp,
537b3001defSlg ehci_isoc_xwrapper_t *itw,
538b3001defSlg usb_flags_t usb_flags)
539b3001defSlg {
540b3001defSlg usba_pipe_handle_data_t *ph = pp->pp_pipe_handle;
541b3001defSlg usb_isoc_req_t *curr_isoc_reqp;
542b3001defSlg usb_isoc_pkt_descr_t *curr_isoc_pkt_descr;
543b3001defSlg size_t curr_isoc_xfer_offset;
544b3001defSlg size_t isoc_pkt_length;
545b3001defSlg uint_t count, xactcount;
546b3001defSlg uint32_t xact_status;
547b3001defSlg uint32_t page, pageselected;
548b3001defSlg uint32_t buf[EHCI_ITD_BUFFER_LIST_SIZE];
549b3001defSlg uint16_t index = 0;
550b3001defSlg uint16_t multi = 0;
551b3001defSlg ehci_itd_t *new_itd;
552b3001defSlg
553b3001defSlg /*
554b3001defSlg * Get the current isochronous request and packet
555b3001defSlg * descriptor pointers.
556b3001defSlg */
557b3001defSlg curr_isoc_reqp = (usb_isoc_req_t *)itw->itw_curr_xfer_reqp;
558b3001defSlg
559b3001defSlg page = itw->itw_cookie.dmac_address;
560b3001defSlg ASSERT((page % EHCI_4K_ALIGN) == 0);
561b3001defSlg
562b3001defSlg USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
563112116d8Sfb "ehci_insert_itd_req: itw_curr_xfer_reqp = 0x%p page = 0x%x,"
564112116d8Sfb " pagesize = 0x%lx", (void *)itw->itw_curr_xfer_reqp, page,
5650a05e705Slc itw->itw_cookie.dmac_size);
566b3001defSlg
567b3001defSlg /* Insert all the isochronous TDs */
568b3001defSlg count = 0;
569b3001defSlg curr_isoc_xfer_offset = 0;
570b3001defSlg
571b3001defSlg while (count < curr_isoc_reqp->isoc_pkts_count) {
572b3001defSlg
573b3001defSlg /* Grab a new itd */
574b3001defSlg new_itd = itw->itw_itd_free_list;
575b3001defSlg
576b3001defSlg ASSERT(new_itd != NULL);
577b3001defSlg
578b3001defSlg itw->itw_itd_free_list = ehci_itd_iommu_to_cpu(ehcip,
579b3001defSlg Get_ITD(new_itd->itd_link_ptr));
580*6aef9e11SToomas Soome Set_ITD(new_itd->itd_link_ptr, 0);
581b3001defSlg
582b3001defSlg bzero(buf, EHCI_ITD_BUFFER_LIST_SIZE * sizeof (uint32_t));
583b3001defSlg
584b3001defSlg multi = CalculateITDMultiField(ph->p_ep.wMaxPacketSize);
585b3001defSlg
586b3001defSlg if (multi > EHCI_ITD_CTRL_MULTI_MASK) {
587b3001defSlg USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
588b3001defSlg "ehci_insert_itd_req: Wrong multi value.");
589b3001defSlg
590b3001defSlg return (USB_FAILURE);
591b3001defSlg }
592b3001defSlg
593b3001defSlg /* Fill 8 transaction for every iTD */
594b3001defSlg for (xactcount = 0, pageselected = 0;
595b3001defSlg xactcount < EHCI_ITD_CTRL_LIST_SIZE; xactcount++) {
596b3001defSlg
597b3001defSlg curr_isoc_pkt_descr = itw->itw_curr_isoc_pktp;
598b3001defSlg
5990a05e705Slc isoc_pkt_length =
6000a05e705Slc curr_isoc_pkt_descr->isoc_pkt_length;
601b3001defSlg
602b3001defSlg curr_isoc_pkt_descr->isoc_pkt_actual_length
603d29f5a71Szhigang lu - Sun Microsystems - Beijing China = (ushort_t)isoc_pkt_length;
604b3001defSlg
605b3001defSlg xact_status = 0;
606b3001defSlg
607b3001defSlg if (pageselected < EHCI_ITD_BUFFER_LIST_SIZE) {
608b3001defSlg
609b3001defSlg buf[pageselected] |= page;
610b3001defSlg } else {
611b3001defSlg USB_DPRINTF_L2(PRINT_MASK_INTR,
612b3001defSlg ehcip->ehci_log_hdl,
613b3001defSlg "ehci_insert_itd_req: "
614b3001defSlg "Error in buffer pointer.");
615b3001defSlg
616b3001defSlg return (USB_FAILURE);
617b3001defSlg }
618b3001defSlg
619d29f5a71Szhigang lu - Sun Microsystems - Beijing China xact_status = (uint32_t)curr_isoc_xfer_offset;
620b3001defSlg xact_status |= (pageselected << 12);
6210a05e705Slc xact_status |= isoc_pkt_length << 16;
622b3001defSlg xact_status |= EHCI_ITD_XFER_ACTIVE;
623b3001defSlg
624b3001defSlg /* Set IOC on the last TD. */
625b3001defSlg if (count == (curr_isoc_reqp->isoc_pkts_count - 1)) {
626b3001defSlg xact_status |= EHCI_ITD_XFER_IOC_ON;
627b3001defSlg }
628b3001defSlg
629b3001defSlg USB_DPRINTF_L3(PRINT_MASK_INTR,
630b3001defSlg ehcip->ehci_log_hdl,
631b3001defSlg "ehci_insert_itd_req: count = 0x%x multi = %d"
632b3001defSlg "status = 0x%x page = 0x%x index = %d "
633112116d8Sfb "pageselected = %d isoc_pkt_length = 0x%lx",
634b3001defSlg xactcount, multi, xact_status, page,
635b3001defSlg index, pageselected, isoc_pkt_length);
636b3001defSlg
637b3001defSlg /* Fill in the new itd */
638b3001defSlg Set_ITD_BODY(new_itd, xactcount, xact_status);
639b3001defSlg
640b3001defSlg itw->itw_curr_isoc_pktp++;
641b3001defSlg Set_ITD_INDEX(new_itd, xactcount, index++);
642b3001defSlg
6430a05e705Slc curr_isoc_xfer_offset += isoc_pkt_length;
644b3001defSlg
645b3001defSlg if (curr_isoc_xfer_offset >= EHCI_4K_ALIGN) {
646b3001defSlg pageselected ++;
647b3001defSlg page += EHCI_4K_ALIGN;
648b3001defSlg curr_isoc_xfer_offset -= EHCI_4K_ALIGN;
649b3001defSlg }
650b3001defSlg
651b3001defSlg count ++;
652b3001defSlg if (count >= curr_isoc_reqp->isoc_pkts_count) {
653b3001defSlg
6540a05e705Slc break;
655b3001defSlg }
656b3001defSlg }
657b3001defSlg
658b3001defSlg buf[0] |= (itw->itw_endpoint_num << 8);
659b3001defSlg buf[0] |= itw->itw_device_addr;
6600a05e705Slc buf[1] |= ph->p_ep.wMaxPacketSize &
6610a05e705Slc EHCI_ITD_CTRL_MAX_PACKET_MASK;
6620a05e705Slc
663b3001defSlg if (itw->itw_direction == USB_EP_DIR_IN) {
664b3001defSlg buf[1] |= EHCI_ITD_CTRL_DIR_IN;
665b3001defSlg }
666b3001defSlg buf[2] |= multi;
667b3001defSlg
668b3001defSlg Set_ITD_BODY(new_itd, EHCI_ITD_BUFFER0, buf[0]);
669b3001defSlg Set_ITD_BODY(new_itd, EHCI_ITD_BUFFER1, buf[1]);
670b3001defSlg Set_ITD_BODY(new_itd, EHCI_ITD_BUFFER2, buf[2]);
671b3001defSlg Set_ITD_BODY(new_itd, EHCI_ITD_BUFFER3, buf[3]);
672b3001defSlg Set_ITD_BODY(new_itd, EHCI_ITD_BUFFER4, buf[4]);
673b3001defSlg Set_ITD_BODY(new_itd, EHCI_ITD_BUFFER5, buf[5]);
674b3001defSlg Set_ITD_BODY(new_itd, EHCI_ITD_BUFFER6, buf[6]);
675b3001defSlg
676b3001defSlg Set_ITD(new_itd->itd_state, EHCI_ITD_ACTIVE);
677b3001defSlg ehci_print_itd(ehcip, new_itd);
678b3001defSlg
679b3001defSlg /*
680b3001defSlg * Add this itd to the itw before we add it in the PFL
681b3001defSlg * If adding it to the PFL fails, we will have to cleanup.
682b3001defSlg */
683b3001defSlg ehci_insert_itd_on_itw(ehcip, itw, new_itd);
684b3001defSlg
685b3001defSlg }
686b3001defSlg
687b3001defSlg return (USB_SUCCESS);
688b3001defSlg }
689b3001defSlg
690b3001defSlg
6917c478bd9Sstevel@tonic-gate /*
6927c478bd9Sstevel@tonic-gate * ehci_insert_sitd_req:
6937c478bd9Sstevel@tonic-gate *
6947c478bd9Sstevel@tonic-gate * Insert an SITD request into the Host Controller's isochronous list.
6957c478bd9Sstevel@tonic-gate */
6967c478bd9Sstevel@tonic-gate /* ARGSUSED */
6977c478bd9Sstevel@tonic-gate static int
ehci_insert_sitd_req(ehci_state_t * ehcip,ehci_pipe_private_t * pp,ehci_isoc_xwrapper_t * itw,usb_flags_t usb_flags)6987c478bd9Sstevel@tonic-gate ehci_insert_sitd_req(
6997c478bd9Sstevel@tonic-gate ehci_state_t *ehcip,
7007c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp,
7017c478bd9Sstevel@tonic-gate ehci_isoc_xwrapper_t *itw,
7027c478bd9Sstevel@tonic-gate usb_flags_t usb_flags)
7037c478bd9Sstevel@tonic-gate {
7047c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle;
7057c478bd9Sstevel@tonic-gate usb_isoc_req_t *curr_isoc_reqp;
7067c478bd9Sstevel@tonic-gate usb_isoc_pkt_descr_t *curr_isoc_pkt_descr;
7077c478bd9Sstevel@tonic-gate size_t curr_isoc_xfer_offset;
7087c478bd9Sstevel@tonic-gate size_t isoc_pkt_length;
709b3001defSlg uint_t count;
7107c478bd9Sstevel@tonic-gate uint32_t ctrl, uframe_sched, xfer_state;
7117c478bd9Sstevel@tonic-gate uint32_t page0, page1, prev_sitd;
7127c478bd9Sstevel@tonic-gate uint32_t ssplit_count;
713b3001defSlg ehci_itd_t *new_sitd;
7147c478bd9Sstevel@tonic-gate
7157c478bd9Sstevel@tonic-gate /*
7167c478bd9Sstevel@tonic-gate * Get the current isochronous request and packet
7177c478bd9Sstevel@tonic-gate * descriptor pointers.
7187c478bd9Sstevel@tonic-gate */
7197c478bd9Sstevel@tonic-gate curr_isoc_reqp = (usb_isoc_req_t *)itw->itw_curr_xfer_reqp;
7207c478bd9Sstevel@tonic-gate
7217c478bd9Sstevel@tonic-gate /* Set the ctrl field */
7227c478bd9Sstevel@tonic-gate ctrl = 0;
7237c478bd9Sstevel@tonic-gate if (itw->itw_direction == USB_EP_DIR_IN) {
7247c478bd9Sstevel@tonic-gate ctrl |= EHCI_SITD_CTRL_DIR_IN;
7257c478bd9Sstevel@tonic-gate } else {
7267c478bd9Sstevel@tonic-gate ctrl |= EHCI_SITD_CTRL_DIR_OUT;
7277c478bd9Sstevel@tonic-gate }
7287c478bd9Sstevel@tonic-gate
7297c478bd9Sstevel@tonic-gate ctrl |= (itw->itw_hub_port << EHCI_SITD_CTRL_PORT_SHIFT) &
7307c478bd9Sstevel@tonic-gate EHCI_SITD_CTRL_PORT_MASK;
7317c478bd9Sstevel@tonic-gate ctrl |= (itw->itw_hub_addr << EHCI_SITD_CTRL_HUB_SHIFT) &
7327c478bd9Sstevel@tonic-gate EHCI_SITD_CTRL_HUB_MASK;
7337c478bd9Sstevel@tonic-gate ctrl |= (itw->itw_endpoint_num << EHCI_SITD_CTRL_END_PT_SHIFT) &
7347c478bd9Sstevel@tonic-gate EHCI_SITD_CTRL_END_PT_MASK;
7357c478bd9Sstevel@tonic-gate ctrl |= (itw->itw_device_addr << EHCI_SITD_CTRL_DEVICE_SHIFT) &
7367c478bd9Sstevel@tonic-gate EHCI_SITD_CTRL_DEVICE_MASK;
7377c478bd9Sstevel@tonic-gate
7387c478bd9Sstevel@tonic-gate /* Set the micro frame schedule */
7397c478bd9Sstevel@tonic-gate uframe_sched = 0;
7407c478bd9Sstevel@tonic-gate uframe_sched |= (pp->pp_smask << EHCI_SITD_UFRAME_SMASK_SHIFT) &
7417c478bd9Sstevel@tonic-gate EHCI_SITD_UFRAME_SMASK_MASK;
7427c478bd9Sstevel@tonic-gate uframe_sched |= (pp->pp_cmask << EHCI_SITD_UFRAME_CMASK_SHIFT) &
7437c478bd9Sstevel@tonic-gate EHCI_SITD_UFRAME_CMASK_MASK;
7447c478bd9Sstevel@tonic-gate
7457c478bd9Sstevel@tonic-gate /* Set the default page information */
7467c478bd9Sstevel@tonic-gate page0 = itw->itw_cookie.dmac_address;
7477c478bd9Sstevel@tonic-gate page1 = 0;
7487c478bd9Sstevel@tonic-gate
7497c478bd9Sstevel@tonic-gate prev_sitd = EHCI_ITD_LINK_PTR_INVALID;
7507c478bd9Sstevel@tonic-gate
7517c478bd9Sstevel@tonic-gate /*
7527c478bd9Sstevel@tonic-gate * Save the number of isochronous TDs needs
7537c478bd9Sstevel@tonic-gate * to be insert to complete current isochronous request.
7547c478bd9Sstevel@tonic-gate */
7557c478bd9Sstevel@tonic-gate itw->itw_num_itds = curr_isoc_reqp->isoc_pkts_count;
7567c478bd9Sstevel@tonic-gate
7577c478bd9Sstevel@tonic-gate /* Insert all the isochronous TDs */
7587c478bd9Sstevel@tonic-gate for (count = 0, curr_isoc_xfer_offset = 0;
7590a05e705Slc count < itw->itw_num_itds; count++) {
7607c478bd9Sstevel@tonic-gate
7617c478bd9Sstevel@tonic-gate curr_isoc_pkt_descr = itw->itw_curr_isoc_pktp;
7627c478bd9Sstevel@tonic-gate
7637c478bd9Sstevel@tonic-gate isoc_pkt_length = curr_isoc_pkt_descr->isoc_pkt_length;
764d29f5a71Szhigang lu - Sun Microsystems - Beijing China curr_isoc_pkt_descr->isoc_pkt_actual_length =
765d29f5a71Szhigang lu - Sun Microsystems - Beijing China (ushort_t)isoc_pkt_length;
7667c478bd9Sstevel@tonic-gate
7677c478bd9Sstevel@tonic-gate /* Set the transfer state information */
7687c478bd9Sstevel@tonic-gate xfer_state = 0;
7697c478bd9Sstevel@tonic-gate
7707c478bd9Sstevel@tonic-gate if (itw->itw_direction == USB_EP_DIR_IN) {
7717c478bd9Sstevel@tonic-gate /* Set the size to the max packet size */
7727c478bd9Sstevel@tonic-gate xfer_state |= (ph->p_ep.wMaxPacketSize <<
7737c478bd9Sstevel@tonic-gate EHCI_SITD_XFER_TOTAL_SHIFT) &
7747c478bd9Sstevel@tonic-gate EHCI_SITD_XFER_TOTAL_MASK;
7757c478bd9Sstevel@tonic-gate } else {
7767c478bd9Sstevel@tonic-gate /* Set the size to the packet length */
7777c478bd9Sstevel@tonic-gate xfer_state |= (isoc_pkt_length <<
7787c478bd9Sstevel@tonic-gate EHCI_SITD_XFER_TOTAL_SHIFT) &
7797c478bd9Sstevel@tonic-gate EHCI_SITD_XFER_TOTAL_MASK;
7807c478bd9Sstevel@tonic-gate }
7817c478bd9Sstevel@tonic-gate xfer_state |= EHCI_SITD_XFER_ACTIVE;
7827c478bd9Sstevel@tonic-gate
7837c478bd9Sstevel@tonic-gate /* Set IOC on the last TD. */
7847c478bd9Sstevel@tonic-gate if (count == (itw->itw_num_itds - 1)) {
7857c478bd9Sstevel@tonic-gate xfer_state |= EHCI_SITD_XFER_IOC_ON;
7867c478bd9Sstevel@tonic-gate }
7877c478bd9Sstevel@tonic-gate
7887c478bd9Sstevel@tonic-gate ssplit_count = isoc_pkt_length / MAX_UFRAME_SITD_XFER;
7897c478bd9Sstevel@tonic-gate if (isoc_pkt_length % MAX_UFRAME_SITD_XFER) {
7907c478bd9Sstevel@tonic-gate ssplit_count++;
7917c478bd9Sstevel@tonic-gate }
7927c478bd9Sstevel@tonic-gate
7937c478bd9Sstevel@tonic-gate page1 = (ssplit_count & EHCI_SITD_XFER_TCOUNT_MASK) <<
7947c478bd9Sstevel@tonic-gate EHCI_SITD_XFER_TCOUNT_SHIFT;
7957c478bd9Sstevel@tonic-gate if (ssplit_count > 1) {
7967c478bd9Sstevel@tonic-gate page1 |= EHCI_SITD_XFER_TP_BEGIN;
7977c478bd9Sstevel@tonic-gate } else {
7987c478bd9Sstevel@tonic-gate page1 |= EHCI_SITD_XFER_TP_ALL;
7997c478bd9Sstevel@tonic-gate }
8007c478bd9Sstevel@tonic-gate
8017c478bd9Sstevel@tonic-gate /* Grab a new sitd */
8027c478bd9Sstevel@tonic-gate new_sitd = itw->itw_itd_free_list;
8037c478bd9Sstevel@tonic-gate
8047c478bd9Sstevel@tonic-gate ASSERT(new_sitd != NULL);
8057c478bd9Sstevel@tonic-gate
8067c478bd9Sstevel@tonic-gate itw->itw_itd_free_list = ehci_itd_iommu_to_cpu(ehcip,
8077c478bd9Sstevel@tonic-gate Get_ITD(new_sitd->itd_link_ptr));
808*6aef9e11SToomas Soome Set_ITD(new_sitd->itd_link_ptr, 0);
8097c478bd9Sstevel@tonic-gate
8107c478bd9Sstevel@tonic-gate /* Fill in the new sitd */
8117c478bd9Sstevel@tonic-gate Set_ITD_BODY(new_sitd, EHCI_SITD_CTRL, ctrl);
8127c478bd9Sstevel@tonic-gate Set_ITD_BODY(new_sitd, EHCI_SITD_UFRAME_SCHED, uframe_sched);
8137c478bd9Sstevel@tonic-gate Set_ITD_BODY(new_sitd, EHCI_SITD_XFER_STATE, xfer_state);
8147c478bd9Sstevel@tonic-gate Set_ITD_BODY(new_sitd, EHCI_SITD_BUFFER0,
8157c478bd9Sstevel@tonic-gate page0 + curr_isoc_xfer_offset);
8167c478bd9Sstevel@tonic-gate Set_ITD_BODY(new_sitd, EHCI_SITD_BUFFER1, page1);
8177c478bd9Sstevel@tonic-gate Set_ITD_BODY(new_sitd, EHCI_SITD_PREV_SITD, prev_sitd);
8187c478bd9Sstevel@tonic-gate
8197c478bd9Sstevel@tonic-gate Set_ITD(new_sitd->itd_state, EHCI_ITD_ACTIVE);
8207c478bd9Sstevel@tonic-gate
8217c478bd9Sstevel@tonic-gate /*
8227c478bd9Sstevel@tonic-gate * Add this itd to the itw before we add it in the PFL
8237c478bd9Sstevel@tonic-gate * If adding it to the PFL fails, we will have to cleanup.
8247c478bd9Sstevel@tonic-gate */
8257c478bd9Sstevel@tonic-gate ehci_insert_itd_on_itw(ehcip, itw, new_sitd);
8267c478bd9Sstevel@tonic-gate
8277c478bd9Sstevel@tonic-gate itw->itw_curr_isoc_pktp++;
8287c478bd9Sstevel@tonic-gate curr_isoc_xfer_offset += isoc_pkt_length;
8297c478bd9Sstevel@tonic-gate }
8307c478bd9Sstevel@tonic-gate
8317c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
8327c478bd9Sstevel@tonic-gate }
8337c478bd9Sstevel@tonic-gate
8347c478bd9Sstevel@tonic-gate
8357c478bd9Sstevel@tonic-gate /*
8367c478bd9Sstevel@tonic-gate * ehci_remove_isoc_itds:
8377c478bd9Sstevel@tonic-gate *
8387c478bd9Sstevel@tonic-gate * Remove all itds from the PFL.
8397c478bd9Sstevel@tonic-gate */
8407c478bd9Sstevel@tonic-gate static void
ehci_remove_isoc_itds(ehci_state_t * ehcip,ehci_pipe_private_t * pp)8417c478bd9Sstevel@tonic-gate ehci_remove_isoc_itds(
8427c478bd9Sstevel@tonic-gate ehci_state_t *ehcip,
8437c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp)
8447c478bd9Sstevel@tonic-gate {
8457c478bd9Sstevel@tonic-gate ehci_isoc_xwrapper_t *curr_itw, *next_itw;
8467c478bd9Sstevel@tonic-gate ehci_itd_t *curr_itd, *next_itd;
8477c478bd9Sstevel@tonic-gate
8487c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
849112116d8Sfb "ehci_remove_isoc_itds: pp = 0x%p", (void *)pp);
8507c478bd9Sstevel@tonic-gate
8517c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
8527c478bd9Sstevel@tonic-gate
8537c478bd9Sstevel@tonic-gate curr_itw = pp->pp_itw_head;
8547c478bd9Sstevel@tonic-gate while (curr_itw) {
8557c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
8567c478bd9Sstevel@tonic-gate "ehci_remove_isoc_itds: itw = 0x%p num itds = %d",
857112116d8Sfb (void *)curr_itw, curr_itw->itw_num_itds);
8587c478bd9Sstevel@tonic-gate
8597c478bd9Sstevel@tonic-gate next_itw = curr_itw->itw_next;
8607c478bd9Sstevel@tonic-gate
8617c478bd9Sstevel@tonic-gate curr_itd = curr_itw->itw_itd_head;
8627c478bd9Sstevel@tonic-gate while (curr_itd) {
8637c478bd9Sstevel@tonic-gate next_itd = ehci_itd_iommu_to_cpu(ehcip,
8647c478bd9Sstevel@tonic-gate Get_ITD(curr_itd->itd_itw_next_itd));
8657c478bd9Sstevel@tonic-gate
8667c478bd9Sstevel@tonic-gate ehci_reclaim_isoc(ehcip, curr_itw, curr_itd, pp);
8677c478bd9Sstevel@tonic-gate
8687c478bd9Sstevel@tonic-gate curr_itd = next_itd;
8697c478bd9Sstevel@tonic-gate }
8707c478bd9Sstevel@tonic-gate
8717c478bd9Sstevel@tonic-gate ehci_deallocate_itw(ehcip, pp, curr_itw);
8727c478bd9Sstevel@tonic-gate
8737c478bd9Sstevel@tonic-gate curr_itw = next_itw;
8747c478bd9Sstevel@tonic-gate }
8757c478bd9Sstevel@tonic-gate }
8767c478bd9Sstevel@tonic-gate
8777c478bd9Sstevel@tonic-gate
8787c478bd9Sstevel@tonic-gate /*
8797c478bd9Sstevel@tonic-gate * ehci_mark_reclaim_isoc:
8807c478bd9Sstevel@tonic-gate *
8817c478bd9Sstevel@tonic-gate * Set active ITDs to RECLAIM.
8827c478bd9Sstevel@tonic-gate * Return number of ITD that need to be processed.
8837c478bd9Sstevel@tonic-gate */
8847c478bd9Sstevel@tonic-gate static void
ehci_mark_reclaim_isoc(ehci_state_t * ehcip,ehci_pipe_private_t * pp)8857c478bd9Sstevel@tonic-gate ehci_mark_reclaim_isoc(
8867c478bd9Sstevel@tonic-gate ehci_state_t *ehcip,
8877c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp)
8887c478bd9Sstevel@tonic-gate {
8897c478bd9Sstevel@tonic-gate usb_frame_number_t current_frame_number;
8907c478bd9Sstevel@tonic-gate ehci_isoc_xwrapper_t *curr_itw, *next_itw;
8917c478bd9Sstevel@tonic-gate ehci_itd_t *curr_itd, *next_itd;
8927c478bd9Sstevel@tonic-gate uint_t ctrl;
8937c478bd9Sstevel@tonic-gate uint_t isActive;
894b3001defSlg int i;
8957c478bd9Sstevel@tonic-gate
8967c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
897112116d8Sfb "ehci_mark_reclaim_isoc: pp = 0x%p", (void *)pp);
8987c478bd9Sstevel@tonic-gate
8997c478bd9Sstevel@tonic-gate if (pp->pp_itw_head == NULL) {
9007c478bd9Sstevel@tonic-gate
9017c478bd9Sstevel@tonic-gate return;
9027c478bd9Sstevel@tonic-gate }
9037c478bd9Sstevel@tonic-gate
9047c478bd9Sstevel@tonic-gate /* Get the current frame number. */
9057c478bd9Sstevel@tonic-gate current_frame_number = ehci_get_current_frame_number(ehcip);
9067c478bd9Sstevel@tonic-gate
9077c478bd9Sstevel@tonic-gate /* Traverse the list of transfer descriptors */
9087c478bd9Sstevel@tonic-gate curr_itw = pp->pp_itw_head;
9097c478bd9Sstevel@tonic-gate while (curr_itw) {
9107c478bd9Sstevel@tonic-gate next_itw = curr_itw->itw_next;
9117c478bd9Sstevel@tonic-gate
9127c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
9137c478bd9Sstevel@tonic-gate "ehci_mark_reclaim_isoc: itw = 0x%p num itds = %d",
914112116d8Sfb (void *)curr_itw, curr_itw->itw_num_itds);
9157c478bd9Sstevel@tonic-gate
9167c478bd9Sstevel@tonic-gate curr_itd = curr_itw->itw_itd_head;
9177c478bd9Sstevel@tonic-gate while (curr_itd) {
9187c478bd9Sstevel@tonic-gate next_itd = ehci_itd_iommu_to_cpu(ehcip,
9197c478bd9Sstevel@tonic-gate Get_ITD(curr_itd->itd_itw_next_itd));
9207c478bd9Sstevel@tonic-gate
9217c478bd9Sstevel@tonic-gate if (curr_itw->itw_port_status == USBA_HIGH_SPEED_DEV) {
9227c478bd9Sstevel@tonic-gate
923b3001defSlg for (i = 0; i < EHCI_ITD_CTRL_LIST_SIZE; i++) {
924b3001defSlg ctrl = Get_ITD_BODY(curr_itd,
925b3001defSlg EHCI_ITD_CTRL0 + i);
926b3001defSlg isActive = ctrl & EHCI_ITD_XFER_ACTIVE;
927b3001defSlg /* If still active, deactivate it */
928b3001defSlg if (isActive) {
929b3001defSlg ctrl &= ~EHCI_ITD_XFER_ACTIVE;
930b3001defSlg Set_ITD_BODY(curr_itd,
931b3001defSlg EHCI_ITD_CTRL0 + i,
932b3001defSlg ctrl);
933b3001defSlg break;
934b3001defSlg }
935b3001defSlg }
9367c478bd9Sstevel@tonic-gate } else {
9377c478bd9Sstevel@tonic-gate ctrl = Get_ITD_BODY(curr_itd,
9387c478bd9Sstevel@tonic-gate EHCI_SITD_XFER_STATE);
9397c478bd9Sstevel@tonic-gate isActive = ctrl & EHCI_SITD_XFER_ACTIVE;
940b3001defSlg /* If it is still active deactivate it */
9417c478bd9Sstevel@tonic-gate if (isActive) {
9427c478bd9Sstevel@tonic-gate ctrl &= ~EHCI_SITD_XFER_ACTIVE;
9437c478bd9Sstevel@tonic-gate Set_ITD_BODY(curr_itd,
9447c478bd9Sstevel@tonic-gate EHCI_SITD_XFER_STATE,
9457c478bd9Sstevel@tonic-gate ctrl);
9467c478bd9Sstevel@tonic-gate }
9477c478bd9Sstevel@tonic-gate }
9487c478bd9Sstevel@tonic-gate
9497c478bd9Sstevel@tonic-gate /*
9507c478bd9Sstevel@tonic-gate * If the itd was active put it on the reclaim status,
9517c478bd9Sstevel@tonic-gate * so the interrupt handler will know not to process it.
9527c478bd9Sstevel@tonic-gate * Otherwise leave it alone and let the interrupt
9537c478bd9Sstevel@tonic-gate * handler process it normally.
9547c478bd9Sstevel@tonic-gate */
9557c478bd9Sstevel@tonic-gate if (isActive) {
9567c478bd9Sstevel@tonic-gate Set_ITD(curr_itd->itd_state, EHCI_ITD_RECLAIM);
9577c478bd9Sstevel@tonic-gate Set_ITD_FRAME(curr_itd->itd_reclaim_number,
9587c478bd9Sstevel@tonic-gate current_frame_number);
9597c478bd9Sstevel@tonic-gate ehci_remove_isoc_from_pfl(ehcip, curr_itd);
9607c478bd9Sstevel@tonic-gate }
9617c478bd9Sstevel@tonic-gate curr_itd = next_itd;
9627c478bd9Sstevel@tonic-gate }
9637c478bd9Sstevel@tonic-gate curr_itw = next_itw;
9647c478bd9Sstevel@tonic-gate }
9657c478bd9Sstevel@tonic-gate }
9667c478bd9Sstevel@tonic-gate
9677c478bd9Sstevel@tonic-gate
9687c478bd9Sstevel@tonic-gate /*
9697c478bd9Sstevel@tonic-gate * ehci_reclaim_isoc:
9707c478bd9Sstevel@tonic-gate *
9717c478bd9Sstevel@tonic-gate * "Reclaim" itds that were marked as RECLAIM.
9727c478bd9Sstevel@tonic-gate */
9737c478bd9Sstevel@tonic-gate static void
ehci_reclaim_isoc(ehci_state_t * ehcip,ehci_isoc_xwrapper_t * itw,ehci_itd_t * itd,ehci_pipe_private_t * pp)9747c478bd9Sstevel@tonic-gate ehci_reclaim_isoc(
9757c478bd9Sstevel@tonic-gate ehci_state_t *ehcip,
9767c478bd9Sstevel@tonic-gate ehci_isoc_xwrapper_t *itw,
9777c478bd9Sstevel@tonic-gate ehci_itd_t *itd,
9787c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp)
9797c478bd9Sstevel@tonic-gate {
9807c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
981112116d8Sfb "ehci_reclaim_isoc: itd = 0x%p", (void *)itd);
9827c478bd9Sstevel@tonic-gate
9837c478bd9Sstevel@tonic-gate /*
9847c478bd9Sstevel@tonic-gate * These are itds that were marked "RECLAIM"
9857c478bd9Sstevel@tonic-gate * by the pipe cleanup.
9867c478bd9Sstevel@tonic-gate *
9877c478bd9Sstevel@tonic-gate * Decrement the num_itds and the periodic in
9887c478bd9Sstevel@tonic-gate * request count if necessary.
9897c478bd9Sstevel@tonic-gate */
9907c478bd9Sstevel@tonic-gate if ((--itw->itw_num_itds == 0) && (itw->itw_curr_xfer_reqp)) {
9917c478bd9Sstevel@tonic-gate if (itw->itw_direction == USB_EP_DIR_IN) {
9927c478bd9Sstevel@tonic-gate
9937c478bd9Sstevel@tonic-gate pp->pp_cur_periodic_req_cnt--;
9947c478bd9Sstevel@tonic-gate
9957c478bd9Sstevel@tonic-gate ehci_deallocate_isoc_in_resource(ehcip, pp, itw);
9967c478bd9Sstevel@tonic-gate } else {
9977c478bd9Sstevel@tonic-gate ehci_hcdi_isoc_callback(pp->pp_pipe_handle, itw,
9987c478bd9Sstevel@tonic-gate USB_CR_FLUSHED);
9997c478bd9Sstevel@tonic-gate }
10007c478bd9Sstevel@tonic-gate }
10017c478bd9Sstevel@tonic-gate
10027c478bd9Sstevel@tonic-gate /* Deallocate this transfer descriptor */
10037c478bd9Sstevel@tonic-gate ehci_deallocate_itd(ehcip, itw, itd);
10047c478bd9Sstevel@tonic-gate }
10057c478bd9Sstevel@tonic-gate
10067c478bd9Sstevel@tonic-gate
10077c478bd9Sstevel@tonic-gate /*
10087c478bd9Sstevel@tonic-gate * ehci_start_isoc_polling:
10097c478bd9Sstevel@tonic-gate *
10107c478bd9Sstevel@tonic-gate * Insert the number of periodic requests corresponding to polling
10117c478bd9Sstevel@tonic-gate * interval as calculated during pipe open.
10127c478bd9Sstevel@tonic-gate */
10137c478bd9Sstevel@tonic-gate int
ehci_start_isoc_polling(ehci_state_t * ehcip,usba_pipe_handle_data_t * ph,usb_flags_t flags)10147c478bd9Sstevel@tonic-gate ehci_start_isoc_polling(
10157c478bd9Sstevel@tonic-gate ehci_state_t *ehcip,
10167c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
10177c478bd9Sstevel@tonic-gate usb_flags_t flags)
10187c478bd9Sstevel@tonic-gate {
10197c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp = (ehci_pipe_private_t *)ph->p_hcd_private;
10207c478bd9Sstevel@tonic-gate ehci_isoc_xwrapper_t *itw_list, *itw;
10217c478bd9Sstevel@tonic-gate int i, total_itws;
10227c478bd9Sstevel@tonic-gate int error = USB_SUCCESS;
10237c478bd9Sstevel@tonic-gate
1024b3001defSlg USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
10250a05e705Slc "ehci_start_isoc_polling:");
1026b3001defSlg
10277c478bd9Sstevel@tonic-gate /* Allocate all the necessary resources for the IN transfer */
10287c478bd9Sstevel@tonic-gate itw_list = NULL;
10297c478bd9Sstevel@tonic-gate total_itws = pp->pp_max_periodic_req_cnt - pp->pp_cur_periodic_req_cnt;
10307c478bd9Sstevel@tonic-gate for (i = 0; i < total_itws; i += 1) {
10317c478bd9Sstevel@tonic-gate itw = ehci_allocate_isoc_resources(ehcip, ph, NULL, flags);
10327c478bd9Sstevel@tonic-gate if (itw == NULL) {
10337c478bd9Sstevel@tonic-gate error = USB_NO_RESOURCES;
10347c478bd9Sstevel@tonic-gate /* There are not enough resources deallocate the ITWs */
10357c478bd9Sstevel@tonic-gate itw = itw_list;
10367c478bd9Sstevel@tonic-gate while (itw != NULL) {
10377c478bd9Sstevel@tonic-gate itw_list = itw->itw_next;
10387c478bd9Sstevel@tonic-gate ehci_deallocate_isoc_in_resource(
10390a05e705Slc ehcip, pp, itw);
10407c478bd9Sstevel@tonic-gate ehci_deallocate_itw(ehcip, pp, itw);
10417c478bd9Sstevel@tonic-gate itw = itw_list;
10427c478bd9Sstevel@tonic-gate }
10437c478bd9Sstevel@tonic-gate
10447c478bd9Sstevel@tonic-gate return (error);
10457c478bd9Sstevel@tonic-gate } else {
10467c478bd9Sstevel@tonic-gate if (itw_list == NULL) {
10477c478bd9Sstevel@tonic-gate itw_list = itw;
10487c478bd9Sstevel@tonic-gate }
10497c478bd9Sstevel@tonic-gate }
10507c478bd9Sstevel@tonic-gate }
10517c478bd9Sstevel@tonic-gate
10527c478bd9Sstevel@tonic-gate i = 0;
10537c478bd9Sstevel@tonic-gate while (pp->pp_cur_periodic_req_cnt < pp->pp_max_periodic_req_cnt) {
10547c478bd9Sstevel@tonic-gate
10557c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
10567c478bd9Sstevel@tonic-gate "ehci_start_isoc_polling: max = %d curr = %d itw = %p:",
10577c478bd9Sstevel@tonic-gate pp->pp_max_periodic_req_cnt, pp->pp_cur_periodic_req_cnt,
1058112116d8Sfb (void *)itw_list);
10597c478bd9Sstevel@tonic-gate
10607c478bd9Sstevel@tonic-gate itw = itw_list;
10617c478bd9Sstevel@tonic-gate itw_list = itw->itw_next;
10627c478bd9Sstevel@tonic-gate
10637c478bd9Sstevel@tonic-gate error = ehci_insert_isoc_req(ehcip, pp, itw, flags);
10647c478bd9Sstevel@tonic-gate
10657c478bd9Sstevel@tonic-gate if (error == USB_SUCCESS) {
10667c478bd9Sstevel@tonic-gate pp->pp_cur_periodic_req_cnt++;
10677c478bd9Sstevel@tonic-gate } else {
10687c478bd9Sstevel@tonic-gate /*
10697c478bd9Sstevel@tonic-gate * Deallocate the remaining tw
10707c478bd9Sstevel@tonic-gate * The current tw should have already been deallocated
10717c478bd9Sstevel@tonic-gate */
10727c478bd9Sstevel@tonic-gate itw = itw_list;
10737c478bd9Sstevel@tonic-gate while (itw != NULL) {
10747c478bd9Sstevel@tonic-gate itw_list = itw->itw_next;
10757c478bd9Sstevel@tonic-gate ehci_deallocate_isoc_in_resource(
10760a05e705Slc ehcip, pp, itw);
10777c478bd9Sstevel@tonic-gate ehci_deallocate_itw(ehcip, pp, itw);
10787c478bd9Sstevel@tonic-gate itw = itw_list;
10797c478bd9Sstevel@tonic-gate }
10807c478bd9Sstevel@tonic-gate /*
10817c478bd9Sstevel@tonic-gate * If this is the first req return an error.
10827c478bd9Sstevel@tonic-gate * Otherwise return success.
10837c478bd9Sstevel@tonic-gate */
10847c478bd9Sstevel@tonic-gate if (i != 0) {
10857c478bd9Sstevel@tonic-gate error = USB_SUCCESS;
10867c478bd9Sstevel@tonic-gate }
10877c478bd9Sstevel@tonic-gate
10887c478bd9Sstevel@tonic-gate break;
10897c478bd9Sstevel@tonic-gate }
10907c478bd9Sstevel@tonic-gate i++;
10917c478bd9Sstevel@tonic-gate }
10927c478bd9Sstevel@tonic-gate
10937c478bd9Sstevel@tonic-gate return (error);
10947c478bd9Sstevel@tonic-gate }
10957c478bd9Sstevel@tonic-gate
10967c478bd9Sstevel@tonic-gate
10977c478bd9Sstevel@tonic-gate /*
10987c478bd9Sstevel@tonic-gate * Isochronronous handling functions.
10997c478bd9Sstevel@tonic-gate */
11007c478bd9Sstevel@tonic-gate /*
11017c478bd9Sstevel@tonic-gate * ehci_traverse_active_isoc_list:
11027c478bd9Sstevel@tonic-gate */
11037c478bd9Sstevel@tonic-gate void
ehci_traverse_active_isoc_list(ehci_state_t * ehcip)11047c478bd9Sstevel@tonic-gate ehci_traverse_active_isoc_list(
11057c478bd9Sstevel@tonic-gate ehci_state_t *ehcip)
11067c478bd9Sstevel@tonic-gate {
11077c478bd9Sstevel@tonic-gate ehci_isoc_xwrapper_t *curr_itw;
11087c478bd9Sstevel@tonic-gate ehci_itd_t *curr_itd, *next_itd;
11097c478bd9Sstevel@tonic-gate uint_t state;
11107c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp;
11117c478bd9Sstevel@tonic-gate
11127c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
11137c478bd9Sstevel@tonic-gate "ehci_traverse_active_isoc_list:");
11147c478bd9Sstevel@tonic-gate
11157c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
11167c478bd9Sstevel@tonic-gate
11177c478bd9Sstevel@tonic-gate /* Sync ITD pool */
11187c478bd9Sstevel@tonic-gate Sync_ITD_Pool(ehcip);
11197c478bd9Sstevel@tonic-gate
11207c478bd9Sstevel@tonic-gate /* Traverse the list of done itds */
11217c478bd9Sstevel@tonic-gate curr_itd = ehci_create_done_itd_list(ehcip);
1122b3001defSlg USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1123112116d8Sfb "ehci_traverse_active_isoc_list: current itd = 0x%p",
1124112116d8Sfb (void *)curr_itd);
11257c478bd9Sstevel@tonic-gate
11267c478bd9Sstevel@tonic-gate while (curr_itd) {
11277c478bd9Sstevel@tonic-gate /* Save the next_itd */
11287c478bd9Sstevel@tonic-gate next_itd = ehci_itd_iommu_to_cpu(ehcip,
11297c478bd9Sstevel@tonic-gate Get_ITD(curr_itd->itd_next_active_itd));
11307c478bd9Sstevel@tonic-gate
11317c478bd9Sstevel@tonic-gate /* Get the transfer wrapper and the pp */
11327c478bd9Sstevel@tonic-gate curr_itw = (ehci_isoc_xwrapper_t *)EHCI_LOOKUP_ID(
11330a05e705Slc (uint32_t)Get_ITD(curr_itd->itd_trans_wrapper));
11347c478bd9Sstevel@tonic-gate pp = curr_itw->itw_pipe_private;
11357c478bd9Sstevel@tonic-gate
1136b3001defSlg if (curr_itw->itw_port_status == USBA_HIGH_SPEED_DEV) {
1137b3001defSlg ehci_print_itd(ehcip, curr_itd);
1138b3001defSlg } else {
1139b3001defSlg ehci_print_sitd(ehcip, curr_itd);
1140b3001defSlg }
11417c478bd9Sstevel@tonic-gate
11427c478bd9Sstevel@tonic-gate /* Get the ITD state */
11437c478bd9Sstevel@tonic-gate state = Get_ITD(curr_itd->itd_state);
11447c478bd9Sstevel@tonic-gate
11457c478bd9Sstevel@tonic-gate /* Only process the ITDs marked as active. */
11467c478bd9Sstevel@tonic-gate if (state == EHCI_ITD_ACTIVE) {
11477c478bd9Sstevel@tonic-gate ehci_parse_isoc_error(ehcip, curr_itw, curr_itd);
11487c478bd9Sstevel@tonic-gate ehci_handle_isoc(ehcip, curr_itw, curr_itd);
11497c478bd9Sstevel@tonic-gate } else {
11507c478bd9Sstevel@tonic-gate ASSERT(state == EHCI_ITD_RECLAIM);
11517c478bd9Sstevel@tonic-gate ehci_reclaim_isoc(ehcip, curr_itw, curr_itd, pp);
11527c478bd9Sstevel@tonic-gate }
11537c478bd9Sstevel@tonic-gate
11547c478bd9Sstevel@tonic-gate /*
11557c478bd9Sstevel@tonic-gate * Deallocate the transfer wrapper if there are no more
11567c478bd9Sstevel@tonic-gate * ITD's for the transfer wrapper. ehci_deallocate_itw()
11577c478bd9Sstevel@tonic-gate * will not deallocate the tw for a periodic in endpoint
11587c478bd9Sstevel@tonic-gate * since it will always have a ITD attached to it.
11597c478bd9Sstevel@tonic-gate */
11607c478bd9Sstevel@tonic-gate ehci_deallocate_itw(ehcip, pp, curr_itw);
11617c478bd9Sstevel@tonic-gate
11627c478bd9Sstevel@tonic-gate /* Check any ISOC is waiting for transfers completion event */
11637c478bd9Sstevel@tonic-gate if (pp->pp_itw_head == NULL) {
11647c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
11657c478bd9Sstevel@tonic-gate "ehci_traverse_active_isoc_list: "
1166112116d8Sfb "Sent transfers completion event pp = 0x%p",
1167112116d8Sfb (void *)pp);
11687c478bd9Sstevel@tonic-gate cv_signal(&pp->pp_xfer_cmpl_cv);
11697c478bd9Sstevel@tonic-gate }
11707c478bd9Sstevel@tonic-gate
11717c478bd9Sstevel@tonic-gate curr_itd = next_itd;
1172b3001defSlg
1173b3001defSlg USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1174b3001defSlg "ehci_traverse_active_isoc_list: state = 0x%x "
1175b3001defSlg "pp = 0x%p itw = 0x%p itd = 0x%p next_itd = 0x%p",
1176112116d8Sfb state, (void *)pp, (void *)curr_itw, (void *)curr_itd,
1177112116d8Sfb (void *)next_itd);
11787c478bd9Sstevel@tonic-gate }
11797c478bd9Sstevel@tonic-gate }
11807c478bd9Sstevel@tonic-gate
11817c478bd9Sstevel@tonic-gate
11827c478bd9Sstevel@tonic-gate static void
ehci_handle_isoc(ehci_state_t * ehcip,ehci_isoc_xwrapper_t * itw,ehci_itd_t * itd)11837c478bd9Sstevel@tonic-gate ehci_handle_isoc(
11847c478bd9Sstevel@tonic-gate ehci_state_t *ehcip,
11857c478bd9Sstevel@tonic-gate ehci_isoc_xwrapper_t *itw,
11867c478bd9Sstevel@tonic-gate ehci_itd_t *itd)
11877c478bd9Sstevel@tonic-gate {
11887c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp; /* Pipe private field */
11897c478bd9Sstevel@tonic-gate
11907c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
11917c478bd9Sstevel@tonic-gate
11927c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
11937c478bd9Sstevel@tonic-gate "ehci_handle_isoc:");
11947c478bd9Sstevel@tonic-gate
11957c478bd9Sstevel@tonic-gate /* Obtain the pipe private structure */
11967c478bd9Sstevel@tonic-gate pp = itw->itw_pipe_private;
11977c478bd9Sstevel@tonic-gate
1198b3001defSlg ehci_handle_itd(ehcip, pp, itw, itd, itw->itw_handle_callback_value);
11997c478bd9Sstevel@tonic-gate }
12007c478bd9Sstevel@tonic-gate
12017c478bd9Sstevel@tonic-gate
12027c478bd9Sstevel@tonic-gate /*
12037c478bd9Sstevel@tonic-gate * ehci_handle_itd:
12047c478bd9Sstevel@tonic-gate *
1205b3001defSlg * Handle an (split) isochronous transfer descriptor.
12067c478bd9Sstevel@tonic-gate * This function will deallocate the itd from the list as well.
12077c478bd9Sstevel@tonic-gate */
12087c478bd9Sstevel@tonic-gate /* ARGSUSED */
12097c478bd9Sstevel@tonic-gate static void
ehci_handle_itd(ehci_state_t * ehcip,ehci_pipe_private_t * pp,ehci_isoc_xwrapper_t * itw,ehci_itd_t * itd,void * tw_handle_callback_value)1210b3001defSlg ehci_handle_itd(
12117c478bd9Sstevel@tonic-gate ehci_state_t *ehcip,
12127c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp,
12137c478bd9Sstevel@tonic-gate ehci_isoc_xwrapper_t *itw,
12147c478bd9Sstevel@tonic-gate ehci_itd_t *itd,
12157c478bd9Sstevel@tonic-gate void *tw_handle_callback_value)
12167c478bd9Sstevel@tonic-gate {
12177c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle;
12187c478bd9Sstevel@tonic-gate usb_isoc_req_t *curr_isoc_reqp =
12190a05e705Slc (usb_isoc_req_t *)itw->itw_curr_xfer_reqp;
12207c478bd9Sstevel@tonic-gate int error = USB_SUCCESS;
1221b3001defSlg int i, index;
12227c478bd9Sstevel@tonic-gate
12237c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1224b3001defSlg "ehci_handle_itd: pp=0x%p itw=0x%p itd=0x%p "
1225112116d8Sfb "isoc_reqp=0%p data=0x%p", (void *)pp, (void *)itw, (void *)itd,
1226112116d8Sfb (void *)curr_isoc_reqp, (void *)curr_isoc_reqp->isoc_data);
12277c478bd9Sstevel@tonic-gate
1228b3001defSlg if (itw->itw_port_status == USBA_HIGH_SPEED_DEV &&
1229b3001defSlg curr_isoc_reqp != NULL) {
1230b3001defSlg
12310a05e705Slc for (i = 0; i < EHCI_ITD_CTRL_LIST_SIZE; i++) {
1232b3001defSlg
12330a05e705Slc index = Get_ITD_INDEX(itd, i);
12340a05e705Slc if (index == EHCI_ITD_UNUSED_INDEX) {
1235b3001defSlg
12360a05e705Slc continue;
12370a05e705Slc }
12380a05e705Slc curr_isoc_reqp->
12390a05e705Slc isoc_pkt_descr[index].isoc_pkt_actual_length =
12400a05e705Slc (Get_ITD_BODY(itd, i) & EHCI_ITD_XFER_LENGTH) >> 16;
1241b3001defSlg }
1242b3001defSlg }
1243b3001defSlg
12447c478bd9Sstevel@tonic-gate /*
12457c478bd9Sstevel@tonic-gate * Decrement the ITDs counter and check whether all the isoc
12467c478bd9Sstevel@tonic-gate * data has been send or received. If ITDs counter reaches
12477c478bd9Sstevel@tonic-gate * zero then inform client driver about completion current
12487c478bd9Sstevel@tonic-gate * isoc request. Otherwise wait for completion of other isoc
12497c478bd9Sstevel@tonic-gate * ITDs or transactions on this pipe.
12507c478bd9Sstevel@tonic-gate */
12517c478bd9Sstevel@tonic-gate if (--itw->itw_num_itds != 0) {
12527c478bd9Sstevel@tonic-gate /* Deallocate this transfer descriptor */
12537c478bd9Sstevel@tonic-gate ehci_deallocate_itd(ehcip, itw, itd);
12547c478bd9Sstevel@tonic-gate
12557c478bd9Sstevel@tonic-gate return;
12567c478bd9Sstevel@tonic-gate }
12577c478bd9Sstevel@tonic-gate
12587c478bd9Sstevel@tonic-gate /*
12597c478bd9Sstevel@tonic-gate * If this is a isoc in pipe, return the data to the client.
12607c478bd9Sstevel@tonic-gate * For a isoc out pipe, there is no need to do anything.
12617c478bd9Sstevel@tonic-gate */
12627c478bd9Sstevel@tonic-gate if (itw->itw_direction == USB_EP_DIR_OUT) {
12637c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1264112116d8Sfb "ehci_handle_itd: Isoc out pipe, isoc_reqp=0x%p, data=0x%p",
1265112116d8Sfb (void *)curr_isoc_reqp, (void *)curr_isoc_reqp->isoc_data);
12667c478bd9Sstevel@tonic-gate
12677c478bd9Sstevel@tonic-gate /* Do the callback */
12687c478bd9Sstevel@tonic-gate ehci_hcdi_isoc_callback(ph, itw, USB_CR_OK);
12697c478bd9Sstevel@tonic-gate
12707c478bd9Sstevel@tonic-gate /* Deallocate this transfer descriptor */
12717c478bd9Sstevel@tonic-gate ehci_deallocate_itd(ehcip, itw, itd);
12727c478bd9Sstevel@tonic-gate
12737c478bd9Sstevel@tonic-gate return;
12747c478bd9Sstevel@tonic-gate }
12757c478bd9Sstevel@tonic-gate
12767c478bd9Sstevel@tonic-gate /* Decrement number of IN isochronous request count */
12777c478bd9Sstevel@tonic-gate pp->pp_cur_periodic_req_cnt--;
12787c478bd9Sstevel@tonic-gate
1279b3001defSlg USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1280b3001defSlg "ehci_handle_itd: pp_cur_periodic_req_cnt = 0x%x ",
1281b3001defSlg pp->pp_cur_periodic_req_cnt);
1282b3001defSlg
12837c478bd9Sstevel@tonic-gate /* Call ehci_sendup_itd_message to send message to upstream */
12847c478bd9Sstevel@tonic-gate ehci_sendup_itd_message(ehcip, pp, itw, itd, USB_CR_OK);
12857c478bd9Sstevel@tonic-gate
12867c478bd9Sstevel@tonic-gate /* Deallocate this transfer descriptor */
12877c478bd9Sstevel@tonic-gate ehci_deallocate_itd(ehcip, itw, itd);
12887c478bd9Sstevel@tonic-gate
12897c478bd9Sstevel@tonic-gate /*
12907c478bd9Sstevel@tonic-gate * If isochronous pipe state is still active, insert next isochronous
12917c478bd9Sstevel@tonic-gate * request into the Host Controller's isochronous list.
12927c478bd9Sstevel@tonic-gate */
12937c478bd9Sstevel@tonic-gate if (pp->pp_state != EHCI_PIPE_STATE_ACTIVE) {
12947c478bd9Sstevel@tonic-gate
12957c478bd9Sstevel@tonic-gate return;
12967c478bd9Sstevel@tonic-gate }
12977c478bd9Sstevel@tonic-gate
12987c478bd9Sstevel@tonic-gate if ((error = ehci_allocate_isoc_in_resource(ehcip, pp, itw, 0)) ==
12997c478bd9Sstevel@tonic-gate USB_SUCCESS) {
13007c478bd9Sstevel@tonic-gate curr_isoc_reqp = (usb_isoc_req_t *)itw->itw_curr_xfer_reqp;
13017c478bd9Sstevel@tonic-gate
13027c478bd9Sstevel@tonic-gate ASSERT(curr_isoc_reqp != NULL);
13037c478bd9Sstevel@tonic-gate
13047c478bd9Sstevel@tonic-gate itw->itw_num_itds = ehci_calc_num_itds(itw,
13057c478bd9Sstevel@tonic-gate curr_isoc_reqp->isoc_pkts_count);
13067c478bd9Sstevel@tonic-gate
13077c478bd9Sstevel@tonic-gate if (ehci_allocate_itds_for_itw(ehcip, itw, itw->itw_num_itds) !=
13087c478bd9Sstevel@tonic-gate USB_SUCCESS) {
13097c478bd9Sstevel@tonic-gate ehci_deallocate_isoc_in_resource(ehcip, pp, itw);
13107c478bd9Sstevel@tonic-gate itw->itw_num_itds = 0;
13117c478bd9Sstevel@tonic-gate error = USB_FAILURE;
13127c478bd9Sstevel@tonic-gate }
13137c478bd9Sstevel@tonic-gate }
13147c478bd9Sstevel@tonic-gate
13157c478bd9Sstevel@tonic-gate if ((error != USB_SUCCESS) ||
13167c478bd9Sstevel@tonic-gate (ehci_insert_isoc_req(ehcip, pp, itw, 0) != USB_SUCCESS)) {
13177c478bd9Sstevel@tonic-gate /*
13187c478bd9Sstevel@tonic-gate * Set pipe state to stop polling and error to no
13197c478bd9Sstevel@tonic-gate * resource. Don't insert any more isoch polling
13207c478bd9Sstevel@tonic-gate * requests.
13217c478bd9Sstevel@tonic-gate */
13227c478bd9Sstevel@tonic-gate pp->pp_state = EHCI_PIPE_STATE_STOP_POLLING;
13237c478bd9Sstevel@tonic-gate pp->pp_error = USB_CR_NO_RESOURCES;
13247c478bd9Sstevel@tonic-gate
13257c478bd9Sstevel@tonic-gate } else {
13267c478bd9Sstevel@tonic-gate /* Increment number of IN isochronous request count */
13277c478bd9Sstevel@tonic-gate pp->pp_cur_periodic_req_cnt++;
13287c478bd9Sstevel@tonic-gate
13297c478bd9Sstevel@tonic-gate ASSERT(pp->pp_cur_periodic_req_cnt ==
13307c478bd9Sstevel@tonic-gate pp->pp_max_periodic_req_cnt);
13317c478bd9Sstevel@tonic-gate }
13327c478bd9Sstevel@tonic-gate }
13337c478bd9Sstevel@tonic-gate
13347c478bd9Sstevel@tonic-gate
13357c478bd9Sstevel@tonic-gate /*
13367c478bd9Sstevel@tonic-gate * ehci_sendup_qtd_message:
13377c478bd9Sstevel@tonic-gate * copy data, if necessary and do callback
13387c478bd9Sstevel@tonic-gate */
13397c478bd9Sstevel@tonic-gate /* ARGSUSED */
13407c478bd9Sstevel@tonic-gate static void
ehci_sendup_itd_message(ehci_state_t * ehcip,ehci_pipe_private_t * pp,ehci_isoc_xwrapper_t * itw,ehci_itd_t * td,usb_cr_t error)13417c478bd9Sstevel@tonic-gate ehci_sendup_itd_message(
13427c478bd9Sstevel@tonic-gate ehci_state_t *ehcip,
13437c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp,
13447c478bd9Sstevel@tonic-gate ehci_isoc_xwrapper_t *itw,
13457c478bd9Sstevel@tonic-gate ehci_itd_t *td,
13467c478bd9Sstevel@tonic-gate usb_cr_t error)
13477c478bd9Sstevel@tonic-gate {
13487c478bd9Sstevel@tonic-gate usb_isoc_req_t *isoc_reqp = itw->itw_curr_xfer_reqp;
13497c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle;
13507c478bd9Sstevel@tonic-gate size_t length;
13517c478bd9Sstevel@tonic-gate uchar_t *buf;
13527c478bd9Sstevel@tonic-gate mblk_t *mp;
13537c478bd9Sstevel@tonic-gate
13547c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
13557c478bd9Sstevel@tonic-gate
13567c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
13577c478bd9Sstevel@tonic-gate "ehci_sendup_itd_message:");
13587c478bd9Sstevel@tonic-gate
13597c478bd9Sstevel@tonic-gate ASSERT(itw != NULL);
13607c478bd9Sstevel@tonic-gate
13617c478bd9Sstevel@tonic-gate length = itw->itw_length;
13627c478bd9Sstevel@tonic-gate
13637c478bd9Sstevel@tonic-gate /* Copy the data into the mblk_t */
13647c478bd9Sstevel@tonic-gate buf = (uchar_t *)itw->itw_buf;
13657c478bd9Sstevel@tonic-gate
1366b3001defSlg USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1367112116d8Sfb "ehci_sendup_itd_message: length %ld error %d", length, error);
13687c478bd9Sstevel@tonic-gate
13697c478bd9Sstevel@tonic-gate /* Get the message block */
13707c478bd9Sstevel@tonic-gate mp = isoc_reqp->isoc_data;
13717c478bd9Sstevel@tonic-gate
13727c478bd9Sstevel@tonic-gate ASSERT(mp != NULL);
13737c478bd9Sstevel@tonic-gate
13747c478bd9Sstevel@tonic-gate if (length) {
13757c478bd9Sstevel@tonic-gate /* Sync IO buffer */
13767c478bd9Sstevel@tonic-gate Sync_IO_Buffer(itw->itw_dmahandle, length);
13777c478bd9Sstevel@tonic-gate
13787c478bd9Sstevel@tonic-gate /* Copy the data into the message */
1379b3001defSlg ddi_rep_get8(itw->itw_accesshandle,
1380b3001defSlg mp->b_rptr, buf, length, DDI_DEV_AUTOINCR);
13817c478bd9Sstevel@tonic-gate
13827c478bd9Sstevel@tonic-gate /* Increment the write pointer */
13837c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_wptr + length;
13847c478bd9Sstevel@tonic-gate } else {
13857c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
13867c478bd9Sstevel@tonic-gate "ehci_sendup_itd_message: Zero length packet");
13877c478bd9Sstevel@tonic-gate }
13887c478bd9Sstevel@tonic-gate
13897c478bd9Sstevel@tonic-gate ehci_hcdi_isoc_callback(ph, itw, error);
13907c478bd9Sstevel@tonic-gate }
13917c478bd9Sstevel@tonic-gate
13927c478bd9Sstevel@tonic-gate
13937c478bd9Sstevel@tonic-gate /*
13947c478bd9Sstevel@tonic-gate * ehci_hcdi_isoc_callback:
13957c478bd9Sstevel@tonic-gate *
13967c478bd9Sstevel@tonic-gate * Convenience wrapper around usba_hcdi_cb() other than root hub.
13977c478bd9Sstevel@tonic-gate */
13987c478bd9Sstevel@tonic-gate void
ehci_hcdi_isoc_callback(usba_pipe_handle_data_t * ph,ehci_isoc_xwrapper_t * itw,usb_cr_t completion_reason)13997c478bd9Sstevel@tonic-gate ehci_hcdi_isoc_callback(
14007c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
14017c478bd9Sstevel@tonic-gate ehci_isoc_xwrapper_t *itw,
14027c478bd9Sstevel@tonic-gate usb_cr_t completion_reason)
14037c478bd9Sstevel@tonic-gate {
14047c478bd9Sstevel@tonic-gate ehci_state_t *ehcip = ehci_obtain_state(
14050a05e705Slc ph->p_usba_device->usb_root_hub_dip);
14067c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp = (ehci_pipe_private_t *)ph->p_hcd_private;
14077c478bd9Sstevel@tonic-gate usb_opaque_t curr_xfer_reqp;
14087c478bd9Sstevel@tonic-gate uint_t pipe_state = 0;
14097c478bd9Sstevel@tonic-gate
14107c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
14117c478bd9Sstevel@tonic-gate "ehci_hcdi_isoc_callback: ph = 0x%p, itw = 0x%p, cr = 0x%x",
1412112116d8Sfb (void *)ph, (void *)itw, completion_reason);
14137c478bd9Sstevel@tonic-gate
14147c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
14157c478bd9Sstevel@tonic-gate
14167c478bd9Sstevel@tonic-gate /* Set the pipe state as per completion reason */
14177c478bd9Sstevel@tonic-gate switch (completion_reason) {
14187c478bd9Sstevel@tonic-gate case USB_CR_OK:
14197c478bd9Sstevel@tonic-gate pipe_state = pp->pp_state;
14207c478bd9Sstevel@tonic-gate break;
14217c478bd9Sstevel@tonic-gate case USB_CR_NO_RESOURCES:
14227c478bd9Sstevel@tonic-gate case USB_CR_NOT_SUPPORTED:
14237c478bd9Sstevel@tonic-gate case USB_CR_PIPE_RESET:
14247c478bd9Sstevel@tonic-gate case USB_CR_STOPPED_POLLING:
14257c478bd9Sstevel@tonic-gate pipe_state = EHCI_PIPE_STATE_IDLE;
14267c478bd9Sstevel@tonic-gate break;
14277c478bd9Sstevel@tonic-gate case USB_CR_PIPE_CLOSING:
14287c478bd9Sstevel@tonic-gate break;
14297c478bd9Sstevel@tonic-gate }
14307c478bd9Sstevel@tonic-gate
14317c478bd9Sstevel@tonic-gate pp->pp_state = pipe_state;
14327c478bd9Sstevel@tonic-gate
14337c478bd9Sstevel@tonic-gate if (itw && itw->itw_curr_xfer_reqp) {
14347c478bd9Sstevel@tonic-gate curr_xfer_reqp = (usb_opaque_t)itw->itw_curr_xfer_reqp;
14357c478bd9Sstevel@tonic-gate itw->itw_curr_xfer_reqp = NULL;
14367c478bd9Sstevel@tonic-gate } else {
14377c478bd9Sstevel@tonic-gate ASSERT(pp->pp_client_periodic_in_reqp != NULL);
14387c478bd9Sstevel@tonic-gate
14397c478bd9Sstevel@tonic-gate curr_xfer_reqp = pp->pp_client_periodic_in_reqp;
14407c478bd9Sstevel@tonic-gate pp->pp_client_periodic_in_reqp = NULL;
14417c478bd9Sstevel@tonic-gate }
14427c478bd9Sstevel@tonic-gate
14437c478bd9Sstevel@tonic-gate ASSERT(curr_xfer_reqp != NULL);
14447c478bd9Sstevel@tonic-gate
14457c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
14467c478bd9Sstevel@tonic-gate
14477c478bd9Sstevel@tonic-gate usba_hcdi_cb(ph, curr_xfer_reqp, completion_reason);
14487c478bd9Sstevel@tonic-gate
14497c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
14507c478bd9Sstevel@tonic-gate }
1451