1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*7c478bd9Sstevel@tonic-gate 
28*7c478bd9Sstevel@tonic-gate /*
29*7c478bd9Sstevel@tonic-gate  * EHCI Host Controller Driver (EHCI)
30*7c478bd9Sstevel@tonic-gate  *
31*7c478bd9Sstevel@tonic-gate  * The EHCI driver is a software driver which interfaces to the Universal
32*7c478bd9Sstevel@tonic-gate  * Serial Bus layer (USBA) and the Host Controller (HC). The interface to
33*7c478bd9Sstevel@tonic-gate  * the Host Controller is defined by the EHCI Host Controller Interface.
34*7c478bd9Sstevel@tonic-gate  *
35*7c478bd9Sstevel@tonic-gate  * This module contains the specific EHCI code used in POLLED mode. This
36*7c478bd9Sstevel@tonic-gate  * code is in a separate file since it will never become part of the EHCI
37*7c478bd9Sstevel@tonic-gate  * driver.
38*7c478bd9Sstevel@tonic-gate  */
39*7c478bd9Sstevel@tonic-gate 
40*7c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usbai_version.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehcid.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_xfer.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_intr.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_util.h>
45*7c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_polled.h>
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate /*
48*7c478bd9Sstevel@tonic-gate  * Internal Function Prototypes
49*7c478bd9Sstevel@tonic-gate  */
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate /* Polled initialization routines */
52*7c478bd9Sstevel@tonic-gate static int	ehci_polled_init(
53*7c478bd9Sstevel@tonic-gate 				usba_pipe_handle_data_t	*ph,
54*7c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip,
55*7c478bd9Sstevel@tonic-gate 				usb_console_info_impl_t	*console_input_info);
56*7c478bd9Sstevel@tonic-gate 
57*7c478bd9Sstevel@tonic-gate /* Polled deinitialization routines */
58*7c478bd9Sstevel@tonic-gate static int	ehci_polled_fini(ehci_polled_t		*ehci_polledp);
59*7c478bd9Sstevel@tonic-gate 
60*7c478bd9Sstevel@tonic-gate /* Polled save state routines */
61*7c478bd9Sstevel@tonic-gate static void	ehci_polled_save_state(ehci_polled_t	*ehci_polledp);
62*7c478bd9Sstevel@tonic-gate 
63*7c478bd9Sstevel@tonic-gate /* Polled restore state routines */
64*7c478bd9Sstevel@tonic-gate static void	ehci_polled_restore_state(ehci_polled_t	*ehci_polledp);
65*7c478bd9Sstevel@tonic-gate static void	ehci_polled_stop_processing(
66*7c478bd9Sstevel@tonic-gate 				ehci_polled_t		*ehci_polledp);
67*7c478bd9Sstevel@tonic-gate static void	ehci_polled_start_processing(
68*7c478bd9Sstevel@tonic-gate 				ehci_polled_t		*ehci_polledp);
69*7c478bd9Sstevel@tonic-gate 
70*7c478bd9Sstevel@tonic-gate /* Polled read routines */
71*7c478bd9Sstevel@tonic-gate static int	ehci_polled_process_active_intr_qtd_list(
72*7c478bd9Sstevel@tonic-gate 				ehci_polled_t		*ehci_polledp);
73*7c478bd9Sstevel@tonic-gate static int	ehci_polled_handle_normal_qtd(
74*7c478bd9Sstevel@tonic-gate 				ehci_polled_t		*ehci_polledp,
75*7c478bd9Sstevel@tonic-gate 				ehci_qtd_t		*qtd);
76*7c478bd9Sstevel@tonic-gate static void	ehci_polled_insert_qtd(
77*7c478bd9Sstevel@tonic-gate 				ehci_polled_t		*ehci_polledp,
78*7c478bd9Sstevel@tonic-gate 				ehci_qtd_t		*qtd);
79*7c478bd9Sstevel@tonic-gate static void	ehci_polled_fill_in_qtd(
80*7c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip,
81*7c478bd9Sstevel@tonic-gate 				ehci_qtd_t		*qtd,
82*7c478bd9Sstevel@tonic-gate 				uint_t			qtd_ctrl,
83*7c478bd9Sstevel@tonic-gate 				uint32_t		qtd_iommu_cbp,
84*7c478bd9Sstevel@tonic-gate 				size_t			qtd_length,
85*7c478bd9Sstevel@tonic-gate 				ehci_trans_wrapper_t	*tw);
86*7c478bd9Sstevel@tonic-gate static void	ehci_polled_insert_qtd_on_tw(
87*7c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip,
88*7c478bd9Sstevel@tonic-gate 				ehci_trans_wrapper_t	*tw,
89*7c478bd9Sstevel@tonic-gate 				ehci_qtd_t		*qtd);
90*7c478bd9Sstevel@tonic-gate static ehci_qtd_t *ehci_polled_create_done_qtd_list(
91*7c478bd9Sstevel@tonic-gate 				ehci_polled_t		*ehci_polledp);
92*7c478bd9Sstevel@tonic-gate static void	ehci_polled_insert_qtd_into_active_intr_qtd_list(
93*7c478bd9Sstevel@tonic-gate 				ehci_polled_t		*ehci_polledp,
94*7c478bd9Sstevel@tonic-gate 				ehci_qtd_t		*curr_qtd);
95*7c478bd9Sstevel@tonic-gate static void	ehci_polled_remove_qtd_from_active_intr_qtd_list(
96*7c478bd9Sstevel@tonic-gate 				ehci_polled_t		*ehci_polledp,
97*7c478bd9Sstevel@tonic-gate 				ehci_qtd_t		*curr_qtd);
98*7c478bd9Sstevel@tonic-gate static void	ehci_polled_traverse_qtds(
99*7c478bd9Sstevel@tonic-gate 				ehci_polled_t		*ehci_polledp,
100*7c478bd9Sstevel@tonic-gate 				usba_pipe_handle_data_t	*ph);
101*7c478bd9Sstevel@tonic-gate static void	ehci_polled_finish_interrupt(
102*7c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip,
103*7c478bd9Sstevel@tonic-gate 				uint_t			intr);
104*7c478bd9Sstevel@tonic-gate 
105*7c478bd9Sstevel@tonic-gate /*
106*7c478bd9Sstevel@tonic-gate  * POLLED entry points
107*7c478bd9Sstevel@tonic-gate  *
108*7c478bd9Sstevel@tonic-gate  * These functions are entry points into the POLLED code.
109*7c478bd9Sstevel@tonic-gate  */
110*7c478bd9Sstevel@tonic-gate 
111*7c478bd9Sstevel@tonic-gate /*
112*7c478bd9Sstevel@tonic-gate  * ehci_hcdi_polled_input_init:
113*7c478bd9Sstevel@tonic-gate  *
114*7c478bd9Sstevel@tonic-gate  * This is the initialization routine for handling the USB keyboard
115*7c478bd9Sstevel@tonic-gate  * in POLLED mode.  This routine is not called from POLLED mode, so
116*7c478bd9Sstevel@tonic-gate  * it is OK to acquire mutexes.
117*7c478bd9Sstevel@tonic-gate  */
118*7c478bd9Sstevel@tonic-gate int
119*7c478bd9Sstevel@tonic-gate ehci_hcdi_polled_input_init(
120*7c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
121*7c478bd9Sstevel@tonic-gate 	uchar_t			**polled_buf,
122*7c478bd9Sstevel@tonic-gate 	usb_console_info_impl_t	*console_input_info)
123*7c478bd9Sstevel@tonic-gate {
124*7c478bd9Sstevel@tonic-gate 	ehci_polled_t		*ehci_polledp;
125*7c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip;
126*7c478bd9Sstevel@tonic-gate 	int			ret;
127*7c478bd9Sstevel@tonic-gate 
128*7c478bd9Sstevel@tonic-gate 	ehcip = ehci_obtain_state(ph->p_usba_device->usb_root_hub_dip);
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate 	/*
131*7c478bd9Sstevel@tonic-gate 	 * Grab the ehci_int_mutex so that things don't change on us
132*7c478bd9Sstevel@tonic-gate 	 * if an interrupt comes in.
133*7c478bd9Sstevel@tonic-gate 	 */
134*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
135*7c478bd9Sstevel@tonic-gate 
136*7c478bd9Sstevel@tonic-gate 	ret = ehci_polled_init(ph, ehcip, console_input_info);
137*7c478bd9Sstevel@tonic-gate 
138*7c478bd9Sstevel@tonic-gate 	if (ret != USB_SUCCESS) {
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate 		/* Allow interrupts to continue */
141*7c478bd9Sstevel@tonic-gate 		mutex_exit(&ehcip->ehci_int_mutex);
142*7c478bd9Sstevel@tonic-gate 		return (ret);
143*7c478bd9Sstevel@tonic-gate 	}
144*7c478bd9Sstevel@tonic-gate 
145*7c478bd9Sstevel@tonic-gate 	ehci_polledp = (ehci_polled_t *)console_input_info->uci_private;
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate 	/*
148*7c478bd9Sstevel@tonic-gate 	 * Mark the structure so that if we are using it, we don't free
149*7c478bd9Sstevel@tonic-gate 	 * the structures if one of them is unplugged.
150*7c478bd9Sstevel@tonic-gate 	 */
151*7c478bd9Sstevel@tonic-gate 	ehci_polledp->ehci_polled_flags |= POLLED_INPUT_MODE;
152*7c478bd9Sstevel@tonic-gate 
153*7c478bd9Sstevel@tonic-gate 	/* increase the counter for keyboard connected */
154*7c478bd9Sstevel@tonic-gate 	ehcip->ehci_polled_kbd_count ++;
155*7c478bd9Sstevel@tonic-gate 
156*7c478bd9Sstevel@tonic-gate 	/*
157*7c478bd9Sstevel@tonic-gate 	 * This is the buffer we will copy characters into. It will be
158*7c478bd9Sstevel@tonic-gate 	 * copied into at this layer, so we need to keep track of it.
159*7c478bd9Sstevel@tonic-gate 	 */
160*7c478bd9Sstevel@tonic-gate 	ehci_polledp->ehci_polled_buf =
161*7c478bd9Sstevel@tonic-gate 	    (uchar_t *)kmem_zalloc(POLLED_RAW_BUF_SIZE, KM_SLEEP);
162*7c478bd9Sstevel@tonic-gate 
163*7c478bd9Sstevel@tonic-gate 	*polled_buf = ehci_polledp->ehci_polled_buf;
164*7c478bd9Sstevel@tonic-gate 
165*7c478bd9Sstevel@tonic-gate 	/*
166*7c478bd9Sstevel@tonic-gate 	 * This is a software workaround to fix schizo hardware bug.
167*7c478bd9Sstevel@tonic-gate 	 * Existence of "no-prom-cdma-sync"  property means consistent
168*7c478bd9Sstevel@tonic-gate 	 * dma sync should not be done while in prom or polled mode.
169*7c478bd9Sstevel@tonic-gate 	 */
170*7c478bd9Sstevel@tonic-gate 	if (ddi_prop_exists(DDI_DEV_T_ANY, ehcip->ehci_dip,
171*7c478bd9Sstevel@tonic-gate 	    DDI_PROP_NOTPROM, "no-prom-cdma-sync")) {
172*7c478bd9Sstevel@tonic-gate 		ehci_polledp->ehci_polled_no_sync_flag = B_TRUE;
173*7c478bd9Sstevel@tonic-gate 	}
174*7c478bd9Sstevel@tonic-gate 
175*7c478bd9Sstevel@tonic-gate 	/* Allow interrupts to continue */
176*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
177*7c478bd9Sstevel@tonic-gate 
178*7c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
179*7c478bd9Sstevel@tonic-gate }
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate 
182*7c478bd9Sstevel@tonic-gate /*
183*7c478bd9Sstevel@tonic-gate  * ehci_hcdi_polled_input_fini:
184*7c478bd9Sstevel@tonic-gate  */
185*7c478bd9Sstevel@tonic-gate int
186*7c478bd9Sstevel@tonic-gate ehci_hcdi_polled_input_fini(usb_console_info_impl_t *info)
187*7c478bd9Sstevel@tonic-gate {
188*7c478bd9Sstevel@tonic-gate 	ehci_polled_t		*ehci_polledp;
189*7c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip;
190*7c478bd9Sstevel@tonic-gate 	int			ret;
191*7c478bd9Sstevel@tonic-gate 
192*7c478bd9Sstevel@tonic-gate 	ehci_polledp = (ehci_polled_t *)info->uci_private;
193*7c478bd9Sstevel@tonic-gate 
194*7c478bd9Sstevel@tonic-gate 	ehcip = ehci_polledp->ehci_polled_ehcip;
195*7c478bd9Sstevel@tonic-gate 
196*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
197*7c478bd9Sstevel@tonic-gate 
198*7c478bd9Sstevel@tonic-gate 	/*
199*7c478bd9Sstevel@tonic-gate 	 * Reset the POLLED_INPUT_MODE flag so that we can tell if
200*7c478bd9Sstevel@tonic-gate 	 * this structure is in use in the ehci_polled_fini routine.
201*7c478bd9Sstevel@tonic-gate 	 */
202*7c478bd9Sstevel@tonic-gate 	ehci_polledp->ehci_polled_flags &= ~POLLED_INPUT_MODE;
203*7c478bd9Sstevel@tonic-gate 
204*7c478bd9Sstevel@tonic-gate 	/* decrease the counter for keyboard disconnected */
205*7c478bd9Sstevel@tonic-gate 	ehcip->ehci_polled_kbd_count --;
206*7c478bd9Sstevel@tonic-gate 
207*7c478bd9Sstevel@tonic-gate 	/* Free the buffer that we copied data into */
208*7c478bd9Sstevel@tonic-gate 	kmem_free(ehci_polledp->ehci_polled_buf, POLLED_RAW_BUF_SIZE);
209*7c478bd9Sstevel@tonic-gate 
210*7c478bd9Sstevel@tonic-gate 	ret = ehci_polled_fini(ehci_polledp);
211*7c478bd9Sstevel@tonic-gate 
212*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
213*7c478bd9Sstevel@tonic-gate 
214*7c478bd9Sstevel@tonic-gate 	return (ret);
215*7c478bd9Sstevel@tonic-gate }
216*7c478bd9Sstevel@tonic-gate 
217*7c478bd9Sstevel@tonic-gate 
218*7c478bd9Sstevel@tonic-gate /*
219*7c478bd9Sstevel@tonic-gate  * ehci_hcdi_polled_input_enter:
220*7c478bd9Sstevel@tonic-gate  *
221*7c478bd9Sstevel@tonic-gate  * This is where we enter into POLLED mode.  This routine sets up
222*7c478bd9Sstevel@tonic-gate  * everything so that calls to	ehci_hcdi_polled_read will return
223*7c478bd9Sstevel@tonic-gate  * characters.
224*7c478bd9Sstevel@tonic-gate  */
225*7c478bd9Sstevel@tonic-gate int
226*7c478bd9Sstevel@tonic-gate ehci_hcdi_polled_input_enter(usb_console_info_impl_t *info)
227*7c478bd9Sstevel@tonic-gate {
228*7c478bd9Sstevel@tonic-gate 	ehci_polled_t		*ehci_polledp;
229*7c478bd9Sstevel@tonic-gate 
230*7c478bd9Sstevel@tonic-gate 	ehci_polledp = (ehci_polled_t *)info->uci_private;
231*7c478bd9Sstevel@tonic-gate 
232*7c478bd9Sstevel@tonic-gate 	ehci_polledp->ehci_polled_entry++;
233*7c478bd9Sstevel@tonic-gate 
234*7c478bd9Sstevel@tonic-gate 	/*
235*7c478bd9Sstevel@tonic-gate 	 * If the controller is already switched over, just return
236*7c478bd9Sstevel@tonic-gate 	 */
237*7c478bd9Sstevel@tonic-gate 	if (ehci_polledp->ehci_polled_entry > 1) {
238*7c478bd9Sstevel@tonic-gate 
239*7c478bd9Sstevel@tonic-gate 		return (USB_SUCCESS);
240*7c478bd9Sstevel@tonic-gate 	}
241*7c478bd9Sstevel@tonic-gate 
242*7c478bd9Sstevel@tonic-gate 	ehci_polled_save_state(ehci_polledp);
243*7c478bd9Sstevel@tonic-gate 
244*7c478bd9Sstevel@tonic-gate 	ehci_polledp->ehci_polled_flags |= POLLED_INPUT_MODE_INUSE;
245*7c478bd9Sstevel@tonic-gate 
246*7c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
247*7c478bd9Sstevel@tonic-gate }
248*7c478bd9Sstevel@tonic-gate 
249*7c478bd9Sstevel@tonic-gate 
250*7c478bd9Sstevel@tonic-gate /*
251*7c478bd9Sstevel@tonic-gate  * ehci_hcdi_polled_input_exit:
252*7c478bd9Sstevel@tonic-gate  *
253*7c478bd9Sstevel@tonic-gate  * This is where we exit POLLED mode. This routine restores
254*7c478bd9Sstevel@tonic-gate  * everything that is needed to continue operation.
255*7c478bd9Sstevel@tonic-gate  */
256*7c478bd9Sstevel@tonic-gate int
257*7c478bd9Sstevel@tonic-gate ehci_hcdi_polled_input_exit(usb_console_info_impl_t *info)
258*7c478bd9Sstevel@tonic-gate {
259*7c478bd9Sstevel@tonic-gate 	ehci_polled_t		*ehci_polledp;
260*7c478bd9Sstevel@tonic-gate 
261*7c478bd9Sstevel@tonic-gate 	ehci_polledp = (ehci_polled_t *)info->uci_private;
262*7c478bd9Sstevel@tonic-gate 
263*7c478bd9Sstevel@tonic-gate 	ehci_polledp->ehci_polled_entry--;
264*7c478bd9Sstevel@tonic-gate 
265*7c478bd9Sstevel@tonic-gate 	/*
266*7c478bd9Sstevel@tonic-gate 	 * If there are still outstanding "enters", just return
267*7c478bd9Sstevel@tonic-gate 	 */
268*7c478bd9Sstevel@tonic-gate 	if (ehci_polledp->ehci_polled_entry > 0) {
269*7c478bd9Sstevel@tonic-gate 
270*7c478bd9Sstevel@tonic-gate 		return (USB_SUCCESS);
271*7c478bd9Sstevel@tonic-gate 	}
272*7c478bd9Sstevel@tonic-gate 
273*7c478bd9Sstevel@tonic-gate 	ehci_polledp->ehci_polled_flags &= ~POLLED_INPUT_MODE_INUSE;
274*7c478bd9Sstevel@tonic-gate 
275*7c478bd9Sstevel@tonic-gate 	ehci_polled_restore_state(ehci_polledp);
276*7c478bd9Sstevel@tonic-gate 
277*7c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
278*7c478bd9Sstevel@tonic-gate }
279*7c478bd9Sstevel@tonic-gate 
280*7c478bd9Sstevel@tonic-gate 
281*7c478bd9Sstevel@tonic-gate /*
282*7c478bd9Sstevel@tonic-gate  * ehci_hcdi_polled_read:
283*7c478bd9Sstevel@tonic-gate  *
284*7c478bd9Sstevel@tonic-gate  * Get a key character
285*7c478bd9Sstevel@tonic-gate  */
286*7c478bd9Sstevel@tonic-gate int
287*7c478bd9Sstevel@tonic-gate ehci_hcdi_polled_read(
288*7c478bd9Sstevel@tonic-gate 	usb_console_info_impl_t	*info,
289*7c478bd9Sstevel@tonic-gate 	uint_t			*num_characters)
290*7c478bd9Sstevel@tonic-gate {
291*7c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip;
292*7c478bd9Sstevel@tonic-gate 	ehci_polled_t		*ehci_polledp;
293*7c478bd9Sstevel@tonic-gate 	uint_t			intr;
294*7c478bd9Sstevel@tonic-gate 
295*7c478bd9Sstevel@tonic-gate 	ehci_polledp = (ehci_polled_t *)info->uci_private;
296*7c478bd9Sstevel@tonic-gate 
297*7c478bd9Sstevel@tonic-gate 	ehcip = ehci_polledp->ehci_polled_ehcip;
298*7c478bd9Sstevel@tonic-gate 
299*7c478bd9Sstevel@tonic-gate #ifndef lint
300*7c478bd9Sstevel@tonic-gate 	_NOTE(NO_COMPETING_THREADS_NOW);
301*7c478bd9Sstevel@tonic-gate #endif
302*7c478bd9Sstevel@tonic-gate 
303*7c478bd9Sstevel@tonic-gate 	*num_characters = 0;
304*7c478bd9Sstevel@tonic-gate 
305*7c478bd9Sstevel@tonic-gate 	intr = ((Get_OpReg(ehci_status) & Get_OpReg(ehci_interrupt)) &
306*7c478bd9Sstevel@tonic-gate 	    (EHCI_INTR_FRAME_LIST_ROLLOVER |
307*7c478bd9Sstevel@tonic-gate 	    EHCI_INTR_USB | EHCI_INTR_USB_ERROR));
308*7c478bd9Sstevel@tonic-gate 
309*7c478bd9Sstevel@tonic-gate 	/*
310*7c478bd9Sstevel@tonic-gate 	 * Check whether any frame list rollover interrupt is pending
311*7c478bd9Sstevel@tonic-gate 	 * and if it is pending, process this interrupt.
312*7c478bd9Sstevel@tonic-gate 	 */
313*7c478bd9Sstevel@tonic-gate 	if (intr & EHCI_INTR_FRAME_LIST_ROLLOVER) {
314*7c478bd9Sstevel@tonic-gate 		/* Check any frame list rollover interrupt is pending */
315*7c478bd9Sstevel@tonic-gate 		ehci_handle_frame_list_rollover(ehcip);
316*7c478bd9Sstevel@tonic-gate 		ehci_polled_finish_interrupt(ehcip,
317*7c478bd9Sstevel@tonic-gate 		    EHCI_INTR_FRAME_LIST_ROLLOVER);
318*7c478bd9Sstevel@tonic-gate 	}
319*7c478bd9Sstevel@tonic-gate 
320*7c478bd9Sstevel@tonic-gate 	/* Check for any USB transaction completion notification */
321*7c478bd9Sstevel@tonic-gate 	if (intr & (EHCI_INTR_USB | EHCI_INTR_USB_ERROR)) {
322*7c478bd9Sstevel@tonic-gate 		ehcip->ehci_polled_read_count ++;
323*7c478bd9Sstevel@tonic-gate 		/* Process any QTD's on the active interrupt qtd list */
324*7c478bd9Sstevel@tonic-gate 		*num_characters =
325*7c478bd9Sstevel@tonic-gate 		    ehci_polled_process_active_intr_qtd_list(ehci_polledp);
326*7c478bd9Sstevel@tonic-gate 
327*7c478bd9Sstevel@tonic-gate 		if (ehcip->ehci_polled_read_count ==
328*7c478bd9Sstevel@tonic-gate 		    ehcip->ehci_polled_enter_count) {
329*7c478bd9Sstevel@tonic-gate 			/* Acknowledge the frame list rollover interrupt */
330*7c478bd9Sstevel@tonic-gate 			ehci_polled_finish_interrupt(ehcip,
331*7c478bd9Sstevel@tonic-gate 			    intr & (EHCI_INTR_USB | EHCI_INTR_USB_ERROR));
332*7c478bd9Sstevel@tonic-gate 			ehcip->ehci_polled_read_count = 0;
333*7c478bd9Sstevel@tonic-gate 		}
334*7c478bd9Sstevel@tonic-gate 	}
335*7c478bd9Sstevel@tonic-gate 
336*7c478bd9Sstevel@tonic-gate #ifndef lint
337*7c478bd9Sstevel@tonic-gate 	_NOTE(COMPETING_THREADS_NOW);
338*7c478bd9Sstevel@tonic-gate #endif
339*7c478bd9Sstevel@tonic-gate 
340*7c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
341*7c478bd9Sstevel@tonic-gate }
342*7c478bd9Sstevel@tonic-gate 
343*7c478bd9Sstevel@tonic-gate 
344*7c478bd9Sstevel@tonic-gate /*
345*7c478bd9Sstevel@tonic-gate  * Internal Functions
346*7c478bd9Sstevel@tonic-gate  */
347*7c478bd9Sstevel@tonic-gate 
348*7c478bd9Sstevel@tonic-gate /*
349*7c478bd9Sstevel@tonic-gate  * Polled initialization routines
350*7c478bd9Sstevel@tonic-gate  */
351*7c478bd9Sstevel@tonic-gate 
352*7c478bd9Sstevel@tonic-gate 
353*7c478bd9Sstevel@tonic-gate /*
354*7c478bd9Sstevel@tonic-gate  * ehci_polled_init:
355*7c478bd9Sstevel@tonic-gate  *
356*7c478bd9Sstevel@tonic-gate  * Initialize generic information Uthat is needed to provide USB/POLLED
357*7c478bd9Sstevel@tonic-gate  * support.
358*7c478bd9Sstevel@tonic-gate  */
359*7c478bd9Sstevel@tonic-gate static int
360*7c478bd9Sstevel@tonic-gate ehci_polled_init(
361*7c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
362*7c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip,
363*7c478bd9Sstevel@tonic-gate 	usb_console_info_impl_t	*console_info)
364*7c478bd9Sstevel@tonic-gate {
365*7c478bd9Sstevel@tonic-gate 	ehci_polled_t		*ehci_polledp;
366*7c478bd9Sstevel@tonic-gate 	ehci_pipe_private_t	*pp;
367*7c478bd9Sstevel@tonic-gate 	ehci_qtd_t		*qtd;
368*7c478bd9Sstevel@tonic-gate 
369*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
370*7c478bd9Sstevel@tonic-gate 
371*7c478bd9Sstevel@tonic-gate 	/*
372*7c478bd9Sstevel@tonic-gate 	 * We have already initialized this structure. If the structure
373*7c478bd9Sstevel@tonic-gate 	 * has already been initialized, then we don't need to redo it.
374*7c478bd9Sstevel@tonic-gate 	 */
375*7c478bd9Sstevel@tonic-gate 	if (console_info->uci_private) {
376*7c478bd9Sstevel@tonic-gate 
377*7c478bd9Sstevel@tonic-gate 		return (USB_SUCCESS);
378*7c478bd9Sstevel@tonic-gate 	}
379*7c478bd9Sstevel@tonic-gate 
380*7c478bd9Sstevel@tonic-gate 	/* Allocate and intitialize a state structure */
381*7c478bd9Sstevel@tonic-gate 	ehci_polledp = (ehci_polled_t *)
382*7c478bd9Sstevel@tonic-gate 	    kmem_zalloc(sizeof (ehci_polled_t), KM_SLEEP);
383*7c478bd9Sstevel@tonic-gate 
384*7c478bd9Sstevel@tonic-gate 	console_info->uci_private = (usb_console_info_private_t)ehci_polledp;
385*7c478bd9Sstevel@tonic-gate 
386*7c478bd9Sstevel@tonic-gate 	/*
387*7c478bd9Sstevel@tonic-gate 	 * Store away the ehcip so that we can get to it when we are in
388*7c478bd9Sstevel@tonic-gate 	 * POLLED mode. We don't want to have to call ehci_obtain_state
389*7c478bd9Sstevel@tonic-gate 	 * every time we want to access this structure.
390*7c478bd9Sstevel@tonic-gate 	 */
391*7c478bd9Sstevel@tonic-gate 	ehci_polledp->ehci_polled_ehcip = ehcip;
392*7c478bd9Sstevel@tonic-gate 	/*
393*7c478bd9Sstevel@tonic-gate 	 * Save usb device and endpoint number information from the usb
394*7c478bd9Sstevel@tonic-gate 	 * pipe handle.
395*7c478bd9Sstevel@tonic-gate 	 */
396*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ph->p_mutex);
397*7c478bd9Sstevel@tonic-gate 	ehci_polledp->ehci_polled_usb_dev = ph->p_usba_device;
398*7c478bd9Sstevel@tonic-gate 	ehci_polledp->ehci_polled_ep_addr = ph->p_ep.bEndpointAddress;
399*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ph->p_mutex);
400*7c478bd9Sstevel@tonic-gate 
401*7c478bd9Sstevel@tonic-gate 	/*
402*7c478bd9Sstevel@tonic-gate 	 * Allocate memory to make duplicate of original usb pipe handle.
403*7c478bd9Sstevel@tonic-gate 	 */
404*7c478bd9Sstevel@tonic-gate 	ehci_polledp->ehci_polled_input_pipe_handle =
405*7c478bd9Sstevel@tonic-gate 	    kmem_zalloc(sizeof (usba_pipe_handle_data_t), KM_SLEEP);
406*7c478bd9Sstevel@tonic-gate 
407*7c478bd9Sstevel@tonic-gate 	/*
408*7c478bd9Sstevel@tonic-gate 	 * Copy the USB handle into the new pipe handle. Also
409*7c478bd9Sstevel@tonic-gate 	 * create new lock for the new pipe handle.
410*7c478bd9Sstevel@tonic-gate 	 */
411*7c478bd9Sstevel@tonic-gate 	bcopy((void *)ph,
412*7c478bd9Sstevel@tonic-gate 	    (void *)ehci_polledp->ehci_polled_input_pipe_handle,
413*7c478bd9Sstevel@tonic-gate 	    sizeof (usba_pipe_handle_data_t));
414*7c478bd9Sstevel@tonic-gate 
415*7c478bd9Sstevel@tonic-gate 	/*
416*7c478bd9Sstevel@tonic-gate 	 * uint64_t typecast to make sure amd64 can compile
417*7c478bd9Sstevel@tonic-gate 	 */
418*7c478bd9Sstevel@tonic-gate 	mutex_init(&ehci_polledp->ehci_polled_input_pipe_handle->p_mutex,
419*7c478bd9Sstevel@tonic-gate 	    NULL, MUTEX_DRIVER, (void *)(uintptr_t)ehcip->ehci_intr_pri);
420*7c478bd9Sstevel@tonic-gate 
421*7c478bd9Sstevel@tonic-gate 	/*
422*7c478bd9Sstevel@tonic-gate 	 * Create a new ehci pipe private structure
423*7c478bd9Sstevel@tonic-gate 	 */
424*7c478bd9Sstevel@tonic-gate 	pp = (ehci_pipe_private_t *)
425*7c478bd9Sstevel@tonic-gate 	    kmem_zalloc(sizeof (ehci_pipe_private_t), KM_SLEEP);
426*7c478bd9Sstevel@tonic-gate 
427*7c478bd9Sstevel@tonic-gate 	/*
428*7c478bd9Sstevel@tonic-gate 	 * Store the pointer in the pipe handle. This structure was also
429*7c478bd9Sstevel@tonic-gate 	 * just allocated.
430*7c478bd9Sstevel@tonic-gate 	 */
431*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ehci_polledp->ehci_polled_input_pipe_handle->p_mutex);
432*7c478bd9Sstevel@tonic-gate 
433*7c478bd9Sstevel@tonic-gate 	ehci_polledp->ehci_polled_input_pipe_handle->
434*7c478bd9Sstevel@tonic-gate 	    p_hcd_private = (usb_opaque_t)pp;
435*7c478bd9Sstevel@tonic-gate 
436*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ehci_polledp->ehci_polled_input_pipe_handle->p_mutex);
437*7c478bd9Sstevel@tonic-gate 
438*7c478bd9Sstevel@tonic-gate 	/*
439*7c478bd9Sstevel@tonic-gate 	 * Store a pointer to the pipe handle. This structure was  just
440*7c478bd9Sstevel@tonic-gate 	 * allocated and it is not in use yet.	The locking is there to
441*7c478bd9Sstevel@tonic-gate 	 * satisfy warlock.
442*7c478bd9Sstevel@tonic-gate 	 */
443*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ph->p_mutex);
444*7c478bd9Sstevel@tonic-gate 
445*7c478bd9Sstevel@tonic-gate 	bcopy(&ph->p_policy, &pp->pp_policy, sizeof (usb_pipe_policy_t));
446*7c478bd9Sstevel@tonic-gate 
447*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ph->p_mutex);
448*7c478bd9Sstevel@tonic-gate 
449*7c478bd9Sstevel@tonic-gate 	pp->pp_pipe_handle = ehci_polledp->ehci_polled_input_pipe_handle;
450*7c478bd9Sstevel@tonic-gate 
451*7c478bd9Sstevel@tonic-gate 	/*
452*7c478bd9Sstevel@tonic-gate 	 * Allocate a dummy for the interrupt table. This dummy will be
453*7c478bd9Sstevel@tonic-gate 	 * put into the action when we	switch interrupt  tables during
454*7c478bd9Sstevel@tonic-gate 	 * ehci_hcdi_polled_enter. Dummy is placed on the unused lattice
455*7c478bd9Sstevel@tonic-gate 	 * entries. When the QH is allocated we will replace dummy QH by
456*7c478bd9Sstevel@tonic-gate 	 * valid interrupt QH in one or more locations in the interrupt
457*7c478bd9Sstevel@tonic-gate 	 * lattice depending on the requested polling interval. Also we
458*7c478bd9Sstevel@tonic-gate 	 * will hang a dummy QTD to the QH & dummy QTD is used to indicate
459*7c478bd9Sstevel@tonic-gate 	 * the end of the QTD chain.
460*7c478bd9Sstevel@tonic-gate 	 */
461*7c478bd9Sstevel@tonic-gate 	ehci_polledp->ehci_polled_dummy_qh =
462*7c478bd9Sstevel@tonic-gate 	    ehci_alloc_qh(ehcip, NULL, EHCI_POLLED_MODE_FLAG);
463*7c478bd9Sstevel@tonic-gate 
464*7c478bd9Sstevel@tonic-gate 	if (ehci_polledp->ehci_polled_dummy_qh == NULL) {
465*7c478bd9Sstevel@tonic-gate 
466*7c478bd9Sstevel@tonic-gate 		return (USB_NO_RESOURCES);
467*7c478bd9Sstevel@tonic-gate 	}
468*7c478bd9Sstevel@tonic-gate 
469*7c478bd9Sstevel@tonic-gate 	/*
470*7c478bd9Sstevel@tonic-gate 	 * Allocate the interrupt endpoint. This QH will be inserted in
471*7c478bd9Sstevel@tonic-gate 	 * to the lattice chain for the  keyboard device. This endpoint
472*7c478bd9Sstevel@tonic-gate 	 * will have the QTDs hanging off of it for the processing.
473*7c478bd9Sstevel@tonic-gate 	 */
474*7c478bd9Sstevel@tonic-gate 	ehci_polledp->ehci_polled_qh = ehci_alloc_qh(
475*7c478bd9Sstevel@tonic-gate 	    ehcip, ph, EHCI_POLLED_MODE_FLAG);
476*7c478bd9Sstevel@tonic-gate 
477*7c478bd9Sstevel@tonic-gate 	if (ehci_polledp->ehci_polled_qh == NULL) {
478*7c478bd9Sstevel@tonic-gate 
479*7c478bd9Sstevel@tonic-gate 		return (USB_NO_RESOURCES);
480*7c478bd9Sstevel@tonic-gate 	}
481*7c478bd9Sstevel@tonic-gate 
482*7c478bd9Sstevel@tonic-gate 	/* Set the state of pipe as idle */
483*7c478bd9Sstevel@tonic-gate 	pp->pp_state = EHCI_PIPE_STATE_IDLE;
484*7c478bd9Sstevel@tonic-gate 
485*7c478bd9Sstevel@tonic-gate 	/* Set polled mode flag */
486*7c478bd9Sstevel@tonic-gate 	pp->pp_flag = EHCI_POLLED_MODE_FLAG;
487*7c478bd9Sstevel@tonic-gate 
488*7c478bd9Sstevel@tonic-gate 	/* Insert the endpoint onto the pipe handle */
489*7c478bd9Sstevel@tonic-gate 	pp->pp_qh = ehci_polledp->ehci_polled_qh;
490*7c478bd9Sstevel@tonic-gate 
491*7c478bd9Sstevel@tonic-gate 	/*
492*7c478bd9Sstevel@tonic-gate 	 * Set soft interrupt handler flag in the normal mode usb
493*7c478bd9Sstevel@tonic-gate 	 * pipe handle.
494*7c478bd9Sstevel@tonic-gate 	 */
495*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ph->p_mutex);
496*7c478bd9Sstevel@tonic-gate 	ph->p_spec_flag |= USBA_PH_FLAG_USE_SOFT_INTR;
497*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ph->p_mutex);
498*7c478bd9Sstevel@tonic-gate 
499*7c478bd9Sstevel@tonic-gate 	/*
500*7c478bd9Sstevel@tonic-gate 	 * Insert a Interrupt polling request onto the endpoint.
501*7c478bd9Sstevel@tonic-gate 	 *
502*7c478bd9Sstevel@tonic-gate 	 * There will now be two QTDs on the QH, one is the dummy QTD that
503*7c478bd9Sstevel@tonic-gate 	 * was allocated above in the  ehci_alloc_qh and this new one.
504*7c478bd9Sstevel@tonic-gate 	 */
505*7c478bd9Sstevel@tonic-gate 	if ((ehci_start_periodic_pipe_polling(ehcip,
506*7c478bd9Sstevel@tonic-gate 	    ehci_polledp->ehci_polled_input_pipe_handle,
507*7c478bd9Sstevel@tonic-gate 	    NULL, USB_FLAGS_SLEEP)) != USB_SUCCESS) {
508*7c478bd9Sstevel@tonic-gate 
509*7c478bd9Sstevel@tonic-gate 		return (USB_NO_RESOURCES);
510*7c478bd9Sstevel@tonic-gate 	}
511*7c478bd9Sstevel@tonic-gate 
512*7c478bd9Sstevel@tonic-gate 	/* Get the given new interrupt qtd */
513*7c478bd9Sstevel@tonic-gate 	qtd = (ehci_qtd_t *)(ehci_qtd_iommu_to_cpu(ehcip,
514*7c478bd9Sstevel@tonic-gate 	    (Get_QH(pp->pp_qh->qh_next_qtd) & EHCI_QH_NEXT_QTD_PTR)));
515*7c478bd9Sstevel@tonic-gate 
516*7c478bd9Sstevel@tonic-gate 	/* Insert this qtd into active interrupt QTD list */
517*7c478bd9Sstevel@tonic-gate 	ehci_polled_insert_qtd_into_active_intr_qtd_list(ehci_polledp, qtd);
518*7c478bd9Sstevel@tonic-gate 
519*7c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
520*7c478bd9Sstevel@tonic-gate }
521*7c478bd9Sstevel@tonic-gate 
522*7c478bd9Sstevel@tonic-gate 
523*7c478bd9Sstevel@tonic-gate /*
524*7c478bd9Sstevel@tonic-gate  * Polled deinitialization routines
525*7c478bd9Sstevel@tonic-gate  */
526*7c478bd9Sstevel@tonic-gate 
527*7c478bd9Sstevel@tonic-gate 
528*7c478bd9Sstevel@tonic-gate /*
529*7c478bd9Sstevel@tonic-gate  * ehci_polled_fini:
530*7c478bd9Sstevel@tonic-gate  */
531*7c478bd9Sstevel@tonic-gate static int
532*7c478bd9Sstevel@tonic-gate ehci_polled_fini(ehci_polled_t	*ehci_polledp)
533*7c478bd9Sstevel@tonic-gate {
534*7c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip = ehci_polledp->ehci_polled_ehcip;
535*7c478bd9Sstevel@tonic-gate 	ehci_pipe_private_t	*pp;
536*7c478bd9Sstevel@tonic-gate 
537*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
538*7c478bd9Sstevel@tonic-gate 
539*7c478bd9Sstevel@tonic-gate 	/* If the structure is already in use, then don't free it */
540*7c478bd9Sstevel@tonic-gate 	if (ehci_polledp->ehci_polled_flags & POLLED_INPUT_MODE) {
541*7c478bd9Sstevel@tonic-gate 
542*7c478bd9Sstevel@tonic-gate 		return (USB_SUCCESS);
543*7c478bd9Sstevel@tonic-gate 	}
544*7c478bd9Sstevel@tonic-gate 
545*7c478bd9Sstevel@tonic-gate 	pp = (ehci_pipe_private_t *)
546*7c478bd9Sstevel@tonic-gate 	    ehci_polledp->ehci_polled_input_pipe_handle->p_hcd_private;
547*7c478bd9Sstevel@tonic-gate 
548*7c478bd9Sstevel@tonic-gate 	/* Deallocate all the pre-allocated interrupt requests */
549*7c478bd9Sstevel@tonic-gate 	ehci_handle_outstanding_requests(ehcip, pp);
550*7c478bd9Sstevel@tonic-gate 
551*7c478bd9Sstevel@tonic-gate 	/*
552*7c478bd9Sstevel@tonic-gate 	 * Traverse the list of QTD's on this endpoint and these QTD's
553*7c478bd9Sstevel@tonic-gate 	 * have outstanding transfer requests. Since list processing
554*7c478bd9Sstevel@tonic-gate 	 * is stopped, these QTDs can be deallocated.
555*7c478bd9Sstevel@tonic-gate 	 */
556*7c478bd9Sstevel@tonic-gate 	ehci_polled_traverse_qtds(ehci_polledp, pp->pp_pipe_handle);
557*7c478bd9Sstevel@tonic-gate 
558*7c478bd9Sstevel@tonic-gate 	/* Free DMA resources */
559*7c478bd9Sstevel@tonic-gate 	ehci_free_dma_resources(ehcip, pp->pp_pipe_handle);
560*7c478bd9Sstevel@tonic-gate 
561*7c478bd9Sstevel@tonic-gate 	/*
562*7c478bd9Sstevel@tonic-gate 	 * Deallocate the endpoint descriptors that we allocated
563*7c478bd9Sstevel@tonic-gate 	 * with ehci_alloc_qh.
564*7c478bd9Sstevel@tonic-gate 	 */
565*7c478bd9Sstevel@tonic-gate 	if (ehci_polledp->ehci_polled_dummy_qh) {
566*7c478bd9Sstevel@tonic-gate 		ehci_deallocate_qh(ehcip, ehci_polledp->ehci_polled_dummy_qh);
567*7c478bd9Sstevel@tonic-gate 	}
568*7c478bd9Sstevel@tonic-gate 
569*7c478bd9Sstevel@tonic-gate 	if (ehci_polledp->ehci_polled_qh) {
570*7c478bd9Sstevel@tonic-gate 		ehci_deallocate_qh(ehcip, ehci_polledp->ehci_polled_qh);
571*7c478bd9Sstevel@tonic-gate 	}
572*7c478bd9Sstevel@tonic-gate 
573*7c478bd9Sstevel@tonic-gate 	mutex_destroy(&ehci_polledp->ehci_polled_input_pipe_handle->p_mutex);
574*7c478bd9Sstevel@tonic-gate 
575*7c478bd9Sstevel@tonic-gate 	/*
576*7c478bd9Sstevel@tonic-gate 	 * Destroy everything about the pipe that we allocated in
577*7c478bd9Sstevel@tonic-gate 	 * ehci_polled_duplicate_pipe_handle
578*7c478bd9Sstevel@tonic-gate 	 */
579*7c478bd9Sstevel@tonic-gate 	kmem_free(pp, sizeof (ehci_pipe_private_t));
580*7c478bd9Sstevel@tonic-gate 
581*7c478bd9Sstevel@tonic-gate 	kmem_free(ehci_polledp->ehci_polled_input_pipe_handle,
582*7c478bd9Sstevel@tonic-gate 	    sizeof (usba_pipe_handle_data_t));
583*7c478bd9Sstevel@tonic-gate 
584*7c478bd9Sstevel@tonic-gate 	/*
585*7c478bd9Sstevel@tonic-gate 	 * We use this field to determine if a QTD is for input or not,
586*7c478bd9Sstevel@tonic-gate 	 * so NULL the pointer so we don't check deallocated data.
587*7c478bd9Sstevel@tonic-gate 	 */
588*7c478bd9Sstevel@tonic-gate 	ehci_polledp->ehci_polled_input_pipe_handle = NULL;
589*7c478bd9Sstevel@tonic-gate 
590*7c478bd9Sstevel@tonic-gate 	/*
591*7c478bd9Sstevel@tonic-gate 	 * Finally, free off the structure that we use to keep track
592*7c478bd9Sstevel@tonic-gate 	 * of all this.
593*7c478bd9Sstevel@tonic-gate 	 */
594*7c478bd9Sstevel@tonic-gate 	kmem_free(ehci_polledp, sizeof (ehci_polled_t));
595*7c478bd9Sstevel@tonic-gate 
596*7c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
597*7c478bd9Sstevel@tonic-gate }
598*7c478bd9Sstevel@tonic-gate 
599*7c478bd9Sstevel@tonic-gate 
600*7c478bd9Sstevel@tonic-gate /*
601*7c478bd9Sstevel@tonic-gate  * Polled save state routines
602*7c478bd9Sstevel@tonic-gate  */
603*7c478bd9Sstevel@tonic-gate 
604*7c478bd9Sstevel@tonic-gate 
605*7c478bd9Sstevel@tonic-gate /*
606*7c478bd9Sstevel@tonic-gate  * ehci_polled_save_state:
607*7c478bd9Sstevel@tonic-gate  */
608*7c478bd9Sstevel@tonic-gate static void
609*7c478bd9Sstevel@tonic-gate ehci_polled_save_state(ehci_polled_t	*ehci_polledp)
610*7c478bd9Sstevel@tonic-gate {
611*7c478bd9Sstevel@tonic-gate 	int				i;
612*7c478bd9Sstevel@tonic-gate 	ehci_state_t			*ehcip;
613*7c478bd9Sstevel@tonic-gate 	uint_t				polled_toggle;
614*7c478bd9Sstevel@tonic-gate 	uint_t				real_toggle;
615*7c478bd9Sstevel@tonic-gate 	ehci_pipe_private_t		*pp = NULL; /* Normal mode Pipe */
616*7c478bd9Sstevel@tonic-gate 	ehci_pipe_private_t		*polled_pp; /* Polled mode Pipe */
617*7c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t		*ph;
618*7c478bd9Sstevel@tonic-gate 	uint8_t				ep_addr;
619*7c478bd9Sstevel@tonic-gate 	ehci_regs_t			*ehci_polled_regsp;
620*7c478bd9Sstevel@tonic-gate 	ehci_qh_t			*qh;
621*7c478bd9Sstevel@tonic-gate 
622*7c478bd9Sstevel@tonic-gate #ifndef lint
623*7c478bd9Sstevel@tonic-gate 	_NOTE(NO_COMPETING_THREADS_NOW);
624*7c478bd9Sstevel@tonic-gate #endif
625*7c478bd9Sstevel@tonic-gate 
626*7c478bd9Sstevel@tonic-gate 	/*
627*7c478bd9Sstevel@tonic-gate 	 * If either of these two flags are set, then we have already
628*7c478bd9Sstevel@tonic-gate 	 * saved off the state information and setup the controller.
629*7c478bd9Sstevel@tonic-gate 	 */
630*7c478bd9Sstevel@tonic-gate 	if (ehci_polledp->ehci_polled_flags & POLLED_INPUT_MODE_INUSE) {
631*7c478bd9Sstevel@tonic-gate #ifndef lint
632*7c478bd9Sstevel@tonic-gate 		_NOTE(COMPETING_THREADS_NOW);
633*7c478bd9Sstevel@tonic-gate #endif
634*7c478bd9Sstevel@tonic-gate 		return;
635*7c478bd9Sstevel@tonic-gate 	}
636*7c478bd9Sstevel@tonic-gate 
637*7c478bd9Sstevel@tonic-gate 	ehcip = ehci_polledp->ehci_polled_ehcip;
638*7c478bd9Sstevel@tonic-gate 
639*7c478bd9Sstevel@tonic-gate 	/*
640*7c478bd9Sstevel@tonic-gate 	 * Check if the number of keyboard reach the max number we can
641*7c478bd9Sstevel@tonic-gate 	 * support in polled mode
642*7c478bd9Sstevel@tonic-gate 	 */
643*7c478bd9Sstevel@tonic-gate 	if (++ ehcip->ehci_polled_enter_count > MAX_NUM_FOR_KEYBOARD) {
644*7c478bd9Sstevel@tonic-gate #ifndef lint
645*7c478bd9Sstevel@tonic-gate 		_NOTE(COMPETING_THREADS_NOW);
646*7c478bd9Sstevel@tonic-gate #endif
647*7c478bd9Sstevel@tonic-gate 		return;
648*7c478bd9Sstevel@tonic-gate 	}
649*7c478bd9Sstevel@tonic-gate 	ehci_polled_regsp = &ehcip->ehci_polled_save_regs;
650*7c478bd9Sstevel@tonic-gate 
651*7c478bd9Sstevel@tonic-gate 	/* Get the endpoint addr. */
652*7c478bd9Sstevel@tonic-gate 	ep_addr = ehci_polledp->ehci_polled_ep_addr;
653*7c478bd9Sstevel@tonic-gate 
654*7c478bd9Sstevel@tonic-gate 	/* Get the normal mode usb pipe handle */
655*7c478bd9Sstevel@tonic-gate 	ph = usba_hcdi_get_ph_data(ehci_polledp->ehci_polled_usb_dev, ep_addr);
656*7c478bd9Sstevel@tonic-gate 
657*7c478bd9Sstevel@tonic-gate 	/*
658*7c478bd9Sstevel@tonic-gate 	 * The first enter keyboard entry should save info of the normal mode,
659*7c478bd9Sstevel@tonic-gate 	 * disable all list processing and interrupt, initialize the
660*7c478bd9Sstevel@tonic-gate 	 * frame list table with dummy QHs.
661*7c478bd9Sstevel@tonic-gate 	 */
662*7c478bd9Sstevel@tonic-gate 	if (ehcip->ehci_polled_enter_count == 1) {
663*7c478bd9Sstevel@tonic-gate 		/*
664*7c478bd9Sstevel@tonic-gate 		 * Save the current normal mode ehci registers	and later this
665*7c478bd9Sstevel@tonic-gate 		 * saved register copy is used to replace some of required ehci
666*7c478bd9Sstevel@tonic-gate 		 * registers before switching from polled mode to normal mode.
667*7c478bd9Sstevel@tonic-gate 		 */
668*7c478bd9Sstevel@tonic-gate 
669*7c478bd9Sstevel@tonic-gate 		bzero((void *)ehci_polled_regsp, sizeof (ehci_regs_t));
670*7c478bd9Sstevel@tonic-gate 
671*7c478bd9Sstevel@tonic-gate 		/* Save current ehci registers */
672*7c478bd9Sstevel@tonic-gate 		ehci_polled_regsp->ehci_command = Get_OpReg(ehci_command);
673*7c478bd9Sstevel@tonic-gate 		ehci_polled_regsp->ehci_interrupt = Get_OpReg(ehci_interrupt);
674*7c478bd9Sstevel@tonic-gate 		ehci_polled_regsp->ehci_ctrl_segment =
675*7c478bd9Sstevel@tonic-gate 		    Get_OpReg(ehci_ctrl_segment);
676*7c478bd9Sstevel@tonic-gate 		ehci_polled_regsp->
677*7c478bd9Sstevel@tonic-gate 		    ehci_async_list_addr = Get_OpReg(ehci_async_list_addr);
678*7c478bd9Sstevel@tonic-gate 		ehci_polled_regsp->ehci_config_flag =
679*7c478bd9Sstevel@tonic-gate 		    Get_OpReg(ehci_config_flag);
680*7c478bd9Sstevel@tonic-gate 		ehci_polled_regsp->ehci_periodic_list_base =
681*7c478bd9Sstevel@tonic-gate 		    Get_OpReg(ehci_periodic_list_base);
682*7c478bd9Sstevel@tonic-gate 
683*7c478bd9Sstevel@tonic-gate 		/* Disable all list processing and interrupts */
684*7c478bd9Sstevel@tonic-gate 		Set_OpReg(ehci_command, Get_OpReg(ehci_command) &
685*7c478bd9Sstevel@tonic-gate 		    ~(EHCI_CMD_ASYNC_SCHED_ENABLE |
686*7c478bd9Sstevel@tonic-gate 		    EHCI_CMD_PERIODIC_SCHED_ENABLE));
687*7c478bd9Sstevel@tonic-gate 
688*7c478bd9Sstevel@tonic-gate 		/* Wait for few milliseconds */
689*7c478bd9Sstevel@tonic-gate 		drv_usecwait(EHCI_POLLED_TIMEWAIT);
690*7c478bd9Sstevel@tonic-gate 
691*7c478bd9Sstevel@tonic-gate 		/* Save any unprocessed normal mode ehci interrupts */
692*7c478bd9Sstevel@tonic-gate 		ehcip->ehci_missed_intr_sts = EHCI_INTR_USB;
693*7c478bd9Sstevel@tonic-gate 
694*7c478bd9Sstevel@tonic-gate 		/*
695*7c478bd9Sstevel@tonic-gate 		 * Save the current interrupt lattice and  replace this lattice
696*7c478bd9Sstevel@tonic-gate 		 * with an lattice used in POLLED mode. We will restore lattice
697*7c478bd9Sstevel@tonic-gate 		 * back when we exit from the POLLED mode.
698*7c478bd9Sstevel@tonic-gate 		 */
699*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < EHCI_NUM_PERIODIC_FRAME_LISTS; i++) {
700*7c478bd9Sstevel@tonic-gate 			ehcip->ehci_polled_frame_list_table[i] =
701*7c478bd9Sstevel@tonic-gate 			    (ehci_qh_t *)(uintptr_t)Get_PFLT(ehcip->
702*7c478bd9Sstevel@tonic-gate 			    ehci_periodic_frame_list_tablep->
703*7c478bd9Sstevel@tonic-gate 			    ehci_periodic_frame_list_table[i]);
704*7c478bd9Sstevel@tonic-gate 		}
705*7c478bd9Sstevel@tonic-gate 
706*7c478bd9Sstevel@tonic-gate 		/*
707*7c478bd9Sstevel@tonic-gate 		 * Fill in the lattice with dummy QHs. These QHs are used so the
708*7c478bd9Sstevel@tonic-gate 		 * controller can tell that it is at the end of the QH list.
709*7c478bd9Sstevel@tonic-gate 		 */
710*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < EHCI_NUM_PERIODIC_FRAME_LISTS; i++) {
711*7c478bd9Sstevel@tonic-gate 			Set_PFLT(ehcip->ehci_periodic_frame_list_tablep->
712*7c478bd9Sstevel@tonic-gate 			    ehci_periodic_frame_list_table[i],
713*7c478bd9Sstevel@tonic-gate 			    ehci_qh_cpu_to_iommu(ehcip,
714*7c478bd9Sstevel@tonic-gate 			    ehci_polledp->ehci_polled_dummy_qh) |
715*7c478bd9Sstevel@tonic-gate 			    (EHCI_QH_LINK_REF_QH | EHCI_QH_LINK_PTR_VALID));
716*7c478bd9Sstevel@tonic-gate 		}
717*7c478bd9Sstevel@tonic-gate 
718*7c478bd9Sstevel@tonic-gate 	}
719*7c478bd9Sstevel@tonic-gate 
720*7c478bd9Sstevel@tonic-gate 	/* Get the polled mode ehci pipe private structure */
721*7c478bd9Sstevel@tonic-gate 	polled_pp = (ehci_pipe_private_t *)
722*7c478bd9Sstevel@tonic-gate 	    ehci_polledp->ehci_polled_input_pipe_handle->p_hcd_private;
723*7c478bd9Sstevel@tonic-gate 
724*7c478bd9Sstevel@tonic-gate 	/*
725*7c478bd9Sstevel@tonic-gate 	 * Before replacing the lattice, adjust the data togggle on the
726*7c478bd9Sstevel@tonic-gate 	 * on the ehci's interrupt ed
727*7c478bd9Sstevel@tonic-gate 	 */
728*7c478bd9Sstevel@tonic-gate 	polled_toggle = (Get_QH(polled_pp->pp_qh->qh_status) &
729*7c478bd9Sstevel@tonic-gate 	    EHCI_QH_STS_DATA_TOGGLE) ? DATA1:DATA0;
730*7c478bd9Sstevel@tonic-gate 
731*7c478bd9Sstevel@tonic-gate 	/*
732*7c478bd9Sstevel@tonic-gate 	 * If normal mode interrupt pipe endpoint is active, get the data
733*7c478bd9Sstevel@tonic-gate 	 * toggle from the this interrupt endpoint through the corresponding
734*7c478bd9Sstevel@tonic-gate 	 * interrupt pipe handle. Else get the data toggle information from
735*7c478bd9Sstevel@tonic-gate 	 * the usb device structure and this information is saved during the
736*7c478bd9Sstevel@tonic-gate 	 * normal mode interrupt pipe close. Use this data toggle information
737*7c478bd9Sstevel@tonic-gate 	 * to fix the data toggle of polled mode interrupt endpoint.
738*7c478bd9Sstevel@tonic-gate 	 */
739*7c478bd9Sstevel@tonic-gate 	if (ph) {
740*7c478bd9Sstevel@tonic-gate 		/* Get the normal mode ehci pipe private structure */
741*7c478bd9Sstevel@tonic-gate 		pp = (ehci_pipe_private_t *)ph->p_hcd_private;
742*7c478bd9Sstevel@tonic-gate 
743*7c478bd9Sstevel@tonic-gate 		real_toggle = (Get_QH(pp->pp_qh->qh_status) &
744*7c478bd9Sstevel@tonic-gate 		    EHCI_QH_STS_DATA_TOGGLE) ? DATA1:DATA0;
745*7c478bd9Sstevel@tonic-gate 	} else {
746*7c478bd9Sstevel@tonic-gate 		real_toggle = usba_hcdi_get_data_toggle(
747*7c478bd9Sstevel@tonic-gate 		    ehci_polledp->ehci_polled_usb_dev, ep_addr);
748*7c478bd9Sstevel@tonic-gate 	}
749*7c478bd9Sstevel@tonic-gate 
750*7c478bd9Sstevel@tonic-gate 	if (polled_toggle != real_toggle) {
751*7c478bd9Sstevel@tonic-gate 		if (real_toggle == DATA0) {
752*7c478bd9Sstevel@tonic-gate 			Set_QH(polled_pp->pp_qh->qh_status,
753*7c478bd9Sstevel@tonic-gate 			    Get_QH(polled_pp->pp_qh->qh_status) &
754*7c478bd9Sstevel@tonic-gate 			    ~EHCI_QH_STS_DATA_TOGGLE);
755*7c478bd9Sstevel@tonic-gate 		} else {
756*7c478bd9Sstevel@tonic-gate 			Set_QH(polled_pp->pp_qh->qh_status,
757*7c478bd9Sstevel@tonic-gate 			    Get_QH(polled_pp->pp_qh->qh_status) |
758*7c478bd9Sstevel@tonic-gate 			    EHCI_QH_STS_DATA_TOGGLE);
759*7c478bd9Sstevel@tonic-gate 		}
760*7c478bd9Sstevel@tonic-gate 	}
761*7c478bd9Sstevel@tonic-gate 
762*7c478bd9Sstevel@tonic-gate 	/*
763*7c478bd9Sstevel@tonic-gate 	 * Check whether Halt bit is set in the QH and if so  clear the
764*7c478bd9Sstevel@tonic-gate 	 * halt bit.
765*7c478bd9Sstevel@tonic-gate 	 */
766*7c478bd9Sstevel@tonic-gate 	if (polled_pp->pp_qh->qh_status & EHCI_QH_STS_HALTED) {
767*7c478bd9Sstevel@tonic-gate 
768*7c478bd9Sstevel@tonic-gate 		/* Clear the halt bit */
769*7c478bd9Sstevel@tonic-gate 		Set_QH(polled_pp->pp_qh->qh_status,
770*7c478bd9Sstevel@tonic-gate 		    (Get_QH(polled_pp->pp_qh->qh_status) &
771*7c478bd9Sstevel@tonic-gate 		    ~EHCI_QH_STS_HALTED));
772*7c478bd9Sstevel@tonic-gate 	}
773*7c478bd9Sstevel@tonic-gate 
774*7c478bd9Sstevel@tonic-gate 	/*
775*7c478bd9Sstevel@tonic-gate 	 * Initialize the qh overlay area
776*7c478bd9Sstevel@tonic-gate 	 */
777*7c478bd9Sstevel@tonic-gate 	qh = ehci_polledp->ehci_polled_qh;
778*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < 5; i++) {
779*7c478bd9Sstevel@tonic-gate 		Set_QH(qh->qh_buf[i], NULL);
780*7c478bd9Sstevel@tonic-gate 		Set_QH(qh->qh_buf_high[i], NULL);
781*7c478bd9Sstevel@tonic-gate 	}
782*7c478bd9Sstevel@tonic-gate 	Set_QH(qh->qh_next_qtd, ehci_qtd_cpu_to_iommu(ehcip,
783*7c478bd9Sstevel@tonic-gate 	    ehci_polledp->ehci_polled_active_intr_qtd_list));
784*7c478bd9Sstevel@tonic-gate 
785*7c478bd9Sstevel@tonic-gate 	/*
786*7c478bd9Sstevel@tonic-gate 	 * Now, add the endpoint to the lattice that we will  hang  our
787*7c478bd9Sstevel@tonic-gate 	 * QTD's off of.  We need to poll this device at  every 8 ms and
788*7c478bd9Sstevel@tonic-gate 	 * hence add this QH needs 4 entries in interrupt lattice.
789*7c478bd9Sstevel@tonic-gate 	 */
790*7c478bd9Sstevel@tonic-gate 	for (i = ehcip->ehci_polled_enter_count - 1;
791*7c478bd9Sstevel@tonic-gate 	    i < EHCI_NUM_PERIODIC_FRAME_LISTS;
792*7c478bd9Sstevel@tonic-gate 	    i = i + LS_MIN_POLL_INTERVAL) {
793*7c478bd9Sstevel@tonic-gate 		Set_PFLT(ehcip->ehci_periodic_frame_list_tablep->
794*7c478bd9Sstevel@tonic-gate 		    ehci_periodic_frame_list_table[i],
795*7c478bd9Sstevel@tonic-gate 		    ehci_qh_cpu_to_iommu(ehcip,
796*7c478bd9Sstevel@tonic-gate 		    ehci_polledp->ehci_polled_qh) | EHCI_QH_LINK_REF_QH);
797*7c478bd9Sstevel@tonic-gate 	}
798*7c478bd9Sstevel@tonic-gate 	/* The first enter keyboard entry enable interrupts and periodic list */
799*7c478bd9Sstevel@tonic-gate 	if (ehcip->ehci_polled_enter_count == 1) {
800*7c478bd9Sstevel@tonic-gate 		/* Enable USB and Frame list rollover interrupts */
801*7c478bd9Sstevel@tonic-gate 		Set_OpReg(ehci_interrupt, (EHCI_INTR_USB |
802*7c478bd9Sstevel@tonic-gate 		    EHCI_INTR_USB_ERROR | EHCI_INTR_FRAME_LIST_ROLLOVER));
803*7c478bd9Sstevel@tonic-gate 
804*7c478bd9Sstevel@tonic-gate 		/* Enable the periodic list */
805*7c478bd9Sstevel@tonic-gate 		Set_OpReg(ehci_command,
806*7c478bd9Sstevel@tonic-gate 		    (Get_OpReg(ehci_command) | EHCI_CMD_PERIODIC_SCHED_ENABLE));
807*7c478bd9Sstevel@tonic-gate 
808*7c478bd9Sstevel@tonic-gate 		/* Wait for few milliseconds */
809*7c478bd9Sstevel@tonic-gate 		drv_usecwait(EHCI_POLLED_TIMEWAIT);
810*7c478bd9Sstevel@tonic-gate 	}
811*7c478bd9Sstevel@tonic-gate #ifndef lint
812*7c478bd9Sstevel@tonic-gate 	_NOTE(COMPETING_THREADS_NOW);
813*7c478bd9Sstevel@tonic-gate #endif
814*7c478bd9Sstevel@tonic-gate }
815*7c478bd9Sstevel@tonic-gate 
816*7c478bd9Sstevel@tonic-gate 
817*7c478bd9Sstevel@tonic-gate /*
818*7c478bd9Sstevel@tonic-gate  * Polled restore state routines
819*7c478bd9Sstevel@tonic-gate  */
820*7c478bd9Sstevel@tonic-gate 
821*7c478bd9Sstevel@tonic-gate 
822*7c478bd9Sstevel@tonic-gate /*
823*7c478bd9Sstevel@tonic-gate  * ehci_polled_restore_state:
824*7c478bd9Sstevel@tonic-gate  */
825*7c478bd9Sstevel@tonic-gate static void
826*7c478bd9Sstevel@tonic-gate ehci_polled_restore_state(ehci_polled_t	*ehci_polledp)
827*7c478bd9Sstevel@tonic-gate {
828*7c478bd9Sstevel@tonic-gate 	ehci_state_t			*ehcip;
829*7c478bd9Sstevel@tonic-gate 	int				i;
830*7c478bd9Sstevel@tonic-gate 	uint_t				polled_toggle;
831*7c478bd9Sstevel@tonic-gate 	uint_t				real_toggle;
832*7c478bd9Sstevel@tonic-gate 	ehci_pipe_private_t		*pp = NULL; /* Normal mode Pipe */
833*7c478bd9Sstevel@tonic-gate 	ehci_pipe_private_t		*polled_pp; /* Polled mode Pipe */
834*7c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t		*ph;
835*7c478bd9Sstevel@tonic-gate 	uint8_t				ep_addr;
836*7c478bd9Sstevel@tonic-gate 
837*7c478bd9Sstevel@tonic-gate #ifndef lint
838*7c478bd9Sstevel@tonic-gate 	_NOTE(NO_COMPETING_THREADS_NOW);
839*7c478bd9Sstevel@tonic-gate #endif
840*7c478bd9Sstevel@tonic-gate 
841*7c478bd9Sstevel@tonic-gate 	/*
842*7c478bd9Sstevel@tonic-gate 	 * If this flag is set, then we are still using this structure,
843*7c478bd9Sstevel@tonic-gate 	 * so don't restore any controller state information yet.
844*7c478bd9Sstevel@tonic-gate 	 */
845*7c478bd9Sstevel@tonic-gate 	if (ehci_polledp->ehci_polled_flags & POLLED_INPUT_MODE_INUSE) {
846*7c478bd9Sstevel@tonic-gate 
847*7c478bd9Sstevel@tonic-gate #ifndef lint
848*7c478bd9Sstevel@tonic-gate 		_NOTE(COMPETING_THREADS_NOW);
849*7c478bd9Sstevel@tonic-gate #endif
850*7c478bd9Sstevel@tonic-gate 
851*7c478bd9Sstevel@tonic-gate 		return;
852*7c478bd9Sstevel@tonic-gate 	}
853*7c478bd9Sstevel@tonic-gate 
854*7c478bd9Sstevel@tonic-gate 	ehcip = ehci_polledp->ehci_polled_ehcip;
855*7c478bd9Sstevel@tonic-gate 	ehcip->ehci_polled_enter_count --;
856*7c478bd9Sstevel@tonic-gate 
857*7c478bd9Sstevel@tonic-gate 	/* Get the endpoint addr */
858*7c478bd9Sstevel@tonic-gate 	ep_addr = ehci_polledp->ehci_polled_ep_addr;
859*7c478bd9Sstevel@tonic-gate 
860*7c478bd9Sstevel@tonic-gate 	/* Get the normal mode usb pipe handle */
861*7c478bd9Sstevel@tonic-gate 	ph = usba_hcdi_get_ph_data(ehci_polledp->ehci_polled_usb_dev, ep_addr);
862*7c478bd9Sstevel@tonic-gate 
863*7c478bd9Sstevel@tonic-gate 	/* Disable list processing and other things */
864*7c478bd9Sstevel@tonic-gate 	ehci_polled_stop_processing(ehci_polledp);
865*7c478bd9Sstevel@tonic-gate 
866*7c478bd9Sstevel@tonic-gate 	/* Get the polled mode ehci pipe private structure */
867*7c478bd9Sstevel@tonic-gate 	polled_pp = (ehci_pipe_private_t *)
868*7c478bd9Sstevel@tonic-gate 	    ehci_polledp->ehci_polled_input_pipe_handle->p_hcd_private;
869*7c478bd9Sstevel@tonic-gate 
870*7c478bd9Sstevel@tonic-gate 	/*
871*7c478bd9Sstevel@tonic-gate 	 * Before replacing the lattice, adjust the data togggle
872*7c478bd9Sstevel@tonic-gate 	 * on the on the ehci's interrupt ed
873*7c478bd9Sstevel@tonic-gate 	 */
874*7c478bd9Sstevel@tonic-gate 	polled_toggle = (Get_QH(polled_pp->pp_qh->qh_status) &
875*7c478bd9Sstevel@tonic-gate 	    EHCI_QH_STS_DATA_TOGGLE) ? DATA1:DATA0;
876*7c478bd9Sstevel@tonic-gate 
877*7c478bd9Sstevel@tonic-gate 	/*
878*7c478bd9Sstevel@tonic-gate 	 * If normal mode interrupt pipe endpoint is active, fix the
879*7c478bd9Sstevel@tonic-gate 	 * data toggle for this interrupt endpoint by getting the data
880*7c478bd9Sstevel@tonic-gate 	 * toggle information from the polled interrupt endpoint. Else
881*7c478bd9Sstevel@tonic-gate 	 * save the data toggle information in usb device structure.
882*7c478bd9Sstevel@tonic-gate 	 */
883*7c478bd9Sstevel@tonic-gate 	if (ph) {
884*7c478bd9Sstevel@tonic-gate 		/* Get the normal mode ehci pipe private structure */
885*7c478bd9Sstevel@tonic-gate 		pp = (ehci_pipe_private_t *)ph->p_hcd_private;
886*7c478bd9Sstevel@tonic-gate 
887*7c478bd9Sstevel@tonic-gate 		real_toggle = (Get_QH(pp->pp_qh->qh_status) &
888*7c478bd9Sstevel@tonic-gate 		    EHCI_QH_STS_DATA_TOGGLE) ? DATA1:DATA0;
889*7c478bd9Sstevel@tonic-gate 
890*7c478bd9Sstevel@tonic-gate 		if (polled_toggle != real_toggle) {
891*7c478bd9Sstevel@tonic-gate 			if (polled_toggle == DATA0) {
892*7c478bd9Sstevel@tonic-gate 				Set_QH(pp->pp_qh->qh_status,
893*7c478bd9Sstevel@tonic-gate 				    Get_QH(pp->pp_qh->qh_status) &
894*7c478bd9Sstevel@tonic-gate 				    ~EHCI_QH_STS_DATA_TOGGLE);
895*7c478bd9Sstevel@tonic-gate 			} else {
896*7c478bd9Sstevel@tonic-gate 				Set_QH(pp->pp_qh->qh_status,
897*7c478bd9Sstevel@tonic-gate 				    Get_QH(pp->pp_qh->qh_status) |
898*7c478bd9Sstevel@tonic-gate 				    EHCI_QH_STS_DATA_TOGGLE);
899*7c478bd9Sstevel@tonic-gate 			}
900*7c478bd9Sstevel@tonic-gate 		}
901*7c478bd9Sstevel@tonic-gate 	} else {
902*7c478bd9Sstevel@tonic-gate 		usba_hcdi_set_data_toggle(ehci_polledp->ehci_polled_usb_dev,
903*7c478bd9Sstevel@tonic-gate 		    ep_addr, polled_toggle);
904*7c478bd9Sstevel@tonic-gate 	}
905*7c478bd9Sstevel@tonic-gate 
906*7c478bd9Sstevel@tonic-gate 	/*
907*7c478bd9Sstevel@tonic-gate 	 * Only the last leave keyboard entry restore the save frame
908*7c478bd9Sstevel@tonic-gate 	 * list table and start processing.
909*7c478bd9Sstevel@tonic-gate 	 */
910*7c478bd9Sstevel@tonic-gate 	if (ehcip->ehci_polled_enter_count == 0) {
911*7c478bd9Sstevel@tonic-gate 
912*7c478bd9Sstevel@tonic-gate 		/* Replace the lattice */
913*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < EHCI_NUM_PERIODIC_FRAME_LISTS; i++) {
914*7c478bd9Sstevel@tonic-gate 			Set_PFLT(ehcip->ehci_periodic_frame_list_tablep->
915*7c478bd9Sstevel@tonic-gate 			    ehci_periodic_frame_list_table[i],
916*7c478bd9Sstevel@tonic-gate 			    ehcip->ehci_polled_frame_list_table[i]);
917*7c478bd9Sstevel@tonic-gate 		}
918*7c478bd9Sstevel@tonic-gate 		ehci_polled_start_processing(ehci_polledp);
919*7c478bd9Sstevel@tonic-gate 	}
920*7c478bd9Sstevel@tonic-gate 
921*7c478bd9Sstevel@tonic-gate #ifndef lint
922*7c478bd9Sstevel@tonic-gate 	_NOTE(COMPETING_THREADS_NOW);
923*7c478bd9Sstevel@tonic-gate #endif
924*7c478bd9Sstevel@tonic-gate }
925*7c478bd9Sstevel@tonic-gate 
926*7c478bd9Sstevel@tonic-gate 
927*7c478bd9Sstevel@tonic-gate /*
928*7c478bd9Sstevel@tonic-gate  * ehci_polled_stop_processing:
929*7c478bd9Sstevel@tonic-gate  */
930*7c478bd9Sstevel@tonic-gate static void
931*7c478bd9Sstevel@tonic-gate ehci_polled_stop_processing(ehci_polled_t	*ehci_polledp)
932*7c478bd9Sstevel@tonic-gate {
933*7c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip;
934*7c478bd9Sstevel@tonic-gate 	ehci_qh_t		*qh = ehci_polledp->ehci_polled_qh;
935*7c478bd9Sstevel@tonic-gate 
936*7c478bd9Sstevel@tonic-gate 	ehcip = ehci_polledp->ehci_polled_ehcip;
937*7c478bd9Sstevel@tonic-gate 
938*7c478bd9Sstevel@tonic-gate 	/* First inactive this QH */
939*7c478bd9Sstevel@tonic-gate 	Set_QH(qh->qh_ctrl,
940*7c478bd9Sstevel@tonic-gate 	    Get_QH(qh->qh_ctrl) | EHCI_QH_CTRL_ED_INACTIVATE);
941*7c478bd9Sstevel@tonic-gate 
942*7c478bd9Sstevel@tonic-gate 	/* Only first leave keyboard entry turn off periodic list processing */
943*7c478bd9Sstevel@tonic-gate 	if (Get_OpReg(ehci_command) & EHCI_CMD_PERIODIC_SCHED_ENABLE) {
944*7c478bd9Sstevel@tonic-gate 		Set_OpReg(ehci_command, (Get_OpReg(ehci_command) &
945*7c478bd9Sstevel@tonic-gate 			~EHCI_CMD_PERIODIC_SCHED_ENABLE));
946*7c478bd9Sstevel@tonic-gate 
947*7c478bd9Sstevel@tonic-gate 		/* Wait for few milliseconds */
948*7c478bd9Sstevel@tonic-gate 		drv_usecwait(EHCI_POLLED_TIMEWAIT);
949*7c478bd9Sstevel@tonic-gate 	}
950*7c478bd9Sstevel@tonic-gate 	/*
951*7c478bd9Sstevel@tonic-gate 	 * Now clear all required fields of QH
952*7c478bd9Sstevel@tonic-gate 	 * including inactive bit.
953*7c478bd9Sstevel@tonic-gate 	 */
954*7c478bd9Sstevel@tonic-gate 	Set_QH(qh->qh_ctrl,
955*7c478bd9Sstevel@tonic-gate 	    Get_QH(qh->qh_ctrl) & ~(EHCI_QH_CTRL_ED_INACTIVATE));
956*7c478bd9Sstevel@tonic-gate 	Set_QH(qh->qh_status,
957*7c478bd9Sstevel@tonic-gate 	    Get_QH(qh->qh_status) & ~(EHCI_QH_STS_XACT_STATUS));
958*7c478bd9Sstevel@tonic-gate 	Set_QH(qh->qh_curr_qtd, NULL);
959*7c478bd9Sstevel@tonic-gate 	Set_QH(qh->qh_alt_next_qtd, EHCI_QH_ALT_NEXT_QTD_PTR_VALID);
960*7c478bd9Sstevel@tonic-gate 
961*7c478bd9Sstevel@tonic-gate 	/*
962*7c478bd9Sstevel@tonic-gate 	 * Now look up at the QTD's that are in the active qtd list &
963*7c478bd9Sstevel@tonic-gate 	 * re-insert them back into the QH's QTD list.
964*7c478bd9Sstevel@tonic-gate 	 */
965*7c478bd9Sstevel@tonic-gate 	(void) ehci_polled_process_active_intr_qtd_list(ehci_polledp);
966*7c478bd9Sstevel@tonic-gate }
967*7c478bd9Sstevel@tonic-gate 
968*7c478bd9Sstevel@tonic-gate 
969*7c478bd9Sstevel@tonic-gate /*
970*7c478bd9Sstevel@tonic-gate  * ehci_polled_start_processing:
971*7c478bd9Sstevel@tonic-gate  */
972*7c478bd9Sstevel@tonic-gate static void
973*7c478bd9Sstevel@tonic-gate ehci_polled_start_processing(ehci_polled_t	*ehci_polledp)
974*7c478bd9Sstevel@tonic-gate {
975*7c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip;
976*7c478bd9Sstevel@tonic-gate 	uint32_t		mask;
977*7c478bd9Sstevel@tonic-gate 	ehci_regs_t		*ehci_polled_regsp;
978*7c478bd9Sstevel@tonic-gate 
979*7c478bd9Sstevel@tonic-gate 	ehcip = ehci_polledp->ehci_polled_ehcip;
980*7c478bd9Sstevel@tonic-gate 	ehci_polled_regsp = &ehcip->ehci_polled_save_regs;
981*7c478bd9Sstevel@tonic-gate 
982*7c478bd9Sstevel@tonic-gate 	mask = ((uint32_t)ehci_polled_regsp->ehci_interrupt &
983*7c478bd9Sstevel@tonic-gate 	    (EHCI_INTR_HOST_SYSTEM_ERROR | EHCI_INTR_FRAME_LIST_ROLLOVER |
984*7c478bd9Sstevel@tonic-gate 	    EHCI_INTR_USB_ERROR | EHCI_INTR_USB | EHCI_INTR_ASYNC_ADVANCE));
985*7c478bd9Sstevel@tonic-gate 
986*7c478bd9Sstevel@tonic-gate 	/* Enable all required EHCI interrupts */
987*7c478bd9Sstevel@tonic-gate 	Set_OpReg(ehci_interrupt, mask);
988*7c478bd9Sstevel@tonic-gate 
989*7c478bd9Sstevel@tonic-gate 	mask = ((uint32_t)ehci_polled_regsp->ehci_command &
990*7c478bd9Sstevel@tonic-gate 	    (EHCI_CMD_ASYNC_SCHED_ENABLE | EHCI_CMD_PERIODIC_SCHED_ENABLE));
991*7c478bd9Sstevel@tonic-gate 
992*7c478bd9Sstevel@tonic-gate 	/* Enable all reuired list processing */
993*7c478bd9Sstevel@tonic-gate 	Set_OpReg(ehci_command, (Get_OpReg(ehci_command) | mask));
994*7c478bd9Sstevel@tonic-gate 
995*7c478bd9Sstevel@tonic-gate 	/* Wait for few milliseconds */
996*7c478bd9Sstevel@tonic-gate 	drv_usecwait(EHCI_POLLED_TIMEWAIT);
997*7c478bd9Sstevel@tonic-gate }
998*7c478bd9Sstevel@tonic-gate 
999*7c478bd9Sstevel@tonic-gate 
1000*7c478bd9Sstevel@tonic-gate /*
1001*7c478bd9Sstevel@tonic-gate  * Polled read routines
1002*7c478bd9Sstevel@tonic-gate  */
1003*7c478bd9Sstevel@tonic-gate 
1004*7c478bd9Sstevel@tonic-gate 
1005*7c478bd9Sstevel@tonic-gate /*
1006*7c478bd9Sstevel@tonic-gate  * ehci_polled_process_active_intr_qtd_list:
1007*7c478bd9Sstevel@tonic-gate  *
1008*7c478bd9Sstevel@tonic-gate  * This routine takes the QTD's off of the input done head and processes
1009*7c478bd9Sstevel@tonic-gate  * them.  It returns the number of characters that have been copied for
1010*7c478bd9Sstevel@tonic-gate  * input.
1011*7c478bd9Sstevel@tonic-gate  */
1012*7c478bd9Sstevel@tonic-gate static int
1013*7c478bd9Sstevel@tonic-gate ehci_polled_process_active_intr_qtd_list(ehci_polled_t	*ehci_polledp)
1014*7c478bd9Sstevel@tonic-gate {
1015*7c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip = ehci_polledp->ehci_polled_ehcip;
1016*7c478bd9Sstevel@tonic-gate 	ehci_qtd_t		*qtd, *next_qtd;
1017*7c478bd9Sstevel@tonic-gate 	uint_t			num_characters = 0;
1018*7c478bd9Sstevel@tonic-gate 	uint_t			ctrl;
1019*7c478bd9Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw;
1020*7c478bd9Sstevel@tonic-gate 	ehci_pipe_private_t	*pp;
1021*7c478bd9Sstevel@tonic-gate 	usb_cr_t 		error;
1022*7c478bd9Sstevel@tonic-gate 
1023*7c478bd9Sstevel@tonic-gate 	/* Sync QH and QTD pool */
1024*7c478bd9Sstevel@tonic-gate 	if (ehci_polledp->ehci_polled_no_sync_flag == B_FALSE) {
1025*7c478bd9Sstevel@tonic-gate 		Sync_QH_QTD_Pool(ehcip);
1026*7c478bd9Sstevel@tonic-gate 	}
1027*7c478bd9Sstevel@tonic-gate 
1028*7c478bd9Sstevel@tonic-gate 	/* Create done qtd list */
1029*7c478bd9Sstevel@tonic-gate 	qtd = ehci_polled_create_done_qtd_list(ehci_polledp);
1030*7c478bd9Sstevel@tonic-gate 
1031*7c478bd9Sstevel@tonic-gate 	/*
1032*7c478bd9Sstevel@tonic-gate 	 * Traverse the list of transfer descriptors.  We can't destroy
1033*7c478bd9Sstevel@tonic-gate 	 * the qtd_next pointers of these QTDs because we are using it
1034*7c478bd9Sstevel@tonic-gate 	 * to traverse the done list.  Therefore, we can not put these
1035*7c478bd9Sstevel@tonic-gate 	 * QTD's back on the QH until we are done processing all of them.
1036*7c478bd9Sstevel@tonic-gate 	 */
1037*7c478bd9Sstevel@tonic-gate 	while (qtd) {
1038*7c478bd9Sstevel@tonic-gate 		/* Get next active QTD from the active QTD list */
1039*7c478bd9Sstevel@tonic-gate 		next_qtd = ehci_qtd_iommu_to_cpu(ehcip,
1040*7c478bd9Sstevel@tonic-gate 		    Get_QTD(qtd->qtd_active_qtd_next));
1041*7c478bd9Sstevel@tonic-gate 
1042*7c478bd9Sstevel@tonic-gate 		/* Obtain the transfer wrapper from the QTD */
1043*7c478bd9Sstevel@tonic-gate 		tw = (ehci_trans_wrapper_t *)EHCI_LOOKUP_ID(
1044*7c478bd9Sstevel@tonic-gate 		    (uint32_t)Get_QTD(qtd->qtd_trans_wrapper));
1045*7c478bd9Sstevel@tonic-gate 
1046*7c478bd9Sstevel@tonic-gate 		/* Get ohci pipe from transfer wrapper */
1047*7c478bd9Sstevel@tonic-gate 		pp = tw->tw_pipe_private;
1048*7c478bd9Sstevel@tonic-gate 
1049*7c478bd9Sstevel@tonic-gate 		/* Look at the status */
1050*7c478bd9Sstevel@tonic-gate 		ctrl = (uint_t)Get_QTD(qtd->qtd_ctrl) &
1051*7c478bd9Sstevel@tonic-gate 		    (uint32_t)EHCI_QTD_CTRL_XACT_STATUS;
1052*7c478bd9Sstevel@tonic-gate 
1053*7c478bd9Sstevel@tonic-gate 		error = ehci_check_for_error(ehcip, pp, tw, qtd, ctrl);
1054*7c478bd9Sstevel@tonic-gate 
1055*7c478bd9Sstevel@tonic-gate 		/*
1056*7c478bd9Sstevel@tonic-gate 		 * Check to see if there is an error. If there is error
1057*7c478bd9Sstevel@tonic-gate 		 * clear the halt condition in the Endpoint  Descriptor
1058*7c478bd9Sstevel@tonic-gate 		 * (QH) associated with this Transfer  Descriptor (QTD).
1059*7c478bd9Sstevel@tonic-gate 		 */
1060*7c478bd9Sstevel@tonic-gate 		if (error == USB_CR_OK) {
1061*7c478bd9Sstevel@tonic-gate 			num_characters +=
1062*7c478bd9Sstevel@tonic-gate 			    ehci_polled_handle_normal_qtd(ehci_polledp, qtd);
1063*7c478bd9Sstevel@tonic-gate 		} else {
1064*7c478bd9Sstevel@tonic-gate 			/* Clear the halt bit */
1065*7c478bd9Sstevel@tonic-gate 			Set_QH(pp->pp_qh->qh_status,
1066*7c478bd9Sstevel@tonic-gate 			    Get_QH(pp->pp_qh->qh_status) &
1067*7c478bd9Sstevel@tonic-gate 			    ~(EHCI_QH_STS_XACT_STATUS));
1068*7c478bd9Sstevel@tonic-gate 		}
1069*7c478bd9Sstevel@tonic-gate 
1070*7c478bd9Sstevel@tonic-gate 		/* Insert this qtd back into QH's qtd list */
1071*7c478bd9Sstevel@tonic-gate 		ehci_polled_insert_qtd(ehci_polledp, qtd);
1072*7c478bd9Sstevel@tonic-gate 
1073*7c478bd9Sstevel@tonic-gate 		qtd = next_qtd;
1074*7c478bd9Sstevel@tonic-gate 	}
1075*7c478bd9Sstevel@tonic-gate 
1076*7c478bd9Sstevel@tonic-gate 	return (num_characters);
1077*7c478bd9Sstevel@tonic-gate }
1078*7c478bd9Sstevel@tonic-gate 
1079*7c478bd9Sstevel@tonic-gate 
1080*7c478bd9Sstevel@tonic-gate /*
1081*7c478bd9Sstevel@tonic-gate  * ehci_polled_handle_normal_qtd:
1082*7c478bd9Sstevel@tonic-gate  */
1083*7c478bd9Sstevel@tonic-gate static int
1084*7c478bd9Sstevel@tonic-gate ehci_polled_handle_normal_qtd(
1085*7c478bd9Sstevel@tonic-gate 	ehci_polled_t		*ehci_polledp,
1086*7c478bd9Sstevel@tonic-gate 	ehci_qtd_t		*qtd)
1087*7c478bd9Sstevel@tonic-gate {
1088*7c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip = ehci_polledp->ehci_polled_ehcip;
1089*7c478bd9Sstevel@tonic-gate 	uchar_t			*buf;
1090*7c478bd9Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw;
1091*7c478bd9Sstevel@tonic-gate 	size_t			length;
1092*7c478bd9Sstevel@tonic-gate 	uint32_t		residue;
1093*7c478bd9Sstevel@tonic-gate 
1094*7c478bd9Sstevel@tonic-gate 	/* Obtain the transfer wrapper from the QTD */
1095*7c478bd9Sstevel@tonic-gate 	tw = (ehci_trans_wrapper_t *)EHCI_LOOKUP_ID((uint32_t)
1096*7c478bd9Sstevel@tonic-gate 		Get_QTD(qtd->qtd_trans_wrapper));
1097*7c478bd9Sstevel@tonic-gate 
1098*7c478bd9Sstevel@tonic-gate 	ASSERT(tw != NULL);
1099*7c478bd9Sstevel@tonic-gate 
1100*7c478bd9Sstevel@tonic-gate 	buf = (uchar_t *)tw->tw_buf;
1101*7c478bd9Sstevel@tonic-gate 
1102*7c478bd9Sstevel@tonic-gate 	length = tw->tw_length;
1103*7c478bd9Sstevel@tonic-gate 
1104*7c478bd9Sstevel@tonic-gate 	/*
1105*7c478bd9Sstevel@tonic-gate 	 * If "Total bytes of xfer" in control field of qtd is not equal to 0,
1106*7c478bd9Sstevel@tonic-gate 	 * then we received less data from the usb device than requested by us.
1107*7c478bd9Sstevel@tonic-gate 	 * In that case, get the actual received data size.
1108*7c478bd9Sstevel@tonic-gate 	 */
1109*7c478bd9Sstevel@tonic-gate 	residue = ((Get_QTD(qtd->qtd_ctrl) &
1110*7c478bd9Sstevel@tonic-gate 	    EHCI_QTD_CTRL_BYTES_TO_XFER) >> EHCI_QTD_CTRL_BYTES_TO_XFER_SHIFT);
1111*7c478bd9Sstevel@tonic-gate 
1112*7c478bd9Sstevel@tonic-gate 	if (residue) {
1113*7c478bd9Sstevel@tonic-gate 
1114*7c478bd9Sstevel@tonic-gate 		length = (Get_QTD(qtd->qtd_xfer_addr) +
1115*7c478bd9Sstevel@tonic-gate 		    Get_QTD(qtd->qtd_xfer_len) - residue) -
1116*7c478bd9Sstevel@tonic-gate 		    tw->tw_cookie.dmac_address;
1117*7c478bd9Sstevel@tonic-gate 	}
1118*7c478bd9Sstevel@tonic-gate 
1119*7c478bd9Sstevel@tonic-gate 	/* Sync IO buffer */
1120*7c478bd9Sstevel@tonic-gate 	if (ehci_polledp->ehci_polled_no_sync_flag == B_FALSE) {
1121*7c478bd9Sstevel@tonic-gate 		Sync_IO_Buffer(tw->tw_dmahandle, length);
1122*7c478bd9Sstevel@tonic-gate 	}
1123*7c478bd9Sstevel@tonic-gate 
1124*7c478bd9Sstevel@tonic-gate 	/* Copy the data into the message */
1125*7c478bd9Sstevel@tonic-gate 	bcopy(buf, ehci_polledp->ehci_polled_buf, length);
1126*7c478bd9Sstevel@tonic-gate 
1127*7c478bd9Sstevel@tonic-gate 	return (length);
1128*7c478bd9Sstevel@tonic-gate }
1129*7c478bd9Sstevel@tonic-gate 
1130*7c478bd9Sstevel@tonic-gate 
1131*7c478bd9Sstevel@tonic-gate /*
1132*7c478bd9Sstevel@tonic-gate  * ehci_polled_insert_qtd:
1133*7c478bd9Sstevel@tonic-gate  *
1134*7c478bd9Sstevel@tonic-gate  * Insert a Transfer Descriptor (QTD) on an Endpoint Descriptor (QH).
1135*7c478bd9Sstevel@tonic-gate  */
1136*7c478bd9Sstevel@tonic-gate static void
1137*7c478bd9Sstevel@tonic-gate ehci_polled_insert_qtd(
1138*7c478bd9Sstevel@tonic-gate 	ehci_polled_t		*ehci_polledp,
1139*7c478bd9Sstevel@tonic-gate 	ehci_qtd_t		*qtd)
1140*7c478bd9Sstevel@tonic-gate {
1141*7c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip = ehci_polledp->ehci_polled_ehcip;
1142*7c478bd9Sstevel@tonic-gate 	ehci_qtd_t		*curr_dummy_qtd, *next_dummy_qtd;
1143*7c478bd9Sstevel@tonic-gate 	ehci_qtd_t		*new_dummy_qtd;
1144*7c478bd9Sstevel@tonic-gate 	uint_t			qtd_control;
1145*7c478bd9Sstevel@tonic-gate 	ehci_pipe_private_t	*pp;
1146*7c478bd9Sstevel@tonic-gate 	ehci_qh_t		*qh;
1147*7c478bd9Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw;
1148*7c478bd9Sstevel@tonic-gate 
1149*7c478bd9Sstevel@tonic-gate 	/* Obtain the transfer wrapper from the QTD */
1150*7c478bd9Sstevel@tonic-gate 	tw = (ehci_trans_wrapper_t *)EHCI_LOOKUP_ID(
1151*7c478bd9Sstevel@tonic-gate 	    (uint32_t)Get_QTD(qtd->qtd_trans_wrapper));
1152*7c478bd9Sstevel@tonic-gate 
1153*7c478bd9Sstevel@tonic-gate 	pp = tw->tw_pipe_private;
1154*7c478bd9Sstevel@tonic-gate 
1155*7c478bd9Sstevel@tonic-gate 	/* Obtain the endpoint and interrupt request */
1156*7c478bd9Sstevel@tonic-gate 	qh = pp->pp_qh;
1157*7c478bd9Sstevel@tonic-gate 
1158*7c478bd9Sstevel@tonic-gate 	/*
1159*7c478bd9Sstevel@tonic-gate 	 * Take this QTD off the transfer wrapper's list since
1160*7c478bd9Sstevel@tonic-gate 	 * the pipe is FIFO, this must be the first QTD on the
1161*7c478bd9Sstevel@tonic-gate 	 * list.
1162*7c478bd9Sstevel@tonic-gate 	 */
1163*7c478bd9Sstevel@tonic-gate 	ASSERT((ehci_qtd_t *)tw->tw_qtd_head == qtd);
1164*7c478bd9Sstevel@tonic-gate 
1165*7c478bd9Sstevel@tonic-gate 	tw->tw_qtd_head = (ehci_qtd_t *)
1166*7c478bd9Sstevel@tonic-gate 	    ehci_qtd_iommu_to_cpu(ehcip, Get_QTD(qtd->qtd_tw_next_qtd));
1167*7c478bd9Sstevel@tonic-gate 
1168*7c478bd9Sstevel@tonic-gate 	/*
1169*7c478bd9Sstevel@tonic-gate 	 * If the head becomes NULL, then there are no more
1170*7c478bd9Sstevel@tonic-gate 	 * active QTD's for this transfer wrapper. Also	set
1171*7c478bd9Sstevel@tonic-gate 	 * the tail to NULL.
1172*7c478bd9Sstevel@tonic-gate 	 */
1173*7c478bd9Sstevel@tonic-gate 	if (tw->tw_qtd_head == NULL) {
1174*7c478bd9Sstevel@tonic-gate 		tw->tw_qtd_tail = NULL;
1175*7c478bd9Sstevel@tonic-gate 	}
1176*7c478bd9Sstevel@tonic-gate 
1177*7c478bd9Sstevel@tonic-gate 	/* Convert current valid QTD as new dummy QTD */
1178*7c478bd9Sstevel@tonic-gate 	bzero((char *)qtd, sizeof (ehci_qtd_t));
1179*7c478bd9Sstevel@tonic-gate 	Set_QTD(qtd->qtd_state, EHCI_QTD_DUMMY);
1180*7c478bd9Sstevel@tonic-gate 
1181*7c478bd9Sstevel@tonic-gate 	/* Rename qtd as new_dummy_qtd */
1182*7c478bd9Sstevel@tonic-gate 	new_dummy_qtd = qtd;
1183*7c478bd9Sstevel@tonic-gate 
1184*7c478bd9Sstevel@tonic-gate 	/* Get the current and next dummy QTDs */
1185*7c478bd9Sstevel@tonic-gate 	curr_dummy_qtd = ehci_qtd_iommu_to_cpu(ehcip,
1186*7c478bd9Sstevel@tonic-gate 	    Get_QH(qh->qh_dummy_qtd));
1187*7c478bd9Sstevel@tonic-gate 	next_dummy_qtd = ehci_qtd_iommu_to_cpu(ehcip,
1188*7c478bd9Sstevel@tonic-gate 	    Get_QTD(curr_dummy_qtd->qtd_next_qtd));
1189*7c478bd9Sstevel@tonic-gate 
1190*7c478bd9Sstevel@tonic-gate 	/* Update QH's dummy qtd field */
1191*7c478bd9Sstevel@tonic-gate 	Set_QH(qh->qh_dummy_qtd, ehci_qtd_cpu_to_iommu(ehcip, next_dummy_qtd));
1192*7c478bd9Sstevel@tonic-gate 
1193*7c478bd9Sstevel@tonic-gate 	/* Update next dummy's next qtd pointer */
1194*7c478bd9Sstevel@tonic-gate 	Set_QTD(next_dummy_qtd->qtd_next_qtd,
1195*7c478bd9Sstevel@tonic-gate 	    ehci_qtd_cpu_to_iommu(ehcip, new_dummy_qtd));
1196*7c478bd9Sstevel@tonic-gate 
1197*7c478bd9Sstevel@tonic-gate 	qtd_control = (tw->tw_direction | EHCI_QTD_CTRL_INTR_ON_COMPLETE);
1198*7c478bd9Sstevel@tonic-gate 
1199*7c478bd9Sstevel@tonic-gate 	/*
1200*7c478bd9Sstevel@tonic-gate 	 * Fill in the current dummy qtd and
1201*7c478bd9Sstevel@tonic-gate 	 * add the new dummy to the end.
1202*7c478bd9Sstevel@tonic-gate 	 */
1203*7c478bd9Sstevel@tonic-gate 	ehci_polled_fill_in_qtd(ehcip, curr_dummy_qtd, qtd_control,
1204*7c478bd9Sstevel@tonic-gate 	    tw->tw_cookie.dmac_address, tw->tw_length, tw);
1205*7c478bd9Sstevel@tonic-gate 
1206*7c478bd9Sstevel@tonic-gate 	/* Insert this qtd onto the tw */
1207*7c478bd9Sstevel@tonic-gate 	ehci_polled_insert_qtd_on_tw(ehcip, tw, curr_dummy_qtd);
1208*7c478bd9Sstevel@tonic-gate 
1209*7c478bd9Sstevel@tonic-gate 	/* Insert this qtd into active interrupt QTD list */
1210*7c478bd9Sstevel@tonic-gate 	ehci_polled_insert_qtd_into_active_intr_qtd_list(
1211*7c478bd9Sstevel@tonic-gate 	    ehci_polledp, curr_dummy_qtd);
1212*7c478bd9Sstevel@tonic-gate }
1213*7c478bd9Sstevel@tonic-gate 
1214*7c478bd9Sstevel@tonic-gate 
1215*7c478bd9Sstevel@tonic-gate /*
1216*7c478bd9Sstevel@tonic-gate  * ehci_polled_fill_in_qtd:
1217*7c478bd9Sstevel@tonic-gate  *
1218*7c478bd9Sstevel@tonic-gate  * Fill in the fields of a Transfer Descriptor (QTD).
1219*7c478bd9Sstevel@tonic-gate  *
1220*7c478bd9Sstevel@tonic-gate  * Unlike the it's ehci_fill_in_qtd counterpart, we do not
1221*7c478bd9Sstevel@tonic-gate  * set the alternative ptr in polled mode.  There is not need
1222*7c478bd9Sstevel@tonic-gate  * for it in polled mode, because it doesn't need to cleanup
1223*7c478bd9Sstevel@tonic-gate  * short xfer conditions.
1224*7c478bd9Sstevel@tonic-gate  */
1225*7c478bd9Sstevel@tonic-gate static void
1226*7c478bd9Sstevel@tonic-gate ehci_polled_fill_in_qtd(
1227*7c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip,
1228*7c478bd9Sstevel@tonic-gate 	ehci_qtd_t		*qtd,
1229*7c478bd9Sstevel@tonic-gate 	uint_t			qtd_ctrl,
1230*7c478bd9Sstevel@tonic-gate 	uint32_t		qtd_iommu_cbp,
1231*7c478bd9Sstevel@tonic-gate 	size_t			qtd_length,
1232*7c478bd9Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw)
1233*7c478bd9Sstevel@tonic-gate {
1234*7c478bd9Sstevel@tonic-gate 	uint32_t		buf_addr = qtd_iommu_cbp;
1235*7c478bd9Sstevel@tonic-gate 	size_t			buf_len = qtd_length;
1236*7c478bd9Sstevel@tonic-gate 	uint32_t		ctrl = qtd_ctrl;
1237*7c478bd9Sstevel@tonic-gate 	uint_t			i = 0;
1238*7c478bd9Sstevel@tonic-gate 
1239*7c478bd9Sstevel@tonic-gate 	/* Assert that the qtd to be filled in is a dummy */
1240*7c478bd9Sstevel@tonic-gate 	ASSERT(Get_QTD(qtd->qtd_state) == EHCI_QTD_DUMMY);
1241*7c478bd9Sstevel@tonic-gate 
1242*7c478bd9Sstevel@tonic-gate 	/* Change QTD's state Active */
1243*7c478bd9Sstevel@tonic-gate 	Set_QTD(qtd->qtd_state, EHCI_QTD_ACTIVE);
1244*7c478bd9Sstevel@tonic-gate 
1245*7c478bd9Sstevel@tonic-gate 	/* Set the total length data tarnsfer */
1246*7c478bd9Sstevel@tonic-gate 	ctrl |= (((qtd_length << EHCI_QTD_CTRL_BYTES_TO_XFER_SHIFT)
1247*7c478bd9Sstevel@tonic-gate 	    & EHCI_QTD_CTRL_BYTES_TO_XFER) | EHCI_QTD_CTRL_MAX_ERR_COUNTS);
1248*7c478bd9Sstevel@tonic-gate 
1249*7c478bd9Sstevel@tonic-gate 	/*
1250*7c478bd9Sstevel@tonic-gate 	 * Save the starting buffer address used and
1251*7c478bd9Sstevel@tonic-gate 	 * length of data that will be transfered in
1252*7c478bd9Sstevel@tonic-gate 	 * the current QTD.
1253*7c478bd9Sstevel@tonic-gate 	 */
1254*7c478bd9Sstevel@tonic-gate 	Set_QTD(qtd->qtd_xfer_addr, buf_addr);
1255*7c478bd9Sstevel@tonic-gate 	Set_QTD(qtd->qtd_xfer_len, buf_len);
1256*7c478bd9Sstevel@tonic-gate 
1257*7c478bd9Sstevel@tonic-gate 	while (buf_len) {
1258*7c478bd9Sstevel@tonic-gate 		/* Update the beginning of the buffer */
1259*7c478bd9Sstevel@tonic-gate 		Set_QTD(qtd->qtd_buf[i], buf_addr);
1260*7c478bd9Sstevel@tonic-gate 
1261*7c478bd9Sstevel@tonic-gate 		if (buf_len <= EHCI_MAX_QTD_BUF_SIZE) {
1262*7c478bd9Sstevel@tonic-gate 			break;
1263*7c478bd9Sstevel@tonic-gate 		} else {
1264*7c478bd9Sstevel@tonic-gate 			buf_len -= EHCI_MAX_QTD_BUF_SIZE;
1265*7c478bd9Sstevel@tonic-gate 			buf_addr += EHCI_MAX_QTD_BUF_SIZE;
1266*7c478bd9Sstevel@tonic-gate 		}
1267*7c478bd9Sstevel@tonic-gate 
1268*7c478bd9Sstevel@tonic-gate 		i++;
1269*7c478bd9Sstevel@tonic-gate 	}
1270*7c478bd9Sstevel@tonic-gate 
1271*7c478bd9Sstevel@tonic-gate 	/*
1272*7c478bd9Sstevel@tonic-gate 	 * For control, bulk and interrupt QTD, now
1273*7c478bd9Sstevel@tonic-gate 	 * enable current QTD by setting active bit.
1274*7c478bd9Sstevel@tonic-gate 	 */
1275*7c478bd9Sstevel@tonic-gate 	Set_QTD(qtd->qtd_ctrl, (ctrl | EHCI_QTD_CTRL_ACTIVE_XACT));
1276*7c478bd9Sstevel@tonic-gate 
1277*7c478bd9Sstevel@tonic-gate 	Set_QTD(qtd->qtd_trans_wrapper, (uint32_t)tw->tw_id);
1278*7c478bd9Sstevel@tonic-gate }
1279*7c478bd9Sstevel@tonic-gate 
1280*7c478bd9Sstevel@tonic-gate 
1281*7c478bd9Sstevel@tonic-gate /*
1282*7c478bd9Sstevel@tonic-gate  * ehci_polled_insert_qtd_on_tw:
1283*7c478bd9Sstevel@tonic-gate  *
1284*7c478bd9Sstevel@tonic-gate  * The transfer wrapper keeps a list of all Transfer Descriptors (QTD) that
1285*7c478bd9Sstevel@tonic-gate  * are allocated for this transfer. Insert a QTD  onto this list. The  list
1286*7c478bd9Sstevel@tonic-gate  * of QTD's does not include the dummy QTD that is at the end of the list of
1287*7c478bd9Sstevel@tonic-gate  * QTD's for the endpoint.
1288*7c478bd9Sstevel@tonic-gate  */
1289*7c478bd9Sstevel@tonic-gate static void
1290*7c478bd9Sstevel@tonic-gate ehci_polled_insert_qtd_on_tw(
1291*7c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip,
1292*7c478bd9Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw,
1293*7c478bd9Sstevel@tonic-gate 	ehci_qtd_t		*qtd)
1294*7c478bd9Sstevel@tonic-gate {
1295*7c478bd9Sstevel@tonic-gate 	/*
1296*7c478bd9Sstevel@tonic-gate 	 * Set the next pointer to NULL because
1297*7c478bd9Sstevel@tonic-gate 	 * this is the last QTD on list.
1298*7c478bd9Sstevel@tonic-gate 	 */
1299*7c478bd9Sstevel@tonic-gate 	Set_QTD(qtd->qtd_tw_next_qtd, NULL);
1300*7c478bd9Sstevel@tonic-gate 
1301*7c478bd9Sstevel@tonic-gate 	if (tw->tw_qtd_head == NULL) {
1302*7c478bd9Sstevel@tonic-gate 		ASSERT(tw->tw_qtd_tail == NULL);
1303*7c478bd9Sstevel@tonic-gate 		tw->tw_qtd_head = qtd;
1304*7c478bd9Sstevel@tonic-gate 		tw->tw_qtd_tail = qtd;
1305*7c478bd9Sstevel@tonic-gate 	} else {
1306*7c478bd9Sstevel@tonic-gate 		ehci_qtd_t *dummy = (ehci_qtd_t *)tw->tw_qtd_tail;
1307*7c478bd9Sstevel@tonic-gate 
1308*7c478bd9Sstevel@tonic-gate 		ASSERT(dummy != NULL);
1309*7c478bd9Sstevel@tonic-gate 		ASSERT(dummy != qtd);
1310*7c478bd9Sstevel@tonic-gate 		ASSERT(Get_QTD(qtd->qtd_state) != EHCI_QTD_DUMMY);
1311*7c478bd9Sstevel@tonic-gate 
1312*7c478bd9Sstevel@tonic-gate 		/* Add the qtd to the end of the list */
1313*7c478bd9Sstevel@tonic-gate 		Set_QTD(dummy->qtd_tw_next_qtd,
1314*7c478bd9Sstevel@tonic-gate 		    ehci_qtd_cpu_to_iommu(ehcip, qtd));
1315*7c478bd9Sstevel@tonic-gate 
1316*7c478bd9Sstevel@tonic-gate 		tw->tw_qtd_tail = qtd;
1317*7c478bd9Sstevel@tonic-gate 
1318*7c478bd9Sstevel@tonic-gate 		ASSERT(Get_QTD(qtd->qtd_tw_next_qtd) == NULL);
1319*7c478bd9Sstevel@tonic-gate 	}
1320*7c478bd9Sstevel@tonic-gate }
1321*7c478bd9Sstevel@tonic-gate 
1322*7c478bd9Sstevel@tonic-gate 
1323*7c478bd9Sstevel@tonic-gate /*
1324*7c478bd9Sstevel@tonic-gate  * ehci_polled_create_done_qtd_list:
1325*7c478bd9Sstevel@tonic-gate  *
1326*7c478bd9Sstevel@tonic-gate  * Create done qtd list from active qtd list.
1327*7c478bd9Sstevel@tonic-gate  */
1328*7c478bd9Sstevel@tonic-gate static ehci_qtd_t *
1329*7c478bd9Sstevel@tonic-gate ehci_polled_create_done_qtd_list(
1330*7c478bd9Sstevel@tonic-gate 	ehci_polled_t		*ehci_polledp)
1331*7c478bd9Sstevel@tonic-gate {
1332*7c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip = ehci_polledp->ehci_polled_ehcip;
1333*7c478bd9Sstevel@tonic-gate 	ehci_qtd_t		*curr_qtd = NULL, *next_qtd = NULL;
1334*7c478bd9Sstevel@tonic-gate 	ehci_qtd_t		*done_qtd_list = NULL, *last_done_qtd = NULL;
1335*7c478bd9Sstevel@tonic-gate 
1336*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1337*7c478bd9Sstevel@tonic-gate 	    "ehci_polled_create_done_qtd_list:");
1338*7c478bd9Sstevel@tonic-gate 
1339*7c478bd9Sstevel@tonic-gate 	curr_qtd = ehci_polledp->ehci_polled_active_intr_qtd_list;
1340*7c478bd9Sstevel@tonic-gate 
1341*7c478bd9Sstevel@tonic-gate 	while (curr_qtd) {
1342*7c478bd9Sstevel@tonic-gate 
1343*7c478bd9Sstevel@tonic-gate 		/* Get next qtd from the active qtd list */
1344*7c478bd9Sstevel@tonic-gate 		next_qtd = ehci_qtd_iommu_to_cpu(ehcip,
1345*7c478bd9Sstevel@tonic-gate 		    Get_QTD(curr_qtd->qtd_active_qtd_next));
1346*7c478bd9Sstevel@tonic-gate 
1347*7c478bd9Sstevel@tonic-gate 		/* Check this QTD has been processed by Host Controller */
1348*7c478bd9Sstevel@tonic-gate 		if (!(Get_QTD(curr_qtd->qtd_ctrl) &
1349*7c478bd9Sstevel@tonic-gate 		    EHCI_QTD_CTRL_ACTIVE_XACT)) {
1350*7c478bd9Sstevel@tonic-gate 
1351*7c478bd9Sstevel@tonic-gate 			/* Remove this QTD from active QTD list */
1352*7c478bd9Sstevel@tonic-gate 			ehci_polled_remove_qtd_from_active_intr_qtd_list(
1353*7c478bd9Sstevel@tonic-gate 			    ehci_polledp, curr_qtd);
1354*7c478bd9Sstevel@tonic-gate 
1355*7c478bd9Sstevel@tonic-gate 			Set_QTD(curr_qtd->qtd_active_qtd_next, NULL);
1356*7c478bd9Sstevel@tonic-gate 
1357*7c478bd9Sstevel@tonic-gate 			if (done_qtd_list) {
1358*7c478bd9Sstevel@tonic-gate 				Set_QTD(last_done_qtd->qtd_active_qtd_next,
1359*7c478bd9Sstevel@tonic-gate 				    ehci_qtd_cpu_to_iommu(ehcip, curr_qtd));
1360*7c478bd9Sstevel@tonic-gate 
1361*7c478bd9Sstevel@tonic-gate 				last_done_qtd = curr_qtd;
1362*7c478bd9Sstevel@tonic-gate 			} else {
1363*7c478bd9Sstevel@tonic-gate 				done_qtd_list = curr_qtd;
1364*7c478bd9Sstevel@tonic-gate 				last_done_qtd = curr_qtd;
1365*7c478bd9Sstevel@tonic-gate 			}
1366*7c478bd9Sstevel@tonic-gate 		}
1367*7c478bd9Sstevel@tonic-gate 
1368*7c478bd9Sstevel@tonic-gate 		curr_qtd = next_qtd;
1369*7c478bd9Sstevel@tonic-gate 	}
1370*7c478bd9Sstevel@tonic-gate 
1371*7c478bd9Sstevel@tonic-gate 	return (done_qtd_list);
1372*7c478bd9Sstevel@tonic-gate }
1373*7c478bd9Sstevel@tonic-gate 
1374*7c478bd9Sstevel@tonic-gate 
1375*7c478bd9Sstevel@tonic-gate /*
1376*7c478bd9Sstevel@tonic-gate  * ehci_polled_insert_qtd_into_active_intr_qtd_list:
1377*7c478bd9Sstevel@tonic-gate  *
1378*7c478bd9Sstevel@tonic-gate  * Insert current QTD into active interrupt QTD list.
1379*7c478bd9Sstevel@tonic-gate  */
1380*7c478bd9Sstevel@tonic-gate static void
1381*7c478bd9Sstevel@tonic-gate ehci_polled_insert_qtd_into_active_intr_qtd_list(
1382*7c478bd9Sstevel@tonic-gate 	ehci_polled_t		*ehci_polledp,
1383*7c478bd9Sstevel@tonic-gate 	ehci_qtd_t		*qtd)
1384*7c478bd9Sstevel@tonic-gate {
1385*7c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip = ehci_polledp->ehci_polled_ehcip;
1386*7c478bd9Sstevel@tonic-gate 	ehci_qtd_t		*curr_qtd, *next_qtd;
1387*7c478bd9Sstevel@tonic-gate 
1388*7c478bd9Sstevel@tonic-gate 	curr_qtd = ehci_polledp->ehci_polled_active_intr_qtd_list;
1389*7c478bd9Sstevel@tonic-gate 
1390*7c478bd9Sstevel@tonic-gate 	/* Insert this qtd into active intr qtd list */
1391*7c478bd9Sstevel@tonic-gate 	if (curr_qtd) {
1392*7c478bd9Sstevel@tonic-gate 		next_qtd = ehci_qtd_iommu_to_cpu(ehcip,
1393*7c478bd9Sstevel@tonic-gate 		    Get_QTD(curr_qtd->qtd_active_qtd_next));
1394*7c478bd9Sstevel@tonic-gate 
1395*7c478bd9Sstevel@tonic-gate 		while (next_qtd) {
1396*7c478bd9Sstevel@tonic-gate 			curr_qtd = next_qtd;
1397*7c478bd9Sstevel@tonic-gate 			next_qtd = ehci_qtd_iommu_to_cpu(ehcip,
1398*7c478bd9Sstevel@tonic-gate 			    Get_QTD(curr_qtd->qtd_active_qtd_next));
1399*7c478bd9Sstevel@tonic-gate 		}
1400*7c478bd9Sstevel@tonic-gate 
1401*7c478bd9Sstevel@tonic-gate 		Set_QTD(qtd->qtd_active_qtd_prev,
1402*7c478bd9Sstevel@tonic-gate 		    ehci_qtd_cpu_to_iommu(ehcip, curr_qtd));
1403*7c478bd9Sstevel@tonic-gate 
1404*7c478bd9Sstevel@tonic-gate 		Set_QTD(curr_qtd->qtd_active_qtd_next,
1405*7c478bd9Sstevel@tonic-gate 		    ehci_qtd_cpu_to_iommu(ehcip, qtd));
1406*7c478bd9Sstevel@tonic-gate 	} else {
1407*7c478bd9Sstevel@tonic-gate 		ehci_polledp->ehci_polled_active_intr_qtd_list = qtd;
1408*7c478bd9Sstevel@tonic-gate 		Set_QTD(qtd->qtd_active_qtd_next, NULL);
1409*7c478bd9Sstevel@tonic-gate 		Set_QTD(qtd->qtd_active_qtd_prev, NULL);
1410*7c478bd9Sstevel@tonic-gate 	}
1411*7c478bd9Sstevel@tonic-gate }
1412*7c478bd9Sstevel@tonic-gate 
1413*7c478bd9Sstevel@tonic-gate 
1414*7c478bd9Sstevel@tonic-gate /*
1415*7c478bd9Sstevel@tonic-gate  * ehci_polled_remove_qtd_from_active_intr_qtd_list:
1416*7c478bd9Sstevel@tonic-gate  *
1417*7c478bd9Sstevel@tonic-gate  * Remove current QTD from the active QTD list.
1418*7c478bd9Sstevel@tonic-gate  */
1419*7c478bd9Sstevel@tonic-gate void
1420*7c478bd9Sstevel@tonic-gate ehci_polled_remove_qtd_from_active_intr_qtd_list(
1421*7c478bd9Sstevel@tonic-gate 	ehci_polled_t		*ehci_polledp,
1422*7c478bd9Sstevel@tonic-gate 	ehci_qtd_t		*qtd)
1423*7c478bd9Sstevel@tonic-gate {
1424*7c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip = ehci_polledp->ehci_polled_ehcip;
1425*7c478bd9Sstevel@tonic-gate 	ehci_qtd_t		*curr_qtd, *prev_qtd, *next_qtd;
1426*7c478bd9Sstevel@tonic-gate 
1427*7c478bd9Sstevel@tonic-gate 	ASSERT(qtd != NULL);
1428*7c478bd9Sstevel@tonic-gate 
1429*7c478bd9Sstevel@tonic-gate 	curr_qtd = ehci_polledp->ehci_polled_active_intr_qtd_list;
1430*7c478bd9Sstevel@tonic-gate 
1431*7c478bd9Sstevel@tonic-gate 	while ((curr_qtd) && (curr_qtd != qtd)) {
1432*7c478bd9Sstevel@tonic-gate 		curr_qtd = ehci_qtd_iommu_to_cpu(ehcip,
1433*7c478bd9Sstevel@tonic-gate 		    Get_QTD(curr_qtd->qtd_active_qtd_next));
1434*7c478bd9Sstevel@tonic-gate 	}
1435*7c478bd9Sstevel@tonic-gate 
1436*7c478bd9Sstevel@tonic-gate 	if ((curr_qtd) && (curr_qtd == qtd)) {
1437*7c478bd9Sstevel@tonic-gate 		prev_qtd = ehci_qtd_iommu_to_cpu(ehcip,
1438*7c478bd9Sstevel@tonic-gate 		    Get_QTD(curr_qtd->qtd_active_qtd_prev));
1439*7c478bd9Sstevel@tonic-gate 		next_qtd = ehci_qtd_iommu_to_cpu(ehcip,
1440*7c478bd9Sstevel@tonic-gate 		    Get_QTD(curr_qtd->qtd_active_qtd_next));
1441*7c478bd9Sstevel@tonic-gate 
1442*7c478bd9Sstevel@tonic-gate 		if (prev_qtd) {
1443*7c478bd9Sstevel@tonic-gate 			Set_QTD(prev_qtd->qtd_active_qtd_next,
1444*7c478bd9Sstevel@tonic-gate 			    Get_QTD(curr_qtd->qtd_active_qtd_next));
1445*7c478bd9Sstevel@tonic-gate 		} else {
1446*7c478bd9Sstevel@tonic-gate 			ehci_polledp->
1447*7c478bd9Sstevel@tonic-gate 			    ehci_polled_active_intr_qtd_list = next_qtd;
1448*7c478bd9Sstevel@tonic-gate 		}
1449*7c478bd9Sstevel@tonic-gate 
1450*7c478bd9Sstevel@tonic-gate 		if (next_qtd) {
1451*7c478bd9Sstevel@tonic-gate 			Set_QTD(next_qtd->qtd_active_qtd_prev,
1452*7c478bd9Sstevel@tonic-gate 			    Get_QTD(curr_qtd->qtd_active_qtd_prev));
1453*7c478bd9Sstevel@tonic-gate 		}
1454*7c478bd9Sstevel@tonic-gate 	}
1455*7c478bd9Sstevel@tonic-gate }
1456*7c478bd9Sstevel@tonic-gate 
1457*7c478bd9Sstevel@tonic-gate 
1458*7c478bd9Sstevel@tonic-gate /*
1459*7c478bd9Sstevel@tonic-gate  * ehci_polled_traverse_qtds:
1460*7c478bd9Sstevel@tonic-gate  *
1461*7c478bd9Sstevel@tonic-gate  * Traverse the list of QTDs for given pipe using transfer wrapper.  Since
1462*7c478bd9Sstevel@tonic-gate  * the endpoint is marked as Halted, the Host Controller (HC) is no longer
1463*7c478bd9Sstevel@tonic-gate  * accessing these QTDs. Remove all the QTDs that are attached to endpoint.
1464*7c478bd9Sstevel@tonic-gate  */
1465*7c478bd9Sstevel@tonic-gate static void
1466*7c478bd9Sstevel@tonic-gate ehci_polled_traverse_qtds(
1467*7c478bd9Sstevel@tonic-gate 	ehci_polled_t		*ehci_polledp,
1468*7c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph)
1469*7c478bd9Sstevel@tonic-gate {
1470*7c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip = ehci_polledp->ehci_polled_ehcip;
1471*7c478bd9Sstevel@tonic-gate 	ehci_pipe_private_t	*pp = (ehci_pipe_private_t *)ph->p_hcd_private;
1472*7c478bd9Sstevel@tonic-gate 	ehci_trans_wrapper_t	*next_tw;
1473*7c478bd9Sstevel@tonic-gate 	ehci_qtd_t		*qtd;
1474*7c478bd9Sstevel@tonic-gate 	ehci_qtd_t		*next_qtd;
1475*7c478bd9Sstevel@tonic-gate 
1476*7c478bd9Sstevel@tonic-gate 	/* Process the transfer wrappers for this pipe */
1477*7c478bd9Sstevel@tonic-gate 	next_tw = pp->pp_tw_head;
1478*7c478bd9Sstevel@tonic-gate 
1479*7c478bd9Sstevel@tonic-gate 	while (next_tw) {
1480*7c478bd9Sstevel@tonic-gate 		qtd = (ehci_qtd_t *)next_tw->tw_qtd_head;
1481*7c478bd9Sstevel@tonic-gate 
1482*7c478bd9Sstevel@tonic-gate 		/* Walk through each QTD for this transfer wrapper */
1483*7c478bd9Sstevel@tonic-gate 		while (qtd) {
1484*7c478bd9Sstevel@tonic-gate 			/* Remove this QTD from active QTD list */
1485*7c478bd9Sstevel@tonic-gate 			ehci_polled_remove_qtd_from_active_intr_qtd_list(
1486*7c478bd9Sstevel@tonic-gate 			    ehci_polledp, qtd);
1487*7c478bd9Sstevel@tonic-gate 
1488*7c478bd9Sstevel@tonic-gate 			next_qtd = ehci_qtd_iommu_to_cpu(ehcip,
1489*7c478bd9Sstevel@tonic-gate 			    Get_QTD(qtd->qtd_tw_next_qtd));
1490*7c478bd9Sstevel@tonic-gate 
1491*7c478bd9Sstevel@tonic-gate 			/* Deallocate this QTD */
1492*7c478bd9Sstevel@tonic-gate 			ehci_deallocate_qtd(ehcip, qtd);
1493*7c478bd9Sstevel@tonic-gate 
1494*7c478bd9Sstevel@tonic-gate 			qtd = next_qtd;
1495*7c478bd9Sstevel@tonic-gate 		}
1496*7c478bd9Sstevel@tonic-gate 
1497*7c478bd9Sstevel@tonic-gate 		next_tw = next_tw->tw_next;
1498*7c478bd9Sstevel@tonic-gate 	}
1499*7c478bd9Sstevel@tonic-gate 
1500*7c478bd9Sstevel@tonic-gate 	/* Clear current qtd pointer */
1501*7c478bd9Sstevel@tonic-gate 	Set_QH(pp->pp_qh->qh_curr_qtd, (uint32_t)0x00000000);
1502*7c478bd9Sstevel@tonic-gate 
1503*7c478bd9Sstevel@tonic-gate 	/* Update the next qtd pointer in the QH */
1504*7c478bd9Sstevel@tonic-gate 	Set_QH(pp->pp_qh->qh_next_qtd, Get_QH(pp->pp_qh->qh_dummy_qtd));
1505*7c478bd9Sstevel@tonic-gate }
1506*7c478bd9Sstevel@tonic-gate 
1507*7c478bd9Sstevel@tonic-gate 
1508*7c478bd9Sstevel@tonic-gate /*
1509*7c478bd9Sstevel@tonic-gate  * ehci_polled_finish_interrupt:
1510*7c478bd9Sstevel@tonic-gate  */
1511*7c478bd9Sstevel@tonic-gate static void
1512*7c478bd9Sstevel@tonic-gate ehci_polled_finish_interrupt(
1513*7c478bd9Sstevel@tonic-gate 	ehci_state_t	*ehcip,
1514*7c478bd9Sstevel@tonic-gate 	uint_t		intr)
1515*7c478bd9Sstevel@tonic-gate {
1516*7c478bd9Sstevel@tonic-gate 	/* Acknowledge the interrupt */
1517*7c478bd9Sstevel@tonic-gate 	Set_OpReg(ehci_status, intr);
1518*7c478bd9Sstevel@tonic-gate 
1519*7c478bd9Sstevel@tonic-gate 	/*
1520*7c478bd9Sstevel@tonic-gate 	 * Read interrupt status register to make sure that any PIO
1521*7c478bd9Sstevel@tonic-gate 	 * store to clear the ISR has made it on the PCI bus before
1522*7c478bd9Sstevel@tonic-gate 	 * returning from its interrupt handler.
1523*7c478bd9Sstevel@tonic-gate 	 */
1524*7c478bd9Sstevel@tonic-gate 	(void) Get_OpReg(ehci_status);
1525*7c478bd9Sstevel@tonic-gate }
1526