1*53ee8cc1Swenshuai.xi //<MStar Software>
2*53ee8cc1Swenshuai.xi //******************************************************************************
3*53ee8cc1Swenshuai.xi // MStar Software
4*53ee8cc1Swenshuai.xi // Copyright (c) 2010 - 2012 MStar Semiconductor, Inc. All rights reserved.
5*53ee8cc1Swenshuai.xi // All software, firmware and related documentation herein ("MStar Software") are
6*53ee8cc1Swenshuai.xi // intellectual property of MStar Semiconductor, Inc. ("MStar") and protected by
7*53ee8cc1Swenshuai.xi // law, including, but not limited to, copyright law and international treaties.
8*53ee8cc1Swenshuai.xi // Any use, modification, reproduction, retransmission, or republication of all
9*53ee8cc1Swenshuai.xi // or part of MStar Software is expressly prohibited, unless prior written
10*53ee8cc1Swenshuai.xi // permission has been granted by MStar.
11*53ee8cc1Swenshuai.xi //
12*53ee8cc1Swenshuai.xi // By accessing, browsing and/or using MStar Software, you acknowledge that you
13*53ee8cc1Swenshuai.xi // have read, understood, and agree, to be bound by below terms ("Terms") and to
14*53ee8cc1Swenshuai.xi // comply with all applicable laws and regulations:
15*53ee8cc1Swenshuai.xi //
16*53ee8cc1Swenshuai.xi // 1. MStar shall retain any and all right, ownership and interest to MStar
17*53ee8cc1Swenshuai.xi // Software and any modification/derivatives thereof.
18*53ee8cc1Swenshuai.xi // No right, ownership, or interest to MStar Software and any
19*53ee8cc1Swenshuai.xi // modification/derivatives thereof is transferred to you under Terms.
20*53ee8cc1Swenshuai.xi //
21*53ee8cc1Swenshuai.xi // 2. You understand that MStar Software might include, incorporate or be
22*53ee8cc1Swenshuai.xi // supplied together with third party`s software and the use of MStar
23*53ee8cc1Swenshuai.xi // Software may require additional licenses from third parties.
24*53ee8cc1Swenshuai.xi // Therefore, you hereby agree it is your sole responsibility to separately
25*53ee8cc1Swenshuai.xi // obtain any and all third party right and license necessary for your use of
26*53ee8cc1Swenshuai.xi // such third party`s software.
27*53ee8cc1Swenshuai.xi //
28*53ee8cc1Swenshuai.xi // 3. MStar Software and any modification/derivatives thereof shall be deemed as
29*53ee8cc1Swenshuai.xi // MStar`s confidential information and you agree to keep MStar`s
30*53ee8cc1Swenshuai.xi // confidential information in strictest confidence and not disclose to any
31*53ee8cc1Swenshuai.xi // third party.
32*53ee8cc1Swenshuai.xi //
33*53ee8cc1Swenshuai.xi // 4. MStar Software is provided on an "AS IS" basis without warranties of any
34*53ee8cc1Swenshuai.xi // kind. Any warranties are hereby expressly disclaimed by MStar, including
35*53ee8cc1Swenshuai.xi // without limitation, any warranties of merchantability, non-infringement of
36*53ee8cc1Swenshuai.xi // intellectual property rights, fitness for a particular purpose, error free
37*53ee8cc1Swenshuai.xi // and in conformity with any international standard. You agree to waive any
38*53ee8cc1Swenshuai.xi // claim against MStar for any loss, damage, cost or expense that you may
39*53ee8cc1Swenshuai.xi // incur related to your use of MStar Software.
40*53ee8cc1Swenshuai.xi // In no event shall MStar be liable for any direct, indirect, incidental or
41*53ee8cc1Swenshuai.xi // consequential damages, including without limitation, lost of profit or
42*53ee8cc1Swenshuai.xi // revenues, lost or damage of data, and unauthorized system use.
43*53ee8cc1Swenshuai.xi // You agree that this Section 4 shall still apply without being affected
44*53ee8cc1Swenshuai.xi // even if MStar Software has been modified by MStar in accordance with your
45*53ee8cc1Swenshuai.xi // request or instruction for your use, except otherwise agreed by both
46*53ee8cc1Swenshuai.xi // parties in writing.
47*53ee8cc1Swenshuai.xi //
48*53ee8cc1Swenshuai.xi // 5. If requested, MStar may from time to time provide technical supports or
49*53ee8cc1Swenshuai.xi // services in relation with MStar Software to you for your use of
50*53ee8cc1Swenshuai.xi // MStar Software in conjunction with your or your customer`s product
51*53ee8cc1Swenshuai.xi // ("Services").
52*53ee8cc1Swenshuai.xi // You understand and agree that, except otherwise agreed by both parties in
53*53ee8cc1Swenshuai.xi // writing, Services are provided on an "AS IS" basis and the warranty
54*53ee8cc1Swenshuai.xi // disclaimer set forth in Section 4 above shall apply.
55*53ee8cc1Swenshuai.xi //
56*53ee8cc1Swenshuai.xi // 6. Nothing contained herein shall be construed as by implication, estoppels
57*53ee8cc1Swenshuai.xi // or otherwise:
58*53ee8cc1Swenshuai.xi // (a) conferring any license or right to use MStar name, trademark, service
59*53ee8cc1Swenshuai.xi // mark, symbol or any other identification;
60*53ee8cc1Swenshuai.xi // (b) obligating MStar or any of its affiliates to furnish any person,
61*53ee8cc1Swenshuai.xi // including without limitation, you and your customers, any assistance
62*53ee8cc1Swenshuai.xi // of any kind whatsoever, or any information; or
63*53ee8cc1Swenshuai.xi // (c) conferring any license or right under any intellectual property right.
64*53ee8cc1Swenshuai.xi //
65*53ee8cc1Swenshuai.xi // 7. These terms shall be governed by and construed in accordance with the laws
66*53ee8cc1Swenshuai.xi // of Taiwan, R.O.C., excluding its conflict of law rules.
67*53ee8cc1Swenshuai.xi // Any and all dispute arising out hereof or related hereto shall be finally
68*53ee8cc1Swenshuai.xi // settled by arbitration referred to the Chinese Arbitration Association,
69*53ee8cc1Swenshuai.xi // Taipei in accordance with the ROC Arbitration Law and the Arbitration
70*53ee8cc1Swenshuai.xi // Rules of the Association by three (3) arbitrators appointed in accordance
71*53ee8cc1Swenshuai.xi // with the said Rules.
72*53ee8cc1Swenshuai.xi // The place of arbitration shall be in Taipei, Taiwan and the language shall
73*53ee8cc1Swenshuai.xi // be English.
74*53ee8cc1Swenshuai.xi // The arbitration award shall be final and binding to both parties.
75*53ee8cc1Swenshuai.xi //
76*53ee8cc1Swenshuai.xi //******************************************************************************
77*53ee8cc1Swenshuai.xi //<MStar Software>
78*53ee8cc1Swenshuai.xi int ms_ehci_get_frame_idx (struct usb_hcd *hcd);
79*53ee8cc1Swenshuai.xi
80*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
ms_periodic_unlink(struct ehci_hcd * pEhci,U32 u32Frame,void * ptr)81*53ee8cc1Swenshuai.xi static void ms_periodic_unlink (struct ehci_hcd *pEhci, U32 u32Frame, void *ptr)
82*53ee8cc1Swenshuai.xi {
83*53ee8cc1Swenshuai.xi union ehci_qh_shadow *prev_p = &pEhci->pshadow [u32Frame];
84*53ee8cc1Swenshuai.xi U32 *hw_p = &pEhci->pPeriodic [u32Frame];
85*53ee8cc1Swenshuai.xi union ehci_qh_shadow here = *prev_p;
86*53ee8cc1Swenshuai.xi union ehci_qh_shadow *next_p1;
87*53ee8cc1Swenshuai.xi
88*53ee8cc1Swenshuai.xi while (here.ptr && here.ptr != ptr)
89*53ee8cc1Swenshuai.xi {
90*53ee8cc1Swenshuai.xi prev_p = (Q_NEXT_TYPE (*hw_p) == QH_TYPE)
91*53ee8cc1Swenshuai.xi ? (union ehci_qh_shadow *)(&prev_p->qh->qh_next)
92*53ee8cc1Swenshuai.xi : NULL;
93*53ee8cc1Swenshuai.xi //hw_p = &here.qh->hw_next_qh;
94*53ee8cc1Swenshuai.xi hw_p = here.hw_next;
95*53ee8cc1Swenshuai.xi here = *prev_p;
96*53ee8cc1Swenshuai.xi }
97*53ee8cc1Swenshuai.xi if (!here.ptr)
98*53ee8cc1Swenshuai.xi {
99*53ee8cc1Swenshuai.xi ms_debug_msg ("[periodic_unlink] entry %p no longer on u32Frame [%d]\n", ptr, (int)u32Frame);
100*53ee8cc1Swenshuai.xi return;
101*53ee8cc1Swenshuai.xi }
102*53ee8cc1Swenshuai.xi
103*53ee8cc1Swenshuai.xi next_p1 = (Q_NEXT_TYPE (*hw_p) == QH_TYPE)
104*53ee8cc1Swenshuai.xi ? (union ehci_qh_shadow *)(&here.qh->qh_next)
105*53ee8cc1Swenshuai.xi : NULL;
106*53ee8cc1Swenshuai.xi //*hw_p = here.qh->hw_next_qh;
107*53ee8cc1Swenshuai.xi *hw_p = *here.hw_next;
108*53ee8cc1Swenshuai.xi *prev_p = *next_p1;
109*53ee8cc1Swenshuai.xi //next_p1->ptr = 0; // no meaning code
110*53ee8cc1Swenshuai.xi }
111*53ee8cc1Swenshuai.xi
ms_periodic_usecs(struct ehci_hcd * pEhci,U32 u32Frame,U32 u32uFrame)112*53ee8cc1Swenshuai.xi static U16 ms_periodic_usecs (struct ehci_hcd *pEhci, U32 u32Frame, U32 u32uFrame)
113*53ee8cc1Swenshuai.xi {
114*53ee8cc1Swenshuai.xi U32 *phw_p = &pEhci->pPeriodic [u32Frame];
115*53ee8cc1Swenshuai.xi union ehci_qh_shadow *pQh = &pEhci->pshadow [u32Frame];
116*53ee8cc1Swenshuai.xi U32 u32uSecs = 0;
117*53ee8cc1Swenshuai.xi
118*53ee8cc1Swenshuai.xi while (pQh->ptr)
119*53ee8cc1Swenshuai.xi {
120*53ee8cc1Swenshuai.xi if (Q_NEXT_TYPE (*phw_p) == QH_TYPE)
121*53ee8cc1Swenshuai.xi {
122*53ee8cc1Swenshuai.xi if (pQh->qh->hw_ep_state2 & (1 << u32uFrame))
123*53ee8cc1Swenshuai.xi u32uSecs += pQh->qh->u8Usecs;
124*53ee8cc1Swenshuai.xi if (pQh->qh->hw_ep_state2 & (1 << (8 + u32uFrame)))
125*53ee8cc1Swenshuai.xi u32uSecs += pQh->qh->c_usecs;
126*53ee8cc1Swenshuai.xi phw_p = &pQh->qh->hw_next_qh; // patch from Linux, move hardware pointer too
127*53ee8cc1Swenshuai.xi pQh = &pQh->qh->qh_next;
128*53ee8cc1Swenshuai.xi }
129*53ee8cc1Swenshuai.xi else
130*53ee8cc1Swenshuai.xi USB_ASSERT (0, "Next list type not qH type!\n");
131*53ee8cc1Swenshuai.xi }
132*53ee8cc1Swenshuai.xi #ifdef DEBUG
133*53ee8cc1Swenshuai.xi /*
134*53ee8cc1Swenshuai.xi * set standard 80% (== 100 usec/uframe) periodic
135*53ee8cc1Swenshuai.xi * bandwidth as required by USB 2.0 by default, (100/125)
136*53ee8cc1Swenshuai.xi */
137*53ee8cc1Swenshuai.xi if (u32uSecs > 100)
138*53ee8cc1Swenshuai.xi ms_debug_err("overallocated u32uFrame %d, periodic is %d u32uSecs",
139*53ee8cc1Swenshuai.xi u32Frame * 8 + u32uFrame, u32uSecs);
140*53ee8cc1Swenshuai.xi #endif
141*53ee8cc1Swenshuai.xi return u32uSecs;
142*53ee8cc1Swenshuai.xi }
143*53ee8cc1Swenshuai.xi
144*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
ms_enable_periodic(struct ehci_hcd * pEhci)145*53ee8cc1Swenshuai.xi static int ms_enable_periodic (struct ehci_hcd *pEhci)
146*53ee8cc1Swenshuai.xi {
147*53ee8cc1Swenshuai.xi U32 u32Cmd;
148*53ee8cc1Swenshuai.xi int iStatus;
149*53ee8cc1Swenshuai.xi
150*53ee8cc1Swenshuai.xi if (pEhci->u32PeriodicSched++) // patch from Linux
151*53ee8cc1Swenshuai.xi return 0;
152*53ee8cc1Swenshuai.xi
153*53ee8cc1Swenshuai.xi ms_debug_func("<%s> ++\n", __FUNCTION__);
154*53ee8cc1Swenshuai.xi iStatus = ms_check_status (&pEhci->op_regs->usbsts, USBSTS_PSS, 0, 9 * 125);
155*53ee8cc1Swenshuai.xi if (iStatus != 0)
156*53ee8cc1Swenshuai.xi {
157*53ee8cc1Swenshuai.xi pEhci->hcd.state = HCD_STATE_HALT;
158*53ee8cc1Swenshuai.xi ms_debug_err("enable periodic schedule time out!!!!\n");
159*53ee8cc1Swenshuai.xi return iStatus;
160*53ee8cc1Swenshuai.xi }
161*53ee8cc1Swenshuai.xi
162*53ee8cc1Swenshuai.xi u32Cmd = hcd_reg_readl ((U32)&pEhci->op_regs->usbcmd) | USBCMD_PSE;
163*53ee8cc1Swenshuai.xi hcd_reg_writel (u32Cmd, (U32)&pEhci->op_regs->usbcmd);
164*53ee8cc1Swenshuai.xi pEhci->hcd.state = HCD_STATE_RUNNING;
165*53ee8cc1Swenshuai.xi pEhci->iNextUframe = hcd_reg_readl ((U32)&pEhci->op_regs->frindex)
166*53ee8cc1Swenshuai.xi % (pEhci->u32PeriodicSize << 3);
167*53ee8cc1Swenshuai.xi return 0;
168*53ee8cc1Swenshuai.xi }
169*53ee8cc1Swenshuai.xi
ms_disable_periodic(struct ehci_hcd * pEhci)170*53ee8cc1Swenshuai.xi static int ms_disable_periodic (struct ehci_hcd *pEhci)
171*53ee8cc1Swenshuai.xi {
172*53ee8cc1Swenshuai.xi U32 u32Cmd;
173*53ee8cc1Swenshuai.xi int iStatus;
174*53ee8cc1Swenshuai.xi
175*53ee8cc1Swenshuai.xi if (--pEhci->u32PeriodicSched) // patch from Linux
176*53ee8cc1Swenshuai.xi return 0;
177*53ee8cc1Swenshuai.xi
178*53ee8cc1Swenshuai.xi ms_debug_func("<%s> ++\n", __FUNCTION__);
179*53ee8cc1Swenshuai.xi iStatus = ms_check_status (&pEhci->op_regs->usbsts, USBSTS_PSS, USBSTS_PSS, 9 * 125);
180*53ee8cc1Swenshuai.xi if (iStatus != 0)
181*53ee8cc1Swenshuai.xi {
182*53ee8cc1Swenshuai.xi ms_debug_err("disable periodic schedule time out!!!!\n");
183*53ee8cc1Swenshuai.xi return iStatus;
184*53ee8cc1Swenshuai.xi }
185*53ee8cc1Swenshuai.xi
186*53ee8cc1Swenshuai.xi u32Cmd = hcd_reg_readl ((U32)&pEhci->op_regs->usbcmd) & ~USBCMD_PSE;
187*53ee8cc1Swenshuai.xi hcd_reg_writel (u32Cmd, (U32)&pEhci->op_regs->usbcmd);
188*53ee8cc1Swenshuai.xi pEhci->iNextUframe = -1;
189*53ee8cc1Swenshuai.xi return 0;
190*53ee8cc1Swenshuai.xi }
191*53ee8cc1Swenshuai.xi
192*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
193*53ee8cc1Swenshuai.xi static int ms_qh_schedule (struct ehci_hcd *pEhci, struct ehci_qh *pQh);
ms_intr_deschedule(struct ehci_hcd * pEhci,struct ehci_qh * pQh1)194*53ee8cc1Swenshuai.xi static void ms_intr_deschedule (
195*53ee8cc1Swenshuai.xi struct ehci_hcd *pEhci,
196*53ee8cc1Swenshuai.xi struct ehci_qh *pQh1
197*53ee8cc1Swenshuai.xi )
198*53ee8cc1Swenshuai.xi {
199*53ee8cc1Swenshuai.xi U32 u32Frame = pQh1->u16Start;
200*53ee8cc1Swenshuai.xi U32 iWait;
201*53ee8cc1Swenshuai.xi U32 period;
202*53ee8cc1Swenshuai.xi //int rc;
203*53ee8cc1Swenshuai.xi
204*53ee8cc1Swenshuai.xi ms_debug_func("<%s> ++\n", __FUNCTION__);
205*53ee8cc1Swenshuai.xi
206*53ee8cc1Swenshuai.xi /*** qh_unlink_periodic statement ***/
207*53ee8cc1Swenshuai.xi if ((period = pQh1->u16Period) == 0)
208*53ee8cc1Swenshuai.xi period = 1;
209*53ee8cc1Swenshuai.xi
210*53ee8cc1Swenshuai.xi /*** qh_unlink_periodic statement ***/
211*53ee8cc1Swenshuai.xi do
212*53ee8cc1Swenshuai.xi {
213*53ee8cc1Swenshuai.xi ms_periodic_unlink (pEhci, u32Frame, pQh1);
214*53ee8cc1Swenshuai.xi //ms_qh_put (pEhci, pQh1); // moved
215*53ee8cc1Swenshuai.xi u32Frame += period;
216*53ee8cc1Swenshuai.xi } while (u32Frame < pEhci->u32PeriodicSize);
217*53ee8cc1Swenshuai.xi
218*53ee8cc1Swenshuai.xi // TODO: update bandwidth per ep if required
219*53ee8cc1Swenshuai.xi pQh1->qh_status = QH_STS_UNLINK;
220*53ee8cc1Swenshuai.xi pQh1->qh_next.ptr = 0;
221*53ee8cc1Swenshuai.xi ms_qh_put (pEhci, pQh1); // patch from Linux here
222*53ee8cc1Swenshuai.xi
223*53ee8cc1Swenshuai.xi #if 1
224*53ee8cc1Swenshuai.xi ms_disable_periodic(pEhci);
225*53ee8cc1Swenshuai.xi #else
226*53ee8cc1Swenshuai.xi pEhci->u32PeriodicSched--;
227*53ee8cc1Swenshuai.xi if (!pEhci->u32PeriodicSched)
228*53ee8cc1Swenshuai.xi ms_disable_periodic (pEhci);
229*53ee8cc1Swenshuai.xi else
230*53ee8cc1Swenshuai.xi {
231*53ee8cc1Swenshuai.xi ms_debug_msg ("periodic schedule still enabled\n");
232*53ee8cc1Swenshuai.xi }
233*53ee8cc1Swenshuai.xi #endif
234*53ee8cc1Swenshuai.xi /*** end of qh_unlink_periodic statement ***/
235*53ee8cc1Swenshuai.xi wmb(); // make sure hardware visible (hint from linux 3.10.40)
236*53ee8cc1Swenshuai.xi
237*53ee8cc1Swenshuai.xi /* patch from Linux 2.6.28 */
238*53ee8cc1Swenshuai.xi if (list_empty (&pQh1->qtd_list) || (QH_CMASK & pQh1->hw_ep_state2) != 0)
239*53ee8cc1Swenshuai.xi iWait = 2;
240*53ee8cc1Swenshuai.xi else
241*53ee8cc1Swenshuai.xi iWait = 55;
242*53ee8cc1Swenshuai.xi
243*53ee8cc1Swenshuai.xi udelay (iWait);
244*53ee8cc1Swenshuai.xi #if 0
245*53ee8cc1Swenshuai.xi if (((ms_ehci_get_frame_idx (&pEhci->hcd) - u32Frame) % pQh1->u16Period) == 0)
246*53ee8cc1Swenshuai.xi {
247*53ee8cc1Swenshuai.xi if (iWait)
248*53ee8cc1Swenshuai.xi {
249*53ee8cc1Swenshuai.xi udelay (125);
250*53ee8cc1Swenshuai.xi pQh1->hw_next_qh = EHCI_LIST_END;
251*53ee8cc1Swenshuai.xi }
252*53ee8cc1Swenshuai.xi else
253*53ee8cc1Swenshuai.xi {
254*53ee8cc1Swenshuai.xi ms_debug_msg ("ms_intr_deschedule...\n");
255*53ee8cc1Swenshuai.xi }
256*53ee8cc1Swenshuai.xi }
257*53ee8cc1Swenshuai.xi else
258*53ee8cc1Swenshuai.xi pQh1->hw_next_qh = EHCI_LIST_END;
259*53ee8cc1Swenshuai.xi #endif
260*53ee8cc1Swenshuai.xi
261*53ee8cc1Swenshuai.xi pQh1->qh_status = QH_STS_IDLE;
262*53ee8cc1Swenshuai.xi
263*53ee8cc1Swenshuai.xi ms_debug_debug ("descheduled qh %p, period = %d u32Frame = %d count = %d, u32PeriodicSched = %d\n",
264*53ee8cc1Swenshuai.xi pQh1, pQh1->u16Period, (int)u32Frame,
265*53ee8cc1Swenshuai.xi osapi_atomic_read(&pQh1->tRefCnt), (int)pEhci->u32PeriodicSched);
266*53ee8cc1Swenshuai.xi
267*53ee8cc1Swenshuai.xi #if 1 // patch from Linux
268*53ee8cc1Swenshuai.xi pQh1->hw_next_qh = EHCI_LIST_END;
269*53ee8cc1Swenshuai.xi wmb ();
270*53ee8cc1Swenshuai.xi #endif
271*53ee8cc1Swenshuai.xi
272*53ee8cc1Swenshuai.xi #if 0
273*53ee8cc1Swenshuai.xi ms_qh_completions(pEhci, pQh1, NULL);
274*53ee8cc1Swenshuai.xi
275*53ee8cc1Swenshuai.xi if (!list_empty(&pQh1->qtd_list) && HCD_IS_RUNNING(pEhci->hcd.state))
276*53ee8cc1Swenshuai.xi {
277*53ee8cc1Swenshuai.xi rc = ms_qh_schedule(pEhci, pQh1); // reschedule
278*53ee8cc1Swenshuai.xi
279*53ee8cc1Swenshuai.xi if (rc != 0)
280*53ee8cc1Swenshuai.xi ms_debug_err("can't reschedule qh %p, err %d\n", pQh1, rc);
281*53ee8cc1Swenshuai.xi }
282*53ee8cc1Swenshuai.xi #endif
283*53ee8cc1Swenshuai.xi }
284*53ee8cc1Swenshuai.xi
ms_check_period(struct ehci_hcd * pEhci,U32 u32Frame,U32 u32uFrame,U32 u32Period,U32 u32Usecs)285*53ee8cc1Swenshuai.xi static int ms_check_period (
286*53ee8cc1Swenshuai.xi struct ehci_hcd *pEhci,
287*53ee8cc1Swenshuai.xi U32 u32Frame,
288*53ee8cc1Swenshuai.xi U32 u32uFrame,
289*53ee8cc1Swenshuai.xi U32 u32Period,
290*53ee8cc1Swenshuai.xi U32 u32Usecs
291*53ee8cc1Swenshuai.xi )
292*53ee8cc1Swenshuai.xi {
293*53ee8cc1Swenshuai.xi int claimed;
294*53ee8cc1Swenshuai.xi
295*53ee8cc1Swenshuai.xi if (u32uFrame >= 8)
296*53ee8cc1Swenshuai.xi return 0;
297*53ee8cc1Swenshuai.xi
298*53ee8cc1Swenshuai.xi u32Usecs = 100 - u32Usecs; // high speed case
299*53ee8cc1Swenshuai.xi #if 0
300*53ee8cc1Swenshuai.xi if ( pEhci->hcd.eSpeed == USB_HIGH_SPEED )
301*53ee8cc1Swenshuai.xi u32Usecs = 100 - u32Usecs;
302*53ee8cc1Swenshuai.xi else
303*53ee8cc1Swenshuai.xi u32Usecs = 900 - u32Usecs;
304*53ee8cc1Swenshuai.xi #endif
305*53ee8cc1Swenshuai.xi
306*53ee8cc1Swenshuai.xi /* period=0, check every micro-frame, uframe==7??? */
307*53ee8cc1Swenshuai.xi if (u32Period == 0) {
308*53ee8cc1Swenshuai.xi do {
309*53ee8cc1Swenshuai.xi for (u32uFrame = 0; u32uFrame < 7; u32uFrame++) {
310*53ee8cc1Swenshuai.xi claimed = ms_periodic_usecs (pEhci, u32Frame, u32uFrame);
311*53ee8cc1Swenshuai.xi if (claimed > u32Usecs)
312*53ee8cc1Swenshuai.xi return 0;
313*53ee8cc1Swenshuai.xi }
314*53ee8cc1Swenshuai.xi } while ((u32Frame += 1) < pEhci->u32PeriodicSize);
315*53ee8cc1Swenshuai.xi
316*53ee8cc1Swenshuai.xi /* just check the specified uframe, at that period */
317*53ee8cc1Swenshuai.xi } else {
318*53ee8cc1Swenshuai.xi do
319*53ee8cc1Swenshuai.xi {
320*53ee8cc1Swenshuai.xi /* un-patch base on linux code */
321*53ee8cc1Swenshuai.xi //if (pEhci->pshadow [u32Frame].ptr)
322*53ee8cc1Swenshuai.xi // return 0;
323*53ee8cc1Swenshuai.xi
324*53ee8cc1Swenshuai.xi claimed = ms_periodic_usecs (pEhci, u32Frame, u32uFrame);
325*53ee8cc1Swenshuai.xi if ((U32)claimed > u32Usecs)
326*53ee8cc1Swenshuai.xi return 0;
327*53ee8cc1Swenshuai.xi
328*53ee8cc1Swenshuai.xi } while ((u32Frame += u32Period) < pEhci->u32PeriodicSize);
329*53ee8cc1Swenshuai.xi }
330*53ee8cc1Swenshuai.xi
331*53ee8cc1Swenshuai.xi /* pass all check! */
332*53ee8cc1Swenshuai.xi return 1;
333*53ee8cc1Swenshuai.xi }
334*53ee8cc1Swenshuai.xi
ms_same_tt(struct usb_device * dev1,struct usb_device * dev2)335*53ee8cc1Swenshuai.xi static int ms_same_tt (struct usb_device *dev1, struct usb_device *dev2)
336*53ee8cc1Swenshuai.xi {
337*53ee8cc1Swenshuai.xi if (!dev1->tt || !dev2->tt)
338*53ee8cc1Swenshuai.xi return 0;
339*53ee8cc1Swenshuai.xi if (dev1->tt != dev2->tt)
340*53ee8cc1Swenshuai.xi return 0;
341*53ee8cc1Swenshuai.xi if (dev1->tt->multi)
342*53ee8cc1Swenshuai.xi return dev1->u32TTPort == dev2->u32TTPort;
343*53ee8cc1Swenshuai.xi else
344*53ee8cc1Swenshuai.xi return 1;
345*53ee8cc1Swenshuai.xi }
346*53ee8cc1Swenshuai.xi
ms_tt_no_collision(struct ehci_hcd * pEhci,U32 u32Period,struct usb_device * dev,U32 frame,U32 uf_mask)347*53ee8cc1Swenshuai.xi static int ms_tt_no_collision (
348*53ee8cc1Swenshuai.xi struct ehci_hcd *pEhci,
349*53ee8cc1Swenshuai.xi U32 u32Period,
350*53ee8cc1Swenshuai.xi struct usb_device *dev,
351*53ee8cc1Swenshuai.xi U32 frame,
352*53ee8cc1Swenshuai.xi U32 uf_mask
353*53ee8cc1Swenshuai.xi )
354*53ee8cc1Swenshuai.xi {
355*53ee8cc1Swenshuai.xi if (u32Period == 0) /* error */
356*53ee8cc1Swenshuai.xi return 0;
357*53ee8cc1Swenshuai.xi
358*53ee8cc1Swenshuai.xi for (; frame < pEhci->u32PeriodicSize; frame += u32Period) {
359*53ee8cc1Swenshuai.xi union ehci_qh_shadow here;
360*53ee8cc1Swenshuai.xi U32 type;
361*53ee8cc1Swenshuai.xi
362*53ee8cc1Swenshuai.xi here = pEhci->pshadow [frame];
363*53ee8cc1Swenshuai.xi type = Q_NEXT_TYPE(pEhci->pPeriodic [frame]);
364*53ee8cc1Swenshuai.xi while (here.ptr) {
365*53ee8cc1Swenshuai.xi switch (type) {
366*53ee8cc1Swenshuai.xi case QH_TYPE:
367*53ee8cc1Swenshuai.xi if (ms_same_tt (dev, here.qh->dev)) {
368*53ee8cc1Swenshuai.xi U32 mask;
369*53ee8cc1Swenshuai.xi
370*53ee8cc1Swenshuai.xi mask = here.qh->hw_ep_state2;
371*53ee8cc1Swenshuai.xi /* "knows" no gap is needed */
372*53ee8cc1Swenshuai.xi mask |= mask >> 8;
373*53ee8cc1Swenshuai.xi if (mask & uf_mask)
374*53ee8cc1Swenshuai.xi break;
375*53ee8cc1Swenshuai.xi }
376*53ee8cc1Swenshuai.xi type = Q_NEXT_TYPE(here.qh->hw_next_qh);
377*53ee8cc1Swenshuai.xi here = here.qh->qh_next;
378*53ee8cc1Swenshuai.xi continue;
379*53ee8cc1Swenshuai.xi default:
380*53ee8cc1Swenshuai.xi ms_debug_err ("periodic frame %d bogus type %d\n",
381*53ee8cc1Swenshuai.xi frame, type);
382*53ee8cc1Swenshuai.xi }
383*53ee8cc1Swenshuai.xi
384*53ee8cc1Swenshuai.xi /* collision or error */
385*53ee8cc1Swenshuai.xi return 0;
386*53ee8cc1Swenshuai.xi }
387*53ee8cc1Swenshuai.xi }
388*53ee8cc1Swenshuai.xi
389*53ee8cc1Swenshuai.xi /* no collision */
390*53ee8cc1Swenshuai.xi return 1;
391*53ee8cc1Swenshuai.xi }
392*53ee8cc1Swenshuai.xi
ms_check_intr_schedule(struct ehci_hcd * pEhci,U32 u32Frame,U32 u32uFrame,const struct ehci_qh * pQh,U32 * c_maskp)393*53ee8cc1Swenshuai.xi static int ms_check_intr_schedule (
394*53ee8cc1Swenshuai.xi struct ehci_hcd *pEhci,
395*53ee8cc1Swenshuai.xi U32 u32Frame,
396*53ee8cc1Swenshuai.xi U32 u32uFrame,
397*53ee8cc1Swenshuai.xi const struct ehci_qh *pQh,
398*53ee8cc1Swenshuai.xi U32 *c_maskp
399*53ee8cc1Swenshuai.xi )
400*53ee8cc1Swenshuai.xi {
401*53ee8cc1Swenshuai.xi int iRetVal = -ENOSPC;
402*53ee8cc1Swenshuai.xi U8 mask = 0;
403*53ee8cc1Swenshuai.xi
404*53ee8cc1Swenshuai.xi /* patch from linux */
405*53ee8cc1Swenshuai.xi if (pQh->c_usecs && u32uFrame >= 6) /* may be FSTN */
406*53ee8cc1Swenshuai.xi goto done;
407*53ee8cc1Swenshuai.xi
408*53ee8cc1Swenshuai.xi if (!ms_check_period (pEhci, u32Frame, u32uFrame, pQh->u16Period, pQh->u8Usecs))
409*53ee8cc1Swenshuai.xi goto done;
410*53ee8cc1Swenshuai.xi if (!pQh->c_usecs)
411*53ee8cc1Swenshuai.xi {
412*53ee8cc1Swenshuai.xi iRetVal = 0;
413*53ee8cc1Swenshuai.xi *c_maskp = 0;
414*53ee8cc1Swenshuai.xi goto done;
415*53ee8cc1Swenshuai.xi }
416*53ee8cc1Swenshuai.xi
417*53ee8cc1Swenshuai.xi #if 1 // adding tt collision check
418*53ee8cc1Swenshuai.xi mask = 0x03 << (u32uFrame + pQh->u8Gap_uf);
419*53ee8cc1Swenshuai.xi //*c_maskp = cpu_to_hc32(ehci, mask << 8);
420*53ee8cc1Swenshuai.xi *c_maskp = (0x03 << (8 + u32uFrame + pQh->u8Gap_uf));
421*53ee8cc1Swenshuai.xi
422*53ee8cc1Swenshuai.xi mask |= 1 << u32uFrame;
423*53ee8cc1Swenshuai.xi if (ms_tt_no_collision (pEhci, pQh->u16Period, pQh->dev, u32Frame, mask)) {
424*53ee8cc1Swenshuai.xi if (!ms_check_period (pEhci, u32Frame, u32uFrame + pQh->u8Gap_uf + 1,
425*53ee8cc1Swenshuai.xi pQh->u16Period, pQh->c_usecs))
426*53ee8cc1Swenshuai.xi goto done;
427*53ee8cc1Swenshuai.xi if (!ms_check_period (pEhci, u32Frame, u32uFrame + pQh->u8Gap_uf,
428*53ee8cc1Swenshuai.xi pQh->u16Period, pQh->c_usecs))
429*53ee8cc1Swenshuai.xi goto done;
430*53ee8cc1Swenshuai.xi iRetVal = 0; // pass all periodic check
431*53ee8cc1Swenshuai.xi }
432*53ee8cc1Swenshuai.xi
433*53ee8cc1Swenshuai.xi #else
434*53ee8cc1Swenshuai.xi if (!ms_check_period (pEhci, u32Frame, u32uFrame + pQh->u8Gap_uf + 1,
435*53ee8cc1Swenshuai.xi pQh->u16Period, pQh->c_usecs))
436*53ee8cc1Swenshuai.xi goto done;
437*53ee8cc1Swenshuai.xi if (!ms_check_period (pEhci, u32Frame, u32uFrame + pQh->u8Gap_uf,
438*53ee8cc1Swenshuai.xi pQh->u16Period, pQh->c_usecs))
439*53ee8cc1Swenshuai.xi goto done;
440*53ee8cc1Swenshuai.xi
441*53ee8cc1Swenshuai.xi *c_maskp = (0x03 << (8 + u32uFrame + pQh->u8Gap_uf));
442*53ee8cc1Swenshuai.xi iRetVal = 0;
443*53ee8cc1Swenshuai.xi #endif
444*53ee8cc1Swenshuai.xi done:
445*53ee8cc1Swenshuai.xi return iRetVal;
446*53ee8cc1Swenshuai.xi }
447*53ee8cc1Swenshuai.xi
ms_qh_link_periodic(struct ehci_hcd * ehci,struct ehci_qh * qh)448*53ee8cc1Swenshuai.xi static int ms_qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
449*53ee8cc1Swenshuai.xi {
450*53ee8cc1Swenshuai.xi unsigned i;
451*53ee8cc1Swenshuai.xi unsigned period = qh->u16Period;
452*53ee8cc1Swenshuai.xi
453*53ee8cc1Swenshuai.xi ms_debug_debug ("link qh%d-%04x/%p start %d [%d/%d us]\n",
454*53ee8cc1Swenshuai.xi period, qh->hw_ep_state2 & (QH_CMASK | QH_SMASK),
455*53ee8cc1Swenshuai.xi qh, qh->u16Start, qh->u8Usecs, qh->c_usecs);
456*53ee8cc1Swenshuai.xi
457*53ee8cc1Swenshuai.xi /* high bandwidth, or otherwise every microframe */
458*53ee8cc1Swenshuai.xi if (period == 0)
459*53ee8cc1Swenshuai.xi period = 1;
460*53ee8cc1Swenshuai.xi
461*53ee8cc1Swenshuai.xi for (i = qh->u16Start; i < ehci->u32PeriodicSize; i += period) {
462*53ee8cc1Swenshuai.xi union ehci_qh_shadow *prev = &ehci->pshadow[i];
463*53ee8cc1Swenshuai.xi U32 *hw_p = &ehci->pPeriodic[i];
464*53ee8cc1Swenshuai.xi union ehci_qh_shadow here = *prev;
465*53ee8cc1Swenshuai.xi //U32 type = 0;
466*53ee8cc1Swenshuai.xi
467*53ee8cc1Swenshuai.xi /* skip the iso nodes at list head */
468*53ee8cc1Swenshuai.xi #if 0
469*53ee8cc1Swenshuai.xi while (here.ptr) {
470*53ee8cc1Swenshuai.xi type = Q_NEXT_TYPE(*hw_p);
471*53ee8cc1Swenshuai.xi if (type == QH_TYPE)
472*53ee8cc1Swenshuai.xi break;
473*53ee8cc1Swenshuai.xi prev = periodic_next_shadow(ehci, prev, type);
474*53ee8cc1Swenshuai.xi hw_p = shadow_next_periodic(ehci, &here, type);
475*53ee8cc1Swenshuai.xi here = *prev;
476*53ee8cc1Swenshuai.xi }
477*53ee8cc1Swenshuai.xi #endif
478*53ee8cc1Swenshuai.xi
479*53ee8cc1Swenshuai.xi /* sorting each branch by period (slow-->fast)
480*53ee8cc1Swenshuai.xi * enables sharing interior tree nodes
481*53ee8cc1Swenshuai.xi */
482*53ee8cc1Swenshuai.xi while (here.ptr && qh != here.qh) {
483*53ee8cc1Swenshuai.xi if (qh->u16Period > here.qh->u16Period)
484*53ee8cc1Swenshuai.xi break;
485*53ee8cc1Swenshuai.xi prev = &here.qh->qh_next;
486*53ee8cc1Swenshuai.xi hw_p = &here.qh->hw_next_qh;
487*53ee8cc1Swenshuai.xi here = *prev;
488*53ee8cc1Swenshuai.xi }
489*53ee8cc1Swenshuai.xi /* link in this qh, unless some earlier pass did that */
490*53ee8cc1Swenshuai.xi if (qh != here.qh) {
491*53ee8cc1Swenshuai.xi qh->qh_next = here;
492*53ee8cc1Swenshuai.xi if (here.qh)
493*53ee8cc1Swenshuai.xi qh->hw_next_qh = *hw_p;
494*53ee8cc1Swenshuai.xi wmb ();
495*53ee8cc1Swenshuai.xi prev->qh = qh;
496*53ee8cc1Swenshuai.xi *hw_p = QH_NEXT (qh->qh_dma_addr);
497*53ee8cc1Swenshuai.xi }
498*53ee8cc1Swenshuai.xi }
499*53ee8cc1Swenshuai.xi qh->qh_status = QH_STS_LINKED;
500*53ee8cc1Swenshuai.xi qh->xacterrs = 0;
501*53ee8cc1Swenshuai.xi ms_qh_get (qh);
502*53ee8cc1Swenshuai.xi
503*53ee8cc1Swenshuai.xi // TODO: update bandwidth per ep if required
504*53ee8cc1Swenshuai.xi
505*53ee8cc1Swenshuai.xi /* maybe enable periodic schedule processing */
506*53ee8cc1Swenshuai.xi return ms_enable_periodic(ehci);
507*53ee8cc1Swenshuai.xi }
508*53ee8cc1Swenshuai.xi
ms_qh_schedule(struct ehci_hcd * pEhci,struct ehci_qh * pQh)509*53ee8cc1Swenshuai.xi static int ms_qh_schedule (struct ehci_hcd *pEhci, struct ehci_qh *pQh)
510*53ee8cc1Swenshuai.xi {
511*53ee8cc1Swenshuai.xi int iStatus;
512*53ee8cc1Swenshuai.xi U32 u32uFrame1;
513*53ee8cc1Swenshuai.xi U32 u32_C_mask1;
514*53ee8cc1Swenshuai.xi U32 u32Frame1;
515*53ee8cc1Swenshuai.xi
516*53ee8cc1Swenshuai.xi pQh->hw_next_qh = EHCI_LIST_END;
517*53ee8cc1Swenshuai.xi u32Frame1 = pQh->u16Start;
518*53ee8cc1Swenshuai.xi
519*53ee8cc1Swenshuai.xi if (u32Frame1 < pQh->u16Period)
520*53ee8cc1Swenshuai.xi {
521*53ee8cc1Swenshuai.xi u32uFrame1 = ms_find_1st_set (pQh->hw_ep_state2 & 0x00ff);
522*53ee8cc1Swenshuai.xi iStatus = ms_check_intr_schedule (pEhci, u32Frame1, --u32uFrame1,
523*53ee8cc1Swenshuai.xi pQh, &u32_C_mask1);
524*53ee8cc1Swenshuai.xi }
525*53ee8cc1Swenshuai.xi else
526*53ee8cc1Swenshuai.xi {
527*53ee8cc1Swenshuai.xi u32uFrame1 = 0;
528*53ee8cc1Swenshuai.xi u32_C_mask1 = 0;
529*53ee8cc1Swenshuai.xi iStatus = -ENOSPC;
530*53ee8cc1Swenshuai.xi /* the 1st path, pQh->u16Start is initialed as NOFRAME(65535) */
531*53ee8cc1Swenshuai.xi }
532*53ee8cc1Swenshuai.xi
533*53ee8cc1Swenshuai.xi if (iStatus)
534*53ee8cc1Swenshuai.xi {
535*53ee8cc1Swenshuai.xi if (pQh->u16Period) {
536*53ee8cc1Swenshuai.xi //u32Frame1 = pQh->u16Period - 1;
537*53ee8cc1Swenshuai.xi //do
538*53ee8cc1Swenshuai.xi //{
539*53ee8cc1Swenshuai.xi int i;
540*53ee8cc1Swenshuai.xi
541*53ee8cc1Swenshuai.xi for (i = pQh->u16Period; iStatus && i > 0; --i) {
542*53ee8cc1Swenshuai.xi /* patch from linux, to generate relative random start frame */
543*53ee8cc1Swenshuai.xi u32Frame1 = ++pEhci->u32random_frm % pQh->u16Period;
544*53ee8cc1Swenshuai.xi for (u32uFrame1 = 0; u32uFrame1 < 8; u32uFrame1++)
545*53ee8cc1Swenshuai.xi {
546*53ee8cc1Swenshuai.xi iStatus = ms_check_intr_schedule (pEhci, u32Frame1, u32uFrame1, pQh, &u32_C_mask1);
547*53ee8cc1Swenshuai.xi if (iStatus == 0) // first fit @ uframe
548*53ee8cc1Swenshuai.xi {
549*53ee8cc1Swenshuai.xi ms_debug_msg("[USB] first fit (frame,uframe)=(%d,%d)\n", u32Frame1, u32uFrame1);
550*53ee8cc1Swenshuai.xi break;
551*53ee8cc1Swenshuai.xi }
552*53ee8cc1Swenshuai.xi }
553*53ee8cc1Swenshuai.xi //} while (iStatus && u32Frame1--);
554*53ee8cc1Swenshuai.xi }
555*53ee8cc1Swenshuai.xi /* pQh->u16Period == 0 means every uframe */
556*53ee8cc1Swenshuai.xi } else {
557*53ee8cc1Swenshuai.xi u32Frame1 = 0;
558*53ee8cc1Swenshuai.xi iStatus = ms_check_intr_schedule (pEhci, 0, 0, pQh, &u32_C_mask1);
559*53ee8cc1Swenshuai.xi }
560*53ee8cc1Swenshuai.xi if (iStatus) // no time slot fit
561*53ee8cc1Swenshuai.xi {
562*53ee8cc1Swenshuai.xi ms_debug_msg("[USB] no time slot fit\n");
563*53ee8cc1Swenshuai.xi goto done;
564*53ee8cc1Swenshuai.xi }
565*53ee8cc1Swenshuai.xi pQh->u16Start = u32Frame1;
566*53ee8cc1Swenshuai.xi
567*53ee8cc1Swenshuai.xi pQh->hw_ep_state2 &= ~0xffff; // clear QH_CMASK and QH_SMASK
568*53ee8cc1Swenshuai.xi pQh->hw_ep_state2 |= (pQh->u16Period ? (1 << u32uFrame1) : QH_SMASK) | u32_C_mask1;
569*53ee8cc1Swenshuai.xi }
570*53ee8cc1Swenshuai.xi else
571*53ee8cc1Swenshuai.xi ms_debug_msg ("reused previous pQh %p schedule", pQh);
572*53ee8cc1Swenshuai.xi
573*53ee8cc1Swenshuai.xi /* ms_qh_link_periodic() moved, patch as linux 3.10.x */
574*53ee8cc1Swenshuai.xi //iStatus = ms_qh_link_periodic (pEhci, pQh);
575*53ee8cc1Swenshuai.xi
576*53ee8cc1Swenshuai.xi ms_debug_msg ("[ms_qh_schedule] qh->hw_info2:%x ,usecs %d/%d, period %d.0 starting %d.%d (gap %d)\n",
577*53ee8cc1Swenshuai.xi pQh->hw_ep_state2 & (QH_CMASK | QH_SMASK), pQh->u8Usecs, pQh->c_usecs, pQh->u16Period, (int)u32Frame1, (int)u32uFrame1, pQh->u8Gap_uf);
578*53ee8cc1Swenshuai.xi #if 0
579*53ee8cc1Swenshuai.xi pQh->qh_status = QH_STS_LINKED;
580*53ee8cc1Swenshuai.xi ms_debug_msg ("[ms_qh_schedule] scheduled pQh %p usecs %d/%d period %d.0 starting %d.%d (gap %d)\n",
581*53ee8cc1Swenshuai.xi pQh, pQh->u8Usecs, pQh->c_usecs, pQh->u16Period, (int)u32Frame1, (int)u32uFrame1, pQh->u8Gap_uf);
582*53ee8cc1Swenshuai.xi do
583*53ee8cc1Swenshuai.xi {
584*53ee8cc1Swenshuai.xi if (pEhci->pshadow [u32Frame1].ptr != 0)
585*53ee8cc1Swenshuai.xi {
586*53ee8cc1Swenshuai.xi USB_ASSERT (0, "pEhci->pshadow [u32Frame1].ptr != 0\n");
587*53ee8cc1Swenshuai.xi }
588*53ee8cc1Swenshuai.xi else
589*53ee8cc1Swenshuai.xi {
590*53ee8cc1Swenshuai.xi pEhci->pshadow [u32Frame1].qh = ms_qh_get (pQh);
591*53ee8cc1Swenshuai.xi pEhci->pPeriodic [u32Frame1] = QH_NEXT (pQh->qh_dma_addr);
592*53ee8cc1Swenshuai.xi }
593*53ee8cc1Swenshuai.xi wmb ();
594*53ee8cc1Swenshuai.xi u32Frame1 += pQh->u16Period;
595*53ee8cc1Swenshuai.xi } while (u32Frame1 < pEhci->u32PeriodicSize);
596*53ee8cc1Swenshuai.xi
597*53ee8cc1Swenshuai.xi if (!pEhci->u32PeriodicSched++)
598*53ee8cc1Swenshuai.xi iStatus = ms_enable_periodic (pEhci);
599*53ee8cc1Swenshuai.xi #endif
600*53ee8cc1Swenshuai.xi done:
601*53ee8cc1Swenshuai.xi return iStatus;
602*53ee8cc1Swenshuai.xi }
603*53ee8cc1Swenshuai.xi
ms_intr_submit(struct ehci_hcd * pEhci,struct urb * pUrb,struct list_head * qtd_list)604*53ee8cc1Swenshuai.xi static int ms_intr_submit (
605*53ee8cc1Swenshuai.xi struct ehci_hcd *pEhci,
606*53ee8cc1Swenshuai.xi struct urb *pUrb,
607*53ee8cc1Swenshuai.xi struct list_head *qtd_list
608*53ee8cc1Swenshuai.xi )
609*53ee8cc1Swenshuai.xi {
610*53ee8cc1Swenshuai.xi U32 epnum1;
611*53ee8cc1Swenshuai.xi U32 u32Flags;
612*53ee8cc1Swenshuai.xi struct ehci_qh *pQh1;
613*53ee8cc1Swenshuai.xi struct s_hcd_dev *dev;
614*53ee8cc1Swenshuai.xi int is_input;
615*53ee8cc1Swenshuai.xi int status = 0;
616*53ee8cc1Swenshuai.xi struct list_head stEmpty;
617*53ee8cc1Swenshuai.xi
618*53ee8cc1Swenshuai.xi epnum1 = usb_pipeendpoint (pUrb->u32Pipe);
619*53ee8cc1Swenshuai.xi is_input = usb_pipein (pUrb->u32Pipe);
620*53ee8cc1Swenshuai.xi if (is_input && !usb_pipecontrol(pUrb->u32Pipe))
621*53ee8cc1Swenshuai.xi epnum1 |= 0x10;
622*53ee8cc1Swenshuai.xi
623*53ee8cc1Swenshuai.xi osapi_spin_lock_irqsave (&pEhci->tHcdLock, u32Flags);
624*53ee8cc1Swenshuai.xi dev = (struct s_hcd_dev *)pUrb->dev->hcpriv;
625*53ee8cc1Swenshuai.xi
626*53ee8cc1Swenshuai.xi // TODO: HC accessible decision, if not jump to done
627*53ee8cc1Swenshuai.xi
628*53ee8cc1Swenshuai.xi ms_list_init (&stEmpty);
629*53ee8cc1Swenshuai.xi pQh1 = ms_qh_append_tds (pEhci, pUrb, &stEmpty, epnum1, &dev->ep [epnum1]);
630*53ee8cc1Swenshuai.xi if (pQh1 == 0)
631*53ee8cc1Swenshuai.xi {
632*53ee8cc1Swenshuai.xi status = -ENOMEM;
633*53ee8cc1Swenshuai.xi goto done;
634*53ee8cc1Swenshuai.xi }
635*53ee8cc1Swenshuai.xi if (pQh1->qh_status == QH_STS_IDLE)
636*53ee8cc1Swenshuai.xi {
637*53ee8cc1Swenshuai.xi if ((status = ms_qh_schedule (pEhci, pQh1)) != 0)
638*53ee8cc1Swenshuai.xi goto done;
639*53ee8cc1Swenshuai.xi }
640*53ee8cc1Swenshuai.xi
641*53ee8cc1Swenshuai.xi pQh1 = ms_qh_append_tds (pEhci, pUrb, qtd_list, epnum1, &dev->ep [epnum1]);
642*53ee8cc1Swenshuai.xi USB_ASSERT(pQh1!=0, "BUG_ON()!!!! pQh1==NULL\n");
643*53ee8cc1Swenshuai.xi
644*53ee8cc1Swenshuai.xi /* patch from linux code from 3.10.x */
645*53ee8cc1Swenshuai.xi #if 1
646*53ee8cc1Swenshuai.xi /* stuff into the periodic schedule */
647*53ee8cc1Swenshuai.xi if (pQh1->qh_status == QH_STS_IDLE) {
648*53ee8cc1Swenshuai.xi ms_qh_refresh(pEhci, pQh1);
649*53ee8cc1Swenshuai.xi ms_qh_link_periodic(pEhci, pQh1);
650*53ee8cc1Swenshuai.xi }
651*53ee8cc1Swenshuai.xi #endif
652*53ee8cc1Swenshuai.xi Chip_Flush_Memory();
653*53ee8cc1Swenshuai.xi
654*53ee8cc1Swenshuai.xi done:
655*53ee8cc1Swenshuai.xi osapi_spin_unlock_irqrestore (&pEhci->tHcdLock, u32Flags);
656*53ee8cc1Swenshuai.xi if (status)
657*53ee8cc1Swenshuai.xi ms_qtd_register_free (pEhci, qtd_list);
658*53ee8cc1Swenshuai.xi
659*53ee8cc1Swenshuai.xi return status;
660*53ee8cc1Swenshuai.xi }
661*53ee8cc1Swenshuai.xi
ms_intr_complete(struct ehci_hcd * pEhci,struct ehci_qh * pQh,struct stPtRegs * pRegs)662*53ee8cc1Swenshuai.xi static U32 ms_intr_complete (
663*53ee8cc1Swenshuai.xi struct ehci_hcd *pEhci,
664*53ee8cc1Swenshuai.xi struct ehci_qh *pQh,
665*53ee8cc1Swenshuai.xi struct stPtRegs *pRegs
666*53ee8cc1Swenshuai.xi )
667*53ee8cc1Swenshuai.xi {
668*53ee8cc1Swenshuai.xi U32 u32Count;
669*53ee8cc1Swenshuai.xi if ((pQh->hw_token & QTD_STS_ACT) != 0)
670*53ee8cc1Swenshuai.xi return 0;
671*53ee8cc1Swenshuai.xi
672*53ee8cc1Swenshuai.xi if (ms_is_empty_list (&pQh->qtd_list))
673*53ee8cc1Swenshuai.xi {
674*53ee8cc1Swenshuai.xi ms_debug_msg ("[intr qh] %p no TDs?", pQh);
675*53ee8cc1Swenshuai.xi return 0;
676*53ee8cc1Swenshuai.xi }
677*53ee8cc1Swenshuai.xi
678*53ee8cc1Swenshuai.xi u32Count = ms_qh_completions (pEhci, pQh, pRegs);
679*53ee8cc1Swenshuai.xi if (ms_is_empty_list (&pQh->qtd_list))
680*53ee8cc1Swenshuai.xi ms_intr_deschedule (pEhci, pQh);
681*53ee8cc1Swenshuai.xi return u32Count;
682*53ee8cc1Swenshuai.xi }
683*53ee8cc1Swenshuai.xi
684*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
685*53ee8cc1Swenshuai.xi
ms_scan_periodic(struct ehci_hcd * pEhci,struct stPtRegs * pRegs)686*53ee8cc1Swenshuai.xi static void ms_scan_periodic (struct ehci_hcd *pEhci, struct stPtRegs *pRegs)
687*53ee8cc1Swenshuai.xi {
688*53ee8cc1Swenshuai.xi U32 u32Frame, u32Clock, u32clock_uframe, u32Mod;
689*53ee8cc1Swenshuai.xi U32 u32Count = 0;
690*53ee8cc1Swenshuai.xi
691*53ee8cc1Swenshuai.xi u32Mod = pEhci->u32PeriodicSize << 3;
692*53ee8cc1Swenshuai.xi u32Frame = pEhci->iNextUframe >> 3;
693*53ee8cc1Swenshuai.xi if (HCD_IS_RUNNING (pEhci->hcd.state))
694*53ee8cc1Swenshuai.xi u32clock_uframe = hcd_reg_readl ((U32)&pEhci->op_regs->frindex);
695*53ee8cc1Swenshuai.xi else
696*53ee8cc1Swenshuai.xi //u32clock_uframe = (u32Frame << 3) - 1;
697*53ee8cc1Swenshuai.xi u32clock_uframe = pEhci->iNextUframe + u32Mod - 1;
698*53ee8cc1Swenshuai.xi u32clock_uframe %= u32Mod;
699*53ee8cc1Swenshuai.xi u32Clock = u32clock_uframe >> 3;
700*53ee8cc1Swenshuai.xi
701*53ee8cc1Swenshuai.xi for (;;)
702*53ee8cc1Swenshuai.xi {
703*53ee8cc1Swenshuai.xi union ehci_qh_shadow q, *q_p;
704*53ee8cc1Swenshuai.xi U32 u32Type, *hw_p;
705*53ee8cc1Swenshuai.xi
706*53ee8cc1Swenshuai.xi restart:
707*53ee8cc1Swenshuai.xi q_p = &pEhci->pshadow [u32Frame];
708*53ee8cc1Swenshuai.xi hw_p = &pEhci->pPeriodic [u32Frame];
709*53ee8cc1Swenshuai.xi q.ptr = q_p->ptr;
710*53ee8cc1Swenshuai.xi u32Type = Q_NEXT_TYPE (*hw_p);
711*53ee8cc1Swenshuai.xi u32Count = 0;
712*53ee8cc1Swenshuai.xi
713*53ee8cc1Swenshuai.xi while (q.ptr != 0)
714*53ee8cc1Swenshuai.xi {
715*53ee8cc1Swenshuai.xi int last;
716*53ee8cc1Swenshuai.xi union ehci_qh_shadow temp;
717*53ee8cc1Swenshuai.xi
718*53ee8cc1Swenshuai.xi if (u32Type == QH_TYPE)
719*53ee8cc1Swenshuai.xi {
720*53ee8cc1Swenshuai.xi last = (q.qh->hw_next_qh == EHCI_LIST_END);
721*53ee8cc1Swenshuai.xi temp = q.qh->qh_next;
722*53ee8cc1Swenshuai.xi u32Type = Q_NEXT_TYPE (q.qh->hw_next_qh);
723*53ee8cc1Swenshuai.xi u32Count = ms_intr_complete (pEhci, ms_qh_get (q.qh), pRegs);
724*53ee8cc1Swenshuai.xi ms_qh_put (pEhci, q.qh);
725*53ee8cc1Swenshuai.xi q = temp;
726*53ee8cc1Swenshuai.xi }
727*53ee8cc1Swenshuai.xi else
728*53ee8cc1Swenshuai.xi {
729*53ee8cc1Swenshuai.xi ms_debug_msg ("corrupt u32Type %d u32Frame %d shadow %p",
730*53ee8cc1Swenshuai.xi (int)u32Type, (int)u32Frame, q.ptr);
731*53ee8cc1Swenshuai.xi // BUG ();
732*53ee8cc1Swenshuai.xi last = 1;
733*53ee8cc1Swenshuai.xi q.ptr = 0;
734*53ee8cc1Swenshuai.xi }
735*53ee8cc1Swenshuai.xi
736*53ee8cc1Swenshuai.xi if (q.ptr == 0 && !last)
737*53ee8cc1Swenshuai.xi goto restart;
738*53ee8cc1Swenshuai.xi if (u32Count) {
739*53ee8cc1Swenshuai.xi if (pEhci->u32PeriodicSched > 0)
740*53ee8cc1Swenshuai.xi goto restart;
741*53ee8cc1Swenshuai.xi u32Frame = u32Clock;
742*53ee8cc1Swenshuai.xi break;
743*53ee8cc1Swenshuai.xi }
744*53ee8cc1Swenshuai.xi }
745*53ee8cc1Swenshuai.xi
746*53ee8cc1Swenshuai.xi if (u32Frame == u32Clock)
747*53ee8cc1Swenshuai.xi {
748*53ee8cc1Swenshuai.xi U32 now;
749*53ee8cc1Swenshuai.xi
750*53ee8cc1Swenshuai.xi if (!HCD_IS_RUNNING (pEhci->hcd.state) || pEhci->u32PeriodicSched == 0)
751*53ee8cc1Swenshuai.xi break;
752*53ee8cc1Swenshuai.xi
753*53ee8cc1Swenshuai.xi pEhci->iNextUframe = u32clock_uframe;
754*53ee8cc1Swenshuai.xi now = hcd_reg_readl ((U32)&pEhci->op_regs->frindex) % u32Mod;
755*53ee8cc1Swenshuai.xi if (u32clock_uframe == now)
756*53ee8cc1Swenshuai.xi break;
757*53ee8cc1Swenshuai.xi
758*53ee8cc1Swenshuai.xi u32clock_uframe = now;
759*53ee8cc1Swenshuai.xi u32Clock = u32clock_uframe >> 3;
760*53ee8cc1Swenshuai.xi }
761*53ee8cc1Swenshuai.xi else
762*53ee8cc1Swenshuai.xi u32Frame = (u32Frame + 1) % pEhci->u32PeriodicSize;
763*53ee8cc1Swenshuai.xi }
764*53ee8cc1Swenshuai.xi }
765*53ee8cc1Swenshuai.xi
766