xref: /onnv-gate/usr/src/uts/common/io/usb/hcd/ehci/ehci_isoch.c (revision 11066:cebb50cbe4f9)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
53255Slg150142  * Common Development and Distribution License (the "License").
63255Slg150142  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*11066Srafael.vanoni@sun.com  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /*
280Sstevel@tonic-gate  * EHCI Host Controller Driver (EHCI)
290Sstevel@tonic-gate  *
300Sstevel@tonic-gate  * The EHCI driver is a software driver which interfaces to the Universal
310Sstevel@tonic-gate  * Serial Bus layer (USBA) and the Host Controller (HC). The interface to
320Sstevel@tonic-gate  * the Host Controller is defined by the EHCI Host Controller Interface.
330Sstevel@tonic-gate  *
340Sstevel@tonic-gate  * This module contains the EHCI driver isochronous code, which handles all
350Sstevel@tonic-gate  * Checking of status of USB transfers, error recovery and callbacks.
360Sstevel@tonic-gate  */
370Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehcid.h>
380Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_xfer.h>
390Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_util.h>
400Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_isoch.h>
410Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_isoch_util.h>
427492SZhigang.Lu@Sun.COM #include <sys/strsun.h>
430Sstevel@tonic-gate 
440Sstevel@tonic-gate /*
450Sstevel@tonic-gate  * Isochronous initialization functions
460Sstevel@tonic-gate  */
470Sstevel@tonic-gate int ehci_isoc_init(
480Sstevel@tonic-gate 	ehci_state_t		*ehcip);
490Sstevel@tonic-gate void ehci_isoc_cleanup(
500Sstevel@tonic-gate 	ehci_state_t		*ehcip);
510Sstevel@tonic-gate void ehci_isoc_pipe_cleanup(
520Sstevel@tonic-gate 	ehci_state_t		*ehcip,
530Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph);
540Sstevel@tonic-gate static void ehci_wait_for_isoc_completion(
550Sstevel@tonic-gate 	ehci_state_t		*ehcip,
560Sstevel@tonic-gate 	ehci_pipe_private_t	*pp);
570Sstevel@tonic-gate 
580Sstevel@tonic-gate /*
590Sstevel@tonic-gate  * Isochronous request functions
600Sstevel@tonic-gate  */
610Sstevel@tonic-gate ehci_isoc_xwrapper_t *ehci_allocate_isoc_resources(
620Sstevel@tonic-gate 	ehci_state_t		*ehcip,
630Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph,
640Sstevel@tonic-gate 	usb_isoc_req_t		*isoc_reqp,
650Sstevel@tonic-gate 	usb_flags_t		usb_flags);
660Sstevel@tonic-gate int ehci_insert_isoc_req(
670Sstevel@tonic-gate 	ehci_state_t		*ehcip,
680Sstevel@tonic-gate 	ehci_pipe_private_t	*pp,
690Sstevel@tonic-gate 	ehci_isoc_xwrapper_t	*itw,
700Sstevel@tonic-gate 	usb_flags_t		usb_flags);
713255Slg150142 static int ehci_insert_itd_req(
723255Slg150142 	ehci_state_t		*ehcip,
733255Slg150142 	ehci_pipe_private_t	*pp,
743255Slg150142 	ehci_isoc_xwrapper_t	*itw,
753255Slg150142 	usb_flags_t		usb_flags);
760Sstevel@tonic-gate static int ehci_insert_sitd_req(
770Sstevel@tonic-gate 	ehci_state_t		*ehcip,
780Sstevel@tonic-gate 	ehci_pipe_private_t	*pp,
790Sstevel@tonic-gate 	ehci_isoc_xwrapper_t	*itw,
800Sstevel@tonic-gate 	usb_flags_t		usb_flags);
810Sstevel@tonic-gate static void ehci_remove_isoc_itds(
820Sstevel@tonic-gate 	ehci_state_t		*ehcip,
830Sstevel@tonic-gate 	ehci_pipe_private_t	*pp);
840Sstevel@tonic-gate static void ehci_mark_reclaim_isoc(
850Sstevel@tonic-gate 	ehci_state_t		*ehcip,
860Sstevel@tonic-gate 	ehci_pipe_private_t	*pp);
870Sstevel@tonic-gate static void ehci_reclaim_isoc(
880Sstevel@tonic-gate 	ehci_state_t		*ehcip,
890Sstevel@tonic-gate 	ehci_isoc_xwrapper_t	*itw,
900Sstevel@tonic-gate 	ehci_itd_t		*itd,
910Sstevel@tonic-gate 	ehci_pipe_private_t	*pp);
920Sstevel@tonic-gate int	ehci_start_isoc_polling(
930Sstevel@tonic-gate 	ehci_state_t		*ehcip,
940Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
950Sstevel@tonic-gate 	usb_flags_t		flags);
960Sstevel@tonic-gate 
970Sstevel@tonic-gate /*
980Sstevel@tonic-gate  * Isochronronous handling functions.
990Sstevel@tonic-gate  */
1000Sstevel@tonic-gate void ehci_traverse_active_isoc_list(
1010Sstevel@tonic-gate 	ehci_state_t		*ehcip);
1020Sstevel@tonic-gate static void ehci_handle_isoc(
1030Sstevel@tonic-gate 	ehci_state_t		*ehcip,
1040Sstevel@tonic-gate 	ehci_isoc_xwrapper_t	*itw,
1050Sstevel@tonic-gate 	ehci_itd_t		*itd);
1060Sstevel@tonic-gate static void ehci_handle_itd(
1070Sstevel@tonic-gate 	ehci_state_t		*ehcip,
1080Sstevel@tonic-gate 	ehci_pipe_private_t	*pp,
1090Sstevel@tonic-gate 	ehci_isoc_xwrapper_t	*itw,
1100Sstevel@tonic-gate 	ehci_itd_t		*itd,
1110Sstevel@tonic-gate 	void			*tw_handle_callback_value);
1120Sstevel@tonic-gate static void ehci_sendup_itd_message(
1130Sstevel@tonic-gate 	ehci_state_t		*ehcip,
1140Sstevel@tonic-gate 	ehci_pipe_private_t	*pp,
1150Sstevel@tonic-gate 	ehci_isoc_xwrapper_t	*itw,
1160Sstevel@tonic-gate 	ehci_itd_t		*td,
1170Sstevel@tonic-gate 	usb_cr_t		error);
1180Sstevel@tonic-gate void ehci_hcdi_isoc_callback(
1190Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
1200Sstevel@tonic-gate 	ehci_isoc_xwrapper_t	*itw,
1210Sstevel@tonic-gate 	usb_cr_t		completion_reason);
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate /*
1250Sstevel@tonic-gate  * Isochronous initialization functions
1260Sstevel@tonic-gate  */
1270Sstevel@tonic-gate /*
1280Sstevel@tonic-gate  * Initialize all the needed resources needed by isochronous pipes.
1290Sstevel@tonic-gate  */
1300Sstevel@tonic-gate int
ehci_isoc_init(ehci_state_t * ehcip)1310Sstevel@tonic-gate ehci_isoc_init(
1320Sstevel@tonic-gate 	ehci_state_t		*ehcip)
1330Sstevel@tonic-gate {
1340Sstevel@tonic-gate 	return (ehci_allocate_isoc_pools(ehcip));
1350Sstevel@tonic-gate }
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate /*
1390Sstevel@tonic-gate  * Cleanup isochronous resources.
1400Sstevel@tonic-gate  */
1410Sstevel@tonic-gate void
ehci_isoc_cleanup(ehci_state_t * ehcip)1420Sstevel@tonic-gate ehci_isoc_cleanup(
1430Sstevel@tonic-gate 	ehci_state_t		*ehcip)
1440Sstevel@tonic-gate {
1450Sstevel@tonic-gate 	ehci_isoc_xwrapper_t	*itw;
1460Sstevel@tonic-gate 	ehci_pipe_private_t	*pp;
1470Sstevel@tonic-gate 	ehci_itd_t		*itd;
1480Sstevel@tonic-gate 	int			i, ctrl, rval;
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate 	/* Free all the buffers */
1510Sstevel@tonic-gate 	if (ehcip->ehci_itd_pool_addr && ehcip->ehci_itd_pool_mem_handle) {
1520Sstevel@tonic-gate 		for (i = 0; i < ehci_get_itd_pool_size(); i ++) {
1530Sstevel@tonic-gate 			itd = &ehcip->ehci_itd_pool_addr[i];
1540Sstevel@tonic-gate 			ctrl = Get_ITD(ehcip->
1550Sstevel@tonic-gate 			    ehci_itd_pool_addr[i].itd_state);
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate 			if ((ctrl != EHCI_ITD_FREE) &&
1580Sstevel@tonic-gate 			    (ctrl != EHCI_ITD_DUMMY) &&
1590Sstevel@tonic-gate 			    (itd->itd_trans_wrapper)) {
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate 				mutex_enter(&ehcip->ehci_int_mutex);
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate 				itw = (ehci_isoc_xwrapper_t *)
1645653Slc152243 				    EHCI_LOOKUP_ID((uint32_t)
1655653Slc152243 				    Get_ITD(itd->itd_trans_wrapper));
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate 				/* Obtain the pipe private structure */
1680Sstevel@tonic-gate 				pp = itw->itw_pipe_private;
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate 				ehci_deallocate_itd(ehcip, itw, itd);
1710Sstevel@tonic-gate 				ehci_deallocate_itw(ehcip, pp, itw);
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate 				mutex_exit(&ehcip->ehci_int_mutex);
1740Sstevel@tonic-gate 			}
1750Sstevel@tonic-gate 		}
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate 		/*
1780Sstevel@tonic-gate 		 * If EHCI_ITD_POOL_BOUND flag is set, then unbind
1790Sstevel@tonic-gate 		 * the handle for ITD pools.
1800Sstevel@tonic-gate 		 */
1810Sstevel@tonic-gate 		if ((ehcip->ehci_dma_addr_bind_flag &
1820Sstevel@tonic-gate 		    EHCI_ITD_POOL_BOUND) == EHCI_ITD_POOL_BOUND) {
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate 			rval = ddi_dma_unbind_handle(
1850Sstevel@tonic-gate 			    ehcip->ehci_itd_pool_dma_handle);
1860Sstevel@tonic-gate 
1870Sstevel@tonic-gate 			ASSERT(rval == DDI_SUCCESS);
1880Sstevel@tonic-gate 		}
1890Sstevel@tonic-gate 		ddi_dma_mem_free(&ehcip->ehci_itd_pool_mem_handle);
1900Sstevel@tonic-gate 	}
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate 	/* Free the ITD pool */
1930Sstevel@tonic-gate 	if (ehcip->ehci_itd_pool_dma_handle) {
1940Sstevel@tonic-gate 		ddi_dma_free_handle(&ehcip->ehci_itd_pool_dma_handle);
1950Sstevel@tonic-gate 	}
1960Sstevel@tonic-gate }
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate /*
2000Sstevel@tonic-gate  * ehci_isoc_pipe_cleanup
2010Sstevel@tonic-gate  *
2020Sstevel@tonic-gate  * Cleanup ehci isoc pipes.
2030Sstevel@tonic-gate  */
ehci_isoc_pipe_cleanup(ehci_state_t * ehcip,usba_pipe_handle_data_t * ph)2040Sstevel@tonic-gate void ehci_isoc_pipe_cleanup(
2050Sstevel@tonic-gate 	ehci_state_t		*ehcip,
2060Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph) {
2070Sstevel@tonic-gate 	ehci_pipe_private_t	*pp = (ehci_pipe_private_t *)ph->p_hcd_private;
2080Sstevel@tonic-gate 	uint_t			pipe_state = pp->pp_state;
2090Sstevel@tonic-gate 	usb_cr_t		completion_reason;
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
2120Sstevel@tonic-gate 	    "ehci_isoc_pipe_cleanup: ph = 0x%p", (void *)ph);
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate 	/* Stop all further processing */
2170Sstevel@tonic-gate 	ehci_mark_reclaim_isoc(ehcip, pp);
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate 	/*
2200Sstevel@tonic-gate 	 * Wait for processing all completed transfers
2210Sstevel@tonic-gate 	 * and send result upstream/
2220Sstevel@tonic-gate 	 */
2230Sstevel@tonic-gate 	ehci_wait_for_isoc_completion(ehcip, pp);
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate 	/* Go ahead and remove all remaining itds if there are any */
2260Sstevel@tonic-gate 	ehci_remove_isoc_itds(ehcip, pp);
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate 	switch (pipe_state) {
2290Sstevel@tonic-gate 	case EHCI_PIPE_STATE_CLOSE:
2300Sstevel@tonic-gate 		completion_reason = USB_CR_PIPE_CLOSING;
2310Sstevel@tonic-gate 		break;
2320Sstevel@tonic-gate 	case EHCI_PIPE_STATE_RESET:
2330Sstevel@tonic-gate 	case EHCI_PIPE_STATE_STOP_POLLING:
2340Sstevel@tonic-gate 		/* Set completion reason */
2350Sstevel@tonic-gate 		completion_reason = (pipe_state ==
2360Sstevel@tonic-gate 		    EHCI_PIPE_STATE_RESET) ?
2370Sstevel@tonic-gate 		    USB_CR_PIPE_RESET: USB_CR_STOPPED_POLLING;
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate 		/* Set pipe state to idle */
2400Sstevel@tonic-gate 		pp->pp_state = EHCI_PIPE_STATE_IDLE;
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate 		break;
2430Sstevel@tonic-gate 	}
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate 	/*
2460Sstevel@tonic-gate 	 * Do the callback for the original client
2470Sstevel@tonic-gate 	 * periodic IN request.
2480Sstevel@tonic-gate 	 */
2490Sstevel@tonic-gate 	if ((ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK) ==
2500Sstevel@tonic-gate 	    USB_EP_DIR_IN) {
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate 		ehci_do_client_periodic_in_req_callback(
2530Sstevel@tonic-gate 		    ehcip, pp, completion_reason);
2540Sstevel@tonic-gate 	}
2550Sstevel@tonic-gate }
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate /*
2590Sstevel@tonic-gate  * ehci_wait_for_transfers_completion:
2600Sstevel@tonic-gate  *
2610Sstevel@tonic-gate  * Wait for processing all completed transfers and to send results
2620Sstevel@tonic-gate  * to upstream.
2630Sstevel@tonic-gate  */
2640Sstevel@tonic-gate static void
ehci_wait_for_isoc_completion(ehci_state_t * ehcip,ehci_pipe_private_t * pp)2650Sstevel@tonic-gate ehci_wait_for_isoc_completion(
2660Sstevel@tonic-gate 	ehci_state_t		*ehcip,
2670Sstevel@tonic-gate 	ehci_pipe_private_t	*pp)
2680Sstevel@tonic-gate {
2690Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate 	if (pp->pp_itw_head == NULL) {
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate 		return;
2740Sstevel@tonic-gate 	}
2750Sstevel@tonic-gate 
276*11066Srafael.vanoni@sun.com 	(void) cv_reltimedwait(&pp->pp_xfer_cmpl_cv, &ehcip->ehci_int_mutex,
277*11066Srafael.vanoni@sun.com 	    drv_usectohz(EHCI_XFER_CMPL_TIMEWAIT * 1000000), TR_CLOCK_TICK);
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate 	if (pp->pp_itw_head) {
2800Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
2810Sstevel@tonic-gate 		    "ehci_wait_for_isoc_completion: "
2820Sstevel@tonic-gate 		    "No transfers completion confirmation received");
2830Sstevel@tonic-gate 	}
2840Sstevel@tonic-gate }
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate /*
2880Sstevel@tonic-gate  *  Isochronous request functions
2890Sstevel@tonic-gate  */
2900Sstevel@tonic-gate /*
2910Sstevel@tonic-gate  * ehci_allocate_isoc_resources:
2920Sstevel@tonic-gate  *
2930Sstevel@tonic-gate  * Calculates the number of tds necessary for a isoch transfer, and
2940Sstevel@tonic-gate  * allocates all the necessary resources.
2950Sstevel@tonic-gate  *
2960Sstevel@tonic-gate  * Returns NULL if there is insufficient resources otherwise ITW.
2970Sstevel@tonic-gate  */
2980Sstevel@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)2990Sstevel@tonic-gate ehci_allocate_isoc_resources(
3000Sstevel@tonic-gate 	ehci_state_t		*ehcip,
3010Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph,
3020Sstevel@tonic-gate 	usb_isoc_req_t		*isoc_reqp,
3030Sstevel@tonic-gate 	usb_flags_t		usb_flags)
3040Sstevel@tonic-gate {
3050Sstevel@tonic-gate 	ehci_pipe_private_t	*pp = (ehci_pipe_private_t *)ph->p_hcd_private;
3063255Slg150142 	int			pipe_dir, i;
3070Sstevel@tonic-gate 	uint_t			max_ep_pkt_size, max_isoc_xfer_size;
3080Sstevel@tonic-gate 	usb_isoc_pkt_descr_t	*isoc_pkt_descr;
3093255Slg150142 	size_t			isoc_pkt_count, isoc_pkts_length;
3105653Slc152243 	size_t			itw_xfer_size = 0;
3110Sstevel@tonic-gate 	ehci_isoc_xwrapper_t	*itw;
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
3140Sstevel@tonic-gate 	    "ehci_allocate_isoc_resources: flags = 0x%x", usb_flags);
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate 	/*
3190Sstevel@tonic-gate 	 * Check whether pipe is in halted state.
3200Sstevel@tonic-gate 	 */
3210Sstevel@tonic-gate 	if (pp->pp_state == EHCI_PIPE_STATE_ERROR) {
3220Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
3230Sstevel@tonic-gate 		    "ehci_allocate_isoc_resources:"
3240Sstevel@tonic-gate 		    "Pipe is in error state, need pipe reset to continue");
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate 		return (NULL);
3270Sstevel@tonic-gate 	}
3280Sstevel@tonic-gate 
3290Sstevel@tonic-gate 	/* Calculate the maximum isochronous transfer size we allow */
3305653Slc152243 	max_ep_pkt_size = (ph->p_ep.wMaxPacketSize &
3315653Slc152243 	    EHCI_ITD_CTRL_MAX_PACKET_MASK) *
3325653Slc152243 	    CalculateITDMultiField(ph->p_ep.wMaxPacketSize);
3335653Slc152243 
3340Sstevel@tonic-gate 	max_isoc_xfer_size = EHCI_MAX_ISOC_PKTS_PER_XFER * max_ep_pkt_size;
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate 	/* Get the packet descriptor and number of packets to send */
3370Sstevel@tonic-gate 	if (isoc_reqp) {
3380Sstevel@tonic-gate 		isoc_pkt_descr = isoc_reqp->isoc_pkt_descr;
3390Sstevel@tonic-gate 		isoc_pkt_count = isoc_reqp->isoc_pkts_count;
3403255Slg150142 		isoc_pkts_length = isoc_reqp->isoc_pkts_length;
3410Sstevel@tonic-gate 	} else {
3420Sstevel@tonic-gate 		isoc_pkt_descr = ((usb_isoc_req_t *)
3430Sstevel@tonic-gate 		    pp->pp_client_periodic_in_reqp)->isoc_pkt_descr;
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate 		isoc_pkt_count = ((usb_isoc_req_t *)
3460Sstevel@tonic-gate 		    pp->pp_client_periodic_in_reqp)->isoc_pkts_count;
3473255Slg150142 
3483255Slg150142 		isoc_pkts_length = ((usb_isoc_req_t *)
3490Sstevel@tonic-gate 		    pp->pp_client_periodic_in_reqp)->isoc_pkts_length;
3500Sstevel@tonic-gate 	}
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 	/* Calculate the size of the transfer. */
3530Sstevel@tonic-gate 	pipe_dir = ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK;
3540Sstevel@tonic-gate 	if (pipe_dir == USB_EP_DIR_IN) {
3553255Slg150142 		for (i = 0; i < isoc_pkt_count; i++) {
3565653Slc152243 			/*
3575653Slc152243 			 * isoc_pkt_length is used as Transaction Length and
3585653Slc152243 			 * according to EHCI spec Table 3-3, the maximum value
3595653Slc152243 			 * allowed is 3072
3605653Slc152243 			 */
3615653Slc152243 			if (isoc_pkt_descr->isoc_pkt_length > 3072) {
3625653Slc152243 
3635653Slc152243 				return (NULL);
3645653Slc152243 			}
3655653Slc152243 
3663255Slg150142 			itw_xfer_size += isoc_pkt_descr->isoc_pkt_length;
3675653Slc152243 
3683255Slg150142 			isoc_pkt_descr++;
3693255Slg150142 		}
3703255Slg150142 
3713255Slg150142 		if ((isoc_pkts_length) &&
3725653Slc152243 		    (isoc_pkts_length != itw_xfer_size)) {
3733255Slg150142 
3743255Slg150142 			USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
3753255Slg150142 			    "ehci_allocate_isoc_resources: "
3766898Sfb209375 			    "isoc_pkts_length 0x%lx is not equal to the sum of "
3776898Sfb209375 			    "all pkt lengths 0x%lx in an isoc request",
3783255Slg150142 			    isoc_pkts_length, itw_xfer_size);
3793255Slg150142 
3803255Slg150142 			return (NULL);
3813255Slg150142 		}
3823255Slg150142 
3830Sstevel@tonic-gate 	} else {
3840Sstevel@tonic-gate 		ASSERT(isoc_reqp != NULL);
3857492SZhigang.Lu@Sun.COM 		itw_xfer_size = MBLKL(isoc_reqp->isoc_data);
3860Sstevel@tonic-gate 	}
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate 	/* Check the size of isochronous request */
3890Sstevel@tonic-gate 	if (itw_xfer_size > max_isoc_xfer_size) {
3900Sstevel@tonic-gate 
3910Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
3923255Slg150142 		    "ehci_allocate_isoc_resources: Maximum isoc request "
3936898Sfb209375 		    "size 0x%x Given isoc request size 0x%lx",
3940Sstevel@tonic-gate 		    max_isoc_xfer_size, itw_xfer_size);
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 		return (NULL);
3970Sstevel@tonic-gate 	}
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
4006898Sfb209375 	    "ehci_allocate_isoc_resources: length = 0x%lx", itw_xfer_size);
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate 	/* Allocate the itw for this request */
4030Sstevel@tonic-gate 	if ((itw = ehci_allocate_itw_resources(ehcip, pp, itw_xfer_size,
4040Sstevel@tonic-gate 	    usb_flags, isoc_pkt_count)) == NULL) {
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 		return (NULL);
4070Sstevel@tonic-gate 	}
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate 	itw->itw_handle_callback_value = NULL;
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate 	if (pipe_dir == USB_EP_DIR_IN) {
4120Sstevel@tonic-gate 		if (ehci_allocate_isoc_in_resource(ehcip, pp, itw, usb_flags) !=
4130Sstevel@tonic-gate 		    USB_SUCCESS) {
4140Sstevel@tonic-gate 
4150Sstevel@tonic-gate 			ehci_deallocate_itw(ehcip, pp, itw);
4160Sstevel@tonic-gate 
4170Sstevel@tonic-gate 			return (NULL);
4180Sstevel@tonic-gate 		}
4190Sstevel@tonic-gate 	} else {
4200Sstevel@tonic-gate 		if (itw->itw_length) {
4210Sstevel@tonic-gate 			ASSERT(isoc_reqp->isoc_data != NULL);
4220Sstevel@tonic-gate 
4230Sstevel@tonic-gate 			/* Copy the data into the buffer */
4240Sstevel@tonic-gate 			bcopy(isoc_reqp->isoc_data->b_rptr,
4250Sstevel@tonic-gate 			    itw->itw_buf, itw->itw_length);
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate 			Sync_IO_Buffer_for_device(itw->itw_dmahandle,
4280Sstevel@tonic-gate 			    itw->itw_length);
4290Sstevel@tonic-gate 		}
4300Sstevel@tonic-gate 		itw->itw_curr_xfer_reqp = isoc_reqp;
4310Sstevel@tonic-gate 	}
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 	return (itw);
4340Sstevel@tonic-gate }
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate 
4370Sstevel@tonic-gate /*
4380Sstevel@tonic-gate  * ehci_insert_isoc_req:
4390Sstevel@tonic-gate  *
4400Sstevel@tonic-gate  * Insert an isochronous request into the Host Controller's
4410Sstevel@tonic-gate  * isochronous list.
4420Sstevel@tonic-gate  */
4430Sstevel@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)4440Sstevel@tonic-gate ehci_insert_isoc_req(
4450Sstevel@tonic-gate 	ehci_state_t			*ehcip,
4460Sstevel@tonic-gate 	ehci_pipe_private_t		*pp,
4470Sstevel@tonic-gate 	ehci_isoc_xwrapper_t		*itw,
4480Sstevel@tonic-gate 	usb_flags_t			usb_flags)
4490Sstevel@tonic-gate {
4500Sstevel@tonic-gate 	int			error;
4513255Slg150142 	ehci_itd_t		*new_itd, *temp_itd;
4520Sstevel@tonic-gate 
4530Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
4540Sstevel@tonic-gate 	    "ehci_insert_isoc_req: flags = 0x%x port status = 0x%x",
4550Sstevel@tonic-gate 	    usb_flags, itw->itw_port_status);
4560Sstevel@tonic-gate 
4570Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate 	ASSERT(itw->itw_curr_xfer_reqp != NULL);
4600Sstevel@tonic-gate 	ASSERT(itw->itw_curr_xfer_reqp->isoc_pkt_descr != NULL);
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate 	/*
4630Sstevel@tonic-gate 	 * Save address of first usb isochronous packet descriptor.
4640Sstevel@tonic-gate 	 */
4650Sstevel@tonic-gate 	itw->itw_curr_isoc_pktp = itw->itw_curr_xfer_reqp->isoc_pkt_descr;
4660Sstevel@tonic-gate 
4670Sstevel@tonic-gate 	if (itw->itw_port_status == USBA_HIGH_SPEED_DEV) {
4683255Slg150142 		error = ehci_insert_itd_req(ehcip, pp, itw, usb_flags);
4690Sstevel@tonic-gate 	} else {
4700Sstevel@tonic-gate 		error = ehci_insert_sitd_req(ehcip, pp, itw, usb_flags);
4710Sstevel@tonic-gate 	}
4720Sstevel@tonic-gate 
4733255Slg150142 	/* Either all the isocs will be added or none of them will */
4743255Slg150142 	error = ehci_insert_isoc_to_pfl(ehcip, pp, itw);
4753255Slg150142 
4763255Slg150142 	if (error != USB_SUCCESS) {
4773255Slg150142 		/*
4783255Slg150142 		 * Deallocate all the ITDs, otherwise they will be
4793255Slg150142 		 * lost forever.
4803255Slg150142 		 */
4813255Slg150142 		new_itd = itw->itw_itd_head;
4823255Slg150142 		while (new_itd) {
4833255Slg150142 			temp_itd = ehci_itd_iommu_to_cpu(ehcip,
4843255Slg150142 			    Get_ITD(new_itd->itd_itw_next_itd));
4853255Slg150142 			ehci_deallocate_itd(ehcip, itw, new_itd);
4863255Slg150142 			new_itd = temp_itd;
4873255Slg150142 		}
4883255Slg150142 		if ((itw->itw_direction == USB_EP_DIR_IN)) {
4893255Slg150142 			ehci_deallocate_isoc_in_resource(ehcip, pp, itw);
4903255Slg150142 
4913255Slg150142 			if (pp->pp_cur_periodic_req_cnt) {
4923255Slg150142 				/*
4933255Slg150142 				 * Set pipe state to stop polling and
4943255Slg150142 				 * error to no resource. Don't insert
4953255Slg150142 				 * any more isoch polling requests.
4963255Slg150142 				 */
4973255Slg150142 				pp->pp_state =
4983255Slg150142 				    EHCI_PIPE_STATE_STOP_POLLING;
4993255Slg150142 				pp->pp_error = error;
5003255Slg150142 			} else {
5013255Slg150142 				/* Set periodic in pipe state to idle */
5023255Slg150142 				pp->pp_state = EHCI_PIPE_STATE_IDLE;
5033255Slg150142 			}
5043255Slg150142 
5053255Slg150142 			return (error);
5063255Slg150142 		}
5073255Slg150142 
5083255Slg150142 		/* Save how many packets and data actually went */
5093255Slg150142 		itw->itw_num_itds = 0;
5103255Slg150142 		itw->itw_length  = 0;
5113255Slg150142 	}
5123255Slg150142 
5133255Slg150142 	/*
5143255Slg150142 	 * Reset back to the address of first usb isochronous
5153255Slg150142 	 * packet descriptor.
5163255Slg150142 	 */
5173255Slg150142 	itw->itw_curr_isoc_pktp = itw->itw_curr_xfer_reqp->isoc_pkt_descr;
5183255Slg150142 
5193255Slg150142 	/* Reset the CONTINUE flag */
5203255Slg150142 	pp->pp_flag &= ~EHCI_ISOC_XFER_CONTINUE;
5213255Slg150142 
5220Sstevel@tonic-gate 	return (error);
5230Sstevel@tonic-gate }
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate 
5260Sstevel@tonic-gate /*
5273255Slg150142  * ehci_insert_itd_req:
5283255Slg150142  *
5293255Slg150142  * Insert an ITD request into the Host Controller's isochronous list.
5303255Slg150142  */
5313255Slg150142 /* ARGSUSED */
5323255Slg150142 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)5333255Slg150142 ehci_insert_itd_req(
5343255Slg150142 	ehci_state_t		*ehcip,
5353255Slg150142 	ehci_pipe_private_t	*pp,
5363255Slg150142 	ehci_isoc_xwrapper_t	*itw,
5373255Slg150142 	usb_flags_t		usb_flags)
5383255Slg150142 {
5393255Slg150142 	usba_pipe_handle_data_t	*ph = pp->pp_pipe_handle;
5403255Slg150142 	usb_isoc_req_t		*curr_isoc_reqp;
5413255Slg150142 	usb_isoc_pkt_descr_t	*curr_isoc_pkt_descr;
5423255Slg150142 	size_t			curr_isoc_xfer_offset;
5433255Slg150142 	size_t			isoc_pkt_length;
5443255Slg150142 	uint_t			count, xactcount;
5453255Slg150142 	uint32_t		xact_status;
5463255Slg150142 	uint32_t		page, pageselected;
5473255Slg150142 	uint32_t		buf[EHCI_ITD_BUFFER_LIST_SIZE];
5483255Slg150142 	uint16_t		index = 0;
5493255Slg150142 	uint16_t		multi = 0;
5503255Slg150142 	ehci_itd_t		*new_itd;
5513255Slg150142 
5523255Slg150142 	/*
5533255Slg150142 	 * Get the current isochronous request and packet
5543255Slg150142 	 * descriptor pointers.
5553255Slg150142 	 */
5563255Slg150142 	curr_isoc_reqp = (usb_isoc_req_t *)itw->itw_curr_xfer_reqp;
5573255Slg150142 
5583255Slg150142 	page = itw->itw_cookie.dmac_address;
5593255Slg150142 	ASSERT((page % EHCI_4K_ALIGN) == 0);
5603255Slg150142 
5613255Slg150142 	USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
5626898Sfb209375 	    "ehci_insert_itd_req: itw_curr_xfer_reqp = 0x%p page = 0x%x,"
5636898Sfb209375 	    " pagesize = 0x%lx", (void *)itw->itw_curr_xfer_reqp, page,
5645653Slc152243 	    itw->itw_cookie.dmac_size);
5653255Slg150142 
5663255Slg150142 	/* Insert all the isochronous TDs */
5673255Slg150142 	count = 0;
5683255Slg150142 	curr_isoc_xfer_offset = 0;
5693255Slg150142 
5703255Slg150142 	while (count < curr_isoc_reqp->isoc_pkts_count) {
5713255Slg150142 
5723255Slg150142 		/* Grab a new itd */
5733255Slg150142 		new_itd = itw->itw_itd_free_list;
5743255Slg150142 
5753255Slg150142 		ASSERT(new_itd != NULL);
5763255Slg150142 
5773255Slg150142 		itw->itw_itd_free_list = ehci_itd_iommu_to_cpu(ehcip,
5783255Slg150142 		    Get_ITD(new_itd->itd_link_ptr));
5793255Slg150142 		Set_ITD(new_itd->itd_link_ptr, NULL);
5803255Slg150142 
5813255Slg150142 		bzero(buf, EHCI_ITD_BUFFER_LIST_SIZE * sizeof (uint32_t));
5823255Slg150142 
5833255Slg150142 		multi = CalculateITDMultiField(ph->p_ep.wMaxPacketSize);
5843255Slg150142 
5853255Slg150142 		if (multi > EHCI_ITD_CTRL_MULTI_MASK) {
5863255Slg150142 			USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
5873255Slg150142 			    "ehci_insert_itd_req: Wrong multi value.");
5883255Slg150142 
5893255Slg150142 			return (USB_FAILURE);
5903255Slg150142 		}
5913255Slg150142 
5923255Slg150142 		/* Fill 8 transaction for every iTD */
5933255Slg150142 		for (xactcount = 0, pageselected = 0;
5943255Slg150142 		    xactcount < EHCI_ITD_CTRL_LIST_SIZE; xactcount++) {
5953255Slg150142 
5963255Slg150142 			curr_isoc_pkt_descr = itw->itw_curr_isoc_pktp;
5973255Slg150142 
5985653Slc152243 			isoc_pkt_length =
5995653Slc152243 			    curr_isoc_pkt_descr->isoc_pkt_length;
6003255Slg150142 
6013255Slg150142 			curr_isoc_pkt_descr->isoc_pkt_actual_length
6027492SZhigang.Lu@Sun.COM 			    = (ushort_t)isoc_pkt_length;
6033255Slg150142 
6043255Slg150142 			xact_status = 0;
6053255Slg150142 
6063255Slg150142 			if (pageselected < EHCI_ITD_BUFFER_LIST_SIZE) {
6073255Slg150142 
6083255Slg150142 				buf[pageselected] |= page;
6093255Slg150142 			} else {
6103255Slg150142 				USB_DPRINTF_L2(PRINT_MASK_INTR,
6113255Slg150142 				    ehcip->ehci_log_hdl,
6123255Slg150142 				    "ehci_insert_itd_req: "
6133255Slg150142 				    "Error in buffer pointer.");
6143255Slg150142 
6153255Slg150142 				return (USB_FAILURE);
6163255Slg150142 			}
6173255Slg150142 
6187492SZhigang.Lu@Sun.COM 			xact_status = (uint32_t)curr_isoc_xfer_offset;
6193255Slg150142 			xact_status |= (pageselected << 12);
6205653Slc152243 			xact_status |= isoc_pkt_length << 16;
6213255Slg150142 			xact_status |= EHCI_ITD_XFER_ACTIVE;
6223255Slg150142 
6233255Slg150142 			/* Set IOC on the last TD. */
6243255Slg150142 			if (count == (curr_isoc_reqp->isoc_pkts_count - 1)) {
6253255Slg150142 				xact_status |= EHCI_ITD_XFER_IOC_ON;
6263255Slg150142 			}
6273255Slg150142 
6283255Slg150142 			USB_DPRINTF_L3(PRINT_MASK_INTR,
6293255Slg150142 			    ehcip->ehci_log_hdl,
6303255Slg150142 			    "ehci_insert_itd_req: count = 0x%x multi = %d"
6313255Slg150142 			    "status = 0x%x page = 0x%x index = %d "
6326898Sfb209375 			    "pageselected = %d isoc_pkt_length = 0x%lx",
6333255Slg150142 			    xactcount, multi, xact_status, page,
6343255Slg150142 			    index, pageselected, isoc_pkt_length);
6353255Slg150142 
6363255Slg150142 			/* Fill in the new itd */
6373255Slg150142 			Set_ITD_BODY(new_itd, xactcount, xact_status);
6383255Slg150142 
6393255Slg150142 			itw->itw_curr_isoc_pktp++;
6403255Slg150142 			Set_ITD_INDEX(new_itd, xactcount, index++);
6413255Slg150142 
6425653Slc152243 			curr_isoc_xfer_offset += isoc_pkt_length;
6433255Slg150142 
6443255Slg150142 			if (curr_isoc_xfer_offset >= EHCI_4K_ALIGN) {
6453255Slg150142 				pageselected ++;
6463255Slg150142 				page += EHCI_4K_ALIGN;
6473255Slg150142 				curr_isoc_xfer_offset -= EHCI_4K_ALIGN;
6483255Slg150142 			}
6493255Slg150142 
6503255Slg150142 			count ++;
6513255Slg150142 			if (count >= curr_isoc_reqp->isoc_pkts_count) {
6523255Slg150142 
6535653Slc152243 				break;
6543255Slg150142 			}
6553255Slg150142 		}
6563255Slg150142 
6573255Slg150142 		buf[0] |= (itw->itw_endpoint_num << 8);
6583255Slg150142 		buf[0] |= itw->itw_device_addr;
6595653Slc152243 		buf[1] |= ph->p_ep.wMaxPacketSize &
6605653Slc152243 		    EHCI_ITD_CTRL_MAX_PACKET_MASK;
6615653Slc152243 
6623255Slg150142 		if (itw->itw_direction == USB_EP_DIR_IN) {
6633255Slg150142 			buf[1] |= EHCI_ITD_CTRL_DIR_IN;
6643255Slg150142 		}
6653255Slg150142 		buf[2] |= multi;
6663255Slg150142 
6673255Slg150142 		Set_ITD_BODY(new_itd, EHCI_ITD_BUFFER0, buf[0]);
6683255Slg150142 		Set_ITD_BODY(new_itd, EHCI_ITD_BUFFER1, buf[1]);
6693255Slg150142 		Set_ITD_BODY(new_itd, EHCI_ITD_BUFFER2, buf[2]);
6703255Slg150142 		Set_ITD_BODY(new_itd, EHCI_ITD_BUFFER3, buf[3]);
6713255Slg150142 		Set_ITD_BODY(new_itd, EHCI_ITD_BUFFER4, buf[4]);
6723255Slg150142 		Set_ITD_BODY(new_itd, EHCI_ITD_BUFFER5, buf[5]);
6733255Slg150142 		Set_ITD_BODY(new_itd, EHCI_ITD_BUFFER6, buf[6]);
6743255Slg150142 
6753255Slg150142 		Set_ITD(new_itd->itd_state, EHCI_ITD_ACTIVE);
6763255Slg150142 		ehci_print_itd(ehcip, new_itd);
6773255Slg150142 
6783255Slg150142 		/*
6793255Slg150142 		 * Add this itd to the itw before we add it in the PFL
6803255Slg150142 		 * If adding it to the PFL fails, we will have to cleanup.
6813255Slg150142 		 */
6823255Slg150142 		ehci_insert_itd_on_itw(ehcip, itw, new_itd);
6833255Slg150142 
6843255Slg150142 	}
6853255Slg150142 
6863255Slg150142 	return (USB_SUCCESS);
6873255Slg150142 }
6883255Slg150142 
6893255Slg150142 
6903255Slg150142 /*
6910Sstevel@tonic-gate  * ehci_insert_sitd_req:
6920Sstevel@tonic-gate  *
6930Sstevel@tonic-gate  * Insert an SITD request into the Host Controller's isochronous list.
6940Sstevel@tonic-gate  */
6950Sstevel@tonic-gate /* ARGSUSED */
6960Sstevel@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)6970Sstevel@tonic-gate ehci_insert_sitd_req(
6980Sstevel@tonic-gate 	ehci_state_t		*ehcip,
6990Sstevel@tonic-gate 	ehci_pipe_private_t	*pp,
7000Sstevel@tonic-gate 	ehci_isoc_xwrapper_t	*itw,
7010Sstevel@tonic-gate 	usb_flags_t		usb_flags)
7020Sstevel@tonic-gate {
7030Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph = pp->pp_pipe_handle;
7040Sstevel@tonic-gate 	usb_isoc_req_t		*curr_isoc_reqp;
7050Sstevel@tonic-gate 	usb_isoc_pkt_descr_t	*curr_isoc_pkt_descr;
7060Sstevel@tonic-gate 	size_t			curr_isoc_xfer_offset;
7070Sstevel@tonic-gate 	size_t			isoc_pkt_length;
7083255Slg150142 	uint_t			count;
7090Sstevel@tonic-gate 	uint32_t		ctrl, uframe_sched, xfer_state;
7100Sstevel@tonic-gate 	uint32_t		page0, page1, prev_sitd;
7110Sstevel@tonic-gate 	uint32_t		ssplit_count;
7123255Slg150142 	ehci_itd_t		*new_sitd;
7130Sstevel@tonic-gate 
7140Sstevel@tonic-gate 	/*
7150Sstevel@tonic-gate 	 * Get the current isochronous request and packet
7160Sstevel@tonic-gate 	 * descriptor pointers.
7170Sstevel@tonic-gate 	 */
7180Sstevel@tonic-gate 	curr_isoc_reqp = (usb_isoc_req_t *)itw->itw_curr_xfer_reqp;
7190Sstevel@tonic-gate 
7200Sstevel@tonic-gate 	/* Set the ctrl field */
7210Sstevel@tonic-gate 	ctrl = 0;
7220Sstevel@tonic-gate 	if (itw->itw_direction == USB_EP_DIR_IN) {
7230Sstevel@tonic-gate 		ctrl |= EHCI_SITD_CTRL_DIR_IN;
7240Sstevel@tonic-gate 	} else {
7250Sstevel@tonic-gate 		ctrl |= EHCI_SITD_CTRL_DIR_OUT;
7260Sstevel@tonic-gate 	}
7270Sstevel@tonic-gate 
7280Sstevel@tonic-gate 	ctrl |= (itw->itw_hub_port << EHCI_SITD_CTRL_PORT_SHIFT) &
7290Sstevel@tonic-gate 	    EHCI_SITD_CTRL_PORT_MASK;
7300Sstevel@tonic-gate 	ctrl |= (itw->itw_hub_addr << EHCI_SITD_CTRL_HUB_SHIFT) &
7310Sstevel@tonic-gate 	    EHCI_SITD_CTRL_HUB_MASK;
7320Sstevel@tonic-gate 	ctrl |= (itw->itw_endpoint_num << EHCI_SITD_CTRL_END_PT_SHIFT) &
7330Sstevel@tonic-gate 	    EHCI_SITD_CTRL_END_PT_MASK;
7340Sstevel@tonic-gate 	ctrl |= (itw->itw_device_addr << EHCI_SITD_CTRL_DEVICE_SHIFT) &
7350Sstevel@tonic-gate 	    EHCI_SITD_CTRL_DEVICE_MASK;
7360Sstevel@tonic-gate 
7370Sstevel@tonic-gate 	/* Set the micro frame schedule */
7380Sstevel@tonic-gate 	uframe_sched = 0;
7390Sstevel@tonic-gate 	uframe_sched |= (pp->pp_smask << EHCI_SITD_UFRAME_SMASK_SHIFT) &
7400Sstevel@tonic-gate 	    EHCI_SITD_UFRAME_SMASK_MASK;
7410Sstevel@tonic-gate 	uframe_sched |= (pp->pp_cmask << EHCI_SITD_UFRAME_CMASK_SHIFT) &
7420Sstevel@tonic-gate 	    EHCI_SITD_UFRAME_CMASK_MASK;
7430Sstevel@tonic-gate 
7440Sstevel@tonic-gate 	/* Set the default page information */
7450Sstevel@tonic-gate 	page0 = itw->itw_cookie.dmac_address;
7460Sstevel@tonic-gate 	page1 = 0;
7470Sstevel@tonic-gate 
7480Sstevel@tonic-gate 	prev_sitd = EHCI_ITD_LINK_PTR_INVALID;
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate 	/*
7510Sstevel@tonic-gate 	 * Save the number of isochronous TDs needs
7520Sstevel@tonic-gate 	 * to be insert to complete current isochronous request.
7530Sstevel@tonic-gate 	 */
7540Sstevel@tonic-gate 	itw->itw_num_itds = curr_isoc_reqp->isoc_pkts_count;
7550Sstevel@tonic-gate 
7560Sstevel@tonic-gate 	/* Insert all the isochronous TDs */
7570Sstevel@tonic-gate 	for (count = 0, curr_isoc_xfer_offset = 0;
7585653Slc152243 	    count < itw->itw_num_itds; count++) {
7590Sstevel@tonic-gate 
7600Sstevel@tonic-gate 		curr_isoc_pkt_descr = itw->itw_curr_isoc_pktp;
7610Sstevel@tonic-gate 
7620Sstevel@tonic-gate 		isoc_pkt_length = curr_isoc_pkt_descr->isoc_pkt_length;
7637492SZhigang.Lu@Sun.COM 		curr_isoc_pkt_descr->isoc_pkt_actual_length =
7647492SZhigang.Lu@Sun.COM 		    (ushort_t)isoc_pkt_length;
7650Sstevel@tonic-gate 
7660Sstevel@tonic-gate 		/* Set the transfer state information */
7670Sstevel@tonic-gate 		xfer_state = 0;
7680Sstevel@tonic-gate 
7690Sstevel@tonic-gate 		if (itw->itw_direction == USB_EP_DIR_IN) {
7700Sstevel@tonic-gate 			/* Set the size to the max packet size */
7710Sstevel@tonic-gate 			xfer_state |= (ph->p_ep.wMaxPacketSize <<
7720Sstevel@tonic-gate 			    EHCI_SITD_XFER_TOTAL_SHIFT) &
7730Sstevel@tonic-gate 			    EHCI_SITD_XFER_TOTAL_MASK;
7740Sstevel@tonic-gate 		} else {
7750Sstevel@tonic-gate 			/* Set the size to the packet length */
7760Sstevel@tonic-gate 			xfer_state |= (isoc_pkt_length <<
7770Sstevel@tonic-gate 			    EHCI_SITD_XFER_TOTAL_SHIFT) &
7780Sstevel@tonic-gate 			    EHCI_SITD_XFER_TOTAL_MASK;
7790Sstevel@tonic-gate 		}
7800Sstevel@tonic-gate 		xfer_state |=  EHCI_SITD_XFER_ACTIVE;
7810Sstevel@tonic-gate 
7820Sstevel@tonic-gate 		/* Set IOC on the last TD. */
7830Sstevel@tonic-gate 		if (count == (itw->itw_num_itds - 1)) {
7840Sstevel@tonic-gate 			xfer_state |= EHCI_SITD_XFER_IOC_ON;
7850Sstevel@tonic-gate 		}
7860Sstevel@tonic-gate 
7870Sstevel@tonic-gate 		ssplit_count = isoc_pkt_length / MAX_UFRAME_SITD_XFER;
7880Sstevel@tonic-gate 		if (isoc_pkt_length % MAX_UFRAME_SITD_XFER) {
7890Sstevel@tonic-gate 			ssplit_count++;
7900Sstevel@tonic-gate 		}
7910Sstevel@tonic-gate 
7920Sstevel@tonic-gate 		page1 = (ssplit_count & EHCI_SITD_XFER_TCOUNT_MASK) <<
7930Sstevel@tonic-gate 		    EHCI_SITD_XFER_TCOUNT_SHIFT;
7940Sstevel@tonic-gate 		if (ssplit_count > 1) {
7950Sstevel@tonic-gate 			page1 |= EHCI_SITD_XFER_TP_BEGIN;
7960Sstevel@tonic-gate 		} else {
7970Sstevel@tonic-gate 			page1 |= EHCI_SITD_XFER_TP_ALL;
7980Sstevel@tonic-gate 		}
7990Sstevel@tonic-gate 
8000Sstevel@tonic-gate 		/* Grab a new sitd */
8010Sstevel@tonic-gate 		new_sitd = itw->itw_itd_free_list;
8020Sstevel@tonic-gate 
8030Sstevel@tonic-gate 		ASSERT(new_sitd != NULL);
8040Sstevel@tonic-gate 
8050Sstevel@tonic-gate 		itw->itw_itd_free_list = ehci_itd_iommu_to_cpu(ehcip,
8060Sstevel@tonic-gate 		    Get_ITD(new_sitd->itd_link_ptr));
8070Sstevel@tonic-gate 		Set_ITD(new_sitd->itd_link_ptr, NULL);
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate 		/* Fill in the new sitd */
8100Sstevel@tonic-gate 		Set_ITD_BODY(new_sitd, EHCI_SITD_CTRL, ctrl);
8110Sstevel@tonic-gate 		Set_ITD_BODY(new_sitd, EHCI_SITD_UFRAME_SCHED, uframe_sched);
8120Sstevel@tonic-gate 		Set_ITD_BODY(new_sitd, EHCI_SITD_XFER_STATE, xfer_state);
8130Sstevel@tonic-gate 		Set_ITD_BODY(new_sitd, EHCI_SITD_BUFFER0,
8140Sstevel@tonic-gate 		    page0 + curr_isoc_xfer_offset);
8150Sstevel@tonic-gate 		Set_ITD_BODY(new_sitd, EHCI_SITD_BUFFER1, page1);
8160Sstevel@tonic-gate 		Set_ITD_BODY(new_sitd, EHCI_SITD_PREV_SITD, prev_sitd);
8170Sstevel@tonic-gate 
8180Sstevel@tonic-gate 		Set_ITD(new_sitd->itd_state, EHCI_ITD_ACTIVE);
8190Sstevel@tonic-gate 
8200Sstevel@tonic-gate 		/*
8210Sstevel@tonic-gate 		 * Add this itd to the itw before we add it in the PFL
8220Sstevel@tonic-gate 		 * If adding it to the PFL fails, we will have to cleanup.
8230Sstevel@tonic-gate 		 */
8240Sstevel@tonic-gate 		ehci_insert_itd_on_itw(ehcip, itw, new_sitd);
8250Sstevel@tonic-gate 
8260Sstevel@tonic-gate 		itw->itw_curr_isoc_pktp++;
8270Sstevel@tonic-gate 		curr_isoc_xfer_offset += isoc_pkt_length;
8280Sstevel@tonic-gate 	}
8290Sstevel@tonic-gate 
8300Sstevel@tonic-gate 	return (USB_SUCCESS);
8310Sstevel@tonic-gate }
8320Sstevel@tonic-gate 
8330Sstevel@tonic-gate 
8340Sstevel@tonic-gate /*
8350Sstevel@tonic-gate  * ehci_remove_isoc_itds:
8360Sstevel@tonic-gate  *
8370Sstevel@tonic-gate  * Remove all itds from the PFL.
8380Sstevel@tonic-gate  */
8390Sstevel@tonic-gate static void
ehci_remove_isoc_itds(ehci_state_t * ehcip,ehci_pipe_private_t * pp)8400Sstevel@tonic-gate ehci_remove_isoc_itds(
8410Sstevel@tonic-gate 	ehci_state_t		*ehcip,
8420Sstevel@tonic-gate 	ehci_pipe_private_t	*pp)
8430Sstevel@tonic-gate {
8440Sstevel@tonic-gate 	ehci_isoc_xwrapper_t	*curr_itw, *next_itw;
8450Sstevel@tonic-gate 	ehci_itd_t		*curr_itd, *next_itd;
8460Sstevel@tonic-gate 
8470Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
8486898Sfb209375 	    "ehci_remove_isoc_itds: pp = 0x%p", (void *)pp);
8490Sstevel@tonic-gate 
8500Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate 	curr_itw = pp->pp_itw_head;
8530Sstevel@tonic-gate 	while (curr_itw) {
8540Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
8550Sstevel@tonic-gate 		    "ehci_remove_isoc_itds: itw = 0x%p num itds = %d",
8566898Sfb209375 		    (void *)curr_itw, curr_itw->itw_num_itds);
8570Sstevel@tonic-gate 
8580Sstevel@tonic-gate 		next_itw = curr_itw->itw_next;
8590Sstevel@tonic-gate 
8600Sstevel@tonic-gate 		curr_itd = curr_itw->itw_itd_head;
8610Sstevel@tonic-gate 		while (curr_itd) {
8620Sstevel@tonic-gate 			next_itd = ehci_itd_iommu_to_cpu(ehcip,
8630Sstevel@tonic-gate 			    Get_ITD(curr_itd->itd_itw_next_itd));
8640Sstevel@tonic-gate 
8650Sstevel@tonic-gate 			ehci_reclaim_isoc(ehcip, curr_itw, curr_itd, pp);
8660Sstevel@tonic-gate 
8670Sstevel@tonic-gate 			curr_itd = next_itd;
8680Sstevel@tonic-gate 		}
8690Sstevel@tonic-gate 
8700Sstevel@tonic-gate 		ehci_deallocate_itw(ehcip, pp, curr_itw);
8710Sstevel@tonic-gate 
8720Sstevel@tonic-gate 		curr_itw = next_itw;
8730Sstevel@tonic-gate 	}
8740Sstevel@tonic-gate }
8750Sstevel@tonic-gate 
8760Sstevel@tonic-gate 
8770Sstevel@tonic-gate /*
8780Sstevel@tonic-gate  * ehci_mark_reclaim_isoc:
8790Sstevel@tonic-gate  *
8800Sstevel@tonic-gate  * Set active ITDs to RECLAIM.
8810Sstevel@tonic-gate  * Return number of ITD that need to be processed.
8820Sstevel@tonic-gate  */
8830Sstevel@tonic-gate static void
ehci_mark_reclaim_isoc(ehci_state_t * ehcip,ehci_pipe_private_t * pp)8840Sstevel@tonic-gate ehci_mark_reclaim_isoc(
8850Sstevel@tonic-gate 	ehci_state_t		*ehcip,
8860Sstevel@tonic-gate 	ehci_pipe_private_t	*pp)
8870Sstevel@tonic-gate {
8880Sstevel@tonic-gate 	usb_frame_number_t	current_frame_number;
8890Sstevel@tonic-gate 	ehci_isoc_xwrapper_t	*curr_itw, *next_itw;
8900Sstevel@tonic-gate 	ehci_itd_t		*curr_itd, *next_itd;
8910Sstevel@tonic-gate 	uint_t			ctrl;
8920Sstevel@tonic-gate 	uint_t			isActive;
8933255Slg150142 	int			i;
8940Sstevel@tonic-gate 
8950Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
8966898Sfb209375 	    "ehci_mark_reclaim_isoc: pp = 0x%p", (void *)pp);
8970Sstevel@tonic-gate 
8980Sstevel@tonic-gate 	if (pp->pp_itw_head == NULL) {
8990Sstevel@tonic-gate 
9000Sstevel@tonic-gate 		return;
9010Sstevel@tonic-gate 	}
9020Sstevel@tonic-gate 
9030Sstevel@tonic-gate 	/* Get the current frame number. */
9040Sstevel@tonic-gate 	current_frame_number = ehci_get_current_frame_number(ehcip);
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate 	/* Traverse the list of transfer descriptors */
9070Sstevel@tonic-gate 	curr_itw = pp->pp_itw_head;
9080Sstevel@tonic-gate 	while (curr_itw) {
9090Sstevel@tonic-gate 		next_itw = curr_itw->itw_next;
9100Sstevel@tonic-gate 
9110Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
9120Sstevel@tonic-gate 		    "ehci_mark_reclaim_isoc: itw = 0x%p num itds = %d",
9136898Sfb209375 		    (void *)curr_itw, curr_itw->itw_num_itds);
9140Sstevel@tonic-gate 
9150Sstevel@tonic-gate 		curr_itd = curr_itw->itw_itd_head;
9160Sstevel@tonic-gate 		while (curr_itd) {
9170Sstevel@tonic-gate 			next_itd = ehci_itd_iommu_to_cpu(ehcip,
9180Sstevel@tonic-gate 			    Get_ITD(curr_itd->itd_itw_next_itd));
9190Sstevel@tonic-gate 
9200Sstevel@tonic-gate 			if (curr_itw->itw_port_status == USBA_HIGH_SPEED_DEV) {
9210Sstevel@tonic-gate 
9223255Slg150142 				for (i = 0; i < EHCI_ITD_CTRL_LIST_SIZE; i++) {
9233255Slg150142 					ctrl = Get_ITD_BODY(curr_itd,
9243255Slg150142 					    EHCI_ITD_CTRL0 + i);
9253255Slg150142 					isActive = ctrl & EHCI_ITD_XFER_ACTIVE;
9263255Slg150142 					/* If still active, deactivate it */
9273255Slg150142 					if (isActive) {
9283255Slg150142 						ctrl &= ~EHCI_ITD_XFER_ACTIVE;
9293255Slg150142 						Set_ITD_BODY(curr_itd,
9303255Slg150142 						    EHCI_ITD_CTRL0 + i,
9313255Slg150142 						    ctrl);
9323255Slg150142 						break;
9333255Slg150142 					}
9343255Slg150142 				}
9350Sstevel@tonic-gate 			} else {
9360Sstevel@tonic-gate 				ctrl = Get_ITD_BODY(curr_itd,
9370Sstevel@tonic-gate 				    EHCI_SITD_XFER_STATE);
9380Sstevel@tonic-gate 				isActive = ctrl & EHCI_SITD_XFER_ACTIVE;
9393255Slg150142 				/* If it is still active deactivate it */
9400Sstevel@tonic-gate 				if (isActive) {
9410Sstevel@tonic-gate 					ctrl &= ~EHCI_SITD_XFER_ACTIVE;
9420Sstevel@tonic-gate 					Set_ITD_BODY(curr_itd,
9430Sstevel@tonic-gate 					    EHCI_SITD_XFER_STATE,
9440Sstevel@tonic-gate 					    ctrl);
9450Sstevel@tonic-gate 				}
9460Sstevel@tonic-gate 			}
9470Sstevel@tonic-gate 
9480Sstevel@tonic-gate 			/*
9490Sstevel@tonic-gate 			 * If the itd was active put it on the reclaim status,
9500Sstevel@tonic-gate 			 * so the interrupt handler will know not to process it.
9510Sstevel@tonic-gate 			 * Otherwise leave it alone and let the interrupt
9520Sstevel@tonic-gate 			 * handler process it normally.
9530Sstevel@tonic-gate 			 */
9540Sstevel@tonic-gate 			if (isActive) {
9550Sstevel@tonic-gate 				Set_ITD(curr_itd->itd_state, EHCI_ITD_RECLAIM);
9560Sstevel@tonic-gate 				Set_ITD_FRAME(curr_itd->itd_reclaim_number,
9570Sstevel@tonic-gate 				    current_frame_number);
9580Sstevel@tonic-gate 				ehci_remove_isoc_from_pfl(ehcip, curr_itd);
9590Sstevel@tonic-gate 			}
9600Sstevel@tonic-gate 			curr_itd = next_itd;
9610Sstevel@tonic-gate 		}
9620Sstevel@tonic-gate 		curr_itw = next_itw;
9630Sstevel@tonic-gate 	}
9640Sstevel@tonic-gate }
9650Sstevel@tonic-gate 
9660Sstevel@tonic-gate 
9670Sstevel@tonic-gate /*
9680Sstevel@tonic-gate  * ehci_reclaim_isoc:
9690Sstevel@tonic-gate  *
9700Sstevel@tonic-gate  * "Reclaim" itds that were marked as RECLAIM.
9710Sstevel@tonic-gate  */
9720Sstevel@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)9730Sstevel@tonic-gate ehci_reclaim_isoc(
9740Sstevel@tonic-gate 	ehci_state_t		*ehcip,
9750Sstevel@tonic-gate 	ehci_isoc_xwrapper_t	*itw,
9760Sstevel@tonic-gate 	ehci_itd_t		*itd,
9770Sstevel@tonic-gate 	ehci_pipe_private_t	*pp)
9780Sstevel@tonic-gate {
9790Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
9806898Sfb209375 	    "ehci_reclaim_isoc: itd = 0x%p", (void *)itd);
9810Sstevel@tonic-gate 
9820Sstevel@tonic-gate 	/*
9830Sstevel@tonic-gate 	 * These are itds that were marked "RECLAIM"
9840Sstevel@tonic-gate 	 * by the pipe cleanup.
9850Sstevel@tonic-gate 	 *
9860Sstevel@tonic-gate 	 * Decrement the num_itds and the periodic in
9870Sstevel@tonic-gate 	 * request count if necessary.
9880Sstevel@tonic-gate 	 */
9890Sstevel@tonic-gate 	if ((--itw->itw_num_itds == 0) && (itw->itw_curr_xfer_reqp)) {
9900Sstevel@tonic-gate 		if (itw->itw_direction == USB_EP_DIR_IN) {
9910Sstevel@tonic-gate 
9920Sstevel@tonic-gate 			pp->pp_cur_periodic_req_cnt--;
9930Sstevel@tonic-gate 
9940Sstevel@tonic-gate 			ehci_deallocate_isoc_in_resource(ehcip, pp, itw);
9950Sstevel@tonic-gate 		} else {
9960Sstevel@tonic-gate 			ehci_hcdi_isoc_callback(pp->pp_pipe_handle, itw,
9970Sstevel@tonic-gate 			    USB_CR_FLUSHED);
9980Sstevel@tonic-gate 		}
9990Sstevel@tonic-gate 	}
10000Sstevel@tonic-gate 
10010Sstevel@tonic-gate 	/* Deallocate this transfer descriptor */
10020Sstevel@tonic-gate 	ehci_deallocate_itd(ehcip, itw, itd);
10030Sstevel@tonic-gate }
10040Sstevel@tonic-gate 
10050Sstevel@tonic-gate 
10060Sstevel@tonic-gate /*
10070Sstevel@tonic-gate  * ehci_start_isoc_polling:
10080Sstevel@tonic-gate  *
10090Sstevel@tonic-gate  * Insert the number of periodic requests corresponding to polling
10100Sstevel@tonic-gate  * interval as calculated during pipe open.
10110Sstevel@tonic-gate  */
10120Sstevel@tonic-gate int
ehci_start_isoc_polling(ehci_state_t * ehcip,usba_pipe_handle_data_t * ph,usb_flags_t flags)10130Sstevel@tonic-gate ehci_start_isoc_polling(
10140Sstevel@tonic-gate 	ehci_state_t		*ehcip,
10150Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
10160Sstevel@tonic-gate 	usb_flags_t		flags)
10170Sstevel@tonic-gate {
10180Sstevel@tonic-gate 	ehci_pipe_private_t	*pp = (ehci_pipe_private_t *)ph->p_hcd_private;
10190Sstevel@tonic-gate 	ehci_isoc_xwrapper_t	*itw_list, *itw;
10200Sstevel@tonic-gate 	int			i, total_itws;
10210Sstevel@tonic-gate 	int			error = USB_SUCCESS;
10220Sstevel@tonic-gate 
10233255Slg150142 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
10245653Slc152243 	    "ehci_start_isoc_polling:");
10253255Slg150142 
10260Sstevel@tonic-gate 	/* Allocate all the necessary resources for the IN transfer */
10270Sstevel@tonic-gate 	itw_list = NULL;
10280Sstevel@tonic-gate 	total_itws = pp->pp_max_periodic_req_cnt - pp->pp_cur_periodic_req_cnt;
10290Sstevel@tonic-gate 	for (i = 0; i < total_itws; i += 1) {
10300Sstevel@tonic-gate 		itw = ehci_allocate_isoc_resources(ehcip, ph, NULL, flags);
10310Sstevel@tonic-gate 		if (itw == NULL) {
10320Sstevel@tonic-gate 			error = USB_NO_RESOURCES;
10330Sstevel@tonic-gate 			/* There are not enough resources deallocate the ITWs */
10340Sstevel@tonic-gate 			itw = itw_list;
10350Sstevel@tonic-gate 			while (itw != NULL) {
10360Sstevel@tonic-gate 				itw_list = itw->itw_next;
10370Sstevel@tonic-gate 				ehci_deallocate_isoc_in_resource(
10385653Slc152243 				    ehcip, pp, itw);
10390Sstevel@tonic-gate 				ehci_deallocate_itw(ehcip, pp, itw);
10400Sstevel@tonic-gate 				itw = itw_list;
10410Sstevel@tonic-gate 			}
10420Sstevel@tonic-gate 
10430Sstevel@tonic-gate 			return (error);
10440Sstevel@tonic-gate 		} else {
10450Sstevel@tonic-gate 			if (itw_list == NULL) {
10460Sstevel@tonic-gate 				itw_list = itw;
10470Sstevel@tonic-gate 			}
10480Sstevel@tonic-gate 		}
10490Sstevel@tonic-gate 	}
10500Sstevel@tonic-gate 
10510Sstevel@tonic-gate 	i = 0;
10520Sstevel@tonic-gate 	while (pp->pp_cur_periodic_req_cnt < pp->pp_max_periodic_req_cnt) {
10530Sstevel@tonic-gate 
10540Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
10550Sstevel@tonic-gate 		    "ehci_start_isoc_polling: max = %d curr = %d itw = %p:",
10560Sstevel@tonic-gate 		    pp->pp_max_periodic_req_cnt, pp->pp_cur_periodic_req_cnt,
10576898Sfb209375 		    (void *)itw_list);
10580Sstevel@tonic-gate 
10590Sstevel@tonic-gate 		itw = itw_list;
10600Sstevel@tonic-gate 		itw_list = itw->itw_next;
10610Sstevel@tonic-gate 
10620Sstevel@tonic-gate 		error = ehci_insert_isoc_req(ehcip, pp, itw, flags);
10630Sstevel@tonic-gate 
10640Sstevel@tonic-gate 		if (error == USB_SUCCESS) {
10650Sstevel@tonic-gate 			pp->pp_cur_periodic_req_cnt++;
10660Sstevel@tonic-gate 		} else {
10670Sstevel@tonic-gate 			/*
10680Sstevel@tonic-gate 			 * Deallocate the remaining tw
10690Sstevel@tonic-gate 			 * The current tw should have already been deallocated
10700Sstevel@tonic-gate 			 */
10710Sstevel@tonic-gate 			itw = itw_list;
10720Sstevel@tonic-gate 			while (itw != NULL) {
10730Sstevel@tonic-gate 				itw_list = itw->itw_next;
10740Sstevel@tonic-gate 				ehci_deallocate_isoc_in_resource(
10755653Slc152243 				    ehcip, pp, itw);
10760Sstevel@tonic-gate 				ehci_deallocate_itw(ehcip, pp, itw);
10770Sstevel@tonic-gate 				itw = itw_list;
10780Sstevel@tonic-gate 			}
10790Sstevel@tonic-gate 			/*
10800Sstevel@tonic-gate 			 * If this is the first req return an error.
10810Sstevel@tonic-gate 			 * Otherwise return success.
10820Sstevel@tonic-gate 			 */
10830Sstevel@tonic-gate 			if (i != 0) {
10840Sstevel@tonic-gate 				error = USB_SUCCESS;
10850Sstevel@tonic-gate 			}
10860Sstevel@tonic-gate 
10870Sstevel@tonic-gate 			break;
10880Sstevel@tonic-gate 		}
10890Sstevel@tonic-gate 		i++;
10900Sstevel@tonic-gate 	}
10910Sstevel@tonic-gate 
10920Sstevel@tonic-gate 	return (error);
10930Sstevel@tonic-gate }
10940Sstevel@tonic-gate 
10950Sstevel@tonic-gate 
10960Sstevel@tonic-gate /*
10970Sstevel@tonic-gate  * Isochronronous handling functions.
10980Sstevel@tonic-gate  */
10990Sstevel@tonic-gate /*
11000Sstevel@tonic-gate  * ehci_traverse_active_isoc_list:
11010Sstevel@tonic-gate  */
11020Sstevel@tonic-gate void
ehci_traverse_active_isoc_list(ehci_state_t * ehcip)11030Sstevel@tonic-gate ehci_traverse_active_isoc_list(
11040Sstevel@tonic-gate 	ehci_state_t		*ehcip)
11050Sstevel@tonic-gate {
11060Sstevel@tonic-gate 	ehci_isoc_xwrapper_t	*curr_itw;
11070Sstevel@tonic-gate 	ehci_itd_t		*curr_itd, *next_itd;
11080Sstevel@tonic-gate 	uint_t			state;
11090Sstevel@tonic-gate 	ehci_pipe_private_t	*pp;
11100Sstevel@tonic-gate 
11110Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
11120Sstevel@tonic-gate 	    "ehci_traverse_active_isoc_list:");
11130Sstevel@tonic-gate 
11140Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
11150Sstevel@tonic-gate 
11160Sstevel@tonic-gate 	/* Sync ITD pool */
11170Sstevel@tonic-gate 	Sync_ITD_Pool(ehcip);
11180Sstevel@tonic-gate 
11190Sstevel@tonic-gate 	/* Traverse the list of done itds */
11200Sstevel@tonic-gate 	curr_itd = ehci_create_done_itd_list(ehcip);
11213255Slg150142 	USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
11226898Sfb209375 	    "ehci_traverse_active_isoc_list: current itd = 0x%p",
11236898Sfb209375 	    (void *)curr_itd);
11240Sstevel@tonic-gate 
11250Sstevel@tonic-gate 	while (curr_itd) {
11260Sstevel@tonic-gate 		/* Save the next_itd */
11270Sstevel@tonic-gate 		next_itd = ehci_itd_iommu_to_cpu(ehcip,
11280Sstevel@tonic-gate 		    Get_ITD(curr_itd->itd_next_active_itd));
11290Sstevel@tonic-gate 
11300Sstevel@tonic-gate 		/* Get the transfer wrapper and the pp */
11310Sstevel@tonic-gate 		curr_itw = (ehci_isoc_xwrapper_t *)EHCI_LOOKUP_ID(
11325653Slc152243 		    (uint32_t)Get_ITD(curr_itd->itd_trans_wrapper));
11330Sstevel@tonic-gate 		pp = curr_itw->itw_pipe_private;
11340Sstevel@tonic-gate 
11353255Slg150142 		if (curr_itw->itw_port_status == USBA_HIGH_SPEED_DEV) {
11363255Slg150142 			ehci_print_itd(ehcip, curr_itd);
11373255Slg150142 		} else {
11383255Slg150142 			ehci_print_sitd(ehcip, curr_itd);
11393255Slg150142 		}
11400Sstevel@tonic-gate 
11410Sstevel@tonic-gate 		/* Get the ITD state */
11420Sstevel@tonic-gate 		state = Get_ITD(curr_itd->itd_state);
11430Sstevel@tonic-gate 
11440Sstevel@tonic-gate 		/* Only process the ITDs marked as active. */
11450Sstevel@tonic-gate 		if (state == EHCI_ITD_ACTIVE) {
11460Sstevel@tonic-gate 			ehci_parse_isoc_error(ehcip, curr_itw, curr_itd);
11470Sstevel@tonic-gate 			ehci_handle_isoc(ehcip, curr_itw, curr_itd);
11480Sstevel@tonic-gate 		} else {
11490Sstevel@tonic-gate 			ASSERT(state == EHCI_ITD_RECLAIM);
11500Sstevel@tonic-gate 			ehci_reclaim_isoc(ehcip, curr_itw, curr_itd, pp);
11510Sstevel@tonic-gate 		}
11520Sstevel@tonic-gate 
11530Sstevel@tonic-gate 		/*
11540Sstevel@tonic-gate 		 * Deallocate the transfer wrapper if there are no more
11550Sstevel@tonic-gate 		 * ITD's for the transfer wrapper.  ehci_deallocate_itw()
11560Sstevel@tonic-gate 		 * will  not deallocate the tw for a periodic in endpoint
11570Sstevel@tonic-gate 		 * since it will always have a ITD attached to it.
11580Sstevel@tonic-gate 		 */
11590Sstevel@tonic-gate 		ehci_deallocate_itw(ehcip, pp, curr_itw);
11600Sstevel@tonic-gate 
11610Sstevel@tonic-gate 		/* Check any ISOC is waiting for transfers completion event */
11620Sstevel@tonic-gate 		if (pp->pp_itw_head == NULL) {
11630Sstevel@tonic-gate 			USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
11640Sstevel@tonic-gate 			    "ehci_traverse_active_isoc_list: "
11656898Sfb209375 			    "Sent transfers completion event pp = 0x%p",
11666898Sfb209375 			    (void *)pp);
11670Sstevel@tonic-gate 			cv_signal(&pp->pp_xfer_cmpl_cv);
11680Sstevel@tonic-gate 		}
11690Sstevel@tonic-gate 
11700Sstevel@tonic-gate 		curr_itd = next_itd;
11713255Slg150142 
11723255Slg150142 		USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
11733255Slg150142 		    "ehci_traverse_active_isoc_list: state = 0x%x "
11743255Slg150142 		    "pp = 0x%p itw = 0x%p itd = 0x%p next_itd = 0x%p",
11756898Sfb209375 		    state, (void *)pp, (void *)curr_itw, (void *)curr_itd,
11766898Sfb209375 		    (void *)next_itd);
11770Sstevel@tonic-gate 	}
11780Sstevel@tonic-gate }
11790Sstevel@tonic-gate 
11800Sstevel@tonic-gate 
11810Sstevel@tonic-gate static void
ehci_handle_isoc(ehci_state_t * ehcip,ehci_isoc_xwrapper_t * itw,ehci_itd_t * itd)11820Sstevel@tonic-gate ehci_handle_isoc(
11830Sstevel@tonic-gate 	ehci_state_t		*ehcip,
11840Sstevel@tonic-gate 	ehci_isoc_xwrapper_t	*itw,
11850Sstevel@tonic-gate 	ehci_itd_t		*itd)
11860Sstevel@tonic-gate {
11870Sstevel@tonic-gate 	ehci_pipe_private_t	*pp;	/* Pipe private field */
11880Sstevel@tonic-gate 
11890Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
11900Sstevel@tonic-gate 
11910Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
11920Sstevel@tonic-gate 	    "ehci_handle_isoc:");
11930Sstevel@tonic-gate 
11940Sstevel@tonic-gate 	/* Obtain the pipe private structure */
11950Sstevel@tonic-gate 	pp = itw->itw_pipe_private;
11960Sstevel@tonic-gate 
11973255Slg150142 	ehci_handle_itd(ehcip, pp, itw, itd, itw->itw_handle_callback_value);
11980Sstevel@tonic-gate }
11990Sstevel@tonic-gate 
12000Sstevel@tonic-gate 
12010Sstevel@tonic-gate /*
12020Sstevel@tonic-gate  * ehci_handle_itd:
12030Sstevel@tonic-gate  *
12043255Slg150142  * Handle an (split) isochronous transfer descriptor.
12053255Slg150142  * This function will deallocate the itd from the list as well.
12060Sstevel@tonic-gate  */
12070Sstevel@tonic-gate /* ARGSUSED */
12080Sstevel@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)12090Sstevel@tonic-gate ehci_handle_itd(
12100Sstevel@tonic-gate 	ehci_state_t		*ehcip,
12110Sstevel@tonic-gate 	ehci_pipe_private_t	*pp,
12120Sstevel@tonic-gate 	ehci_isoc_xwrapper_t	*itw,
12130Sstevel@tonic-gate 	ehci_itd_t		*itd,
12140Sstevel@tonic-gate 	void			*tw_handle_callback_value)
12150Sstevel@tonic-gate {
12160Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph = pp->pp_pipe_handle;
12170Sstevel@tonic-gate 	usb_isoc_req_t		*curr_isoc_reqp =
12185653Slc152243 	    (usb_isoc_req_t *)itw->itw_curr_xfer_reqp;
12190Sstevel@tonic-gate 	int			error = USB_SUCCESS;
12203255Slg150142 	int			i, index;
12210Sstevel@tonic-gate 
12220Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
12233255Slg150142 	    "ehci_handle_itd: pp=0x%p itw=0x%p itd=0x%p "
12246898Sfb209375 	    "isoc_reqp=0%p data=0x%p", (void *)pp, (void *)itw, (void *)itd,
12256898Sfb209375 	    (void *)curr_isoc_reqp, (void *)curr_isoc_reqp->isoc_data);
12260Sstevel@tonic-gate 
12273255Slg150142 	if (itw->itw_port_status == USBA_HIGH_SPEED_DEV &&
12283255Slg150142 	    curr_isoc_reqp != NULL) {
12293255Slg150142 
12305653Slc152243 		for (i = 0; i < EHCI_ITD_CTRL_LIST_SIZE; i++) {
12313255Slg150142 
12325653Slc152243 			index = Get_ITD_INDEX(itd, i);
12335653Slc152243 			if (index == EHCI_ITD_UNUSED_INDEX) {
12343255Slg150142 
12355653Slc152243 				continue;
12365653Slc152243 			}
12375653Slc152243 			curr_isoc_reqp->
12385653Slc152243 			    isoc_pkt_descr[index].isoc_pkt_actual_length =
12395653Slc152243 			    (Get_ITD_BODY(itd, i) & EHCI_ITD_XFER_LENGTH) >> 16;
12403255Slg150142 		}
12413255Slg150142 	}
12423255Slg150142 
12430Sstevel@tonic-gate 	/*
12440Sstevel@tonic-gate 	 * Decrement the ITDs counter and check whether all the isoc
12450Sstevel@tonic-gate 	 * data has been send or received. If ITDs counter reaches
12460Sstevel@tonic-gate 	 * zero then inform client driver about completion current
12470Sstevel@tonic-gate 	 * isoc request. Otherwise wait for completion of other isoc
12480Sstevel@tonic-gate 	 * ITDs or transactions on this pipe.
12490Sstevel@tonic-gate 	 */
12500Sstevel@tonic-gate 	if (--itw->itw_num_itds != 0) {
12510Sstevel@tonic-gate 		/* Deallocate this transfer descriptor */
12520Sstevel@tonic-gate 		ehci_deallocate_itd(ehcip, itw, itd);
12530Sstevel@tonic-gate 
12540Sstevel@tonic-gate 		return;
12550Sstevel@tonic-gate 	}
12560Sstevel@tonic-gate 
12570Sstevel@tonic-gate 	/*
12580Sstevel@tonic-gate 	 * If this is a isoc in pipe, return the data to the client.
12590Sstevel@tonic-gate 	 * For a isoc out pipe, there is no need to do anything.
12600Sstevel@tonic-gate 	 */
12610Sstevel@tonic-gate 	if (itw->itw_direction == USB_EP_DIR_OUT) {
12620Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
12636898Sfb209375 		    "ehci_handle_itd: Isoc out pipe, isoc_reqp=0x%p, data=0x%p",
12646898Sfb209375 		    (void *)curr_isoc_reqp, (void *)curr_isoc_reqp->isoc_data);
12650Sstevel@tonic-gate 
12660Sstevel@tonic-gate 		/* Do the callback */
12670Sstevel@tonic-gate 		ehci_hcdi_isoc_callback(ph, itw, USB_CR_OK);
12680Sstevel@tonic-gate 
12690Sstevel@tonic-gate 		/* Deallocate this transfer descriptor */
12700Sstevel@tonic-gate 		ehci_deallocate_itd(ehcip, itw, itd);
12710Sstevel@tonic-gate 
12720Sstevel@tonic-gate 		return;
12730Sstevel@tonic-gate 	}
12740Sstevel@tonic-gate 
12750Sstevel@tonic-gate 	/* Decrement number of IN isochronous request count */
12760Sstevel@tonic-gate 	pp->pp_cur_periodic_req_cnt--;
12770Sstevel@tonic-gate 
12783255Slg150142 	USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
12793255Slg150142 	    "ehci_handle_itd: pp_cur_periodic_req_cnt = 0x%x ",
12803255Slg150142 	    pp->pp_cur_periodic_req_cnt);
12813255Slg150142 
12820Sstevel@tonic-gate 	/* Call ehci_sendup_itd_message to send message to upstream */
12830Sstevel@tonic-gate 	ehci_sendup_itd_message(ehcip, pp, itw, itd, USB_CR_OK);
12840Sstevel@tonic-gate 
12850Sstevel@tonic-gate 	/* Deallocate this transfer descriptor */
12860Sstevel@tonic-gate 	ehci_deallocate_itd(ehcip, itw, itd);
12870Sstevel@tonic-gate 
12880Sstevel@tonic-gate 	/*
12890Sstevel@tonic-gate 	 * If isochronous pipe state is still active, insert next isochronous
12900Sstevel@tonic-gate 	 * request into the Host Controller's isochronous list.
12910Sstevel@tonic-gate 	 */
12920Sstevel@tonic-gate 	if (pp->pp_state != EHCI_PIPE_STATE_ACTIVE) {
12930Sstevel@tonic-gate 
12940Sstevel@tonic-gate 		return;
12950Sstevel@tonic-gate 	}
12960Sstevel@tonic-gate 
12970Sstevel@tonic-gate 	if ((error = ehci_allocate_isoc_in_resource(ehcip, pp, itw, 0)) ==
12980Sstevel@tonic-gate 	    USB_SUCCESS) {
12990Sstevel@tonic-gate 		curr_isoc_reqp = (usb_isoc_req_t *)itw->itw_curr_xfer_reqp;
13000Sstevel@tonic-gate 
13010Sstevel@tonic-gate 		ASSERT(curr_isoc_reqp != NULL);
13020Sstevel@tonic-gate 
13030Sstevel@tonic-gate 		itw->itw_num_itds = ehci_calc_num_itds(itw,
13040Sstevel@tonic-gate 		    curr_isoc_reqp->isoc_pkts_count);
13050Sstevel@tonic-gate 
13060Sstevel@tonic-gate 		if (ehci_allocate_itds_for_itw(ehcip, itw, itw->itw_num_itds) !=
13070Sstevel@tonic-gate 		    USB_SUCCESS) {
13080Sstevel@tonic-gate 			ehci_deallocate_isoc_in_resource(ehcip, pp, itw);
13090Sstevel@tonic-gate 			itw->itw_num_itds = 0;
13100Sstevel@tonic-gate 			error = USB_FAILURE;
13110Sstevel@tonic-gate 		}
13120Sstevel@tonic-gate 	}
13130Sstevel@tonic-gate 
13140Sstevel@tonic-gate 	if ((error != USB_SUCCESS) ||
13150Sstevel@tonic-gate 	    (ehci_insert_isoc_req(ehcip, pp, itw, 0) != USB_SUCCESS)) {
13160Sstevel@tonic-gate 		/*
13170Sstevel@tonic-gate 		 * Set pipe state to stop polling and error to no
13180Sstevel@tonic-gate 		 * resource. Don't insert any more isoch polling
13190Sstevel@tonic-gate 		 * requests.
13200Sstevel@tonic-gate 		 */
13210Sstevel@tonic-gate 		pp->pp_state = EHCI_PIPE_STATE_STOP_POLLING;
13220Sstevel@tonic-gate 		pp->pp_error = USB_CR_NO_RESOURCES;
13230Sstevel@tonic-gate 
13240Sstevel@tonic-gate 	} else {
13250Sstevel@tonic-gate 		/* Increment number of IN isochronous request count */
13260Sstevel@tonic-gate 		pp->pp_cur_periodic_req_cnt++;
13270Sstevel@tonic-gate 
13280Sstevel@tonic-gate 		ASSERT(pp->pp_cur_periodic_req_cnt ==
13290Sstevel@tonic-gate 		    pp->pp_max_periodic_req_cnt);
13300Sstevel@tonic-gate 	}
13310Sstevel@tonic-gate }
13320Sstevel@tonic-gate 
13330Sstevel@tonic-gate 
13340Sstevel@tonic-gate /*
13350Sstevel@tonic-gate  * ehci_sendup_qtd_message:
13360Sstevel@tonic-gate  *	copy data, if necessary and do callback
13370Sstevel@tonic-gate  */
13380Sstevel@tonic-gate /* ARGSUSED */
13390Sstevel@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)13400Sstevel@tonic-gate ehci_sendup_itd_message(
13410Sstevel@tonic-gate 	ehci_state_t		*ehcip,
13420Sstevel@tonic-gate 	ehci_pipe_private_t	*pp,
13430Sstevel@tonic-gate 	ehci_isoc_xwrapper_t	*itw,
13440Sstevel@tonic-gate 	ehci_itd_t		*td,
13450Sstevel@tonic-gate 	usb_cr_t		error)
13460Sstevel@tonic-gate {
13470Sstevel@tonic-gate 	usb_isoc_req_t		*isoc_reqp = itw->itw_curr_xfer_reqp;
13480Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph = pp->pp_pipe_handle;
13490Sstevel@tonic-gate 	size_t			length;
13500Sstevel@tonic-gate 	uchar_t			*buf;
13510Sstevel@tonic-gate 	mblk_t			*mp;
13520Sstevel@tonic-gate 
13530Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
13540Sstevel@tonic-gate 
13550Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
13560Sstevel@tonic-gate 	    "ehci_sendup_itd_message:");
13570Sstevel@tonic-gate 
13580Sstevel@tonic-gate 	ASSERT(itw != NULL);
13590Sstevel@tonic-gate 
13600Sstevel@tonic-gate 	length = itw->itw_length;
13610Sstevel@tonic-gate 
13620Sstevel@tonic-gate 	/* Copy the data into the mblk_t */
13630Sstevel@tonic-gate 	buf = (uchar_t *)itw->itw_buf;
13640Sstevel@tonic-gate 
13653255Slg150142 	USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
13666898Sfb209375 	    "ehci_sendup_itd_message: length %ld error %d", length, error);
13670Sstevel@tonic-gate 
13680Sstevel@tonic-gate 	/* Get the message block */
13690Sstevel@tonic-gate 	mp = isoc_reqp->isoc_data;
13700Sstevel@tonic-gate 
13710Sstevel@tonic-gate 	ASSERT(mp != NULL);
13720Sstevel@tonic-gate 
13730Sstevel@tonic-gate 	if (length) {
13740Sstevel@tonic-gate 		/* Sync IO buffer */
13750Sstevel@tonic-gate 		Sync_IO_Buffer(itw->itw_dmahandle, length);
13760Sstevel@tonic-gate 
13770Sstevel@tonic-gate 		/* Copy the data into the message */
13783255Slg150142 		ddi_rep_get8(itw->itw_accesshandle,
13793255Slg150142 		    mp->b_rptr, buf, length, DDI_DEV_AUTOINCR);
13800Sstevel@tonic-gate 
13810Sstevel@tonic-gate 		/* Increment the write pointer */
13820Sstevel@tonic-gate 		mp->b_wptr = mp->b_wptr + length;
13830Sstevel@tonic-gate 	} else {
13840Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
13850Sstevel@tonic-gate 		    "ehci_sendup_itd_message: Zero length packet");
13860Sstevel@tonic-gate 	}
13870Sstevel@tonic-gate 
13880Sstevel@tonic-gate 	ehci_hcdi_isoc_callback(ph, itw, error);
13890Sstevel@tonic-gate }
13900Sstevel@tonic-gate 
13910Sstevel@tonic-gate 
13920Sstevel@tonic-gate /*
13930Sstevel@tonic-gate  * ehci_hcdi_isoc_callback:
13940Sstevel@tonic-gate  *
13950Sstevel@tonic-gate  * Convenience wrapper around usba_hcdi_cb() other than root hub.
13960Sstevel@tonic-gate  */
13970Sstevel@tonic-gate void
ehci_hcdi_isoc_callback(usba_pipe_handle_data_t * ph,ehci_isoc_xwrapper_t * itw,usb_cr_t completion_reason)13980Sstevel@tonic-gate ehci_hcdi_isoc_callback(
13990Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
14000Sstevel@tonic-gate 	ehci_isoc_xwrapper_t	*itw,
14010Sstevel@tonic-gate 	usb_cr_t		completion_reason)
14020Sstevel@tonic-gate {
14030Sstevel@tonic-gate 	ehci_state_t		*ehcip = ehci_obtain_state(
14045653Slc152243 	    ph->p_usba_device->usb_root_hub_dip);
14050Sstevel@tonic-gate 	ehci_pipe_private_t	*pp = (ehci_pipe_private_t *)ph->p_hcd_private;
14060Sstevel@tonic-gate 	usb_opaque_t		curr_xfer_reqp;
14070Sstevel@tonic-gate 	uint_t			pipe_state = 0;
14080Sstevel@tonic-gate 
14090Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
14100Sstevel@tonic-gate 	    "ehci_hcdi_isoc_callback: ph = 0x%p, itw = 0x%p, cr = 0x%x",
14116898Sfb209375 	    (void *)ph, (void *)itw, completion_reason);
14120Sstevel@tonic-gate 
14130Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
14140Sstevel@tonic-gate 
14150Sstevel@tonic-gate 	/* Set the pipe state as per completion reason */
14160Sstevel@tonic-gate 	switch (completion_reason) {
14170Sstevel@tonic-gate 	case USB_CR_OK:
14180Sstevel@tonic-gate 		pipe_state = pp->pp_state;
14190Sstevel@tonic-gate 		break;
14200Sstevel@tonic-gate 	case USB_CR_NO_RESOURCES:
14210Sstevel@tonic-gate 	case USB_CR_NOT_SUPPORTED:
14220Sstevel@tonic-gate 	case USB_CR_PIPE_RESET:
14230Sstevel@tonic-gate 	case USB_CR_STOPPED_POLLING:
14240Sstevel@tonic-gate 		pipe_state = EHCI_PIPE_STATE_IDLE;
14250Sstevel@tonic-gate 		break;
14260Sstevel@tonic-gate 	case USB_CR_PIPE_CLOSING:
14270Sstevel@tonic-gate 		break;
14280Sstevel@tonic-gate 	}
14290Sstevel@tonic-gate 
14300Sstevel@tonic-gate 	pp->pp_state = pipe_state;
14310Sstevel@tonic-gate 
14320Sstevel@tonic-gate 	if (itw && itw->itw_curr_xfer_reqp) {
14330Sstevel@tonic-gate 		curr_xfer_reqp = (usb_opaque_t)itw->itw_curr_xfer_reqp;
14340Sstevel@tonic-gate 		itw->itw_curr_xfer_reqp = NULL;
14350Sstevel@tonic-gate 	} else {
14360Sstevel@tonic-gate 		ASSERT(pp->pp_client_periodic_in_reqp != NULL);
14370Sstevel@tonic-gate 
14380Sstevel@tonic-gate 		curr_xfer_reqp = pp->pp_client_periodic_in_reqp;
14390Sstevel@tonic-gate 		pp->pp_client_periodic_in_reqp = NULL;
14400Sstevel@tonic-gate 	}
14410Sstevel@tonic-gate 
14420Sstevel@tonic-gate 	ASSERT(curr_xfer_reqp != NULL);
14430Sstevel@tonic-gate 
14440Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
14450Sstevel@tonic-gate 
14460Sstevel@tonic-gate 	usba_hcdi_cb(ph, curr_xfer_reqp, completion_reason);
14470Sstevel@tonic-gate 
14480Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
14490Sstevel@tonic-gate }
1450