xref: /utopia/UTPA2-700.0.x/modules/usb/drv/usb_ecos/newhost/drvEhciHcd.c (revision 53ee8cc121a030b8d368113ac3e966b4705770ef)
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 
79*53ee8cc1Swenshuai.xi #include "include/drvConfig.h"
80*53ee8cc1Swenshuai.xi 
81*53ee8cc1Swenshuai.xi #ifdef CONFIG_USB_DEBUG
82*53ee8cc1Swenshuai.xi   #define DEBUG
83*53ee8cc1Swenshuai.xi #else
84*53ee8cc1Swenshuai.xi   #undef DEBUG
85*53ee8cc1Swenshuai.xi #endif
86*53ee8cc1Swenshuai.xi 
87*53ee8cc1Swenshuai.xi //#include <MsCommon.h> // NUSED
88*53ee8cc1Swenshuai.xi //#include "include/drvCompiler.h" // NUSED
89*53ee8cc1Swenshuai.xi //#include "include/drvPorts.h" // NUSED
90*53ee8cc1Swenshuai.xi #include "include/drvErrno.h"
91*53ee8cc1Swenshuai.xi //#include "include/drvPCIMEM.h" // NUSED
92*53ee8cc1Swenshuai.xi //#include "include/drvList.h" // NUSED
93*53ee8cc1Swenshuai.xi //#include "include/drvTimer.h" // NUSED
94*53ee8cc1Swenshuai.xi //#include "include/drvKernel.h" // NUSED
95*53ee8cc1Swenshuai.xi // USB related implemented header files
96*53ee8cc1Swenshuai.xi #include "include/drvUSBHost.h"
97*53ee8cc1Swenshuai.xi #include "drvUsbd.h"
98*53ee8cc1Swenshuai.xi //#include "include/drvCPE_EHCI.h" // NUSED
99*53ee8cc1Swenshuai.xi #include "drvEHCI.h"
100*53ee8cc1Swenshuai.xi #include "drvUSBHwCtl.h"
101*53ee8cc1Swenshuai.xi //#include "include/drvCPE_AMBA.h" // NUSED
102*53ee8cc1Swenshuai.xi //#include "drvUSB.h" // NUSED
103*53ee8cc1Swenshuai.xi /* should applying drvUsbHostConfig.h (inside drvUSBHwctl.h) */
104*53ee8cc1Swenshuai.xi 
105*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
106*53ee8cc1Swenshuai.xi 
107*53ee8cc1Swenshuai.xi 
108*53ee8cc1Swenshuai.xi #define DRIVER_VERSION "eCos Newhost"
109*53ee8cc1Swenshuai.xi #define DRIVER_AUTHOR "Mstar USB Team"
110*53ee8cc1Swenshuai.xi #define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver"
111*53ee8cc1Swenshuai.xi 
112*53ee8cc1Swenshuai.xi // #define EHCI_VERBOSE_DEBUG
113*53ee8cc1Swenshuai.xi //#define EHCI_TD_DEBUG
114*53ee8cc1Swenshuai.xi #define ENABLE_QH_REFRESH
115*53ee8cc1Swenshuai.xi 
116*53ee8cc1Swenshuai.xi #ifdef DEBUG
117*53ee8cc1Swenshuai.xi #define EHCI_STATS
118*53ee8cc1Swenshuai.xi #endif
119*53ee8cc1Swenshuai.xi 
120*53ee8cc1Swenshuai.xi #define  EHCI_RL_NAKCNT     4  /* enable nak throttle mode, spec 4.9 */
121*53ee8cc1Swenshuai.xi #define  EHCI_RL_NAKCNT_TT  0  /* disable nak throttle mode when TT */
122*53ee8cc1Swenshuai.xi #define  EHCI_HI_BW_MULT_HS 1  /* high bandwidth file, transactions number/uframe, spec 4.10.3 */
123*53ee8cc1Swenshuai.xi #define  EHCI_HI_BW_MULT_TT 1
124*53ee8cc1Swenshuai.xi 
125*53ee8cc1Swenshuai.xi #ifdef CONFIG_HC_TEST
126*53ee8cc1Swenshuai.xi #define  EHCI_PERIODIC_FLS      0  /* (max) 1024 frame for schedule */
127*53ee8cc1Swenshuai.xi #else
128*53ee8cc1Swenshuai.xi #define  EHCI_PERIODIC_FLS      2  /* (minl) 256 frame schedule */
129*53ee8cc1Swenshuai.xi #endif
130*53ee8cc1Swenshuai.xi /* Initial IRQ latency:  lower than default */
131*53ee8cc1Swenshuai.xi static int log2_irq_thresh = 0;    // 0 to 6
132*53ee8cc1Swenshuai.xi #define    INTR_MASK (USBSTS_IAA | USBSTS_FATAL | USBSTS_PCD | USBSTS_ERR | USBSTS_INT)
133*53ee8cc1Swenshuai.xi 
134*53ee8cc1Swenshuai.xi #if defined(ENABLE_16US_EOF1)
135*53ee8cc1Swenshuai.xi static U32 park_eco = 3;
136*53ee8cc1Swenshuai.xi #else
137*53ee8cc1Swenshuai.xi static U32 park_eco = 0;
138*53ee8cc1Swenshuai.xi #endif
139*53ee8cc1Swenshuai.xi 
140*53ee8cc1Swenshuai.xi /* Debug print definition */
141*53ee8cc1Swenshuai.xi #define DBG_MSG
142*53ee8cc1Swenshuai.xi #define DBG_WARN
143*53ee8cc1Swenshuai.xi //#define DBG_FUNC
144*53ee8cc1Swenshuai.xi #undef  ms_debug_msg
145*53ee8cc1Swenshuai.xi #undef  ms_debug_warn
146*53ee8cc1Swenshuai.xi #undef  ms_debug_func
147*53ee8cc1Swenshuai.xi 
148*53ee8cc1Swenshuai.xi #ifdef DBG_MSG
149*53ee8cc1Swenshuai.xi #define ms_debug_msg(fmt, arg...)    \
150*53ee8cc1Swenshuai.xi         do {diag_printf(fmt, ##arg);} while(0)
151*53ee8cc1Swenshuai.xi #else
152*53ee8cc1Swenshuai.xi #define ms_debug_msg(fmt, arg...) do {} while (0)
153*53ee8cc1Swenshuai.xi #endif
154*53ee8cc1Swenshuai.xi 
155*53ee8cc1Swenshuai.xi #ifdef DBG_WARN
156*53ee8cc1Swenshuai.xi #define ms_debug_warn(fmt, arg...)    \
157*53ee8cc1Swenshuai.xi         do {diag_printf(fmt, ##arg);} while(0)
158*53ee8cc1Swenshuai.xi #else
159*53ee8cc1Swenshuai.xi #define ms_debug_warn(fmt, arg...) do {} while (0)
160*53ee8cc1Swenshuai.xi #endif
161*53ee8cc1Swenshuai.xi 
162*53ee8cc1Swenshuai.xi #ifdef DBG_FUNC
163*53ee8cc1Swenshuai.xi #define ms_debug_func(fmt, arg...)    \
164*53ee8cc1Swenshuai.xi         do {diag_printf(fmt, ##arg);} while(0)
165*53ee8cc1Swenshuai.xi #else
166*53ee8cc1Swenshuai.xi #define ms_debug_func(fmt, arg...) do {} while (0)
167*53ee8cc1Swenshuai.xi #endif
168*53ee8cc1Swenshuai.xi 
169*53ee8cc1Swenshuai.xi static void ms_unlink_async(struct ehci_hcd *, struct ehci_qh *);
170*53ee8cc1Swenshuai.xi static void ms_intr_deschedule(struct ehci_hcd *, struct ehci_qh *);
171*53ee8cc1Swenshuai.xi static int ms_qh_schedule(struct ehci_hcd *, struct ehci_qh *);
172*53ee8cc1Swenshuai.xi 
173*53ee8cc1Swenshuai.xi void ms_ehci_stoprun_setting(MS_U8 bOption, struct ehci_hcd *ehci);
174*53ee8cc1Swenshuai.xi extern void Chip_Flush_Memory(void);
175*53ee8cc1Swenshuai.xi extern void Chip_Read_Memory(void);
176*53ee8cc1Swenshuai.xi 
177*53ee8cc1Swenshuai.xi #ifdef EHCI_TD_DEBUG
Dump_TD(unsigned int addr,int is_qh)178*53ee8cc1Swenshuai.xi void Dump_TD(unsigned int addr, int is_qh)
179*53ee8cc1Swenshuai.xi {
180*53ee8cc1Swenshuai.xi 	int i;
181*53ee8cc1Swenshuai.xi 
182*53ee8cc1Swenshuai.xi 	diag_printf("[USB] %s:%x -> \n", is_qh?"QH":"QTD", addr);
183*53ee8cc1Swenshuai.xi 	for (i = 0; i < 0x20 ; i = i+4)
184*53ee8cc1Swenshuai.xi 	{
185*53ee8cc1Swenshuai.xi 		diag_printf("%02x ", *(unsigned char volatile *)(addr + i+ 3));
186*53ee8cc1Swenshuai.xi 		diag_printf("%02x ", *(unsigned char volatile *)(addr + i+ 2));
187*53ee8cc1Swenshuai.xi 		diag_printf("%02x ", *(unsigned char volatile *)(addr + i+ 1));
188*53ee8cc1Swenshuai.xi 		diag_printf("%02x ", *(unsigned char volatile *)(addr + i));
189*53ee8cc1Swenshuai.xi 		diag_printf("\n");
190*53ee8cc1Swenshuai.xi 	}
191*53ee8cc1Swenshuai.xi }
192*53ee8cc1Swenshuai.xi #endif
193*53ee8cc1Swenshuai.xi 
ms_check_status(U32 * pPtr,U32 u32Mask,U32 u32Done,int us)194*53ee8cc1Swenshuai.xi static int ms_check_status (U32 *pPtr, U32 u32Mask, U32 u32Done, int us)
195*53ee8cc1Swenshuai.xi {
196*53ee8cc1Swenshuai.xi     U32  u32regv;
197*53ee8cc1Swenshuai.xi 
198*53ee8cc1Swenshuai.xi     ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
199*53ee8cc1Swenshuai.xi     do {
200*53ee8cc1Swenshuai.xi         u32regv = hcd_reg_readl ((U32)pPtr);
201*53ee8cc1Swenshuai.xi         if (u32regv == ~(U32)0)    /* card removed */
202*53ee8cc1Swenshuai.xi         {
203*53ee8cc1Swenshuai.xi             ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
204*53ee8cc1Swenshuai.xi             return -ENODEV;
205*53ee8cc1Swenshuai.xi         }
206*53ee8cc1Swenshuai.xi 
207*53ee8cc1Swenshuai.xi         u32regv &= u32Mask;
208*53ee8cc1Swenshuai.xi         if (u32regv == u32Done)
209*53ee8cc1Swenshuai.xi             return 0;
210*53ee8cc1Swenshuai.xi 
211*53ee8cc1Swenshuai.xi         udelay (1);
212*53ee8cc1Swenshuai.xi         us--;
213*53ee8cc1Swenshuai.xi     } while (us > 0);
214*53ee8cc1Swenshuai.xi 
215*53ee8cc1Swenshuai.xi     ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
216*53ee8cc1Swenshuai.xi     return -ETIMEDOUT;
217*53ee8cc1Swenshuai.xi }
218*53ee8cc1Swenshuai.xi 
ms_ehci_halt(struct ehci_hcd * pEhci)219*53ee8cc1Swenshuai.xi static int ms_ehci_halt (struct ehci_hcd *pEhci)
220*53ee8cc1Swenshuai.xi {
221*53ee8cc1Swenshuai.xi     U32  u32regv = hcd_reg_readl ((U32)&pEhci->op_regs->usbsts);
222*53ee8cc1Swenshuai.xi 
223*53ee8cc1Swenshuai.xi     ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
224*53ee8cc1Swenshuai.xi     if ((u32regv & USBSTS_HALT) != 0)
225*53ee8cc1Swenshuai.xi     {
226*53ee8cc1Swenshuai.xi         ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
227*53ee8cc1Swenshuai.xi         return 0;
228*53ee8cc1Swenshuai.xi     }
229*53ee8cc1Swenshuai.xi 
230*53ee8cc1Swenshuai.xi     u32regv = hcd_reg_readl ((U32)&pEhci->op_regs->usbcmd);
231*53ee8cc1Swenshuai.xi     u32regv &= ~USBCMD_RUN;
232*53ee8cc1Swenshuai.xi     hcd_reg_writel (u32regv, (U32)&pEhci->op_regs->usbcmd);
233*53ee8cc1Swenshuai.xi 
234*53ee8cc1Swenshuai.xi     ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
235*53ee8cc1Swenshuai.xi     return ms_check_status (&pEhci->op_regs->usbsts, USBSTS_HALT, USBSTS_HALT, 16 * 125);
236*53ee8cc1Swenshuai.xi }
237*53ee8cc1Swenshuai.xi 
ms_ehci_reset(struct ehci_hcd * pEhci)238*53ee8cc1Swenshuai.xi static int ms_ehci_reset (struct ehci_hcd *pEhci)
239*53ee8cc1Swenshuai.xi {
240*53ee8cc1Swenshuai.xi     int retv;
241*53ee8cc1Swenshuai.xi     U32  u32regv = hcd_reg_readl ((U32)&pEhci->op_regs->usbcmd);
242*53ee8cc1Swenshuai.xi 
243*53ee8cc1Swenshuai.xi     ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
244*53ee8cc1Swenshuai.xi     u32regv |= USBCMD_RESET;
245*53ee8cc1Swenshuai.xi     hcd_reg_writel (u32regv, (U32)&pEhci->op_regs->usbcmd);
246*53ee8cc1Swenshuai.xi     pEhci->hcd.state = HCD_STATE_HALT;
247*53ee8cc1Swenshuai.xi     //Wait for HC reset complete
248*53ee8cc1Swenshuai.xi     retv = ms_check_status (&pEhci->op_regs->usbcmd, USBCMD_RESET, 0, 250 * 1000);
249*53ee8cc1Swenshuai.xi 
250*53ee8cc1Swenshuai.xi #if defined(ENABLE_UHC_RUN_BIT_ALWAYS_ON_ECO)
251*53ee8cc1Swenshuai.xi     /* Don't close RUN bit when device disconnect */
252*53ee8cc1Swenshuai.xi     {
253*53ee8cc1Swenshuai.xi         U32 u32hcmisc = hcd_reg_readl ((U32)&pEhci->op_regs->hcmisc);
254*53ee8cc1Swenshuai.xi         hcd_reg_writel(u32hcmisc | BIT7, (U32)&pEhci->op_regs->hcmisc);
255*53ee8cc1Swenshuai.xi     }
256*53ee8cc1Swenshuai.xi #endif
257*53ee8cc1Swenshuai.xi 
258*53ee8cc1Swenshuai.xi     ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
259*53ee8cc1Swenshuai.xi     return retv;
260*53ee8cc1Swenshuai.xi }
261*53ee8cc1Swenshuai.xi 
ms_ehci_quiesce(struct ehci_hcd * pEhci)262*53ee8cc1Swenshuai.xi static void ms_ehci_quiesce (struct ehci_hcd *pEhci)
263*53ee8cc1Swenshuai.xi {
264*53ee8cc1Swenshuai.xi     U32  u32regv;
265*53ee8cc1Swenshuai.xi 
266*53ee8cc1Swenshuai.xi     ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
267*53ee8cc1Swenshuai.xi 
268*53ee8cc1Swenshuai.xi     /* check if there is any schedule bit set (patch from Linux 2.6.28  */
269*53ee8cc1Swenshuai.xi     u32regv = hcd_reg_readl ((U32)&pEhci->op_regs->usbcmd) << 10;
270*53ee8cc1Swenshuai.xi     u32regv &= USBSTS_ASS | USBSTS_PSS;
271*53ee8cc1Swenshuai.xi     if (ms_check_status (&pEhci->op_regs->usbsts, USBSTS_ASS | USBSTS_PSS,
272*53ee8cc1Swenshuai.xi         0, 16 * 125) != 0)
273*53ee8cc1Swenshuai.xi     {
274*53ee8cc1Swenshuai.xi         ms_debug_err("Cannot stop scheduler, force halt - 1\n");
275*53ee8cc1Swenshuai.xi         ms_ehci_halt(pEhci);
276*53ee8cc1Swenshuai.xi         pEhci->hcd.state = HCD_STATE_HALT;
277*53ee8cc1Swenshuai.xi         return;
278*53ee8cc1Swenshuai.xi     }
279*53ee8cc1Swenshuai.xi 
280*53ee8cc1Swenshuai.xi     u32regv = hcd_reg_readl ((U32)&pEhci->op_regs->usbcmd);
281*53ee8cc1Swenshuai.xi     u32regv &= ~(USBCMD_ASE | USBCMD_IAAD | USBCMD_PSE);
282*53ee8cc1Swenshuai.xi     hcd_reg_writel (u32regv, (U32)&pEhci->op_regs->usbcmd);
283*53ee8cc1Swenshuai.xi 
284*53ee8cc1Swenshuai.xi     /* wait 16 microframes */
285*53ee8cc1Swenshuai.xi     if (ms_check_status (&pEhci->op_regs->usbsts, USBSTS_ASS | USBSTS_PSS,
286*53ee8cc1Swenshuai.xi         0, 16 * 125) != 0)
287*53ee8cc1Swenshuai.xi     {
288*53ee8cc1Swenshuai.xi         ms_debug_err("Cannot stop scheduler, force halt - 2\n");
289*53ee8cc1Swenshuai.xi         /* patch from Linux 2.6.28 */
290*53ee8cc1Swenshuai.xi         ms_ehci_halt(pEhci);
291*53ee8cc1Swenshuai.xi         pEhci->hcd.state = HCD_STATE_HALT;
292*53ee8cc1Swenshuai.xi         return;
293*53ee8cc1Swenshuai.xi     }
294*53ee8cc1Swenshuai.xi     ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
295*53ee8cc1Swenshuai.xi }
296*53ee8cc1Swenshuai.xi 
297*53ee8cc1Swenshuai.xi /*
298*53ee8cc1Swenshuai.xi   * @brief             clear reset timer
299*53ee8cc1Swenshuai.xi   *
300*53ee8cc1Swenshuai.xi   * @param          struct ehci_hcd  *pEhci
301*53ee8cc1Swenshuai.xi   * @param          int  iIndex
302*53ee8cc1Swenshuai.xi   * @param          int  port_status
303*53ee8cc1Swenshuai.xi   *
304*53ee8cc1Swenshuai.xi   * @return           port_status
305*53ee8cc1Swenshuai.xi   */
306*53ee8cc1Swenshuai.xi 
ms_reset_complete(struct ehci_hcd * pEhci,int iIndex,int port_status)307*53ee8cc1Swenshuai.xi static int ms_reset_complete (
308*53ee8cc1Swenshuai.xi   struct ehci_hcd  *pEhci,
309*53ee8cc1Swenshuai.xi   int    iIndex,
310*53ee8cc1Swenshuai.xi   int    port_status)
311*53ee8cc1Swenshuai.xi {
312*53ee8cc1Swenshuai.xi     ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
313*53ee8cc1Swenshuai.xi 
314*53ee8cc1Swenshuai.xi     if (!(port_status & PORTSC_CONNECT))
315*53ee8cc1Swenshuai.xi     {
316*53ee8cc1Swenshuai.xi         //pEhci->u32ResetEnd [iIndex] = 0; // un-patch from Linux 2.6.28
317*53ee8cc1Swenshuai.xi         return port_status;
318*53ee8cc1Swenshuai.xi     }
319*53ee8cc1Swenshuai.xi 
320*53ee8cc1Swenshuai.xi     /* Mstar EHCI is integrated TT */
321*53ee8cc1Swenshuai.xi     if (!(port_status & PORTSC_PE))
322*53ee8cc1Swenshuai.xi     {
323*53ee8cc1Swenshuai.xi         ms_debug_err("TT roothub not enable port\n");
324*53ee8cc1Swenshuai.xi     }
325*53ee8cc1Swenshuai.xi 
326*53ee8cc1Swenshuai.xi     ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
327*53ee8cc1Swenshuai.xi     return port_status;
328*53ee8cc1Swenshuai.xi }
329*53ee8cc1Swenshuai.xi 
330*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
331*53ee8cc1Swenshuai.xi /*
332*53ee8cc1Swenshuai.xi   * @brief          check hub ports status change
333*53ee8cc1Swenshuai.xi   *                 our echi ip (root hub) supports only one port
334*53ee8cc1Swenshuai.xi   *
335*53ee8cc1Swenshuai.xi   * @param          struct usb_hcd  *pHcd
336*53ee8cc1Swenshuai.xi   * @param          char *pBuf
337*53ee8cc1Swenshuai.xi   *
338*53ee8cc1Swenshuai.xi   * @return         success/false
339*53ee8cc1Swenshuai.xi   */
ms_hub_status_data(struct usb_hcd * pHcd,char * pBuf)340*53ee8cc1Swenshuai.xi int ms_hub_status_data (struct usb_hcd *pHcd, char *pBuf)
341*53ee8cc1Swenshuai.xi {
342*53ee8cc1Swenshuai.xi     struct ehci_hcd  *pEhci = hcd_to_ehci (pHcd);
343*53ee8cc1Swenshuai.xi     U32  u32Temp, u32Status = 0;
344*53ee8cc1Swenshuai.xi     U32  u32Flags;
345*53ee8cc1Swenshuai.xi 
346*53ee8cc1Swenshuai.xi     ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
347*53ee8cc1Swenshuai.xi 
348*53ee8cc1Swenshuai.xi 	if (!HCD_IS_RUNNING(pHcd->state)) // patch from 2.6.28
349*53ee8cc1Swenshuai.xi 		return 0;
350*53ee8cc1Swenshuai.xi 
351*53ee8cc1Swenshuai.xi     /* init u32Status to no-changes */
352*53ee8cc1Swenshuai.xi     pBuf [0] = 0;
353*53ee8cc1Swenshuai.xi 
354*53ee8cc1Swenshuai.xi     /* port 1 changes ? */
355*53ee8cc1Swenshuai.xi     osapi_spin_lock_irqsave (&pEhci->tHcdLock, u32Flags);
356*53ee8cc1Swenshuai.xi 
357*53ee8cc1Swenshuai.xi     u32Temp = hcd_reg_readl ((U32)&pEhci->op_regs->portsc[0]);
358*53ee8cc1Swenshuai.xi 
359*53ee8cc1Swenshuai.xi     /* PCD interrupt mode, not utilize such scheme */
360*53ee8cc1Swenshuai.xi     //if ( ((u32Temp & PORTSC_CONNECT) == 0) && ((pHcd->pre_sts & PORTSC_CONNECT) != 0) )
361*53ee8cc1Swenshuai.xi     //{
362*53ee8cc1Swenshuai.xi     //    ms_debug_msg("<ms_hub_status_data> Add CSC @ root hub %d, DISCONNECT! (psc = 0x%x)\n", (int)pHcd->host_id, (unsigned int)u32Temp);
363*53ee8cc1Swenshuai.xi     //    u32Temp |= PORTSC_CSC;
364*53ee8cc1Swenshuai.xi     //}
365*53ee8cc1Swenshuai.xi     //pHcd->pre_sts = u32Temp;
366*53ee8cc1Swenshuai.xi 
367*53ee8cc1Swenshuai.xi     //if (!(u32Temp & PORTSC_CONNECT))  // un-patch from Linux 2.6.28
368*53ee8cc1Swenshuai.xi     //  pEhci->u32ResetEnd [0] = 0;
369*53ee8cc1Swenshuai.xi 
370*53ee8cc1Swenshuai.xi     /* no need to consider over current for this IP */
371*53ee8cc1Swenshuai.xi     if ((u32Temp & (PORTSC_CSC) || PORTSC_PEC) != 0 ||
372*53ee8cc1Swenshuai.xi             (pEhci->u32ResetEnd[0] && ms_time_after_eq(
373*53ee8cc1Swenshuai.xi 					jiffies, pEhci->u32ResetEnd[0])))
374*53ee8cc1Swenshuai.xi     {
375*53ee8cc1Swenshuai.xi       /* bit 0 is for hub up port u32Status change  */
376*53ee8cc1Swenshuai.xi       pBuf [0] |= 1 << 1;
377*53ee8cc1Swenshuai.xi       u32Status = USBSTS_PCD;
378*53ee8cc1Swenshuai.xi     }
379*53ee8cc1Swenshuai.xi 
380*53ee8cc1Swenshuai.xi     osapi_spin_unlock_irqrestore (&pEhci->tHcdLock, u32Flags);
381*53ee8cc1Swenshuai.xi     ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
382*53ee8cc1Swenshuai.xi     return u32Status ? 1 : 0;
383*53ee8cc1Swenshuai.xi }
384*53ee8cc1Swenshuai.xi 
385*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
386*53ee8cc1Swenshuai.xi /*
387*53ee8cc1Swenshuai.xi   * @brief          fill hub descriptor
388*53ee8cc1Swenshuai.xi   *
389*53ee8cc1Swenshuai.xi   * @param          struct ehci_hcd  *pEhci
390*53ee8cc1Swenshuai.xi   * @param          struct usb_hub_descriptor  *pDesc
391*53ee8cc1Swenshuai.xi   *
392*53ee8cc1Swenshuai.xi   * @return         none
393*53ee8cc1Swenshuai.xi   */
394*53ee8cc1Swenshuai.xi 
ms_get_roothub_desc(struct ehci_hcd * pEhci,struct usb_hub_descriptor * pDesc)395*53ee8cc1Swenshuai.xi static void ms_get_roothub_desc (
396*53ee8cc1Swenshuai.xi   struct ehci_hcd      *pEhci,
397*53ee8cc1Swenshuai.xi   struct usb_hub_descriptor  *pDesc
398*53ee8cc1Swenshuai.xi )
399*53ee8cc1Swenshuai.xi {
400*53ee8cc1Swenshuai.xi   int    iPorts = HCS_N_PORTS (pEhci->hcs_params);
401*53ee8cc1Swenshuai.xi   U16    u16Temp;
402*53ee8cc1Swenshuai.xi 
403*53ee8cc1Swenshuai.xi   ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
404*53ee8cc1Swenshuai.xi   pDesc->bDescriptorType = 0x29;
405*53ee8cc1Swenshuai.xi   pDesc->bPwrOn2PwrGood = 0;
406*53ee8cc1Swenshuai.xi   pDesc->bHubContrCurrent = 0;
407*53ee8cc1Swenshuai.xi   pDesc->bNbrPorts = iPorts;
408*53ee8cc1Swenshuai.xi   u16Temp = 1 + (iPorts / 8);
409*53ee8cc1Swenshuai.xi   pDesc->bDescLength = 7 + 2 * u16Temp;
410*53ee8cc1Swenshuai.xi 
411*53ee8cc1Swenshuai.xi   /* two bitmaps:  iPorts removable, and usb 1.0 legacy PortPwrCtrlMask */
412*53ee8cc1Swenshuai.xi   memset (&pDesc->DeviceRemovable [0], 0, u16Temp);
413*53ee8cc1Swenshuai.xi   memset (&pDesc->DeviceRemovable [u16Temp], 0xff, u16Temp);
414*53ee8cc1Swenshuai.xi 
415*53ee8cc1Swenshuai.xi   u16Temp = 0x0008;       /* Individual Port Over-current Protection */
416*53ee8cc1Swenshuai.xi   if (HCS_PPC (pEhci->hcs_params))
417*53ee8cc1Swenshuai.xi     u16Temp |= 0x0001;    /* Ganged power switching (all iPorts' power at once) */
418*53ee8cc1Swenshuai.xi   if (HCS_P_INDICATOR (pEhci->hcs_params))
419*53ee8cc1Swenshuai.xi     u16Temp |= 0x0080;    /* Individual port indicators (LEDs) */
420*53ee8cc1Swenshuai.xi   pDesc->wHubCharacteristics = u16Temp;
421*53ee8cc1Swenshuai.xi   ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
422*53ee8cc1Swenshuai.xi }
423*53ee8cc1Swenshuai.xi 
424*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
ms_ehci_softrst(struct ehci_hcd * pEhci)425*53ee8cc1Swenshuai.xi void ms_ehci_softrst(struct ehci_hcd  *pEhci)
426*53ee8cc1Swenshuai.xi {
427*53ee8cc1Swenshuai.xi     U32    regTmp[2];
428*53ee8cc1Swenshuai.xi 
429*53ee8cc1Swenshuai.xi     ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
430*53ee8cc1Swenshuai.xi 
431*53ee8cc1Swenshuai.xi     /* ensure HC already stopped before HC Reset
432*53ee8cc1Swenshuai.xi      * otherwise, there will be a fatal error (DMA Error)
433*53ee8cc1Swenshuai.xi      */
434*53ee8cc1Swenshuai.xi     ms_ehci_halt(pEhci);
435*53ee8cc1Swenshuai.xi     /* make sure USB device going to suspend */
436*53ee8cc1Swenshuai.xi     //mdelay(10); // TBD
437*53ee8cc1Swenshuai.xi 
438*53ee8cc1Swenshuai.xi     /* iff asynchronous QH head is not pointed to itself, restore it too */
439*53ee8cc1Swenshuai.xi     if ((pEhci->hcd.rh_disconn == 1) &&
440*53ee8cc1Swenshuai.xi         (pEhci->stAsync->hw_next_qh != QH_NEXT(pEhci->stAsync->qh_dma_addr)))
441*53ee8cc1Swenshuai.xi     {
442*53ee8cc1Swenshuai.xi         ms_debug_err("[EHCI] Head QH not point to itself (%x)!\n\n\n",
443*53ee8cc1Swenshuai.xi             pEhci->stAsync->hw_next_qh);
444*53ee8cc1Swenshuai.xi         pEhci->stAsync->hw_next_qh = QH_NEXT(pEhci->stAsync->qh_dma_addr);
445*53ee8cc1Swenshuai.xi     }
446*53ee8cc1Swenshuai.xi     if (!hcd_reg_readl((U32)&pEhci->op_regs->asynclistaddr))
447*53ee8cc1Swenshuai.xi         ms_debug_err("[EHCI] async reg 0!!!\n");
448*53ee8cc1Swenshuai.xi 
449*53ee8cc1Swenshuai.xi     /* sometimes, replug device quickly crashs aync_base, just restore it */
450*53ee8cc1Swenshuai.xi     hcd_reg_writel ((U32)pEhci->stAsync->qh_dma_addr, (U32)&pEhci->op_regs->asynclistaddr);
451*53ee8cc1Swenshuai.xi 
452*53ee8cc1Swenshuai.xi     regTmp[0] = hcd_reg_readl((U32)&pEhci->op_regs->usbcmd);
453*53ee8cc1Swenshuai.xi     regTmp[1] = hcd_reg_readl((U32)&pEhci->op_regs->usbintr);
454*53ee8cc1Swenshuai.xi     // HC soft reset
455*53ee8cc1Swenshuai.xi     ms_ehci_reset(pEhci);
456*53ee8cc1Swenshuai.xi     // restore regisger setting
457*53ee8cc1Swenshuai.xi     hcd_reg_writel(regTmp[1],(U32)&pEhci->op_regs->usbintr);
458*53ee8cc1Swenshuai.xi     hcd_reg_writel(regTmp[0],(U32)&pEhci->op_regs->usbcmd);
459*53ee8cc1Swenshuai.xi     pEhci->hcd.state = HCD_STATE_RUNNING;
460*53ee8cc1Swenshuai.xi     ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
461*53ee8cc1Swenshuai.xi }
462*53ee8cc1Swenshuai.xi 
463*53ee8cc1Swenshuai.xi static const char *const speed_name_list[] = {
464*53ee8cc1Swenshuai.xi 	"full-speed",
465*53ee8cc1Swenshuai.xi 	"low-speed",
466*53ee8cc1Swenshuai.xi 	"high-speed",
467*53ee8cc1Swenshuai.xi 	"UNKNOWN",
468*53ee8cc1Swenshuai.xi };
469*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
470*53ee8cc1Swenshuai.xi /*
471*53ee8cc1Swenshuai.xi   * @brief          process hub request
472*53ee8cc1Swenshuai.xi   *
473*53ee8cc1Swenshuai.xi   * @param          struct usb_hcd  *pHcd
474*53ee8cc1Swenshuai.xi   * @param          U16    typeReq
475*53ee8cc1Swenshuai.xi   * @param          U16    u16Value
476*53ee8cc1Swenshuai.xi   * @param          U16    u16Index
477*53ee8cc1Swenshuai.xi   * @param          char    *pBuf
478*53ee8cc1Swenshuai.xi   *
479*53ee8cc1Swenshuai.xi   * @return         error code
480*53ee8cc1Swenshuai.xi   *
481*53ee8cc1Swenshuai.xi   */
ms_hub_control(struct usb_hcd * pHcd,U16 typeReq,U16 u16Value,U16 u16Index,char * pBuf)482*53ee8cc1Swenshuai.xi  int ms_hub_control (
483*53ee8cc1Swenshuai.xi   struct usb_hcd  *pHcd,
484*53ee8cc1Swenshuai.xi   U16    typeReq,
485*53ee8cc1Swenshuai.xi   U16    u16Value,
486*53ee8cc1Swenshuai.xi   U16    u16Index,
487*53ee8cc1Swenshuai.xi   char    *pBuf
488*53ee8cc1Swenshuai.xi )
489*53ee8cc1Swenshuai.xi {
490*53ee8cc1Swenshuai.xi   struct ehci_hcd  *pEhci = hcd_to_ehci (pHcd);
491*53ee8cc1Swenshuai.xi   int    iPorts = HCS_N_PORTS (pEhci->hcs_params);
492*53ee8cc1Swenshuai.xi   U32    u32Temp, u32Status, u32Bus_monitor;
493*53ee8cc1Swenshuai.xi   U32  u32Flags;
494*53ee8cc1Swenshuai.xi   int    iRetval = 0;
495*53ee8cc1Swenshuai.xi   int    time_out;
496*53ee8cc1Swenshuai.xi   struct cpe_dev *dev;
497*53ee8cc1Swenshuai.xi   const struct device_s *__mptr = pHcd->controller;
498*53ee8cc1Swenshuai.xi   dev = (struct cpe_dev *)( (char *)__mptr - offsetof(struct cpe_dev,dev) );
499*53ee8cc1Swenshuai.xi   U32 u32RegUTMI = dev->utmibase;
500*53ee8cc1Swenshuai.xi   U32 u32Temp2, u32Speed;
501*53ee8cc1Swenshuai.xi 
502*53ee8cc1Swenshuai.xi   ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
503*53ee8cc1Swenshuai.xi   osapi_spin_lock_irqsave (&pEhci->tHcdLock, u32Flags);
504*53ee8cc1Swenshuai.xi   switch (typeReq)
505*53ee8cc1Swenshuai.xi   {
506*53ee8cc1Swenshuai.xi   case Req_ClearHubFeature:
507*53ee8cc1Swenshuai.xi     if ((u16Value != C_HUB_LOCAL_POWER)&&(u16Value != C_HUB_OVER_CURRENT))
508*53ee8cc1Swenshuai.xi       goto error;
509*53ee8cc1Swenshuai.xi     break;
510*53ee8cc1Swenshuai.xi   case Req_ClearPortFeature:
511*53ee8cc1Swenshuai.xi     if (!u16Index || u16Index > iPorts)
512*53ee8cc1Swenshuai.xi       goto error;
513*53ee8cc1Swenshuai.xi     u16Index--;
514*53ee8cc1Swenshuai.xi     u32Temp = hcd_reg_readl ((U32)&pEhci->op_regs->portsc [u16Index]);
515*53ee8cc1Swenshuai.xi     u32Temp &= ~PORTSC_RWC_BITS;
516*53ee8cc1Swenshuai.xi 
517*53ee8cc1Swenshuai.xi     if (u32Temp & PORTSC_OWNER)
518*53ee8cc1Swenshuai.xi       break;
519*53ee8cc1Swenshuai.xi 
520*53ee8cc1Swenshuai.xi     switch (u16Value)
521*53ee8cc1Swenshuai.xi     {
522*53ee8cc1Swenshuai.xi     case USB_PORT_FEAT_ENABLE:
523*53ee8cc1Swenshuai.xi       ms_debug_debug("Disable port\n");
524*53ee8cc1Swenshuai.xi       hcd_reg_writel (u32Temp & ~PORTSC_PE, (U32)&pEhci->op_regs->portsc [u16Index]);
525*53ee8cc1Swenshuai.xi #if 0
526*53ee8cc1Swenshuai.xi       // not in linux
527*53ee8cc1Swenshuai.xi       //�˸m�Q�������ɭ� ����scheduler
528*53ee8cc1Swenshuai.xi       hcd_reg_writel(hcd_reg_readl((U32)&pEhci->op_regs->usbcmd)&(~(USBCMD_ASE|USBCMD_PSE|USBCMD_IAAD)),(U32)&pEhci->op_regs->usbcmd);
529*53ee8cc1Swenshuai.xi #endif
530*53ee8cc1Swenshuai.xi 
531*53ee8cc1Swenshuai.xi       #if 0 // not to reset EHCI at this time
532*53ee8cc1Swenshuai.xi       //Halt HCD
533*53ee8cc1Swenshuai.xi       ms_host_halt(pEhci);
534*53ee8cc1Swenshuai.xi       ms_ehci_softrst(pEhci);
535*53ee8cc1Swenshuai.xi       #endif
536*53ee8cc1Swenshuai.xi       break;
537*53ee8cc1Swenshuai.xi     case USB_PORT_FEAT_C_ENABLE:
538*53ee8cc1Swenshuai.xi       hcd_reg_writel ((u32Temp /*& ~PORTSC_RWC_BITS*/) | PORTSC_PEC,
539*53ee8cc1Swenshuai.xi         (U32)&pEhci->op_regs->portsc [u16Index]);
540*53ee8cc1Swenshuai.xi       break;
541*53ee8cc1Swenshuai.xi     case USB_PORT_FEAT_SUSPEND:
542*53ee8cc1Swenshuai.xi     case USB_PORT_FEAT_C_SUSPEND:
543*53ee8cc1Swenshuai.xi       break;
544*53ee8cc1Swenshuai.xi     case USB_PORT_FEAT_POWER:
545*53ee8cc1Swenshuai.xi       if (HCS_PPC (pEhci->hcs_params))
546*53ee8cc1Swenshuai.xi         hcd_reg_writel (u32Temp & ~PORTSC_POWER,
547*53ee8cc1Swenshuai.xi           (U32)&pEhci->op_regs->portsc [u16Index]);
548*53ee8cc1Swenshuai.xi       break;
549*53ee8cc1Swenshuai.xi     case USB_PORT_FEAT_C_CONNECTION:
550*53ee8cc1Swenshuai.xi       /* for force HC Reset */
551*53ee8cc1Swenshuai.xi       if(pEhci->u32MoreCSC)
552*53ee8cc1Swenshuai.xi       {
553*53ee8cc1Swenshuai.xi          diag_printf("[EHCI] clear more CSC\n");
554*53ee8cc1Swenshuai.xi          pEhci->u32MoreCSC = false;
555*53ee8cc1Swenshuai.xi       }
556*53ee8cc1Swenshuai.xi       hcd_reg_writel ((u32Temp /*& ~PORTSC_RWC_BITS*/) | PORTSC_CSC,
557*53ee8cc1Swenshuai.xi         (U32)&pEhci->op_regs->portsc [u16Index]);
558*53ee8cc1Swenshuai.xi       break;
559*53ee8cc1Swenshuai.xi     case USB_PORT_FEAT_C_OVER_CURRENT:
560*53ee8cc1Swenshuai.xi       hcd_reg_writel ((u32Temp /*& ~PORTSC_RWC_BITS*/) | PORTSC_OCC,
561*53ee8cc1Swenshuai.xi         (U32)&pEhci->op_regs->portsc [u16Index]);
562*53ee8cc1Swenshuai.xi       break;
563*53ee8cc1Swenshuai.xi     case USB_PORT_FEAT_C_RESET:
564*53ee8cc1Swenshuai.xi       /* GetPortStatus clears reset */
565*53ee8cc1Swenshuai.xi       break;
566*53ee8cc1Swenshuai.xi     default:
567*53ee8cc1Swenshuai.xi       goto error;
568*53ee8cc1Swenshuai.xi     }
569*53ee8cc1Swenshuai.xi     u32Temp = hcd_reg_readl ((U32)&pEhci->op_regs->usbcmd);  /* unblock posted write */
570*53ee8cc1Swenshuai.xi     break;
571*53ee8cc1Swenshuai.xi   case Req_GetHubDescriptor:
572*53ee8cc1Swenshuai.xi     ms_get_roothub_desc(pEhci, (struct usb_hub_descriptor *)
573*53ee8cc1Swenshuai.xi       pBuf);
574*53ee8cc1Swenshuai.xi     break;
575*53ee8cc1Swenshuai.xi   case Req_GetHubStatus:
576*53ee8cc1Swenshuai.xi     /* no hub-wide feature/u32Status u32Flags */
577*53ee8cc1Swenshuai.xi     memset (pBuf, 0, 4);
578*53ee8cc1Swenshuai.xi     //cpu_to_le32s ((U32 *) pBuf);
579*53ee8cc1Swenshuai.xi     break;
580*53ee8cc1Swenshuai.xi   case Req_GetPortStatus:
581*53ee8cc1Swenshuai.xi     if (!u16Index || u16Index > iPorts)
582*53ee8cc1Swenshuai.xi       goto error;
583*53ee8cc1Swenshuai.xi     u16Index--;
584*53ee8cc1Swenshuai.xi     u32Status = 0;
585*53ee8cc1Swenshuai.xi     u32Temp = hcd_reg_readl ((U32)&pEhci->op_regs->portsc [u16Index]);
586*53ee8cc1Swenshuai.xi     // old flow to patch hub polling
587*53ee8cc1Swenshuai.xi     //if ( ((u32Temp & PORTSC_CONNECT) == 0) && ((u32Temp & PORTSC_CSC) == 0) )
588*53ee8cc1Swenshuai.xi     //{
589*53ee8cc1Swenshuai.xi     //    if ((pHcd->pre_temp & PORTSC_CONNECT) != 0)
590*53ee8cc1Swenshuai.xi     //    {
591*53ee8cc1Swenshuai.xi     //        ms_debug_msg("<ms_hub_control> Req_GetPortStatus:Add CSC here, pStatus = %x\n", (unsigned int)u32Temp);
592*53ee8cc1Swenshuai.xi     //        u32Temp |= PORTSC_CSC;
593*53ee8cc1Swenshuai.xi     //    }
594*53ee8cc1Swenshuai.xi     //}
595*53ee8cc1Swenshuai.xi     //pHcd->pre_temp = u32Temp;
596*53ee8cc1Swenshuai.xi 
597*53ee8cc1Swenshuai.xi     /* deal with wPortChange bits */
598*53ee8cc1Swenshuai.xi     if (u32Temp & PORTSC_CSC)
599*53ee8cc1Swenshuai.xi     {
600*53ee8cc1Swenshuai.xi       u32Status |= 1 << USB_PORT_FEAT_C_CONNECTION;
601*53ee8cc1Swenshuai.xi     }
602*53ee8cc1Swenshuai.xi     else if(pEhci->u32MoreCSC)
603*53ee8cc1Swenshuai.xi     {
604*53ee8cc1Swenshuai.xi       diag_printf("[EHCI] retrun more CSC\n");
605*53ee8cc1Swenshuai.xi       u32Status |= 1 << USB_PORT_FEAT_C_CONNECTION;
606*53ee8cc1Swenshuai.xi     }
607*53ee8cc1Swenshuai.xi     if (u32Temp & PORTSC_PEC)
608*53ee8cc1Swenshuai.xi       u32Status |= 1 << USB_PORT_FEAT_C_ENABLE;
609*53ee8cc1Swenshuai.xi     // USB_PORT_FEAT_C_SUSPEND
610*53ee8cc1Swenshuai.xi     if (u32Temp & PORTSC_OCC)
611*53ee8cc1Swenshuai.xi       u32Status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT;
612*53ee8cc1Swenshuai.xi 
613*53ee8cc1Swenshuai.xi     if ((u32Temp & PORTSC_RESET)
614*53ee8cc1Swenshuai.xi         && ms_time_after (jiffies,
615*53ee8cc1Swenshuai.xi           pEhci->u32ResetEnd [u16Index]))
616*53ee8cc1Swenshuai.xi     {
617*53ee8cc1Swenshuai.xi       u32Status |= 1 << USB_PORT_FEAT_C_RESET;
618*53ee8cc1Swenshuai.xi       pEhci->u32ResetEnd [u16Index] = 0; // patch from Linux 2.6.28
619*53ee8cc1Swenshuai.xi       time_out=0;
620*53ee8cc1Swenshuai.xi 
621*53ee8cc1Swenshuai.xi       writeb(UTMI_DISCON_LEVEL_2A ,(void*)(u32RegUTMI+0x2A*2)); // disconnect level
622*53ee8cc1Swenshuai.xi       mdelay(20); // chirp patch
623*53ee8cc1Swenshuai.xi 
624*53ee8cc1Swenshuai.xi       /* Do port reset until finish */
625*53ee8cc1Swenshuai.xi       //hcd_reg_writel (u32Temp & ~PORTSC_RESET,
626*53ee8cc1Swenshuai.xi       hcd_reg_writel (u32Temp & ~(PORTSC_RWC_BITS | PORTSC_RESET),
627*53ee8cc1Swenshuai.xi           (U32)&pEhci->op_regs->portsc [u16Index]);
628*53ee8cc1Swenshuai.xi       do {
629*53ee8cc1Swenshuai.xi         u32Temp = hcd_reg_readl ((U32)&pEhci->op_regs->portsc [u16Index]);
630*53ee8cc1Swenshuai.xi         udelay (10);
631*53ee8cc1Swenshuai.xi       } while ((u32Temp&(PORTSC_RESET|PORTSC_CONNECT)) == (PORTSC_RESET|PORTSC_CONNECT)&&(time_out++<10000));
632*53ee8cc1Swenshuai.xi 
633*53ee8cc1Swenshuai.xi       writeb( UTMI_EYE_SETTING_2C, (void*) (u32RegUTMI+0x2c*2)); // chirp patch
634*53ee8cc1Swenshuai.xi       writeb( UTMI_EYE_SETTING_2D, (void*) (u32RegUTMI+0x2d*2-1)); // chirp patch
635*53ee8cc1Swenshuai.xi       writeb( UTMI_EYE_SETTING_2E, (void*) (u32RegUTMI+0x2e*2)); // chirp patch
636*53ee8cc1Swenshuai.xi       writeb( UTMI_EYE_SETTING_2F, (void*) (u32RegUTMI+0x2f*2-1)); // chirp patch
637*53ee8cc1Swenshuai.xi #ifdef ENABLE_TX_RX_RESET_CLK_GATING_ECO
638*53ee8cc1Swenshuai.xi       // DO UTMI TX/RX RESET
639*53ee8cc1Swenshuai.xi       writeb( readb((void*)(u32RegUTMI+0x06*2)) | 0x03, (void*) (u32RegUTMI+0x06*2));
640*53ee8cc1Swenshuai.xi       writeb( readb((void*)(u32RegUTMI+0x06*2)) & ~0x03, (void*) (u32RegUTMI+0x06*2));
641*53ee8cc1Swenshuai.xi #endif
642*53ee8cc1Swenshuai.xi 
643*53ee8cc1Swenshuai.xi       //Add time-out mechanism to cover HW BUG
644*53ee8cc1Swenshuai.xi       //HW ISSUE?
645*53ee8cc1Swenshuai.xi       if( time_out >= 10000 )
646*53ee8cc1Swenshuai.xi       {
647*53ee8cc1Swenshuai.xi           //Maybe HW bug ==> check it out
648*53ee8cc1Swenshuai.xi           ms_debug_err("ERR: Port reset cannot force complete!!\n");//HW ISSUE?
649*53ee8cc1Swenshuai.xi           ms_ehci_softrst(pEhci);
650*53ee8cc1Swenshuai.xi       }
651*53ee8cc1Swenshuai.xi       u32Speed = (hcd_reg_readl((U32)&pEhci->op_regs->bus_control) >> 9) & 0x3;
652*53ee8cc1Swenshuai.xi       //ms_debug_msg("SPEED: %x\n", (unsigned int)u32Speed);
653*53ee8cc1Swenshuai.xi       ms_debug_msg("RootHub SPEED: %s\n", speed_name_list[u32Speed]);
654*53ee8cc1Swenshuai.xi 
655*53ee8cc1Swenshuai.xi       u32Temp2 = hcd_reg_readl((U32)&pEhci->op_regs->hcmisc) & 0xfffffff3;
656*53ee8cc1Swenshuai.xi 
657*53ee8cc1Swenshuai.xi       /* unset UTMI force full speed hub driving timing */
658*53ee8cc1Swenshuai.xi       ms_UTMI_ANDXBYTE_EX(0x03, (~BIT2), u32RegUTMI);
659*53ee8cc1Swenshuai.xi 
660*53ee8cc1Swenshuai.xi       if (u32Speed == 2) // high u32Speed
661*53ee8cc1Swenshuai.xi       {
662*53ee8cc1Swenshuai.xi         ms_UTMI_ORXBYTE_EX(0x09, 0x80, u32RegUTMI); //HS rx robust enable
663*53ee8cc1Swenshuai.xi #if defined(ENABLE_16US_EOF1)
664*53ee8cc1Swenshuai.xi         /* set EOF1 to 16us for babble prevention under hub case */
665*53ee8cc1Swenshuai.xi         //diag_printf("[EHCI] set 16us EOF1\n ");
666*53ee8cc1Swenshuai.xi         u32Temp2 |= (1 << 2);
667*53ee8cc1Swenshuai.xi #else
668*53ee8cc1Swenshuai.xi         u32Temp2 |= (3 << 2);
669*53ee8cc1Swenshuai.xi #endif
670*53ee8cc1Swenshuai.xi       }
671*53ee8cc1Swenshuai.xi       else if (u32Speed == 0 ) //full u32Speed
672*53ee8cc1Swenshuai.xi       {
673*53ee8cc1Swenshuai.xi         /* set UTMI force full speed hub driving timing */
674*53ee8cc1Swenshuai.xi         ms_UTMI_ORXBYTE_EX(0x03, BIT2, u32RegUTMI);
675*53ee8cc1Swenshuai.xi         ms_UTMI_ANDXBYTE_EX(0x09, 0x7F, u32RegUTMI);
676*53ee8cc1Swenshuai.xi         u32Temp2 |= (2 << 2);
677*53ee8cc1Swenshuai.xi       }
678*53ee8cc1Swenshuai.xi       else if (u32Speed == 1 ) //low u32Speed
679*53ee8cc1Swenshuai.xi       {
680*53ee8cc1Swenshuai.xi         ms_UTMI_ANDXBYTE_EX(0x09, 0x7F, u32RegUTMI);
681*53ee8cc1Swenshuai.xi         u32Temp2 |= (2 << 2);
682*53ee8cc1Swenshuai.xi       }
683*53ee8cc1Swenshuai.xi       hcd_reg_writel (u32Temp2, (U32)&pEhci->op_regs->hcmisc); // misc, EOF1
684*53ee8cc1Swenshuai.xi 
685*53ee8cc1Swenshuai.xi       /* patch from Linux 2.6.28 */
686*53ee8cc1Swenshuai.xi       //u32Temp = ms_reset_complete (pEhci, u16Index, u32Temp);
687*53ee8cc1Swenshuai.xi       u32Temp = ms_reset_complete (pEhci, u16Index,
688*53ee8cc1Swenshuai.xi             hcd_reg_readl ((U32)&pEhci->op_regs->portsc [u16Index]));
689*53ee8cc1Swenshuai.xi       pHcd->isRootHubPortReset = FALSE;
690*53ee8cc1Swenshuai.xi     }
691*53ee8cc1Swenshuai.xi 
692*53ee8cc1Swenshuai.xi     if (!(u32Temp & (PORTSC_RESUME|PORTSC_RESET))) // patch from Linux 2.6.28
693*53ee8cc1Swenshuai.xi         pEhci->u32ResetEnd[u16Index] = 0;
694*53ee8cc1Swenshuai.xi 
695*53ee8cc1Swenshuai.xi     // don't show wPortStatus if it's owned by a companion hc
696*53ee8cc1Swenshuai.xi     /* patch from Linux 2.6.28, TT root hub */
697*53ee8cc1Swenshuai.xi     //if (!(u32Temp & PORTSC_OWNER))
698*53ee8cc1Swenshuai.xi     {
699*53ee8cc1Swenshuai.xi       if (u32Temp & PORTSC_CONNECT)
700*53ee8cc1Swenshuai.xi       {
701*53ee8cc1Swenshuai.xi         u32Status |= USB_PORT_STAT_CONNECTION;
702*53ee8cc1Swenshuai.xi         u32Bus_monitor=hcd_reg_readl ((U32)&pEhci->op_regs->bus_control);
703*53ee8cc1Swenshuai.xi         u32Bus_monitor>>=9;
704*53ee8cc1Swenshuai.xi         if (u32Bus_monitor==2)
705*53ee8cc1Swenshuai.xi             u32Status |= USB_PORT_STAT_HIGH_SPEED;
706*53ee8cc1Swenshuai.xi         else if (u32Bus_monitor==1)
707*53ee8cc1Swenshuai.xi             u32Status |= USB_PORT_STAT_LOW_SPEED;
708*53ee8cc1Swenshuai.xi         //else ==> full u32Speed don't set any bits
709*53ee8cc1Swenshuai.xi 
710*53ee8cc1Swenshuai.xi       }
711*53ee8cc1Swenshuai.xi       if (u32Temp & PORTSC_PE)
712*53ee8cc1Swenshuai.xi         u32Status |= USB_PORT_STAT_ENABLE;
713*53ee8cc1Swenshuai.xi       if (u32Temp & (PORTSC_SUSPEND | PORTSC_RESUME))
714*53ee8cc1Swenshuai.xi         u32Status |= USB_PORT_STAT_SUSPEND;
715*53ee8cc1Swenshuai.xi       if (u32Temp & PORTSC_OC)
716*53ee8cc1Swenshuai.xi         u32Status |= USB_PORT_STAT_OVERCURRENT;
717*53ee8cc1Swenshuai.xi       if (u32Temp & PORTSC_RESET)
718*53ee8cc1Swenshuai.xi         u32Status |= USB_PORT_STAT_RESET;
719*53ee8cc1Swenshuai.xi       if (u32Temp & PORTSC_POWER)
720*53ee8cc1Swenshuai.xi         u32Status |= USB_PORT_STAT_POWER;
721*53ee8cc1Swenshuai.xi     }
722*53ee8cc1Swenshuai.xi 
723*53ee8cc1Swenshuai.xi     *pBuf = u32Status;
724*53ee8cc1Swenshuai.xi     *(pBuf+1) = u32Status >> 8;
725*53ee8cc1Swenshuai.xi     *(pBuf+2) = u32Status >> 16;
726*53ee8cc1Swenshuai.xi     *(pBuf+3) = u32Status >> 24;
727*53ee8cc1Swenshuai.xi     break;
728*53ee8cc1Swenshuai.xi   case Req_SetHubFeature:
729*53ee8cc1Swenshuai.xi     if ((u16Value != C_HUB_LOCAL_POWER)&&(u16Value != C_HUB_OVER_CURRENT))
730*53ee8cc1Swenshuai.xi       goto error;
731*53ee8cc1Swenshuai.xi     break;
732*53ee8cc1Swenshuai.xi   case Req_SetPortFeature:
733*53ee8cc1Swenshuai.xi     if (!u16Index || u16Index > iPorts)
734*53ee8cc1Swenshuai.xi       goto error;
735*53ee8cc1Swenshuai.xi     u16Index--;
736*53ee8cc1Swenshuai.xi     u32Temp = hcd_reg_readl ((U32)&pEhci->op_regs->portsc [u16Index]);
737*53ee8cc1Swenshuai.xi     #if 0 // MStar patch for Faraday IP
738*53ee8cc1Swenshuai.xi     if (u32Temp & PORTSC_OWNER)
739*53ee8cc1Swenshuai.xi       break;
740*53ee8cc1Swenshuai.xi     #endif
741*53ee8cc1Swenshuai.xi     // patch from Linux
742*53ee8cc1Swenshuai.xi     u32Temp &= ~PORTSC_RWC_BITS;
743*53ee8cc1Swenshuai.xi 
744*53ee8cc1Swenshuai.xi     switch (u16Value)
745*53ee8cc1Swenshuai.xi     {
746*53ee8cc1Swenshuai.xi     case USB_PORT_FEAT_SUSPEND:
747*53ee8cc1Swenshuai.xi       ms_debug_msg("SetPortFeature suspend\n");
748*53ee8cc1Swenshuai.xi       hcd_reg_writel (u32Temp | PORTSC_SUSPEND,
749*53ee8cc1Swenshuai.xi         (U32)&pEhci->op_regs->portsc [u16Index]);
750*53ee8cc1Swenshuai.xi       break;
751*53ee8cc1Swenshuai.xi     case USB_PORT_FEAT_POWER:
752*53ee8cc1Swenshuai.xi       if (HCS_PPC (pEhci->hcs_params))
753*53ee8cc1Swenshuai.xi         hcd_reg_writel (u32Temp | PORTSC_POWER,
754*53ee8cc1Swenshuai.xi           (U32)&pEhci->op_regs->portsc [u16Index]);
755*53ee8cc1Swenshuai.xi       break;
756*53ee8cc1Swenshuai.xi     case USB_PORT_FEAT_RESET:
757*53ee8cc1Swenshuai.xi       //Do port reset only if device attaches to this port
758*53ee8cc1Swenshuai.xi       if( u32Temp&PORTSC_CONNECT )
759*53ee8cc1Swenshuai.xi       {
760*53ee8cc1Swenshuai.xi         pHcd->isRootHubPortReset = TRUE;
761*53ee8cc1Swenshuai.xi         ms_ehci_stoprun_setting(HOST20_Enable, pEhci);
762*53ee8cc1Swenshuai.xi 
763*53ee8cc1Swenshuai.xi         writeb(0x10, (void*)(u32RegUTMI+0x2C*2)); // chirp patch
764*53ee8cc1Swenshuai.xi         writeb(0x00, (void*)(u32RegUTMI+0x2D*2-1)); // chirp patch
765*53ee8cc1Swenshuai.xi         writeb(0x00, (void*)(u32RegUTMI+0x2E*2)); // chirp patch
766*53ee8cc1Swenshuai.xi         writeb(0x00, (void*)(u32RegUTMI+0x2F*2-1)); // chirp patch
767*53ee8cc1Swenshuai.xi         // Chirp K detection level: 0x80 => 400mv, 0x20 => 575mv
768*53ee8cc1Swenshuai.xi         writeb(0x80 ,(void*)(u32RegUTMI+0x2A*2)); // chirp patch
769*53ee8cc1Swenshuai.xi 
770*53ee8cc1Swenshuai.xi         u32Temp |= PORTSC_RESET;
771*53ee8cc1Swenshuai.xi         u32Temp &= ~PORTSC_PE;
772*53ee8cc1Swenshuai.xi         /*
773*53ee8cc1Swenshuai.xi         * 50 ms resets on root for usb spec.
774*53ee8cc1Swenshuai.xi         */
775*53ee8cc1Swenshuai.xi         pEhci->u32ResetEnd [u16Index] = jiffies
776*53ee8cc1Swenshuai.xi               + ((50 /* msec */ * HZ) / 1000);
777*53ee8cc1Swenshuai.xi         hcd_reg_writel (u32Temp, (U32)&pEhci->op_regs->portsc [u16Index]); // port reset
778*53ee8cc1Swenshuai.xi       }
779*53ee8cc1Swenshuai.xi       else
780*53ee8cc1Swenshuai.xi       {
781*53ee8cc1Swenshuai.xi         /* fail reset process, if device has gone */
782*53ee8cc1Swenshuai.xi         diag_printf("[USB] device has gone before bus reset\n");
783*53ee8cc1Swenshuai.xi         iRetval = -ENODEV;
784*53ee8cc1Swenshuai.xi       }
785*53ee8cc1Swenshuai.xi       break;
786*53ee8cc1Swenshuai.xi     default:
787*53ee8cc1Swenshuai.xi       goto error;
788*53ee8cc1Swenshuai.xi     }
789*53ee8cc1Swenshuai.xi     u32Temp = hcd_reg_readl ((U32)&pEhci->op_regs->usbcmd);  /* unblock posted writes */
790*53ee8cc1Swenshuai.xi     break;
791*53ee8cc1Swenshuai.xi 
792*53ee8cc1Swenshuai.xi   default:
793*53ee8cc1Swenshuai.xi error:
794*53ee8cc1Swenshuai.xi     /* issue stall */
795*53ee8cc1Swenshuai.xi     iRetval = -EPIPE;
796*53ee8cc1Swenshuai.xi   }
797*53ee8cc1Swenshuai.xi   osapi_spin_unlock_irqrestore (&pEhci->tHcdLock, u32Flags);
798*53ee8cc1Swenshuai.xi   ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
799*53ee8cc1Swenshuai.xi   return iRetval;
800*53ee8cc1Swenshuai.xi }
801*53ee8cc1Swenshuai.xi 
802*53ee8cc1Swenshuai.xi /*------------------------------------------------------------------------------*/
803*53ee8cc1Swenshuai.xi #include "drvEHCI_MEM.cxx"
804*53ee8cc1Swenshuai.xi 
805*53ee8cc1Swenshuai.xi /*
806*53ee8cc1Swenshuai.xi   * @brief          fill qtd buffer from urb
807*53ee8cc1Swenshuai.xi   *
808*53ee8cc1Swenshuai.xi   * @param          struct ehci_qtd *pQtd
809*53ee8cc1Swenshuai.xi   * @param          dma_addr_t tBufAddr
810*53ee8cc1Swenshuai.xi   * @param          size_t total
811*53ee8cc1Swenshuai.xi   * @param          int iToken
812*53ee8cc1Swenshuai.xi   * @param          int iMaxpkt
813*53ee8cc1Swenshuai.xi   *
814*53ee8cc1Swenshuai.xi   * @return         u32Cnt
815*53ee8cc1Swenshuai.xi   */
816*53ee8cc1Swenshuai.xi static int
ms_qtd_pack(struct ehci_qtd * pQtd,dma_addr_t tBufAddr,size_t total,int iToken,int iMaxpkt)817*53ee8cc1Swenshuai.xi ms_qtd_pack (struct ehci_qtd *pQtd, dma_addr_t tBufAddr, size_t total,
818*53ee8cc1Swenshuai.xi     int iToken, int iMaxpkt)
819*53ee8cc1Swenshuai.xi {
820*53ee8cc1Swenshuai.xi   U32 u32Cnt;
821*53ee8cc1Swenshuai.xi   int  i/*, lastnums = 0*/;
822*53ee8cc1Swenshuai.xi   //unsigned char	u8PageShift;
823*53ee8cc1Swenshuai.xi 
824*53ee8cc1Swenshuai.xi   /* buffer must continuous, first page address may not on 4K boundary  */
825*53ee8cc1Swenshuai.xi 
826*53ee8cc1Swenshuai.xi   ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
827*53ee8cc1Swenshuai.xi   pQtd->hw_buffer [0] = tBufAddr;
828*53ee8cc1Swenshuai.xi   u32Cnt = 0x1000 - (tBufAddr & 0x0fff);  /* rest of that page */
829*53ee8cc1Swenshuai.xi   if (total < u32Cnt)    /* ... iff needed */
830*53ee8cc1Swenshuai.xi     u32Cnt = total;
831*53ee8cc1Swenshuai.xi   else
832*53ee8cc1Swenshuai.xi   {
833*53ee8cc1Swenshuai.xi     tBufAddr +=  0x1000;
834*53ee8cc1Swenshuai.xi     tBufAddr &= ~0x0fff;
835*53ee8cc1Swenshuai.xi 
836*53ee8cc1Swenshuai.xi     /* pQtd buffer range : min 16K, max 20K */
837*53ee8cc1Swenshuai.xi     for (i = 1; u32Cnt < total && i < 5; i++)
838*53ee8cc1Swenshuai.xi     {
839*53ee8cc1Swenshuai.xi       pQtd->hw_buffer [i] = tBufAddr;
840*53ee8cc1Swenshuai.xi       //lastnums++;
841*53ee8cc1Swenshuai.xi       tBufAddr += 0x1000;
842*53ee8cc1Swenshuai.xi       u32Cnt = ((u32Cnt+0x1000) < total) ? (u32Cnt+0x1000) : total;
843*53ee8cc1Swenshuai.xi     }
844*53ee8cc1Swenshuai.xi 
845*53ee8cc1Swenshuai.xi     /* short packets on transfer end */
846*53ee8cc1Swenshuai.xi     if (u32Cnt != total)
847*53ee8cc1Swenshuai.xi       u32Cnt -= (u32Cnt % iMaxpkt);
848*53ee8cc1Swenshuai.xi   }
849*53ee8cc1Swenshuai.xi   pQtd->hw_token = (u32Cnt << 16) | iToken;
850*53ee8cc1Swenshuai.xi   pQtd->length = u32Cnt;
851*53ee8cc1Swenshuai.xi   /* un-patched base on linux code */
852*53ee8cc1Swenshuai.xi   //if ((u32Cnt > 0) && (lastnums < 4))
853*53ee8cc1Swenshuai.xi   //{
854*53ee8cc1Swenshuai.xi   //    for (u8PageShift = lastnums + 1;u8PageShift < 5; u8PageShift++)
855*53ee8cc1Swenshuai.xi   //    {
856*53ee8cc1Swenshuai.xi   //        pQtd->hw_buffer[u8PageShift] = pQtd->hw_buffer [lastnums];
857*53ee8cc1Swenshuai.xi   //    }
858*53ee8cc1Swenshuai.xi   //}
859*53ee8cc1Swenshuai.xi   ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
860*53ee8cc1Swenshuai.xi   return u32Cnt;
861*53ee8cc1Swenshuai.xi }
862*53ee8cc1Swenshuai.xi 
863*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
864*53ee8cc1Swenshuai.xi /*
865*53ee8cc1Swenshuai.xi   * @brief          refresh QH overlay, based on Linux 3.10.x
866*53ee8cc1Swenshuai.xi   *                 merge qh_refresh and qh_update
867*53ee8cc1Swenshuai.xi   *
868*53ee8cc1Swenshuai.xi   * @param          struct ehci_hcd *pEhci
869*53ee8cc1Swenshuai.xi   * @param          struct ehci_qh *pQh
870*53ee8cc1Swenshuai.xi   *
871*53ee8cc1Swenshuai.xi   * @return         none
872*53ee8cc1Swenshuai.xi   */
873*53ee8cc1Swenshuai.xi 
874*53ee8cc1Swenshuai.xi static void
ms_qh_refresh(struct ehci_hcd * pEhci,struct ehci_qh * pQh)875*53ee8cc1Swenshuai.xi ms_qh_refresh (struct ehci_hcd *pEhci, struct ehci_qh *pQh)
876*53ee8cc1Swenshuai.xi {
877*53ee8cc1Swenshuai.xi 	struct ehci_qtd *pQtd;
878*53ee8cc1Swenshuai.xi 
879*53ee8cc1Swenshuai.xi 	ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
880*53ee8cc1Swenshuai.xi 	pQtd = entry_to_container(pQh->qtd_list.next, struct ehci_qtd, qtd_list);
881*53ee8cc1Swenshuai.xi 
882*53ee8cc1Swenshuai.xi 	if (pQh->hw_token & QTD_STS_ACT)
883*53ee8cc1Swenshuai.xi 	{
884*53ee8cc1Swenshuai.xi 		ms_debug_debug("[USB] QTD_STS_ACT, (%x,%x)\n", pQh->hw_next_qtd, pQtd->hw_next_qtd);
885*53ee8cc1Swenshuai.xi 		pQh->hw_next_qtd = pQtd->hw_next_qtd;
886*53ee8cc1Swenshuai.xi 	}
887*53ee8cc1Swenshuai.xi 	else {
888*53ee8cc1Swenshuai.xi 		if (pQh->qh_status != QH_STS_IDLE)
889*53ee8cc1Swenshuai.xi 			ms_debug_err("[USB] Not in IDLE state!\n");
890*53ee8cc1Swenshuai.xi 		pQh->hw_next_qtd = (U32)(pQtd->qtd_dma_addr);
891*53ee8cc1Swenshuai.xi 		pQh->hw_alt_next_qtd = EHCI_LIST_END;
892*53ee8cc1Swenshuai.xi 
893*53ee8cc1Swenshuai.xi 		if (!(pQh->hw_ep_state1 & QH_DTC_BIT)) {
894*53ee8cc1Swenshuai.xi 			unsigned	is_out, epnum;
895*53ee8cc1Swenshuai.xi 
896*53ee8cc1Swenshuai.xi 			is_out = usb_pipeout(pQtd->urb->u32Pipe);
897*53ee8cc1Swenshuai.xi 			epnum = (pQh->hw_ep_state1 >> 8) & 0x0f;
898*53ee8cc1Swenshuai.xi 			if (!usb_gettoggle (pQh->dev, epnum, is_out)) {
899*53ee8cc1Swenshuai.xi 				pQh->hw_token &= ~QTD_TOGGLE;
900*53ee8cc1Swenshuai.xi 				usb_settoggle (pQh->dev, epnum, is_out, 1);
901*53ee8cc1Swenshuai.xi 			}
902*53ee8cc1Swenshuai.xi 		}
903*53ee8cc1Swenshuai.xi 
904*53ee8cc1Swenshuai.xi 		pQh->hw_token &= (QTD_TOGGLE | QTD_STS_PERR);
905*53ee8cc1Swenshuai.xi 	}
906*53ee8cc1Swenshuai.xi 
907*53ee8cc1Swenshuai.xi 	ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
908*53ee8cc1Swenshuai.xi }
909*53ee8cc1Swenshuai.xi 
910*53ee8cc1Swenshuai.xi #ifndef ENABLE_QH_REFRESH // replaced by ms_qh_refresh()
911*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
912*53ee8cc1Swenshuai.xi /*
913*53ee8cc1Swenshuai.xi   * @brief          link qtd list to qh
914*53ee8cc1Swenshuai.xi   *
915*53ee8cc1Swenshuai.xi   * @param          struct ehci_qh *pQh
916*53ee8cc1Swenshuai.xi   * @param          struct ehci_qtd *pQtd
917*53ee8cc1Swenshuai.xi   *
918*53ee8cc1Swenshuai.xi   * @return         none
919*53ee8cc1Swenshuai.xi   */
920*53ee8cc1Swenshuai.xi 
921*53ee8cc1Swenshuai.xi static __inline__ void
ms_qh_update_link(struct ehci_qh * pQh,struct ehci_qtd * pQtd)922*53ee8cc1Swenshuai.xi ms_qh_update_link (struct ehci_qh *pQh, struct ehci_qtd *pQtd)
923*53ee8cc1Swenshuai.xi {
924*53ee8cc1Swenshuai.xi   ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
925*53ee8cc1Swenshuai.xi   pQh->hw_next_qtd = (U32)(pQtd->qtd_dma_addr);
926*53ee8cc1Swenshuai.xi   pQh->hw_alt_next_qtd = EHCI_LIST_END;
927*53ee8cc1Swenshuai.xi 
928*53ee8cc1Swenshuai.xi   /* HC must see latest pQtd and pQh data before we clear ACTIVE+HALT */
929*53ee8cc1Swenshuai.xi   wmb ();
930*53ee8cc1Swenshuai.xi   pQh->hw_token &= (QTD_TOGGLE | QTD_STS_PERR);
931*53ee8cc1Swenshuai.xi   ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
932*53ee8cc1Swenshuai.xi }
933*53ee8cc1Swenshuai.xi #endif
934*53ee8cc1Swenshuai.xi 
935*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
936*53ee8cc1Swenshuai.xi /*
937*53ee8cc1Swenshuai.xi   * @brief             check qtd status register
938*53ee8cc1Swenshuai.xi   *
939*53ee8cc1Swenshuai.xi   * @param          struct urb *pUrb
940*53ee8cc1Swenshuai.xi   * @param          size_t length
941*53ee8cc1Swenshuai.xi   * @param          U32 u32Token
942*53ee8cc1Swenshuai.xi   *
943*53ee8cc1Swenshuai.xi   * @return           none
944*53ee8cc1Swenshuai.xi   */
945*53ee8cc1Swenshuai.xi 
ms_qtd_copy_status(struct urb * pUrb,size_t length,U32 u32Token)946*53ee8cc1Swenshuai.xi static void ms_qtd_copy_status (
947*53ee8cc1Swenshuai.xi   struct urb *pUrb,
948*53ee8cc1Swenshuai.xi   size_t length,
949*53ee8cc1Swenshuai.xi   U32 u32Token
950*53ee8cc1Swenshuai.xi )
951*53ee8cc1Swenshuai.xi {
952*53ee8cc1Swenshuai.xi #ifdef USB_EHCI_TT
953*53ee8cc1Swenshuai.xi   struct usb_hcd *hcd = pUrb->dev->bus->hcpriv;
954*53ee8cc1Swenshuai.xi #endif
955*53ee8cc1Swenshuai.xi 
956*53ee8cc1Swenshuai.xi   ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
957*53ee8cc1Swenshuai.xi 
958*53ee8cc1Swenshuai.xi   if (QTD_PID (u32Token) != 2)
959*53ee8cc1Swenshuai.xi     pUrb->u32ActualLength += length - QTD_BYTES (u32Token);
960*53ee8cc1Swenshuai.xi 
961*53ee8cc1Swenshuai.xi   /* error codes ���n�h�復 */
962*53ee8cc1Swenshuai.xi   if (pUrb->s32Status != -EINPROGRESS)
963*53ee8cc1Swenshuai.xi     return;
964*53ee8cc1Swenshuai.xi 
965*53ee8cc1Swenshuai.xi   /* force cleanup , may not a wrong */
966*53ee8cc1Swenshuai.xi   if (IS_SHORT_READ (u32Token))
967*53ee8cc1Swenshuai.xi     pUrb->s32Status = -MS_ERR_REMOTEIO;
968*53ee8cc1Swenshuai.xi 
969*53ee8cc1Swenshuai.xi   if (u32Token & QTD_STS_HALT)
970*53ee8cc1Swenshuai.xi   {
971*53ee8cc1Swenshuai.xi     if (u32Token & QTD_STS_BABBLE)
972*53ee8cc1Swenshuai.xi     {
973*53ee8cc1Swenshuai.xi       diag_printf(" [ !!!!  USB   QTD_STS_BABBLE  !!!!] \n "); // SHOULD BE PRINT
974*53ee8cc1Swenshuai.xi       pUrb->s32Status = -MS_ERR_OVERFLOW;
975*53ee8cc1Swenshuai.xi     }
976*53ee8cc1Swenshuai.xi     else if (u32Token & QTD_STS_MISSMF)
977*53ee8cc1Swenshuai.xi     {
978*53ee8cc1Swenshuai.xi         diag_printf(" [ !!!!  USB	QTD_STS_MISSMF	!!!!] \n "); // SHOULD BE PRINT
979*53ee8cc1Swenshuai.xi       /* FS/LS transfer lost complete-split */
980*53ee8cc1Swenshuai.xi       pUrb->s32Status = -MS_ERR_PROTOCAL;
981*53ee8cc1Swenshuai.xi     }
982*53ee8cc1Swenshuai.xi     else if (u32Token & QTD_STS_DATERR)
983*53ee8cc1Swenshuai.xi     {
984*53ee8cc1Swenshuai.xi         diag_printf(" [ !!!!  USB	QTD_STS_DATERR	!!!!] \n "); // SHOULD BE PRINT
985*53ee8cc1Swenshuai.xi       pUrb->s32Status = (QTD_PID (u32Token) == 1) /* Is IN token? */
986*53ee8cc1Swenshuai.xi         ? -MS_ERR_RECEIVE   /* HCD can't read data */
987*53ee8cc1Swenshuai.xi         : -MS_ERR_SEND;     /* HCD can't write data */
988*53ee8cc1Swenshuai.xi     }
989*53ee8cc1Swenshuai.xi     else if (u32Token & QTD_STS_XACTERR)
990*53ee8cc1Swenshuai.xi     {
991*53ee8cc1Swenshuai.xi         ms_debug_msg(" [ USB	QTD_STS_XACTERR ] \n ");
992*53ee8cc1Swenshuai.xi 
993*53ee8cc1Swenshuai.xi       if (QTD_CERR (u32Token))    /* ���~���Atimeout, bad crc, wrong PID */
994*53ee8cc1Swenshuai.xi         pUrb->s32Status = -EPIPE;
995*53ee8cc1Swenshuai.xi       else
996*53ee8cc1Swenshuai.xi       {
997*53ee8cc1Swenshuai.xi           ms_debug_warn ("devpath %s ep%d%s 3strikes\n",
998*53ee8cc1Swenshuai.xi                 pUrb->dev->devpath,
999*53ee8cc1Swenshuai.xi                 (int)usb_pipeendpoint (pUrb->u32Pipe),
1000*53ee8cc1Swenshuai.xi                 usb_pipein (pUrb->u32Pipe) ? "in" : "out");
1001*53ee8cc1Swenshuai.xi           pUrb->s32Status = -MS_ERR_PROTOCAL;
1002*53ee8cc1Swenshuai.xi       }
1003*53ee8cc1Swenshuai.xi     /* �S��error bit ���O��halt, will stall */
1004*53ee8cc1Swenshuai.xi     }
1005*53ee8cc1Swenshuai.xi     else if (QTD_CERR (u32Token))
1006*53ee8cc1Swenshuai.xi       pUrb->s32Status = -EPIPE;
1007*53ee8cc1Swenshuai.xi     else  /* ���������~ */
1008*53ee8cc1Swenshuai.xi       pUrb->s32Status = -MS_ERR_PROTOCAL;
1009*53ee8cc1Swenshuai.xi 
1010*53ee8cc1Swenshuai.xi     if( pUrb->s32Status < 0 )
1011*53ee8cc1Swenshuai.xi     {
1012*53ee8cc1Swenshuai.xi       ms_debug_warn("dev%d ep%d%s qtd token %08x --> status %d, len=%d\n",
1013*53ee8cc1Swenshuai.xi             (int)usb_pipedevice (pUrb->u32Pipe),
1014*53ee8cc1Swenshuai.xi             (int)usb_pipeendpoint (pUrb->u32Pipe),
1015*53ee8cc1Swenshuai.xi             usb_pipein (pUrb->u32Pipe) ? "in" : "out",
1016*53ee8cc1Swenshuai.xi             (unsigned int)u32Token, (int)pUrb->s32Status, (int)pUrb->u32TransferBufferLength);
1017*53ee8cc1Swenshuai.xi     }
1018*53ee8cc1Swenshuai.xi 
1019*53ee8cc1Swenshuai.xi 
1020*53ee8cc1Swenshuai.xi     /* Stall ��ܻݭn��error recovery */
1021*53ee8cc1Swenshuai.xi     if (pUrb->s32Status == -EPIPE)
1022*53ee8cc1Swenshuai.xi     {
1023*53ee8cc1Swenshuai.xi       /* halt bit obsolete */
1024*53ee8cc1Swenshuai.xi       //int  pipe = pUrb->u32Pipe;
1025*53ee8cc1Swenshuai.xi 
1026*53ee8cc1Swenshuai.xi       //if (!usb_pipecontrol (pipe))
1027*53ee8cc1Swenshuai.xi       //    usb_endpoint_halt (pUrb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe));
1028*53ee8cc1Swenshuai.xi 
1029*53ee8cc1Swenshuai.xi     }
1030*53ee8cc1Swenshuai.xi     /* if async CSPLIT failed, try cleaning out the TT buffer */
1031*53ee8cc1Swenshuai.xi     /* patch from linux 2.6.28 */
1032*53ee8cc1Swenshuai.xi #ifdef USB_EHCI_TT
1033*53ee8cc1Swenshuai.xi     else if (pUrb->dev->tt && !usb_pipeint (pUrb->u32Pipe)
1034*53ee8cc1Swenshuai.xi         && ((u32Token & QTD_STS_MISSMF) != 0 || QTD_CERR(u32Token) == 0)
1035*53ee8cc1Swenshuai.xi         && (pUrb->dev->tt->hub != hcd->self.root_hub))
1036*53ee8cc1Swenshuai.xi     {
1037*53ee8cc1Swenshuai.xi //#ifdef DEBUG
1038*53ee8cc1Swenshuai.xi       ms_debug_msg ("clear tt buffer port %d, a%d ep%d t%08x\n",
1039*53ee8cc1Swenshuai.xi         pUrb->dev->u32TTPort, pUrb->dev->u32DevNum,
1040*53ee8cc1Swenshuai.xi         usb_pipeendpoint (pUrb->u32Pipe), u32Token);
1041*53ee8cc1Swenshuai.xi //#endif
1042*53ee8cc1Swenshuai.xi       ms_usb_hub_tt_clear_buffer (pUrb->dev, pUrb->u32Pipe);
1043*53ee8cc1Swenshuai.xi     }
1044*53ee8cc1Swenshuai.xi #endif
1045*53ee8cc1Swenshuai.xi   }
1046*53ee8cc1Swenshuai.xi   ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1047*53ee8cc1Swenshuai.xi }
1048*53ee8cc1Swenshuai.xi 
1049*53ee8cc1Swenshuai.xi 
1050*53ee8cc1Swenshuai.xi static void
ms_urb_done(struct ehci_hcd * pEhci,struct urb * pUrb,struct stPtRegs * pRegs)1051*53ee8cc1Swenshuai.xi ms_urb_done (struct ehci_hcd *pEhci, struct urb *pUrb, struct stPtRegs *pRegs)
1052*53ee8cc1Swenshuai.xi {
1053*53ee8cc1Swenshuai.xi   ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1054*53ee8cc1Swenshuai.xi   if (pUrb->hcpriv != 0)
1055*53ee8cc1Swenshuai.xi   {
1056*53ee8cc1Swenshuai.xi     struct ehci_qh  *qh = (struct ehci_qh *) pUrb->hcpriv;
1057*53ee8cc1Swenshuai.xi     ms_qh_put (pEhci, qh);
1058*53ee8cc1Swenshuai.xi   }
1059*53ee8cc1Swenshuai.xi 
1060*53ee8cc1Swenshuai.xi   osapi_spin_lock (&pUrb->lock);
1061*53ee8cc1Swenshuai.xi   pUrb->hcpriv = 0;
1062*53ee8cc1Swenshuai.xi   switch (pUrb->s32Status)
1063*53ee8cc1Swenshuai.xi   {
1064*53ee8cc1Swenshuai.xi   case -EINPROGRESS:    /* success */
1065*53ee8cc1Swenshuai.xi     pUrb->s32Status = 0;
1066*53ee8cc1Swenshuai.xi   default:      /* fault */
1067*53ee8cc1Swenshuai.xi     INCREASE (pEhci->stats.u32Complete);
1068*53ee8cc1Swenshuai.xi     break;
1069*53ee8cc1Swenshuai.xi   case -MS_ERR_REMOTEIO:    /* fault or normal */
1070*53ee8cc1Swenshuai.xi     if (!(pUrb->u32TransferFlags & MS_FLAG_URB_SHORT_NOT_OK))
1071*53ee8cc1Swenshuai.xi       pUrb->s32Status = 0;
1072*53ee8cc1Swenshuai.xi     INCREASE (pEhci->stats.u32Complete);
1073*53ee8cc1Swenshuai.xi     break;
1074*53ee8cc1Swenshuai.xi   case -ECONNRESET:    /* canceled */
1075*53ee8cc1Swenshuai.xi   case -ENOENT:
1076*53ee8cc1Swenshuai.xi     INCREASE(pEhci->stats.u32Unlink);
1077*53ee8cc1Swenshuai.xi     break;
1078*53ee8cc1Swenshuai.xi   }
1079*53ee8cc1Swenshuai.xi   osapi_spin_unlock (&pUrb->lock);
1080*53ee8cc1Swenshuai.xi 
1081*53ee8cc1Swenshuai.xi   /* HCD run complete() funciton */
1082*53ee8cc1Swenshuai.xi   osapi_spin_unlock (&pEhci->tHcdLock);
1083*53ee8cc1Swenshuai.xi   ms_usb_hcd_giveback_urb (pUrb, pRegs);
1084*53ee8cc1Swenshuai.xi   osapi_spin_lock (&pEhci->tHcdLock);
1085*53ee8cc1Swenshuai.xi   ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1086*53ee8cc1Swenshuai.xi }
1087*53ee8cc1Swenshuai.xi 
1088*53ee8cc1Swenshuai.xi /*
1089*53ee8cc1Swenshuai.xi   * @brief          free qtd list and run urb's complet function
1090*53ee8cc1Swenshuai.xi   *
1091*53ee8cc1Swenshuai.xi   * @param          struct ehci_hcd *pEhci
1092*53ee8cc1Swenshuai.xi   * @param          struct ehci_qh *pQh
1093*53ee8cc1Swenshuai.xi   * @param          struct stPtRegs *pRegs
1094*53ee8cc1Swenshuai.xi   *
1095*53ee8cc1Swenshuai.xi   * @return         u8Count
1096*53ee8cc1Swenshuai.xi   */
1097*53ee8cc1Swenshuai.xi 
1098*53ee8cc1Swenshuai.xi #define HALT_BIT QTD_STS_HALT
1099*53ee8cc1Swenshuai.xi static unsigned
ms_qh_completions(struct ehci_hcd * pEhci,struct ehci_qh * pQh,struct stPtRegs * pRegs)1100*53ee8cc1Swenshuai.xi ms_qh_completions (struct ehci_hcd *pEhci, struct ehci_qh *pQh, struct stPtRegs *pRegs)
1101*53ee8cc1Swenshuai.xi {
1102*53ee8cc1Swenshuai.xi   struct ehci_qtd    *pLast = 0, *pEnd = pQh->pDummyQtd;
1103*53ee8cc1Swenshuai.xi   struct list_head  *entry, *tmp;
1104*53ee8cc1Swenshuai.xi   int      iStopped;
1105*53ee8cc1Swenshuai.xi   unsigned    u8Count = 0;
1106*53ee8cc1Swenshuai.xi   int      iDoStatus = 0;
1107*53ee8cc1Swenshuai.xi   unsigned char      u8State;
1108*53ee8cc1Swenshuai.xi   //BOOL      bIsPageOver = FALSE; // obsolete
1109*53ee8cc1Swenshuai.xi 
1110*53ee8cc1Swenshuai.xi   ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1111*53ee8cc1Swenshuai.xi   if (ms_is_empty_list (&pQh->qtd_list))
1112*53ee8cc1Swenshuai.xi   {
1113*53ee8cc1Swenshuai.xi     ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1114*53ee8cc1Swenshuai.xi     return u8Count;
1115*53ee8cc1Swenshuai.xi   }
1116*53ee8cc1Swenshuai.xi 
1117*53ee8cc1Swenshuai.xi   u8State = pQh->qh_status;
1118*53ee8cc1Swenshuai.xi   pQh->qh_status = QH_STS_COMPLETING;
1119*53ee8cc1Swenshuai.xi   iStopped = (u8State == QH_STS_IDLE);
1120*53ee8cc1Swenshuai.xi 
1121*53ee8cc1Swenshuai.xi   list_for_loop_ex (entry, tmp, &pQh->qtd_list)
1122*53ee8cc1Swenshuai.xi   {
1123*53ee8cc1Swenshuai.xi     struct ehci_qtd  *pQtd;
1124*53ee8cc1Swenshuai.xi     struct urb  *pUrb;
1125*53ee8cc1Swenshuai.xi     U32    u32Token = 0;
1126*53ee8cc1Swenshuai.xi 
1127*53ee8cc1Swenshuai.xi     pQtd = entry_to_container (entry, struct ehci_qtd, qtd_list);
1128*53ee8cc1Swenshuai.xi     //list_entry (entry, struct ehci_qtd,qtd_list, struct list_head,qtd);
1129*53ee8cc1Swenshuai.xi     pUrb = pQtd->urb;
1130*53ee8cc1Swenshuai.xi 
1131*53ee8cc1Swenshuai.xi     /* obsolete, no such hardware bug */
1132*53ee8cc1Swenshuai.xi     //if ( ((pQtd->hw_token >> 12) & 0x7) > 5)	//For patching H/W bug
1133*53ee8cc1Swenshuai.xi     //{
1134*53ee8cc1Swenshuai.xi     //    bIsPageOver = TRUE;
1135*53ee8cc1Swenshuai.xi     //}
1136*53ee8cc1Swenshuai.xi 
1137*53ee8cc1Swenshuai.xi     /* free previous QTD ...*/
1138*53ee8cc1Swenshuai.xi     if (pLast)
1139*53ee8cc1Swenshuai.xi     {
1140*53ee8cc1Swenshuai.xi       if (pLast->urb != pUrb)
1141*53ee8cc1Swenshuai.xi       {
1142*53ee8cc1Swenshuai.xi         ms_urb_done (pEhci, pLast->urb, pRegs);
1143*53ee8cc1Swenshuai.xi         u8Count++;
1144*53ee8cc1Swenshuai.xi       }
1145*53ee8cc1Swenshuai.xi       ms_ehci_qtd_free (pEhci, pLast);
1146*53ee8cc1Swenshuai.xi       pLast = 0;
1147*53ee8cc1Swenshuai.xi     }
1148*53ee8cc1Swenshuai.xi 
1149*53ee8cc1Swenshuai.xi     if (pQtd == pEnd)
1150*53ee8cc1Swenshuai.xi       break;
1151*53ee8cc1Swenshuai.xi 
1152*53ee8cc1Swenshuai.xi     /* HW implement qtds content copy */
1153*53ee8cc1Swenshuai.xi     rmb ();
1154*53ee8cc1Swenshuai.xi 
1155*53ee8cc1Swenshuai.xi     u32Token = pQtd->hw_token;
1156*53ee8cc1Swenshuai.xi 
1157*53ee8cc1Swenshuai.xi  xacterr_retry:
1158*53ee8cc1Swenshuai.xi     if ((u32Token & QTD_STS_ACT) == 0)
1159*53ee8cc1Swenshuai.xi     {
1160*53ee8cc1Swenshuai.xi       if ((u32Token & QTD_STS_HALT) != 0)
1161*53ee8cc1Swenshuai.xi       {
1162*53ee8cc1Swenshuai.xi         if ((u32Token & QTD_STS_XACTERR) &&
1163*53ee8cc1Swenshuai.xi                 QTD_CERR(u32Token) == 0 &&
1164*53ee8cc1Swenshuai.xi                 --pQh->xacterrs > 0 /*&&                !urb->unlinked*/) {
1165*53ee8cc1Swenshuai.xi                 u32Token &= ~QTD_STS_HALT;
1166*53ee8cc1Swenshuai.xi                 u32Token |= QTD_STS_ACT | (MAX_CERR_CNT << 10);
1167*53ee8cc1Swenshuai.xi                 pQtd->hw_token = u32Token;
1168*53ee8cc1Swenshuai.xi                 wmb();
1169*53ee8cc1Swenshuai.xi                 pQh->hw_token = u32Token;
1170*53ee8cc1Swenshuai.xi                 goto xacterr_retry;
1171*53ee8cc1Swenshuai.xi         }
1172*53ee8cc1Swenshuai.xi         iStopped = 1;
1173*53ee8cc1Swenshuai.xi       }
1174*53ee8cc1Swenshuai.xi       else if (IS_SHORT_READ (u32Token)
1175*53ee8cc1Swenshuai.xi 		/* patch from linux */
1176*53ee8cc1Swenshuai.xi 		&& !(pQtd->hw_alt_next_qtd & EHCI_LIST_END))
1177*53ee8cc1Swenshuai.xi //	  && (pQh->hw_alt_next_qtd & QTD_MASK)
1178*53ee8cc1Swenshuai.xi //	    == pEhci->stAsync->hw_alt_next_qtd)
1179*53ee8cc1Swenshuai.xi       {
1180*53ee8cc1Swenshuai.xi         iStopped = 1;
1181*53ee8cc1Swenshuai.xi         goto halt;
1182*53ee8cc1Swenshuai.xi       }
1183*53ee8cc1Swenshuai.xi     }
1184*53ee8cc1Swenshuai.xi     else if(!iStopped && HCD_IS_RUNNING (pEhci->hcd.state))
1185*53ee8cc1Swenshuai.xi     {
1186*53ee8cc1Swenshuai.xi       break;
1187*53ee8cc1Swenshuai.xi     }
1188*53ee8cc1Swenshuai.xi     else
1189*53ee8cc1Swenshuai.xi     {
1190*53ee8cc1Swenshuai.xi       iStopped = 1;
1191*53ee8cc1Swenshuai.xi 
1192*53ee8cc1Swenshuai.xi       if (pUrb->s32Status == -EINPROGRESS)
1193*53ee8cc1Swenshuai.xi         continue;
1194*53ee8cc1Swenshuai.xi 
1195*53ee8cc1Swenshuai.xi       /* issue status for control transfer */
1196*53ee8cc1Swenshuai.xi       if ((iDoStatus != 0)
1197*53ee8cc1Swenshuai.xi           && QTD_PID (u32Token) == 0)   //Check is OUT token?
1198*53ee8cc1Swenshuai.xi       {
1199*53ee8cc1Swenshuai.xi         iDoStatus = 0;
1200*53ee8cc1Swenshuai.xi         continue;
1201*53ee8cc1Swenshuai.xi       }
1202*53ee8cc1Swenshuai.xi 
1203*53ee8cc1Swenshuai.xi       if (u8State == QH_STS_IDLE
1204*53ee8cc1Swenshuai.xi           && pQtd->qtd_dma_addr
1205*53ee8cc1Swenshuai.xi             == pQh->hw_current_qtd)
1206*53ee8cc1Swenshuai.xi         u32Token = pQh->hw_token;
1207*53ee8cc1Swenshuai.xi 
1208*53ee8cc1Swenshuai.xi       if ((HALT_BIT & pQh->hw_token) == 0)
1209*53ee8cc1Swenshuai.xi       {
1210*53ee8cc1Swenshuai.xi halt:
1211*53ee8cc1Swenshuai.xi         pQh->hw_token |= HALT_BIT;
1212*53ee8cc1Swenshuai.xi         wmb ();
1213*53ee8cc1Swenshuai.xi       }
1214*53ee8cc1Swenshuai.xi     }
1215*53ee8cc1Swenshuai.xi 
1216*53ee8cc1Swenshuai.xi 
1217*53ee8cc1Swenshuai.xi     /* remove it from the queue */
1218*53ee8cc1Swenshuai.xi     osapi_spin_lock (&pUrb->lock);
1219*53ee8cc1Swenshuai.xi     ms_qtd_copy_status (pUrb, pQtd->length, u32Token);
1220*53ee8cc1Swenshuai.xi     /* obsolete, no such hardware bug */
1221*53ee8cc1Swenshuai.xi     //if (bIsPageOver)
1222*53ee8cc1Swenshuai.xi     //{
1223*53ee8cc1Swenshuai.xi     //    ms_debug_warn("urb error because C_Page > 5\n");
1224*53ee8cc1Swenshuai.xi     //    pUrb->s32Status = (QTD_PID (u32Token) == 1) /* Is IN token? */
1225*53ee8cc1Swenshuai.xi     //    ? -MS_ERR_RECEIVE   /* HCD can't read data */
1226*53ee8cc1Swenshuai.xi     //    : -MS_ERR_SEND;     /* HCD can't write data */
1227*53ee8cc1Swenshuai.xi     //}
1228*53ee8cc1Swenshuai.xi     iDoStatus = (pUrb->s32Status == -MS_ERR_REMOTEIO)
1229*53ee8cc1Swenshuai.xi         && usb_pipecontrol (pUrb->u32Pipe);
1230*53ee8cc1Swenshuai.xi     osapi_spin_unlock (&pUrb->lock);
1231*53ee8cc1Swenshuai.xi 
1232*53ee8cc1Swenshuai.xi     if (iStopped && pQtd->qtd_list.prev != &pQh->qtd_list) {
1233*53ee8cc1Swenshuai.xi       pLast = entry_to_container (pQtd->qtd_list.prev, struct ehci_qtd, qtd_list);
1234*53ee8cc1Swenshuai.xi       //list_entry (qtd->qtd_list.prev,struct ehci_qtd,qtd_list, struct list_head,last);
1235*53ee8cc1Swenshuai.xi       pLast->hw_next_qtd = pQtd->hw_next_qtd;
1236*53ee8cc1Swenshuai.xi 
1237*53ee8cc1Swenshuai.xi     }
1238*53ee8cc1Swenshuai.xi     ms_list_remove (&pQtd->qtd_list);
1239*53ee8cc1Swenshuai.xi     pLast = pQtd;
1240*53ee8cc1Swenshuai.xi 
1241*53ee8cc1Swenshuai.xi     pQh->xacterrs = QH_MAX_XACTRTT_RETRY;
1242*53ee8cc1Swenshuai.xi   }
1243*53ee8cc1Swenshuai.xi 
1244*53ee8cc1Swenshuai.xi   if (pLast != 0)
1245*53ee8cc1Swenshuai.xi   {
1246*53ee8cc1Swenshuai.xi     ms_urb_done (pEhci, pLast->urb, pRegs);
1247*53ee8cc1Swenshuai.xi     u8Count++;
1248*53ee8cc1Swenshuai.xi     ms_ehci_qtd_free (pEhci, pLast);
1249*53ee8cc1Swenshuai.xi     pLast = 0;
1250*53ee8cc1Swenshuai.xi   }
1251*53ee8cc1Swenshuai.xi 
1252*53ee8cc1Swenshuai.xi   pQh->qh_status = u8State;
1253*53ee8cc1Swenshuai.xi 
1254*53ee8cc1Swenshuai.xi   if ((iStopped != 0)
1255*53ee8cc1Swenshuai.xi       /* avoid some old EHCI vendor will overlay dummy qtds */
1256*53ee8cc1Swenshuai.xi       || pQh->hw_next_qtd == EHCI_LIST_END)
1257*53ee8cc1Swenshuai.xi   {
1258*53ee8cc1Swenshuai.xi #ifdef ENABLE_QH_REFRESH
1259*53ee8cc1Swenshuai.xi 	/* patch from linux 2.6.x ~ 3.8.x */
1260*53ee8cc1Swenshuai.xi 	if (u8State == QH_STS_IDLE)
1261*53ee8cc1Swenshuai.xi 		ms_qh_refresh(pEhci, pQh);
1262*53ee8cc1Swenshuai.xi 	else if (u8State == QH_STS_LINKED) {
1263*53ee8cc1Swenshuai.xi 		/* patch base on linux 2.6.x */
1264*53ee8cc1Swenshuai.xi 		if ((pQh->hw_ep_state2 & QH_SMASK) != 0) {
1265*53ee8cc1Swenshuai.xi 			ms_intr_deschedule(pEhci, pQh);
1266*53ee8cc1Swenshuai.xi 			ms_qh_schedule(pEhci, pQh);
1267*53ee8cc1Swenshuai.xi 		}
1268*53ee8cc1Swenshuai.xi 		else
1269*53ee8cc1Swenshuai.xi 			ms_unlink_async(pEhci, pQh);
1270*53ee8cc1Swenshuai.xi 	}
1271*53ee8cc1Swenshuai.xi #else // replaced by linux code
1272*53ee8cc1Swenshuai.xi     if (ms_is_empty_list (&pQh->qtd_list))
1273*53ee8cc1Swenshuai.xi       pEnd = pQh->pDummyQtd;
1274*53ee8cc1Swenshuai.xi     else
1275*53ee8cc1Swenshuai.xi     {
1276*53ee8cc1Swenshuai.xi       pEnd = entry_to_container (pQh->qtd_list.next,struct ehci_qtd, qtd_list);
1277*53ee8cc1Swenshuai.xi       if (pEnd->qtd_dma_addr == pQh->hw_current_qtd)
1278*53ee8cc1Swenshuai.xi         pEnd = 0;
1279*53ee8cc1Swenshuai.xi     }
1280*53ee8cc1Swenshuai.xi     if (pEnd)
1281*53ee8cc1Swenshuai.xi       ms_qh_update_link (pQh, pEnd);
1282*53ee8cc1Swenshuai.xi #endif
1283*53ee8cc1Swenshuai.xi   }
1284*53ee8cc1Swenshuai.xi 
1285*53ee8cc1Swenshuai.xi   ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1286*53ee8cc1Swenshuai.xi   return u8Count;
1287*53ee8cc1Swenshuai.xi }
1288*53ee8cc1Swenshuai.xi 
1289*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
1290*53ee8cc1Swenshuai.xi // high bandwidth multiplier, as encoded in highspeed endpoint descriptors
1291*53ee8cc1Swenshuai.xi #define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
1292*53ee8cc1Swenshuai.xi // ... and packet size, for any kind of endpoint descriptor
1293*53ee8cc1Swenshuai.xi #define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff)
1294*53ee8cc1Swenshuai.xi 
ms_qtd_register_free(struct ehci_hcd * pEhci,struct list_head * qtd_list)1295*53ee8cc1Swenshuai.xi static void ms_qtd_register_free (
1296*53ee8cc1Swenshuai.xi   struct ehci_hcd    *pEhci,
1297*53ee8cc1Swenshuai.xi   struct list_head  *qtd_list
1298*53ee8cc1Swenshuai.xi )
1299*53ee8cc1Swenshuai.xi {
1300*53ee8cc1Swenshuai.xi   struct list_head  *pEntry, *pTemp;
1301*53ee8cc1Swenshuai.xi 
1302*53ee8cc1Swenshuai.xi   ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1303*53ee8cc1Swenshuai.xi   list_for_loop_ex (pEntry, pTemp, qtd_list)
1304*53ee8cc1Swenshuai.xi   {
1305*53ee8cc1Swenshuai.xi     struct ehci_qtd  *pQtd;
1306*53ee8cc1Swenshuai.xi 
1307*53ee8cc1Swenshuai.xi     pQtd = entry_to_container (pEntry, struct ehci_qtd, qtd_list);
1308*53ee8cc1Swenshuai.xi     ms_list_remove (&pQtd->qtd_list);
1309*53ee8cc1Swenshuai.xi     ms_ehci_qtd_free (pEhci, pQtd);
1310*53ee8cc1Swenshuai.xi   }
1311*53ee8cc1Swenshuai.xi   ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1312*53ee8cc1Swenshuai.xi }
1313*53ee8cc1Swenshuai.xi 
1314*53ee8cc1Swenshuai.xi /*
1315*53ee8cc1Swenshuai.xi   * @brief             prepare and allocate qtd_list
1316*53ee8cc1Swenshuai.xi   *                       fill buffer to qtd from urb
1317*53ee8cc1Swenshuai.xi   *
1318*53ee8cc1Swenshuai.xi   * @param          struct ehci_hcd    *pEhci
1319*53ee8cc1Swenshuai.xi   * @param          struct urb    *pUrb
1320*53ee8cc1Swenshuai.xi   * @param          struct list_head  *pHead
1321*53ee8cc1Swenshuai.xi   * @param          int      iFlags
1322*53ee8cc1Swenshuai.xi   *
1323*53ee8cc1Swenshuai.xi   * @return           struct list_head *
1324*53ee8cc1Swenshuai.xi   */
1325*53ee8cc1Swenshuai.xi 
1326*53ee8cc1Swenshuai.xi static struct list_head *
ms_qh_urb_process(struct ehci_hcd * pEhci,struct urb * pUrb,struct list_head * pHead,int iFlags)1327*53ee8cc1Swenshuai.xi ms_qh_urb_process (
1328*53ee8cc1Swenshuai.xi   struct ehci_hcd    *pEhci,
1329*53ee8cc1Swenshuai.xi   struct urb    *pUrb,
1330*53ee8cc1Swenshuai.xi   struct list_head  *pHead,
1331*53ee8cc1Swenshuai.xi   int      iFlags
1332*53ee8cc1Swenshuai.xi )
1333*53ee8cc1Swenshuai.xi {
1334*53ee8cc1Swenshuai.xi   struct ehci_qtd    *pQtd, *pQtdPrev;
1335*53ee8cc1Swenshuai.xi   dma_addr_t    tBuf;
1336*53ee8cc1Swenshuai.xi   int      iLen, iMaxpkt;
1337*53ee8cc1Swenshuai.xi   int      iIsInput;
1338*53ee8cc1Swenshuai.xi   U32      u32Token;
1339*53ee8cc1Swenshuai.xi 
1340*53ee8cc1Swenshuai.xi   ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1341*53ee8cc1Swenshuai.xi   pQtd = ms_ehci_qtd_alloc (pEhci, iFlags);
1342*53ee8cc1Swenshuai.xi   if (!pQtd)
1343*53ee8cc1Swenshuai.xi   {
1344*53ee8cc1Swenshuai.xi       ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1345*53ee8cc1Swenshuai.xi       return 0;
1346*53ee8cc1Swenshuai.xi   }
1347*53ee8cc1Swenshuai.xi   ms_insert_list_before (&pQtd->qtd_list, pHead);
1348*53ee8cc1Swenshuai.xi   pQtd->urb = pUrb;
1349*53ee8cc1Swenshuai.xi 
1350*53ee8cc1Swenshuai.xi   u32Token = QTD_STS_ACT;
1351*53ee8cc1Swenshuai.xi   u32Token |= (MAX_CERR_CNT << 10);
1352*53ee8cc1Swenshuai.xi   /* for split transactions, SplitXState initialized to zero */
1353*53ee8cc1Swenshuai.xi 
1354*53ee8cc1Swenshuai.xi   iLen = pUrb->u32TransferBufferLength;
1355*53ee8cc1Swenshuai.xi   iIsInput = usb_pipein (pUrb->u32Pipe);
1356*53ee8cc1Swenshuai.xi   if (usb_pipecontrol (pUrb->u32Pipe))
1357*53ee8cc1Swenshuai.xi   {
1358*53ee8cc1Swenshuai.xi     ms_qtd_pack (pQtd, pUrb->tSetupDma, sizeof (struct usb_ctrlrequest),
1359*53ee8cc1Swenshuai.xi       u32Token | PID_SETUP, 8);
1360*53ee8cc1Swenshuai.xi 
1361*53ee8cc1Swenshuai.xi     /* ... and always at least one more pid */
1362*53ee8cc1Swenshuai.xi     u32Token ^= QTD_TOGGLE;
1363*53ee8cc1Swenshuai.xi     pQtdPrev = pQtd;
1364*53ee8cc1Swenshuai.xi     pQtd = ms_ehci_qtd_alloc (pEhci, iFlags);
1365*53ee8cc1Swenshuai.xi     if (!pQtd)
1366*53ee8cc1Swenshuai.xi       goto cleanup;
1367*53ee8cc1Swenshuai.xi     pQtd->urb = pUrb;
1368*53ee8cc1Swenshuai.xi     pQtdPrev->hw_next_qtd = (U32)(pQtd->qtd_dma_addr);
1369*53ee8cc1Swenshuai.xi     ms_insert_list_before (&pQtd->qtd_list, pHead);
1370*53ee8cc1Swenshuai.xi   }
1371*53ee8cc1Swenshuai.xi 
1372*53ee8cc1Swenshuai.xi   /*
1373*53ee8cc1Swenshuai.xi       * data stage : prepare buffer
1374*53ee8cc1Swenshuai.xi       */
1375*53ee8cc1Swenshuai.xi 
1376*53ee8cc1Swenshuai.xi   if (iLen > 0)
1377*53ee8cc1Swenshuai.xi     tBuf = pUrb->tTransferDma;
1378*53ee8cc1Swenshuai.xi   else
1379*53ee8cc1Swenshuai.xi     tBuf = 0;
1380*53ee8cc1Swenshuai.xi 
1381*53ee8cc1Swenshuai.xi   if (!tBuf || iIsInput)
1382*53ee8cc1Swenshuai.xi     u32Token |= PID_IN;
1383*53ee8cc1Swenshuai.xi 
1384*53ee8cc1Swenshuai.xi   /* patch code from linux */
1385*53ee8cc1Swenshuai.xi   iMaxpkt = max_packet(usb_maxpacket(pUrb->dev, pUrb->u32Pipe, !iIsInput));
1386*53ee8cc1Swenshuai.xi   //if (usb_pipebulk(pUrb->u32Pipe))
1387*53ee8cc1Swenshuai.xi   //{
1388*53ee8cc1Swenshuai.xi   //  switch (pUrb->dev->eSpeed)
1389*53ee8cc1Swenshuai.xi   //  {
1390*53ee8cc1Swenshuai.xi   //    case USB_FULL_SPEED:
1391*53ee8cc1Swenshuai.xi   //      iMaxpkt = max_packet(usb_maxpacket(pUrb->dev, pUrb->u32Pipe, !iIsInput));
1392*53ee8cc1Swenshuai.xi   //      break;
1393*53ee8cc1Swenshuai.xi   //    case USB_HIGH_SPEED:
1394*53ee8cc1Swenshuai.xi   //    default:
1395*53ee8cc1Swenshuai.xi   //      iMaxpkt = 512;
1396*53ee8cc1Swenshuai.xi   //      break;
1397*53ee8cc1Swenshuai.xi   //  }
1398*53ee8cc1Swenshuai.xi   //}
1399*53ee8cc1Swenshuai.xi   //else
1400*53ee8cc1Swenshuai.xi   //{
1401*53ee8cc1Swenshuai.xi   //  iMaxpkt = max_packet(usb_maxpacket(pUrb->dev, pUrb->u32Pipe, !iIsInput));
1402*53ee8cc1Swenshuai.xi   //}
1403*53ee8cc1Swenshuai.xi 
1404*53ee8cc1Swenshuai.xi   for (;;)
1405*53ee8cc1Swenshuai.xi   {
1406*53ee8cc1Swenshuai.xi     int this_qtd_len;
1407*53ee8cc1Swenshuai.xi 
1408*53ee8cc1Swenshuai.xi     this_qtd_len = ms_qtd_pack (pQtd, tBuf, iLen, u32Token, iMaxpkt);
1409*53ee8cc1Swenshuai.xi     iLen -= this_qtd_len;
1410*53ee8cc1Swenshuai.xi     tBuf += this_qtd_len;
1411*53ee8cc1Swenshuai.xi     if (iIsInput)
1412*53ee8cc1Swenshuai.xi       pQtd->hw_alt_next_qtd = pEhci->stAsync->hw_alt_next_qtd;
1413*53ee8cc1Swenshuai.xi 
1414*53ee8cc1Swenshuai.xi     /* for control transaction, maybe needs switch it */
1415*53ee8cc1Swenshuai.xi     if ((iMaxpkt & (this_qtd_len + (iMaxpkt - 1))) == 0)
1416*53ee8cc1Swenshuai.xi       u32Token ^= QTD_TOGGLE;
1417*53ee8cc1Swenshuai.xi 
1418*53ee8cc1Swenshuai.xi     if (iLen <= 0)
1419*53ee8cc1Swenshuai.xi       break;
1420*53ee8cc1Swenshuai.xi 
1421*53ee8cc1Swenshuai.xi     pQtdPrev = pQtd;
1422*53ee8cc1Swenshuai.xi     pQtd = ms_ehci_qtd_alloc (pEhci, iFlags);
1423*53ee8cc1Swenshuai.xi     if (!pQtd)
1424*53ee8cc1Swenshuai.xi       goto cleanup;
1425*53ee8cc1Swenshuai.xi     pQtd->urb = pUrb;
1426*53ee8cc1Swenshuai.xi     pQtdPrev->hw_next_qtd = (U32)(pQtd->qtd_dma_addr);
1427*53ee8cc1Swenshuai.xi     ms_insert_list_before (&pQtd->qtd_list, pHead);
1428*53ee8cc1Swenshuai.xi   }
1429*53ee8cc1Swenshuai.xi 
1430*53ee8cc1Swenshuai.xi   if ((pUrb->u32TransferFlags & MS_FLAG_URB_SHORT_NOT_OK) == 0
1431*53ee8cc1Swenshuai.xi         || usb_pipecontrol (pUrb->u32Pipe))
1432*53ee8cc1Swenshuai.xi     pQtd->hw_alt_next_qtd = EHCI_LIST_END;
1433*53ee8cc1Swenshuai.xi 
1434*53ee8cc1Swenshuai.xi   //if (tBuf != 0)
1435*53ee8cc1Swenshuai.xi   if (pUrb->u32TransferBufferLength != 0)
1436*53ee8cc1Swenshuai.xi   {
1437*53ee8cc1Swenshuai.xi     int  one_more = 0;
1438*53ee8cc1Swenshuai.xi 
1439*53ee8cc1Swenshuai.xi     if (usb_pipecontrol (pUrb->u32Pipe))
1440*53ee8cc1Swenshuai.xi     {
1441*53ee8cc1Swenshuai.xi       one_more = 1;
1442*53ee8cc1Swenshuai.xi       u32Token ^= 0x0100;      /* PID IN/OUT toggled  */
1443*53ee8cc1Swenshuai.xi       u32Token |= QTD_TOGGLE;  /* set DATA1 */
1444*53ee8cc1Swenshuai.xi     }
1445*53ee8cc1Swenshuai.xi     //else if (usb_pipebulk (pUrb->u32Pipe)
1446*53ee8cc1Swenshuai.xi     else if (usb_pipeout (pUrb->u32Pipe)
1447*53ee8cc1Swenshuai.xi         && (pUrb->u32TransferFlags & MS_FLAG_URB_ZERO_PACKET)
1448*53ee8cc1Swenshuai.xi         && !(pUrb->u32TransferBufferLength % iMaxpkt))
1449*53ee8cc1Swenshuai.xi     {
1450*53ee8cc1Swenshuai.xi       one_more = 1;
1451*53ee8cc1Swenshuai.xi     }
1452*53ee8cc1Swenshuai.xi 
1453*53ee8cc1Swenshuai.xi     if (one_more)
1454*53ee8cc1Swenshuai.xi     {
1455*53ee8cc1Swenshuai.xi       pQtdPrev = pQtd;
1456*53ee8cc1Swenshuai.xi       pQtd = ms_ehci_qtd_alloc (pEhci, iFlags);
1457*53ee8cc1Swenshuai.xi       if (!pQtd)
1458*53ee8cc1Swenshuai.xi         goto cleanup;
1459*53ee8cc1Swenshuai.xi       pQtd->urb = pUrb;
1460*53ee8cc1Swenshuai.xi       pQtdPrev->hw_next_qtd = (U32)(pQtd->qtd_dma_addr);
1461*53ee8cc1Swenshuai.xi       ms_insert_list_before (&pQtd->qtd_list, pHead);
1462*53ee8cc1Swenshuai.xi 
1463*53ee8cc1Swenshuai.xi       /* make NULL packet */
1464*53ee8cc1Swenshuai.xi       ms_qtd_pack (pQtd, 0, 0, u32Token, 0);
1465*53ee8cc1Swenshuai.xi     }
1466*53ee8cc1Swenshuai.xi   }
1467*53ee8cc1Swenshuai.xi 
1468*53ee8cc1Swenshuai.xi   /* set interrupt enable when qtd completed */
1469*53ee8cc1Swenshuai.xi   if (!(pUrb->u32TransferFlags & MS_FLAG_URB_NO_INTERRUPT))
1470*53ee8cc1Swenshuai.xi     pQtd->hw_token |= QTD_IOC;
1471*53ee8cc1Swenshuai.xi 
1472*53ee8cc1Swenshuai.xi   ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1473*53ee8cc1Swenshuai.xi   return pHead;
1474*53ee8cc1Swenshuai.xi 
1475*53ee8cc1Swenshuai.xi cleanup:
1476*53ee8cc1Swenshuai.xi 
1477*53ee8cc1Swenshuai.xi   ms_qtd_register_free (pEhci, pHead);
1478*53ee8cc1Swenshuai.xi   ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1479*53ee8cc1Swenshuai.xi   return 0;
1480*53ee8cc1Swenshuai.xi }
1481*53ee8cc1Swenshuai.xi 
1482*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
1483*53ee8cc1Swenshuai.xi /* Obsolete code */
1484*53ee8cc1Swenshuai.xi //static __inline__ void
1485*53ee8cc1Swenshuai.xi //ms_clear_toggle (struct usb_device *pUdev, int iEp, int is_out, struct ehci_qh *pQh)
1486*53ee8cc1Swenshuai.xi //{
1487*53ee8cc1Swenshuai.xi //  ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1488*53ee8cc1Swenshuai.xi //  ms_debug_msg ("clear toggle dev%d iEp 0x%x-%s\n",
1489*53ee8cc1Swenshuai.xi //        (int)pUdev->u32DevNum, iEp, is_out ? "out" : "in");
1490*53ee8cc1Swenshuai.xi //  pQh->hw_token &= ~(QTD_TOGGLE);
1491*53ee8cc1Swenshuai.xi //
1492*53ee8cc1Swenshuai.xi //  usb_settoggle (pUdev, iEp, is_out, 1);
1493*53ee8cc1Swenshuai.xi //  ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1494*53ee8cc1Swenshuai.xi //}
1495*53ee8cc1Swenshuai.xi /*
1496*53ee8cc1Swenshuai.xi   * @brief             allocate and make qh
1497*53ee8cc1Swenshuai.xi   *
1498*53ee8cc1Swenshuai.xi   * @param          struct ehci_hcd    *pEhci
1499*53ee8cc1Swenshuai.xi   * @param          struct urb    *pUrb
1500*53ee8cc1Swenshuai.xi   * @param          int      iFlags
1501*53ee8cc1Swenshuai.xi   *
1502*53ee8cc1Swenshuai.xi   * @return           struct ehci_qh *
1503*53ee8cc1Swenshuai.xi   */
1504*53ee8cc1Swenshuai.xi 
1505*53ee8cc1Swenshuai.xi static struct ehci_qh *
ms_qh_make(struct ehci_hcd * pEhci,struct urb * pUrb,int iFlags)1506*53ee8cc1Swenshuai.xi ms_qh_make (
1507*53ee8cc1Swenshuai.xi   struct ehci_hcd    *pEhci,
1508*53ee8cc1Swenshuai.xi   struct urb    *pUrb,
1509*53ee8cc1Swenshuai.xi   int      iFlags
1510*53ee8cc1Swenshuai.xi )
1511*53ee8cc1Swenshuai.xi {
1512*53ee8cc1Swenshuai.xi   struct ehci_qh    *pQh = ms_ehci_qh_alloc (pEhci, iFlags);
1513*53ee8cc1Swenshuai.xi   U32      u32Info1 = 0, u32Info2 = 0;
1514*53ee8cc1Swenshuai.xi   int      iIsInput, iType;
1515*53ee8cc1Swenshuai.xi   int      iMaxpkt = 0;
1516*53ee8cc1Swenshuai.xi 
1517*53ee8cc1Swenshuai.xi   ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1518*53ee8cc1Swenshuai.xi   if (!pQh)
1519*53ee8cc1Swenshuai.xi   {
1520*53ee8cc1Swenshuai.xi       ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1521*53ee8cc1Swenshuai.xi       return pQh;
1522*53ee8cc1Swenshuai.xi   }
1523*53ee8cc1Swenshuai.xi 
1524*53ee8cc1Swenshuai.xi   u32Info1 |= usb_pipeendpoint (pUrb->u32Pipe) << 8;
1525*53ee8cc1Swenshuai.xi   u32Info1 |= usb_pipedevice (pUrb->u32Pipe) << 0;
1526*53ee8cc1Swenshuai.xi 
1527*53ee8cc1Swenshuai.xi   iIsInput = usb_pipein (pUrb->u32Pipe);
1528*53ee8cc1Swenshuai.xi   iType = usb_pipetype (pUrb->u32Pipe);
1529*53ee8cc1Swenshuai.xi   iMaxpkt = usb_maxpacket (pUrb->dev, pUrb->u32Pipe, !iIsInput);
1530*53ee8cc1Swenshuai.xi 
1531*53ee8cc1Swenshuai.xi   /* check if maximum packet size > 1024 bytes */
1532*53ee8cc1Swenshuai.xi   if (max_packet(iMaxpkt) > 1024) {
1533*53ee8cc1Swenshuai.xi     ms_debug_err("error maxp %d\n", max_packet(iMaxpkt));
1534*53ee8cc1Swenshuai.xi     goto done;
1535*53ee8cc1Swenshuai.xi   }
1536*53ee8cc1Swenshuai.xi 
1537*53ee8cc1Swenshuai.xi   if (iType == EP_INTERRUPT)
1538*53ee8cc1Swenshuai.xi   {
1539*53ee8cc1Swenshuai.xi     pQh->u8Usecs = NS_2_US(ms_usb_calc_bus_time (USB_HIGH_SPEED, iIsInput,
1540*53ee8cc1Swenshuai.xi         hb_mult (iMaxpkt) * max_packet (iMaxpkt)));
1541*53ee8cc1Swenshuai.xi 
1542*53ee8cc1Swenshuai.xi     pQh->u16Start = NO_FRAME;
1543*53ee8cc1Swenshuai.xi 
1544*53ee8cc1Swenshuai.xi     if (pUrb->dev->eSpeed == USB_HIGH_SPEED)
1545*53ee8cc1Swenshuai.xi     {
1546*53ee8cc1Swenshuai.xi       pQh->c_usecs = 0;
1547*53ee8cc1Swenshuai.xi       pQh->u8Gap_uf = 0;
1548*53ee8cc1Swenshuai.xi 
1549*53ee8cc1Swenshuai.xi       /* Warning, highspeed periods < 1 frame. */
1550*53ee8cc1Swenshuai.xi       pQh->u16Period = pUrb->u32Interval >> 3;
1551*53ee8cc1Swenshuai.xi       /* patch from linux, 2.6.28 and 3.10.86 different */
1552*53ee8cc1Swenshuai.xi       //if (pQh->u16Period < 1)
1553*53ee8cc1Swenshuai.xi       if (pQh->u16Period == 1 && pUrb->u32Interval != 1)
1554*53ee8cc1Swenshuai.xi       {
1555*53ee8cc1Swenshuai.xi         ms_debug_warn ("intr period %d uframes, NYET!", (int)pUrb->u32Interval);
1556*53ee8cc1Swenshuai.xi         goto done;
1557*53ee8cc1Swenshuai.xi       }
1558*53ee8cc1Swenshuai.xi     }
1559*53ee8cc1Swenshuai.xi     else
1560*53ee8cc1Swenshuai.xi     {
1561*53ee8cc1Swenshuai.xi 
1562*53ee8cc1Swenshuai.xi       /* FS/LS transfer times */
1563*53ee8cc1Swenshuai.xi       pQh->u8Gap_uf = 1 + ms_usb_calc_bus_time (pUrb->dev->eSpeed,
1564*53ee8cc1Swenshuai.xi           iIsInput, iMaxpkt) / (125 * 1000);
1565*53ee8cc1Swenshuai.xi 
1566*53ee8cc1Swenshuai.xi       /* Warning, let SPLIT/CSPLIT times to close */
1567*53ee8cc1Swenshuai.xi       if (iIsInput)
1568*53ee8cc1Swenshuai.xi       {    // SPLIT, gap, CSPLIT+DATA
1569*53ee8cc1Swenshuai.xi         pQh->c_usecs = pQh->u8Usecs + HIGHSPEED_US (0);
1570*53ee8cc1Swenshuai.xi         pQh->u8Usecs = (U8)HIGHSPEED_US (1);
1571*53ee8cc1Swenshuai.xi       }
1572*53ee8cc1Swenshuai.xi       else
1573*53ee8cc1Swenshuai.xi       {    // SPLIT+DATA, gap, CSPLIT
1574*53ee8cc1Swenshuai.xi         pQh->u8Usecs += HIGHSPEED_US (1);
1575*53ee8cc1Swenshuai.xi         pQh->c_usecs = (U8)HIGHSPEED_US (0);
1576*53ee8cc1Swenshuai.xi       }
1577*53ee8cc1Swenshuai.xi       pQh->u16Period = pUrb->u32Interval;
1578*53ee8cc1Swenshuai.xi 
1579*53ee8cc1Swenshuai.xi     }
1580*53ee8cc1Swenshuai.xi   }
1581*53ee8cc1Swenshuai.xi 
1582*53ee8cc1Swenshuai.xi   /* patch from linux */
1583*53ee8cc1Swenshuai.xi   pQh->dev = pUrb->dev;
1584*53ee8cc1Swenshuai.xi 
1585*53ee8cc1Swenshuai.xi /* merge code into the following switch case description */
1586*53ee8cc1Swenshuai.xi #if 0
1587*53ee8cc1Swenshuai.xi   if (pUrb->dev->eSpeed == USB_HIGH_SPEED)
1588*53ee8cc1Swenshuai.xi   {
1589*53ee8cc1Swenshuai.xi     u32Info1 |= (2 << 12);
1590*53ee8cc1Swenshuai.xi   }
1591*53ee8cc1Swenshuai.xi   else if (pUrb->dev->eSpeed == USB_LOW_SPEED)
1592*53ee8cc1Swenshuai.xi   {
1593*53ee8cc1Swenshuai.xi     u32Info1 |= (1 << 12);
1594*53ee8cc1Swenshuai.xi   }
1595*53ee8cc1Swenshuai.xi   else
1596*53ee8cc1Swenshuai.xi   {
1597*53ee8cc1Swenshuai.xi     if (pUrb->dev->eSpeed != USB_FULL_SPEED)
1598*53ee8cc1Swenshuai.xi        ms_debug_warn ("unknow speed %d", pUrb->dev->eSpeed);
1599*53ee8cc1Swenshuai.xi   }
1600*53ee8cc1Swenshuai.xi #endif
1601*53ee8cc1Swenshuai.xi 
1602*53ee8cc1Swenshuai.xi   /* Is TT? */
1603*53ee8cc1Swenshuai.xi   switch (pUrb->dev->eSpeed)
1604*53ee8cc1Swenshuai.xi   {
1605*53ee8cc1Swenshuai.xi 
1606*53ee8cc1Swenshuai.xi   case USB_LOW_SPEED:
1607*53ee8cc1Swenshuai.xi     //if (iType == EP_CONTROL)
1608*53ee8cc1Swenshuai.xi     //{
1609*53ee8cc1Swenshuai.xi     //  u32Info1 |= 8 << 16;  /* hard code maxpacket item */
1610*53ee8cc1Swenshuai.xi     //}
1611*53ee8cc1Swenshuai.xi     u32Info1 |= (1 << 12);  /* EPS is 1.5 Mb/s */
1612*53ee8cc1Swenshuai.xi 
1613*53ee8cc1Swenshuai.xi   case USB_FULL_SPEED:
1614*53ee8cc1Swenshuai.xi     /* patch from linux, maxp applied */
1615*53ee8cc1Swenshuai.xi     //if (iType == EP_CONTROL && (pUrb->dev->eSpeed == USB_FULL_SPEED) )
1616*53ee8cc1Swenshuai.xi     //{
1617*53ee8cc1Swenshuai.xi     //  //info1 |= 64 << 16;  // fixed maxpacket
1618*53ee8cc1Swenshuai.xi     //  u32Info1 |= max_packet (iMaxpkt) << 16; // PIPE_INTERRUPT,PIPE_BULK,PIPE_ISOCHRONOUS
1619*53ee8cc1Swenshuai.xi     //}
1620*53ee8cc1Swenshuai.xi     //if (iType != EP_CONTROL)
1621*53ee8cc1Swenshuai.xi     //{
1622*53ee8cc1Swenshuai.xi     //  u32Info1 |= max_packet (iMaxpkt) << 16; // PIPE_INTERRUPT,PIPE_BULK,PIPE_ISOCHRONOUS
1623*53ee8cc1Swenshuai.xi     //}
1624*53ee8cc1Swenshuai.xi     u32Info1 |= iMaxpkt << 16;
1625*53ee8cc1Swenshuai.xi     /* EPS 0 means "full" */
1626*53ee8cc1Swenshuai.xi   //  info1 |= (3 << 12);  /* EPS "reserve" */
1627*53ee8cc1Swenshuai.xi     if (iType != EP_INTERRUPT)
1628*53ee8cc1Swenshuai.xi       u32Info1 |= (EHCI_RL_NAKCNT_TT << 28);
1629*53ee8cc1Swenshuai.xi     if (iType == EP_CONTROL)
1630*53ee8cc1Swenshuai.xi     {
1631*53ee8cc1Swenshuai.xi       u32Info1 |= QH_C_BIT;  /* for TT */
1632*53ee8cc1Swenshuai.xi       u32Info1 |= QH_DTC_BIT;    /* toggle from qtd */
1633*53ee8cc1Swenshuai.xi     }
1634*53ee8cc1Swenshuai.xi     u32Info2 |= (EHCI_HI_BW_MULT_TT << 30);
1635*53ee8cc1Swenshuai.xi 
1636*53ee8cc1Swenshuai.xi     /* linux code always sets ttport, but not to set hubaddr iff roothub */
1637*53ee8cc1Swenshuai.xi     u32Info2 |= pUrb->dev->u32TTPort << 23; /* Port Number */
1638*53ee8cc1Swenshuai.xi     if (pUrb->dev->tt && pUrb->dev->tt->hub->u32DevNum != 1) // Skip the Root Hub devnum == 1
1639*53ee8cc1Swenshuai.xi     {
1640*53ee8cc1Swenshuai.xi         u32Info2 |= pUrb->dev->tt->hub->u32DevNum << 16; /* Hub Addr */
1641*53ee8cc1Swenshuai.xi         ms_debug_debug("[USB] set TT and not root hub, (ttport, hubaddr) = (%d,%d)\n", pUrb->dev->u32TTPort, pUrb->dev->tt->hub->u32DevNum);
1642*53ee8cc1Swenshuai.xi     }
1643*53ee8cc1Swenshuai.xi     //if (pUrb->dev->tt->hub->u32DevNum != 1)     // Skip the Root Hub devnum == 1
1644*53ee8cc1Swenshuai.xi     //{
1645*53ee8cc1Swenshuai.xi     //    u32Info2 |= pUrb->dev->u32TTPort << 23; /* Port Number */
1646*53ee8cc1Swenshuai.xi     //    u32Info2 |= pUrb->dev->tt->hub->u32DevNum << 16; /* Hub Addr */
1647*53ee8cc1Swenshuai.xi     //}
1648*53ee8cc1Swenshuai.xi     /* NOTE:  if (EP_INTERRUPT) { scheduler sets c-mask } */
1649*53ee8cc1Swenshuai.xi     break;
1650*53ee8cc1Swenshuai.xi   case USB_HIGH_SPEED:      /* �P TT �L�� */
1651*53ee8cc1Swenshuai.xi     u32Info1 |= (2 << 12);  /* EPS is 480Mb/s */
1652*53ee8cc1Swenshuai.xi 
1653*53ee8cc1Swenshuai.xi     if (iType == EP_CONTROL)
1654*53ee8cc1Swenshuai.xi     {
1655*53ee8cc1Swenshuai.xi       u32Info1 |= (EHCI_RL_NAKCNT << 28);
1656*53ee8cc1Swenshuai.xi       u32Info1 |= 64 << 16;  /* Endpoint (wMaxPacketSize) */
1657*53ee8cc1Swenshuai.xi       u32Info1 |= QH_DTC_BIT;   /* Data toggle control */
1658*53ee8cc1Swenshuai.xi       u32Info2 |= (EHCI_HI_BW_MULT_HS << 30);
1659*53ee8cc1Swenshuai.xi     }
1660*53ee8cc1Swenshuai.xi     else if (iType == EP_BULK)
1661*53ee8cc1Swenshuai.xi     {
1662*53ee8cc1Swenshuai.xi       u32Info1 |= (EHCI_RL_NAKCNT << 28);
1663*53ee8cc1Swenshuai.xi       u32Info1 |= max_packet (iMaxpkt) << 16;  // Philips mp3 player endpoint descriptor bug
1664*53ee8cc1Swenshuai.xi       u32Info2 |= (EHCI_HI_BW_MULT_HS << 30);
1665*53ee8cc1Swenshuai.xi     }
1666*53ee8cc1Swenshuai.xi     else
1667*53ee8cc1Swenshuai.xi     {    /* Other transation type */
1668*53ee8cc1Swenshuai.xi       u32Info1 |= max_packet (iMaxpkt) << 16;
1669*53ee8cc1Swenshuai.xi       u32Info2 |= hb_mult (iMaxpkt) << 30;
1670*53ee8cc1Swenshuai.xi     }
1671*53ee8cc1Swenshuai.xi     break;
1672*53ee8cc1Swenshuai.xi   default:
1673*53ee8cc1Swenshuai.xi      ms_debug_msg ("usb dev %p speed %d", pUrb->dev, pUrb->dev->eSpeed);
1674*53ee8cc1Swenshuai.xi done:
1675*53ee8cc1Swenshuai.xi     ms_qh_put (pEhci, pQh);
1676*53ee8cc1Swenshuai.xi     ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1677*53ee8cc1Swenshuai.xi     return 0;
1678*53ee8cc1Swenshuai.xi   }
1679*53ee8cc1Swenshuai.xi 
1680*53ee8cc1Swenshuai.xi   pQh->qh_status = QH_STS_IDLE;
1681*53ee8cc1Swenshuai.xi   pQh->hw_ep_state1 = u32Info1;
1682*53ee8cc1Swenshuai.xi   pQh->hw_ep_state2 = u32Info2;
1683*53ee8cc1Swenshuai.xi   usb_settoggle (pUrb->dev, usb_pipeendpoint (pUrb->u32Pipe), !iIsInput, 1);
1684*53ee8cc1Swenshuai.xi #ifdef ENABLE_QH_REFRESH
1685*53ee8cc1Swenshuai.xi   /* patch from linux 2.6.x ~ 3.8.x */
1686*53ee8cc1Swenshuai.xi   ms_qh_refresh(pEhci, pQh);
1687*53ee8cc1Swenshuai.xi #else
1688*53ee8cc1Swenshuai.xi   ms_qh_update_link (pQh, pQh->pDummyQtd); // replaced by ms_qh_refresh()
1689*53ee8cc1Swenshuai.xi #endif
1690*53ee8cc1Swenshuai.xi   ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1691*53ee8cc1Swenshuai.xi   return pQh;
1692*53ee8cc1Swenshuai.xi }
1693*53ee8cc1Swenshuai.xi 
1694*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
1695*53ee8cc1Swenshuai.xi /*
1696*53ee8cc1Swenshuai.xi   * @brief          start async schedule
1697*53ee8cc1Swenshuai.xi   *
1698*53ee8cc1Swenshuai.xi   * @param          struct ehci_hcd    *pEhci
1699*53ee8cc1Swenshuai.xi   * @param          struct ehci_qh  *pQh
1700*53ee8cc1Swenshuai.xi   *
1701*53ee8cc1Swenshuai.xi   * @return         none
1702*53ee8cc1Swenshuai.xi   */
1703*53ee8cc1Swenshuai.xi 
ms_qh_link_async(struct ehci_hcd * pEhci,struct ehci_qh * pQh)1704*53ee8cc1Swenshuai.xi static void ms_qh_link_async (struct ehci_hcd *pEhci, struct ehci_qh  *pQh)
1705*53ee8cc1Swenshuai.xi {
1706*53ee8cc1Swenshuai.xi   U32    u32DmaAddr = QH_NEXT (pQh->qh_dma_addr);
1707*53ee8cc1Swenshuai.xi   struct ehci_qh  *pHead;
1708*53ee8cc1Swenshuai.xi 
1709*53ee8cc1Swenshuai.xi   ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1710*53ee8cc1Swenshuai.xi   pHead = pEhci->stAsync;
1711*53ee8cc1Swenshuai.xi   ms_timer_action_done (pEhci, TIMER_ASYNC_OFF);
1712*53ee8cc1Swenshuai.xi 
1713*53ee8cc1Swenshuai.xi   if (!pHead->qh_next.qh)
1714*53ee8cc1Swenshuai.xi   {
1715*53ee8cc1Swenshuai.xi     U32  cmd = hcd_reg_readl ((U32)&pEhci->op_regs->usbcmd);
1716*53ee8cc1Swenshuai.xi     //If disable => restart it
1717*53ee8cc1Swenshuai.xi     if (!(cmd & USBCMD_ASE))
1718*53ee8cc1Swenshuai.xi     {
1719*53ee8cc1Swenshuai.xi       (void) ms_check_status (&pEhci->op_regs->usbsts, USBSTS_ASS, 0, 150);
1720*53ee8cc1Swenshuai.xi       cmd |= USBCMD_ASE | USBCMD_RUN;         //asynchronous scheduler enable
1721*53ee8cc1Swenshuai.xi       hcd_reg_writel (cmd, (U32)&pEhci->op_regs->usbcmd);
1722*53ee8cc1Swenshuai.xi       pEhci->hcd.state = HCD_STATE_RUNNING;
1723*53ee8cc1Swenshuai.xi     }
1724*53ee8cc1Swenshuai.xi   }
1725*53ee8cc1Swenshuai.xi 
1726*53ee8cc1Swenshuai.xi   /* patch from linux code */
1727*53ee8cc1Swenshuai.xi #ifdef ENABLE_QH_REFRESH
1728*53ee8cc1Swenshuai.xi   /* clear toggle */
1729*53ee8cc1Swenshuai.xi   if (pQh->qh_status == QH_STS_IDLE)
1730*53ee8cc1Swenshuai.xi       ms_qh_refresh(pEhci, pQh);
1731*53ee8cc1Swenshuai.xi #else
1732*53ee8cc1Swenshuai.xi   /* Don't write QH memory if not necessary */
1733*53ee8cc1Swenshuai.xi   if(pQh->hw_token & HALT_BIT)
1734*53ee8cc1Swenshuai.xi     pQh->hw_token &= ~HALT_BIT;
1735*53ee8cc1Swenshuai.xi #endif
1736*53ee8cc1Swenshuai.xi 
1737*53ee8cc1Swenshuai.xi   pQh->qh_next = pHead->qh_next;
1738*53ee8cc1Swenshuai.xi   pQh->hw_next_qh = pHead->hw_next_qh;
1739*53ee8cc1Swenshuai.xi   wmb ();
1740*53ee8cc1Swenshuai.xi 
1741*53ee8cc1Swenshuai.xi   pHead->qh_next.qh = pQh;
1742*53ee8cc1Swenshuai.xi   pHead->hw_next_qh = u32DmaAddr;
1743*53ee8cc1Swenshuai.xi 
1744*53ee8cc1Swenshuai.xi   /* note: qh descriptor needs to flush into the memory */
1745*53ee8cc1Swenshuai.xi 
1746*53ee8cc1Swenshuai.xi   pQh->xacterrs = QH_MAX_XACTRTT_RETRY; // maximum xacterr retry count
1747*53ee8cc1Swenshuai.xi   pQh->qh_status = QH_STS_LINKED;
1748*53ee8cc1Swenshuai.xi   /* IRQ will report qtd completions event */
1749*53ee8cc1Swenshuai.xi   ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1750*53ee8cc1Swenshuai.xi }
1751*53ee8cc1Swenshuai.xi 
1752*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
1753*53ee8cc1Swenshuai.xi 
1754*53ee8cc1Swenshuai.xi #define  QH_ADDR_MASK  0x7f
1755*53ee8cc1Swenshuai.xi 
ms_qh_append_tds(struct ehci_hcd * pEhci,struct urb * pUrb,struct list_head * qtd_list,int iEpNum,void ** ptr)1756*53ee8cc1Swenshuai.xi static struct ehci_qh *ms_qh_append_tds (
1757*53ee8cc1Swenshuai.xi   struct ehci_hcd    *pEhci,
1758*53ee8cc1Swenshuai.xi   struct urb    *pUrb,
1759*53ee8cc1Swenshuai.xi   struct list_head  *qtd_list,
1760*53ee8cc1Swenshuai.xi   int      iEpNum,
1761*53ee8cc1Swenshuai.xi   void      **ptr
1762*53ee8cc1Swenshuai.xi )
1763*53ee8cc1Swenshuai.xi {
1764*53ee8cc1Swenshuai.xi   struct ehci_qh    *pQh = 0;
1765*53ee8cc1Swenshuai.xi   //int maxp;
1766*53ee8cc1Swenshuai.xi 
1767*53ee8cc1Swenshuai.xi   ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1768*53ee8cc1Swenshuai.xi   pQh = (struct ehci_qh *) *ptr;
1769*53ee8cc1Swenshuai.xi   if (pQh == 0)
1770*53ee8cc1Swenshuai.xi   {
1771*53ee8cc1Swenshuai.xi     pQh = ms_qh_make (pEhci, pUrb, GFP_ATOMIC);
1772*53ee8cc1Swenshuai.xi     *ptr = pQh;
1773*53ee8cc1Swenshuai.xi   }
1774*53ee8cc1Swenshuai.xi 
1775*53ee8cc1Swenshuai.xi   if (pQh != 0)
1776*53ee8cc1Swenshuai.xi   {
1777*53ee8cc1Swenshuai.xi     struct ehci_qtd  *pQtd;
1778*53ee8cc1Swenshuai.xi 
1779*53ee8cc1Swenshuai.xi     if (ms_is_empty_list (qtd_list))
1780*53ee8cc1Swenshuai.xi       pQtd = 0;
1781*53ee8cc1Swenshuai.xi     else
1782*53ee8cc1Swenshuai.xi     {
1783*53ee8cc1Swenshuai.xi       pQtd = entry_to_container (qtd_list->next, struct ehci_qtd, qtd_list);
1784*53ee8cc1Swenshuai.xi       //list_entry (qtd_list->next, struct ehci_qtd, qtd_list, struct list_head, qtd);
1785*53ee8cc1Swenshuai.xi     }
1786*53ee8cc1Swenshuai.xi 
1787*53ee8cc1Swenshuai.xi     /* control qh may need patching after enumeration */
1788*53ee8cc1Swenshuai.xi     if (iEpNum == 0)
1789*53ee8cc1Swenshuai.xi     {
1790*53ee8cc1Swenshuai.xi       /* ep0 maxpacket will be updated here after HCD issue get_descriptor. */
1791*53ee8cc1Swenshuai.xi       /* the purpose like usb_ep0_reinit */
1792*53ee8cc1Swenshuai.xi       if (!(pQh->hw_ep_state1 & (0x3 << 12)))
1793*53ee8cc1Swenshuai.xi       {
1794*53ee8cc1Swenshuai.xi         int maxp, hw_maxp;
1795*53ee8cc1Swenshuai.xi 
1796*53ee8cc1Swenshuai.xi         maxp = usb_maxpacket (pUrb->dev, pUrb->u32Pipe, !(usb_pipein (pUrb->u32Pipe)));
1797*53ee8cc1Swenshuai.xi         hw_maxp = max_packet(pQh->hw_ep_state1 >> 16);
1798*53ee8cc1Swenshuai.xi         if (maxp != hw_maxp)
1799*53ee8cc1Swenshuai.xi             ms_debug_debug("[USB] hw_map(%x) <-> maxp(%x)\n", hw_maxp, maxp);
1800*53ee8cc1Swenshuai.xi 
1801*53ee8cc1Swenshuai.xi         if (maxp > hw_maxp)
1802*53ee8cc1Swenshuai.xi         {
1803*53ee8cc1Swenshuai.xi           U32  u32Info = pQh->hw_ep_state1;
1804*53ee8cc1Swenshuai.xi 
1805*53ee8cc1Swenshuai.xi           u32Info &= ~(0x07ff << 16);
1806*53ee8cc1Swenshuai.xi           u32Info |= maxp << 16;
1807*53ee8cc1Swenshuai.xi           pQh->hw_ep_state1 = u32Info;
1808*53ee8cc1Swenshuai.xi         }
1809*53ee8cc1Swenshuai.xi       }
1810*53ee8cc1Swenshuai.xi 
1811*53ee8cc1Swenshuai.xi       /* usb_reset_device() back the device address to 0 */
1812*53ee8cc1Swenshuai.xi       if (usb_pipedevice (pUrb->u32Pipe) == 0)
1813*53ee8cc1Swenshuai.xi           pQh->hw_ep_state1 &= ~QH_ADDR_MASK;
1814*53ee8cc1Swenshuai.xi       /* modify device address, the purpose like usb_ep0_reinit */
1815*53ee8cc1Swenshuai.xi       else if ((pQh->hw_ep_state1 & QH_ADDR_MASK) == 0) {
1816*53ee8cc1Swenshuai.xi            ms_debug_debug("[USB] qh device addr 0, append urb device addr %d\n", usb_pipedevice (pUrb->u32Pipe));
1817*53ee8cc1Swenshuai.xi            pQh->hw_ep_state1 |= usb_pipedevice (pUrb->u32Pipe);
1818*53ee8cc1Swenshuai.xi       }
1819*53ee8cc1Swenshuai.xi     }
1820*53ee8cc1Swenshuai.xi 
1821*53ee8cc1Swenshuai.xi     /* Obsolete code */
1822*53ee8cc1Swenshuai.xi     //if ((!usb_gettoggle (pUrb->dev,
1823*53ee8cc1Swenshuai.xi     //      (iEpNum & 0x0f), !(iEpNum & 0x10)))
1824*53ee8cc1Swenshuai.xi     //    && !usb_pipecontrol (pUrb->u32Pipe))
1825*53ee8cc1Swenshuai.xi     //{
1826*53ee8cc1Swenshuai.xi     //  /* "never happens": drivers do stall cleanup right */
1827*53ee8cc1Swenshuai.xi     //  if (pQh->qh_status != QH_STS_IDLE
1828*53ee8cc1Swenshuai.xi     //        && !ms_is_empty_list (&pQh->qtd_list)
1829*53ee8cc1Swenshuai.xi     //        && pQh->qh_status != QH_STS_COMPLETING)
1830*53ee8cc1Swenshuai.xi     //      ms_debug_msg ("clear toggle dev%d ep%d%s: not idle\n", (int)usb_pipedevice (pUrb->u32Pipe), iEpNum & 0x0f,  usb_pipein (pUrb->u32Pipe) ? "in" : "out");
1831*53ee8cc1Swenshuai.xi     //  ms_clear_toggle (pUrb->dev, iEpNum & 0x0f, !(iEpNum & 0x10), pQh);
1832*53ee8cc1Swenshuai.xi     //  diag_printf("[USB] clear toggle called!!!\n");
1833*53ee8cc1Swenshuai.xi     //}
1834*53ee8cc1Swenshuai.xi 
1835*53ee8cc1Swenshuai.xi     if (pQtd != 0)
1836*53ee8cc1Swenshuai.xi     {
1837*53ee8cc1Swenshuai.xi       struct ehci_qtd    *dummy;
1838*53ee8cc1Swenshuai.xi       dma_addr_t    tDmaAddr;
1839*53ee8cc1Swenshuai.xi       U32      pToken;
1840*53ee8cc1Swenshuai.xi 
1841*53ee8cc1Swenshuai.xi       pToken = pQtd->hw_token;
1842*53ee8cc1Swenshuai.xi       pQtd->hw_token = HALT_BIT;
1843*53ee8cc1Swenshuai.xi       wmb ();
1844*53ee8cc1Swenshuai.xi       dummy = pQh->pDummyQtd;
1845*53ee8cc1Swenshuai.xi       /* Copy qtd's data to dummy except dummy->qtd_dma */
1846*53ee8cc1Swenshuai.xi       tDmaAddr = dummy->qtd_dma_addr;
1847*53ee8cc1Swenshuai.xi       *dummy = *pQtd;
1848*53ee8cc1Swenshuai.xi       dummy->qtd_dma_addr = tDmaAddr;
1849*53ee8cc1Swenshuai.xi 
1850*53ee8cc1Swenshuai.xi       ms_list_remove (&pQtd->qtd_list);
1851*53ee8cc1Swenshuai.xi       ms_insert_list_after (&dummy->qtd_list, qtd_list);
1852*53ee8cc1Swenshuai.xi       ms_list_join (qtd_list, pQh->qtd_list.prev);
1853*53ee8cc1Swenshuai.xi 
1854*53ee8cc1Swenshuai.xi       ms_ehci_qtd_init (pQtd, pQtd->qtd_dma_addr);
1855*53ee8cc1Swenshuai.xi       pQh->pDummyQtd = pQtd;
1856*53ee8cc1Swenshuai.xi 
1857*53ee8cc1Swenshuai.xi       /* hc must see the new dummy at list end */
1858*53ee8cc1Swenshuai.xi       tDmaAddr = pQtd->qtd_dma_addr;
1859*53ee8cc1Swenshuai.xi       pQtd = entry_to_container (pQh->qtd_list.prev, struct ehci_qtd, qtd_list);
1860*53ee8cc1Swenshuai.xi       //list_entry (qh->qtd_list.prev, struct ehci_qtd, qtd_list,struct list_head, qtd);
1861*53ee8cc1Swenshuai.xi       //the last qtd of qh before spliceing qtd_list
1862*53ee8cc1Swenshuai.xi       pQtd->hw_next_qtd = (U32)(tDmaAddr);
1863*53ee8cc1Swenshuai.xi 
1864*53ee8cc1Swenshuai.xi       /* let the hc process these next qtds */
1865*53ee8cc1Swenshuai.xi       wmb ();
1866*53ee8cc1Swenshuai.xi       dummy->hw_token = pToken;
1867*53ee8cc1Swenshuai.xi 
1868*53ee8cc1Swenshuai.xi       pUrb->hcpriv = ms_qh_get (pQh);
1869*53ee8cc1Swenshuai.xi     }
1870*53ee8cc1Swenshuai.xi   }
1871*53ee8cc1Swenshuai.xi   ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1872*53ee8cc1Swenshuai.xi   return pQh;
1873*53ee8cc1Swenshuai.xi }
1874*53ee8cc1Swenshuai.xi 
1875*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
1876*53ee8cc1Swenshuai.xi static int
ms_submit_async(struct ehci_hcd * pEhci,struct urb * pUrb,struct list_head * qtd_list)1877*53ee8cc1Swenshuai.xi ms_submit_async (
1878*53ee8cc1Swenshuai.xi   struct ehci_hcd    *pEhci,
1879*53ee8cc1Swenshuai.xi   struct urb    *pUrb,
1880*53ee8cc1Swenshuai.xi   struct list_head  *qtd_list
1881*53ee8cc1Swenshuai.xi )
1882*53ee8cc1Swenshuai.xi {
1883*53ee8cc1Swenshuai.xi   //struct ehci_qtd    *pQtd;
1884*53ee8cc1Swenshuai.xi   struct s_hcd_dev    *pDev;
1885*53ee8cc1Swenshuai.xi   int      iEpNum;
1886*53ee8cc1Swenshuai.xi   U32    u32Flags;
1887*53ee8cc1Swenshuai.xi   struct ehci_qh    *pQh = 0;
1888*53ee8cc1Swenshuai.xi 
1889*53ee8cc1Swenshuai.xi   ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1890*53ee8cc1Swenshuai.xi   /* only urb trace code needs qtd information */
1891*53ee8cc1Swenshuai.xi   //pQtd = entry_to_container (qtd_list->next, struct ehci_qtd, qtd_list);
1892*53ee8cc1Swenshuai.xi   //list_entry (qtd_list->next, struct ehci_qtd, qtd_list, struct list_head, qtd);
1893*53ee8cc1Swenshuai.xi   pDev = (struct s_hcd_dev *)pUrb->dev->hcpriv;
1894*53ee8cc1Swenshuai.xi   iEpNum = usb_pipeendpoint (pUrb->u32Pipe);
1895*53ee8cc1Swenshuai.xi   if (usb_pipein (pUrb->u32Pipe) && !usb_pipecontrol (pUrb->u32Pipe))
1896*53ee8cc1Swenshuai.xi     iEpNum |= 0x10;
1897*53ee8cc1Swenshuai.xi 
1898*53ee8cc1Swenshuai.xi   osapi_spin_lock_irqsave (&pEhci->tHcdLock, u32Flags);
1899*53ee8cc1Swenshuai.xi   pQh = ms_qh_append_tds (pEhci, pUrb, qtd_list, iEpNum, &pDev->ep [iEpNum]);
1900*53ee8cc1Swenshuai.xi   /* EP Control/bulk �g�L TT ���ݭn scheduling */
1901*53ee8cc1Swenshuai.xi   if (pQh != 0)
1902*53ee8cc1Swenshuai.xi   {
1903*53ee8cc1Swenshuai.xi     if (pQh->qh_status == QH_STS_IDLE)
1904*53ee8cc1Swenshuai.xi       ms_qh_link_async (pEhci, ms_qh_get (pQh));
1905*53ee8cc1Swenshuai.xi   }
1906*53ee8cc1Swenshuai.xi 
1907*53ee8cc1Swenshuai.xi   Chip_Flush_Memory();
1908*53ee8cc1Swenshuai.xi 
1909*53ee8cc1Swenshuai.xi   osapi_spin_unlock_irqrestore (&pEhci->tHcdLock, u32Flags);
1910*53ee8cc1Swenshuai.xi   if (pQh == 0)
1911*53ee8cc1Swenshuai.xi   {
1912*53ee8cc1Swenshuai.xi       ms_qtd_register_free (pEhci, qtd_list);
1913*53ee8cc1Swenshuai.xi       return -ENOMEM;
1914*53ee8cc1Swenshuai.xi   }
1915*53ee8cc1Swenshuai.xi   ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1916*53ee8cc1Swenshuai.xi   return 0;
1917*53ee8cc1Swenshuai.xi }
1918*53ee8cc1Swenshuai.xi 
1919*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
1920*53ee8cc1Swenshuai.xi 
1921*53ee8cc1Swenshuai.xi static void ms_start_unlink_async (struct ehci_hcd *pEhci, struct ehci_qh *pQh);
ms_end_unlink_async(struct ehci_hcd * pEhci,struct stPtRegs * pRegs)1922*53ee8cc1Swenshuai.xi static void ms_end_unlink_async (struct ehci_hcd *pEhci, struct stPtRegs *pRegs)
1923*53ee8cc1Swenshuai.xi {
1924*53ee8cc1Swenshuai.xi   struct ehci_qh    *pQh = pEhci->stReclaim;
1925*53ee8cc1Swenshuai.xi   struct ehci_qh    *pNext;
1926*53ee8cc1Swenshuai.xi 
1927*53ee8cc1Swenshuai.xi   ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1928*53ee8cc1Swenshuai.xi   if(pQh == NULL)
1929*53ee8cc1Swenshuai.xi   {
1930*53ee8cc1Swenshuai.xi      ms_debug_err("--[%s] reclaim NULL\n", __FUNCTION__);
1931*53ee8cc1Swenshuai.xi      return;
1932*53ee8cc1Swenshuai.xi   }
1933*53ee8cc1Swenshuai.xi 
1934*53ee8cc1Swenshuai.xi   //ms_timer_action_done (pEhci, TIMER_IAA_WATCHDOG);
1935*53ee8cc1Swenshuai.xi   ms_iaa_watchdog_done(pEhci);
1936*53ee8cc1Swenshuai.xi 
1937*53ee8cc1Swenshuai.xi   Chip_Read_Memory(); // 20121218, 20121225
1938*53ee8cc1Swenshuai.xi 
1939*53ee8cc1Swenshuai.xi   pQh->qh_status = QH_STS_IDLE;
1940*53ee8cc1Swenshuai.xi   pQh->qh_next.qh = 0;
1941*53ee8cc1Swenshuai.xi   ms_qh_put (pEhci, pQh);      // pQh is directed to reclaim
1942*53ee8cc1Swenshuai.xi 
1943*53ee8cc1Swenshuai.xi   pNext = pQh->pReclaimQh;
1944*53ee8cc1Swenshuai.xi   pEhci->stReclaim = pNext;
1945*53ee8cc1Swenshuai.xi   //pEhci->iReclaimReady = 0;
1946*53ee8cc1Swenshuai.xi   pQh->pReclaimQh = 0;
1947*53ee8cc1Swenshuai.xi 
1948*53ee8cc1Swenshuai.xi   ms_qh_completions (pEhci, pQh, pRegs);
1949*53ee8cc1Swenshuai.xi 
1950*53ee8cc1Swenshuai.xi   if (!ms_is_empty_list (&pQh->qtd_list)
1951*53ee8cc1Swenshuai.xi       && HCD_IS_RUNNING (pEhci->hcd.state))
1952*53ee8cc1Swenshuai.xi     ms_qh_link_async (pEhci, pQh);
1953*53ee8cc1Swenshuai.xi   else
1954*53ee8cc1Swenshuai.xi   {
1955*53ee8cc1Swenshuai.xi     ms_qh_put (pEhci, pQh);    // pQh is directed from async list
1956*53ee8cc1Swenshuai.xi 
1957*53ee8cc1Swenshuai.xi     if (HCD_IS_RUNNING (pEhci->hcd.state)
1958*53ee8cc1Swenshuai.xi         && pEhci->stAsync->qh_next.qh == 0)
1959*53ee8cc1Swenshuai.xi       ms_timer_action (pEhci, TIMER_ASYNC_OFF);
1960*53ee8cc1Swenshuai.xi   }
1961*53ee8cc1Swenshuai.xi 
1962*53ee8cc1Swenshuai.xi   if (pNext)
1963*53ee8cc1Swenshuai.xi   {
1964*53ee8cc1Swenshuai.xi     pEhci->stReclaim = 0;
1965*53ee8cc1Swenshuai.xi     ms_start_unlink_async (pEhci, pNext);
1966*53ee8cc1Swenshuai.xi   }
1967*53ee8cc1Swenshuai.xi   ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1968*53ee8cc1Swenshuai.xi }
1969*53ee8cc1Swenshuai.xi 
ms_start_unlink_async(struct ehci_hcd * pEhci,struct ehci_qh * pQh)1970*53ee8cc1Swenshuai.xi static void ms_start_unlink_async (struct ehci_hcd *pEhci, struct ehci_qh *pQh)
1971*53ee8cc1Swenshuai.xi {
1972*53ee8cc1Swenshuai.xi   int    iUsbCmd = hcd_reg_readl ((U32)&pEhci->op_regs->usbcmd);
1973*53ee8cc1Swenshuai.xi   struct ehci_qh  *pPrev;
1974*53ee8cc1Swenshuai.xi 
1975*53ee8cc1Swenshuai.xi   ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
1976*53ee8cc1Swenshuai.xi #ifdef DEBUG
1977*53ee8cc1Swenshuai.xi   if (pEhci->stReclaim
1978*53ee8cc1Swenshuai.xi       || (pQh->qh_status != QH_STS_LINKED
1979*53ee8cc1Swenshuai.xi         && pQh->qh_status != QH_STS_UNLINK_WAIT)
1980*53ee8cc1Swenshuai.xi // If support SMP, needs to check locked
1981*53ee8cc1Swenshuai.xi //      || !spin_is_locked (&pEhci->tHcdLock)
1982*53ee8cc1Swenshuai.xi       )
1983*53ee8cc1Swenshuai.xi       USB_ASSERT(0, "BUG()!\n");
1984*53ee8cc1Swenshuai.xi #endif
1985*53ee8cc1Swenshuai.xi 
1986*53ee8cc1Swenshuai.xi   if (pQh == pEhci->stAsync)
1987*53ee8cc1Swenshuai.xi   {
1988*53ee8cc1Swenshuai.xi     if (pEhci->hcd.state != HCD_STATE_HALT && !pEhci->stReclaim)
1989*53ee8cc1Swenshuai.xi     {
1990*53ee8cc1Swenshuai.xi       /* stop async schedule */
1991*53ee8cc1Swenshuai.xi       hcd_reg_writel (iUsbCmd & ~USBCMD_ASE, (U32)&pEhci->op_regs->usbcmd);
1992*53ee8cc1Swenshuai.xi       wmb ();
1993*53ee8cc1Swenshuai.xi       // handshake later, if we need to
1994*53ee8cc1Swenshuai.xi       ms_timer_action_done (pEhci, TIMER_ASYNC_OFF);
1995*53ee8cc1Swenshuai.xi     }
1996*53ee8cc1Swenshuai.xi     return;
1997*53ee8cc1Swenshuai.xi   }
1998*53ee8cc1Swenshuai.xi 
1999*53ee8cc1Swenshuai.xi   pQh->qh_status = QH_STS_UNLINK;
2000*53ee8cc1Swenshuai.xi   pEhci->stReclaim = pQh = ms_qh_get (pQh);
2001*53ee8cc1Swenshuai.xi 
2002*53ee8cc1Swenshuai.xi   pPrev = pEhci->stAsync;
2003*53ee8cc1Swenshuai.xi   while (pPrev->qh_next.qh != pQh)
2004*53ee8cc1Swenshuai.xi     pPrev = pPrev->qh_next.qh;
2005*53ee8cc1Swenshuai.xi 
2006*53ee8cc1Swenshuai.xi #ifdef _USB_ENABLE_BDMA_PATCH // BDMA SW patch
2007*53ee8cc1Swenshuai.xi 	if (get_64bit_OBF_cipher()) {
2008*53ee8cc1Swenshuai.xi 		m_BDMA_write(pQh->qh_dma_addr, pPrev->qh_dma_addr);
2009*53ee8cc1Swenshuai.xi 		USB_ASSERT(pPrev->hw_next_qh == pQh->hw_next_qh,
2010*53ee8cc1Swenshuai.xi 			"[BDMA] hw_next not matched!\n");
2011*53ee8cc1Swenshuai.xi 	}
2012*53ee8cc1Swenshuai.xi 	else
2013*53ee8cc1Swenshuai.xi 		pPrev->hw_next_qh = pQh->hw_next_qh;
2014*53ee8cc1Swenshuai.xi #else
2015*53ee8cc1Swenshuai.xi   pPrev->hw_next_qh = pQh->hw_next_qh;
2016*53ee8cc1Swenshuai.xi #endif
2017*53ee8cc1Swenshuai.xi   pPrev->qh_next = pQh->qh_next;
2018*53ee8cc1Swenshuai.xi   wmb ();
2019*53ee8cc1Swenshuai.xi 
2020*53ee8cc1Swenshuai.xi   Chip_Flush_Memory(); // (20140827 to push the pipe)
2021*53ee8cc1Swenshuai.xi 
2022*53ee8cc1Swenshuai.xi   //if (pEhci->hcd.state == HCD_STATE_HALT)
2023*53ee8cc1Swenshuai.xi   if (!HCD_IS_RUNNING(pEhci->hcd.state))
2024*53ee8cc1Swenshuai.xi   {
2025*53ee8cc1Swenshuai.xi     ms_end_unlink_async (pEhci, NULL);
2026*53ee8cc1Swenshuai.xi     ms_debug_err("HCD not running, end unlink directly\n");
2027*53ee8cc1Swenshuai.xi     return;
2028*53ee8cc1Swenshuai.xi   }
2029*53ee8cc1Swenshuai.xi   //inform HC thar something has been removed from asyn. schedule
2030*53ee8cc1Swenshuai.xi   //pEhci->iReclaimReady = 0;
2031*53ee8cc1Swenshuai.xi #if 1   // For bug 125MHz copy error (HALT)
2032*53ee8cc1Swenshuai.xi   //if (!pEhci->uDontSendIAA) // 20130110 no need flag control
2033*53ee8cc1Swenshuai.xi   {
2034*53ee8cc1Swenshuai.xi     iUsbCmd |= USBCMD_IAAD;
2035*53ee8cc1Swenshuai.xi     hcd_reg_writel (iUsbCmd, (U32)&pEhci->op_regs->usbcmd);
2036*53ee8cc1Swenshuai.xi   }
2037*53ee8cc1Swenshuai.xi #endif
2038*53ee8cc1Swenshuai.xi   //ms_timer_action (pEhci, TIMER_IAA_WATCHDOG);
2039*53ee8cc1Swenshuai.xi   ms_iaa_watchdog_begin(pEhci);
2040*53ee8cc1Swenshuai.xi   ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2041*53ee8cc1Swenshuai.xi }
2042*53ee8cc1Swenshuai.xi 
ms_unlink_async(struct ehci_hcd * pEhci,struct ehci_qh * pQh)2043*53ee8cc1Swenshuai.xi static void ms_unlink_async (struct ehci_hcd *pEhci, struct ehci_qh *pQh)
2044*53ee8cc1Swenshuai.xi {
2045*53ee8cc1Swenshuai.xi             if (!HCD_IS_RUNNING (pEhci->hcd.state) && pEhci->stReclaim)
2046*53ee8cc1Swenshuai.xi                 ms_end_unlink_async (pEhci, NULL);
2047*53ee8cc1Swenshuai.xi 
2048*53ee8cc1Swenshuai.xi             if (pQh->qh_status != QH_STS_LINKED)
2049*53ee8cc1Swenshuai.xi                 ;
2050*53ee8cc1Swenshuai.xi             else if (pEhci->stReclaim)
2051*53ee8cc1Swenshuai.xi             {
2052*53ee8cc1Swenshuai.xi                 struct ehci_qh    *pLast;
2053*53ee8cc1Swenshuai.xi 
2054*53ee8cc1Swenshuai.xi                 for (pLast = pEhci->stReclaim;
2055*53ee8cc1Swenshuai.xi                     pLast->pReclaimQh;
2056*53ee8cc1Swenshuai.xi                     pLast = pLast->pReclaimQh)
2057*53ee8cc1Swenshuai.xi                   continue;
2058*53ee8cc1Swenshuai.xi                 pQh->qh_status = QH_STS_UNLINK_WAIT;
2059*53ee8cc1Swenshuai.xi                 pLast->pReclaimQh = pQh;
2060*53ee8cc1Swenshuai.xi                 /* bypass IAA if the hc can't care */
2061*53ee8cc1Swenshuai.xi                 diag_printf("[EHCI] set QH_STS_UNLINK_WAIT\n");
2062*53ee8cc1Swenshuai.xi             }
2063*53ee8cc1Swenshuai.xi             else
2064*53ee8cc1Swenshuai.xi                 ms_start_unlink_async (pEhci, pQh);
2065*53ee8cc1Swenshuai.xi }
2066*53ee8cc1Swenshuai.xi 
2067*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
2068*53ee8cc1Swenshuai.xi /*
2069*53ee8cc1Swenshuai.xi   * @brief          free qtd list but kept qh for plug test shall cause some problems
2070*53ee8cc1Swenshuai.xi   *
2071*53ee8cc1Swenshuai.xi   * @param          struct ehci_hcd *pEhci
2072*53ee8cc1Swenshuai.xi   * @param          struct stPtRegs *pRegs
2073*53ee8cc1Swenshuai.xi   *
2074*53ee8cc1Swenshuai.xi   * @return         none
2075*53ee8cc1Swenshuai.xi   */
2076*53ee8cc1Swenshuai.xi 
2077*53ee8cc1Swenshuai.xi static void
ms_scan_async(struct ehci_hcd * pEhci,struct stPtRegs * pRegs)2078*53ee8cc1Swenshuai.xi ms_scan_async (struct ehci_hcd *pEhci, struct stPtRegs *pRegs)
2079*53ee8cc1Swenshuai.xi {
2080*53ee8cc1Swenshuai.xi   struct ehci_qh    *pQh;
2081*53ee8cc1Swenshuai.xi   enum ehci_timer_event  eAction = TIMER_IO_WATCHDOG;
2082*53ee8cc1Swenshuai.xi 
2083*53ee8cc1Swenshuai.xi   ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2084*53ee8cc1Swenshuai.xi   if (!++(pEhci->u32Stamp))
2085*53ee8cc1Swenshuai.xi       pEhci->u32Stamp++;
2086*53ee8cc1Swenshuai.xi   ms_timer_action_done (pEhci, TIMER_ASYNC_SHRINK);
2087*53ee8cc1Swenshuai.xi rescan:
2088*53ee8cc1Swenshuai.xi   pQh = pEhci->stAsync->qh_next.qh;
2089*53ee8cc1Swenshuai.xi   if (pQh != 0)
2090*53ee8cc1Swenshuai.xi   {
2091*53ee8cc1Swenshuai.xi     do
2092*53ee8cc1Swenshuai.xi     {
2093*53ee8cc1Swenshuai.xi       /* free qtd for this qh */
2094*53ee8cc1Swenshuai.xi       if (!ms_is_empty_list (&pQh->qtd_list)
2095*53ee8cc1Swenshuai.xi           && pQh->u32Stamp != pEhci->u32Stamp)
2096*53ee8cc1Swenshuai.xi       {
2097*53ee8cc1Swenshuai.xi         int temp;
2098*53ee8cc1Swenshuai.xi 
2099*53ee8cc1Swenshuai.xi         pQh = ms_qh_get (pQh);
2100*53ee8cc1Swenshuai.xi         pQh->u32Stamp = pEhci->u32Stamp;
2101*53ee8cc1Swenshuai.xi         temp = ms_qh_completions (pEhci, pQh, pRegs);
2102*53ee8cc1Swenshuai.xi         ms_qh_put (pEhci, pQh);
2103*53ee8cc1Swenshuai.xi         if (temp != 0)
2104*53ee8cc1Swenshuai.xi         {
2105*53ee8cc1Swenshuai.xi             goto rescan;
2106*53ee8cc1Swenshuai.xi         }
2107*53ee8cc1Swenshuai.xi       }
2108*53ee8cc1Swenshuai.xi 
2109*53ee8cc1Swenshuai.xi       //FIXME: #if 1 is correct procedure but it will cause some problems when do plug testing
2110*53ee8cc1Swenshuai.xi       //Watchdog timer will be unlink for unknow reason ==> Therefore, qHD can not be
2111*53ee8cc1Swenshuai.xi       //unlinked from async list. (qh->state == USB_STATE_LINKED but HCD_STATE_HALT)
2112*53ee8cc1Swenshuai.xi       //So when disconnect attached device ep1in (Bulk in) cannot be released.
2113*53ee8cc1Swenshuai.xi #if 1
2114*53ee8cc1Swenshuai.xi       #if 0
2115*53ee8cc1Swenshuai.xi       if (ms_is_empty_list (&pQh->qtd_list))
2116*53ee8cc1Swenshuai.xi       {
2117*53ee8cc1Swenshuai.xi         if (pQh->u32Stamp == pEhci->u32Stamp)
2118*53ee8cc1Swenshuai.xi           eAction = TIMER_ASYNC_SHRINK;
2119*53ee8cc1Swenshuai.xi         else if (!pEhci->stReclaim
2120*53ee8cc1Swenshuai.xi               && pQh->qh_status == QH_STS_LINKED)
2121*53ee8cc1Swenshuai.xi           ms_start_unlink_async (pEhci, pQh);
2122*53ee8cc1Swenshuai.xi       }
2123*53ee8cc1Swenshuai.xi       #else
2124*53ee8cc1Swenshuai.xi       #define MS_QH_SHRINK_FRAMES 5
2125*53ee8cc1Swenshuai.xi       if (ms_is_empty_list (&pQh->qtd_list) && (pQh->qh_status == QH_STS_LINKED))
2126*53ee8cc1Swenshuai.xi       {
2127*53ee8cc1Swenshuai.xi         if (!pEhci->stReclaim
2128*53ee8cc1Swenshuai.xi               && ((pEhci->u32Stamp - pQh->u32Stamp) & 0x1fff) >= MS_QH_SHRINK_FRAMES * 8)
2129*53ee8cc1Swenshuai.xi         {
2130*53ee8cc1Swenshuai.xi           //diag_printf("[USB][%d] %s start_unlink sts1:%x\n",
2131*53ee8cc1Swenshuai.xi           //                    jiffies, __func__, pQh->hw_ep_state1);
2132*53ee8cc1Swenshuai.xi           ms_start_unlink_async (pEhci, pQh);
2133*53ee8cc1Swenshuai.xi         }
2134*53ee8cc1Swenshuai.xi         else
2135*53ee8cc1Swenshuai.xi         {
2136*53ee8cc1Swenshuai.xi           //diag_printf("[USB] TIMER_ASYNC_SHRINK qh_sts:0x%x\n", pQh->hw_ep_state1);
2137*53ee8cc1Swenshuai.xi           eAction = TIMER_ASYNC_SHRINK;
2138*53ee8cc1Swenshuai.xi         }
2139*53ee8cc1Swenshuai.xi       }
2140*53ee8cc1Swenshuai.xi       #endif
2141*53ee8cc1Swenshuai.xi #else
2142*53ee8cc1Swenshuai.xi       if (ms_is_empty_list (&pQh->qtd_list))
2143*53ee8cc1Swenshuai.xi       {
2144*53ee8cc1Swenshuai.xi         if (!pEhci->stReclaim && pQh->qh_status == QH_STS_LINKED)
2145*53ee8cc1Swenshuai.xi           ms_start_unlink_async (pEhci, pQh);
2146*53ee8cc1Swenshuai.xi       }
2147*53ee8cc1Swenshuai.xi #endif
2148*53ee8cc1Swenshuai.xi       pQh = pQh->qh_next.qh;
2149*53ee8cc1Swenshuai.xi     } while (pQh);
2150*53ee8cc1Swenshuai.xi   }
2151*53ee8cc1Swenshuai.xi   if (eAction == TIMER_ASYNC_SHRINK)
2152*53ee8cc1Swenshuai.xi     ms_timer_action (pEhci, TIMER_ASYNC_SHRINK);
2153*53ee8cc1Swenshuai.xi   ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2154*53ee8cc1Swenshuai.xi }
2155*53ee8cc1Swenshuai.xi 
2156*53ee8cc1Swenshuai.xi #ifdef EHCI_TD_DEBUG
dbg_timeout_async(struct usb_hcd * hcd)2157*53ee8cc1Swenshuai.xi void dbg_timeout_async(struct usb_hcd *hcd)
2158*53ee8cc1Swenshuai.xi {
2159*53ee8cc1Swenshuai.xi #if defined(CPU_TYPE_MIPS)
2160*53ee8cc1Swenshuai.xi #define PA2VA(a) (0xA0000000+(a))
2161*53ee8cc1Swenshuai.xi #elif defined(CPU_TYPE_ARM)
2162*53ee8cc1Swenshuai.xi #define PA2VA(a) (0x20000000+(a))
2163*53ee8cc1Swenshuai.xi #endif
2164*53ee8cc1Swenshuai.xi #define HW_NEXT(a) ((a) & 0xffffffe0)
2165*53ee8cc1Swenshuai.xi 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
2166*53ee8cc1Swenshuai.xi 	struct ehci_qh *qh;
2167*53ee8cc1Swenshuai.xi 	unsigned int *hw_p;
2168*53ee8cc1Swenshuai.xi 	unsigned int hw_next;
2169*53ee8cc1Swenshuai.xi 
2170*53ee8cc1Swenshuai.xi 	/* print out async register */
2171*53ee8cc1Swenshuai.xi 	hw_next = hcd_reg_readl ((U32)&ehci->op_regs->asynclistaddr);
2172*53ee8cc1Swenshuai.xi 	diag_printf("[EHCI] async register %x\n", hw_next);
2173*53ee8cc1Swenshuai.xi 	/* print out hardware asynchronous qh link */
2174*53ee8cc1Swenshuai.xi 	hw_next = (U32)ehci->stAsync;
2175*53ee8cc1Swenshuai.xi 	diag_printf("--> %8x", hw_next);
2176*53ee8cc1Swenshuai.xi 	diag_printf("--> %8x", hw_next+0x80);
2177*53ee8cc1Swenshuai.xi 	diag_printf("--> %8x", hw_next+0x100);
2178*53ee8cc1Swenshuai.xi 	diag_printf("--> %8x\n", hw_next+0x180);
2179*53ee8cc1Swenshuai.xi 
2180*53ee8cc1Swenshuai.xi 	hw_p = (unsigned int *)hw_next;
2181*53ee8cc1Swenshuai.xi 	diag_printf("--> %8x", *hw_p);
2182*53ee8cc1Swenshuai.xi 	hw_next += 0x80;
2183*53ee8cc1Swenshuai.xi 	hw_p = (unsigned int *)hw_next;
2184*53ee8cc1Swenshuai.xi 	diag_printf("--> %8x", *hw_p);
2185*53ee8cc1Swenshuai.xi 	hw_next += 0x80;
2186*53ee8cc1Swenshuai.xi 	hw_p = (unsigned int *)hw_next;
2187*53ee8cc1Swenshuai.xi 	diag_printf("--> %8x", *hw_p);
2188*53ee8cc1Swenshuai.xi 	hw_next += 0x80;
2189*53ee8cc1Swenshuai.xi 	hw_p = (unsigned int *)hw_next;
2190*53ee8cc1Swenshuai.xi 	diag_printf("--> %8x", *hw_p);
2191*53ee8cc1Swenshuai.xi 	diag_printf("\n");
2192*53ee8cc1Swenshuai.xi 
2193*53ee8cc1Swenshuai.xi 	/* print out asynchronous qh list */
2194*53ee8cc1Swenshuai.xi 	qh = ehci->stAsync->qh_next.qh;
2195*53ee8cc1Swenshuai.xi 	if (qh == 0) {
2196*53ee8cc1Swenshuai.xi 		diag_printf("[EHCI] no QH list\n");
2197*53ee8cc1Swenshuai.xi 		return;
2198*53ee8cc1Swenshuai.xi 	}
2199*53ee8cc1Swenshuai.xi 	do {
2200*53ee8cc1Swenshuai.xi 		unsigned int c_qtd;
2201*53ee8cc1Swenshuai.xi 		int cqtd_n_list = 1;
2202*53ee8cc1Swenshuai.xi 
2203*53ee8cc1Swenshuai.xi 		diag_printf("qh status %d, dummy_qtd %x\n",
2204*53ee8cc1Swenshuai.xi 			qh->qh_status, (unsigned int)qh->pDummyQtd);
2205*53ee8cc1Swenshuai.xi 		Dump_TD((unsigned int)qh, 1);
2206*53ee8cc1Swenshuai.xi 		c_qtd = (unsigned int)PA2VA(qh->hw_current_qtd);
2207*53ee8cc1Swenshuai.xi 		if (!ms_is_empty_list (&qh->qtd_list)) {
2208*53ee8cc1Swenshuai.xi 			struct list_head  *entry, *tmp;
2209*53ee8cc1Swenshuai.xi 
2210*53ee8cc1Swenshuai.xi 			list_for_loop_ex (entry, tmp, &qh->qtd_list) {
2211*53ee8cc1Swenshuai.xi 				struct ehci_qtd *qtd;
2212*53ee8cc1Swenshuai.xi 
2213*53ee8cc1Swenshuai.xi 				qtd = entry_to_container (entry, struct ehci_qtd, qtd_list);
2214*53ee8cc1Swenshuai.xi 				Dump_TD((unsigned int)qtd, 0);
2215*53ee8cc1Swenshuai.xi 				if (c_qtd == (unsigned int)qtd)
2216*53ee8cc1Swenshuai.xi 					cqtd_n_list = 0;
2217*53ee8cc1Swenshuai.xi 			}
2218*53ee8cc1Swenshuai.xi 		}
2219*53ee8cc1Swenshuai.xi 		if (cqtd_n_list) {
2220*53ee8cc1Swenshuai.xi 			diag_printf("    CURRENT QTD\n");
2221*53ee8cc1Swenshuai.xi 			Dump_TD((unsigned int)PA2VA(qh->hw_current_qtd), 0);
2222*53ee8cc1Swenshuai.xi 		}
2223*53ee8cc1Swenshuai.xi 		qh = qh->qh_next.qh;
2224*53ee8cc1Swenshuai.xi 	} while (qh);
2225*53ee8cc1Swenshuai.xi }
2226*53ee8cc1Swenshuai.xi #endif
2227*53ee8cc1Swenshuai.xi 
2228*53ee8cc1Swenshuai.xi #include "drvEHCI_SCHD.cxx"
2229*53ee8cc1Swenshuai.xi 
2230*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
2231*53ee8cc1Swenshuai.xi 
2232*53ee8cc1Swenshuai.xi static void ms_ehci_work(struct ehci_hcd *ehci, struct stPtRegs *regs);
ms_ehci_iaa_watchdog(U32 u32Param)2233*53ee8cc1Swenshuai.xi static void ms_ehci_iaa_watchdog(U32 u32Param)
2234*53ee8cc1Swenshuai.xi {
2235*53ee8cc1Swenshuai.xi 	struct ehci_hcd		*pEhci = (struct ehci_hcd *) u32Param;
2236*53ee8cc1Swenshuai.xi 	unsigned long		u32Flags;
2237*53ee8cc1Swenshuai.xi 
2238*53ee8cc1Swenshuai.xi     ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2239*53ee8cc1Swenshuai.xi 	osapi_spin_lock_irqsave (&pEhci->tHcdLock, u32Flags);
2240*53ee8cc1Swenshuai.xi 
2241*53ee8cc1Swenshuai.xi 	/* see Linux 2.6.28.9 ehci_iaa_watchdog description
2242*53ee8cc1Swenshuai.xi 	 */
2243*53ee8cc1Swenshuai.xi 	if (pEhci->stReclaim
2244*53ee8cc1Swenshuai.xi 			&& !ms_timer_pending(&pEhci->stiaa_Watchdog)
2245*53ee8cc1Swenshuai.xi 			&& HCD_IS_RUNNING(pEhci->hcd.state)) {
2246*53ee8cc1Swenshuai.xi 		U32 u32Cmd, u32Status;
2247*53ee8cc1Swenshuai.xi 
2248*53ee8cc1Swenshuai.xi 		u32Cmd = hcd_reg_readl((U32)&pEhci->op_regs->usbcmd);
2249*53ee8cc1Swenshuai.xi 		if (u32Cmd & USBCMD_IAAD)
2250*53ee8cc1Swenshuai.xi 			hcd_reg_writel(u32Cmd & ~USBCMD_IAAD,
2251*53ee8cc1Swenshuai.xi 					(U32)&pEhci->op_regs->usbcmd);
2252*53ee8cc1Swenshuai.xi 
2253*53ee8cc1Swenshuai.xi 		u32Status = hcd_reg_readl((U32)&pEhci->op_regs->usbsts);
2254*53ee8cc1Swenshuai.xi 		if ((u32Status & USBSTS_IAA) || !(u32Cmd & USBCMD_IAAD)) {
2255*53ee8cc1Swenshuai.xi 			INCREASE (pEhci->stats.u32LostIAA);
2256*53ee8cc1Swenshuai.xi 			ms_debug_err("IAA watchdog (lost IAA): status %x cmd %x\n",
2257*53ee8cc1Swenshuai.xi 				u32Status, u32Cmd);
2258*53ee8cc1Swenshuai.xi 			hcd_reg_writel(USBSTS_IAA, (U32)&pEhci->op_regs->usbsts);
2259*53ee8cc1Swenshuai.xi 		}
2260*53ee8cc1Swenshuai.xi 
2261*53ee8cc1Swenshuai.xi 		ms_debug_func("IAA watchdog: status %x cmd %x\n",
2262*53ee8cc1Swenshuai.xi 				u32Status, u32Cmd);
2263*53ee8cc1Swenshuai.xi 		ms_end_unlink_async(pEhci, NULL);
2264*53ee8cc1Swenshuai.xi 	}
2265*53ee8cc1Swenshuai.xi 
2266*53ee8cc1Swenshuai.xi 	osapi_spin_unlock_irqrestore(&pEhci->tHcdLock, u32Flags);
2267*53ee8cc1Swenshuai.xi     ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2268*53ee8cc1Swenshuai.xi }
2269*53ee8cc1Swenshuai.xi 
ms_ehci_watchdog(U32 u32Param)2270*53ee8cc1Swenshuai.xi static void ms_ehci_watchdog (U32 u32Param)
2271*53ee8cc1Swenshuai.xi {
2272*53ee8cc1Swenshuai.xi     struct ehci_hcd    *pEhci = (struct ehci_hcd *) u32Param;
2273*53ee8cc1Swenshuai.xi     U32    u32Flags;
2274*53ee8cc1Swenshuai.xi 
2275*53ee8cc1Swenshuai.xi     ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2276*53ee8cc1Swenshuai.xi     ms_debug_func("[%s] action: 0x%08X\n", __FUNCTION__, (U32)pEhci->u32Actions);
2277*53ee8cc1Swenshuai.xi     osapi_spin_lock_irqsave (&pEhci->tHcdLock, u32Flags);
2278*53ee8cc1Swenshuai.xi 
2279*53ee8cc1Swenshuai.xi #if 0 // old reclaim flow
2280*53ee8cc1Swenshuai.xi     /* avoid vt8235 lost IAA irqs */
2281*53ee8cc1Swenshuai.xi     if (pEhci->stReclaim)
2282*53ee8cc1Swenshuai.xi     {
2283*53ee8cc1Swenshuai.xi         U32    status = hcd_reg_readl ((U32)&pEhci->op_regs->usbsts);
2284*53ee8cc1Swenshuai.xi 
2285*53ee8cc1Swenshuai.xi         if (status & USBSTS_IAA)
2286*53ee8cc1Swenshuai.xi         {
2287*53ee8cc1Swenshuai.xi             INCREASE(pEhci->stats.u32LostIAA);
2288*53ee8cc1Swenshuai.xi             hcd_reg_writel (USBSTS_IAA, (U32)&pEhci->op_regs->usbsts);
2289*53ee8cc1Swenshuai.xi             pEhci->iReclaimReady = 1;
2290*53ee8cc1Swenshuai.xi         }
2291*53ee8cc1Swenshuai.xi         else if ( (hcd_reg_readl((U32)&pEhci->op_regs->usbcmd)&USBCMD_IAAD) && !(status & USBSTS_IAA))
2292*53ee8cc1Swenshuai.xi         {
2293*53ee8cc1Swenshuai.xi             ms_debug_warn ("Something wrong ==>lost IAA\n");//HW ISSUE?
2294*53ee8cc1Swenshuai.xi             pEhci->iReclaimReady = 1;
2295*53ee8cc1Swenshuai.xi         }
2296*53ee8cc1Swenshuai.xi     }
2297*53ee8cc1Swenshuai.xi #endif
2298*53ee8cc1Swenshuai.xi 
2299*53ee8cc1Swenshuai.xi     /* stop async processing after it's idled a bit */
2300*53ee8cc1Swenshuai.xi     //Periodic schedule issue was fixed, so reopen it
2301*53ee8cc1Swenshuai.xi     if (ms_test_bit (TIMER_ASYNC_OFF, &pEhci->u32Actions))
2302*53ee8cc1Swenshuai.xi         ms_start_unlink_async (pEhci, pEhci->stAsync);
2303*53ee8cc1Swenshuai.xi 
2304*53ee8cc1Swenshuai.xi     /* pEhci could run by timer, without IRQs ... */
2305*53ee8cc1Swenshuai.xi     //if (ms_test_bit (TIMER_IO_WATCHDOG, &pEhci->u32Actions))
2306*53ee8cc1Swenshuai.xi         ms_ehci_work(pEhci, NULL);
2307*53ee8cc1Swenshuai.xi 
2308*53ee8cc1Swenshuai.xi     osapi_spin_unlock_irqrestore (&pEhci->tHcdLock, u32Flags);
2309*53ee8cc1Swenshuai.xi     ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2310*53ee8cc1Swenshuai.xi 
2311*53ee8cc1Swenshuai.xi }
2312*53ee8cc1Swenshuai.xi 
ms_ehci_init(struct usb_hcd * pHcd)2313*53ee8cc1Swenshuai.xi int ms_ehci_init (struct usb_hcd *pHcd)
2314*53ee8cc1Swenshuai.xi {
2315*53ee8cc1Swenshuai.xi   struct ehci_hcd    *ehci = hcd_to_ehci (pHcd);
2316*53ee8cc1Swenshuai.xi 
2317*53ee8cc1Swenshuai.xi   ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2318*53ee8cc1Swenshuai.xi   osapi_spin_lock_init (&ehci->tHcdLock);
2319*53ee8cc1Swenshuai.xi 
2320*53ee8cc1Swenshuai.xi   ehci->u32MoreCSC = false;
2321*53ee8cc1Swenshuai.xi   ehci->ehci_port_not_change_cnt = 0;
2322*53ee8cc1Swenshuai.xi 
2323*53ee8cc1Swenshuai.xi   ehci->cap_regs = (struct ehci_cap_regs *) pHcd->uhc_regs;
2324*53ee8cc1Swenshuai.xi   ehci->op_regs = (struct ehci_op_regs *) ( (U32)pHcd->uhc_regs +
2325*53ee8cc1Swenshuai.xi         (U32)hcd_reg_readb ((U32)&ehci->cap_regs->caplength));
2326*53ee8cc1Swenshuai.xi 
2327*53ee8cc1Swenshuai.xi   ehci->hcs_params = hcd_reg_readl ((U32)&ehci->cap_regs->hcsparams);
2328*53ee8cc1Swenshuai.xi   ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2329*53ee8cc1Swenshuai.xi   return ms_ehci_halt (ehci);
2330*53ee8cc1Swenshuai.xi }
2331*53ee8cc1Swenshuai.xi 
2332*53ee8cc1Swenshuai.xi /*
2333*53ee8cc1Swenshuai.xi   * @brief          start ehci controller
2334*53ee8cc1Swenshuai.xi   *
2335*53ee8cc1Swenshuai.xi   * @param          struct usb_hcd *hcd
2336*53ee8cc1Swenshuai.xi   *
2337*53ee8cc1Swenshuai.xi   * @return         error code
2338*53ee8cc1Swenshuai.xi   */
2339*53ee8cc1Swenshuai.xi 
2340*53ee8cc1Swenshuai.xi extern void ms_hcd_poll_rh_status(struct usb_hcd *pHcd);
2341*53ee8cc1Swenshuai.xi extern MS_U8 MDrv_SYS_GetChipRev(void);
ms_ehci_begin(struct usb_hcd * hcd)2342*53ee8cc1Swenshuai.xi int ms_ehci_begin (struct usb_hcd *hcd)
2343*53ee8cc1Swenshuai.xi {
2344*53ee8cc1Swenshuai.xi   struct ehci_hcd    *ehci = hcd_to_ehci (hcd);
2345*53ee8cc1Swenshuai.xi   U32      u32Temp;
2346*53ee8cc1Swenshuai.xi   struct usb_device  *pUdev;
2347*53ee8cc1Swenshuai.xi   struct usb_bus    *pBus;
2348*53ee8cc1Swenshuai.xi   int      iRetval;
2349*53ee8cc1Swenshuai.xi   U32      u32HccParams;
2350*53ee8cc1Swenshuai.xi 
2351*53ee8cc1Swenshuai.xi   ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2352*53ee8cc1Swenshuai.xi 
2353*53ee8cc1Swenshuai.xi   ehci->u32PeriodicSize = DEFAULT_I_TDPS;
2354*53ee8cc1Swenshuai.xi   if ((iRetval = ms_ehci_mem_init (ehci, SLAB_KERNEL)) < 0)
2355*53ee8cc1Swenshuai.xi     return iRetval;
2356*53ee8cc1Swenshuai.xi 
2357*53ee8cc1Swenshuai.xi   u32HccParams = hcd_reg_readl ((U32)&ehci->cap_regs->hcc_params);
2358*53ee8cc1Swenshuai.xi   if (HCC_ISO_CACHE (u32HccParams))   // full frame cache
2359*53ee8cc1Swenshuai.xi     ehci->u32IThresh = 8;
2360*53ee8cc1Swenshuai.xi   else          // N microframes cached
2361*53ee8cc1Swenshuai.xi     ehci->u32IThresh = 2 + HCC_ISO_THRES (u32HccParams);
2362*53ee8cc1Swenshuai.xi 
2363*53ee8cc1Swenshuai.xi   ehci->stReclaim = 0;
2364*53ee8cc1Swenshuai.xi   ehci->iNextUframe = -1;
2365*53ee8cc1Swenshuai.xi 
2366*53ee8cc1Swenshuai.xi   if ((iRetval = ms_ehci_reset (ehci)) != 0)
2367*53ee8cc1Swenshuai.xi   {
2368*53ee8cc1Swenshuai.xi     ms_ehci_mem_cleanup (ehci);
2369*53ee8cc1Swenshuai.xi     return iRetval;
2370*53ee8cc1Swenshuai.xi   }
2371*53ee8cc1Swenshuai.xi 
2372*53ee8cc1Swenshuai.xi   hcd_reg_writel (INTR_MASK, (U32)&ehci->op_regs->usbintr);
2373*53ee8cc1Swenshuai.xi   u32Temp=hcd_reg_readl((U32)&ehci->op_regs->bus_control);
2374*53ee8cc1Swenshuai.xi  // temp|=INT_POLAR+HALF_SPEED;
2375*53ee8cc1Swenshuai.xi   u32Temp|=INT_POLAR;
2376*53ee8cc1Swenshuai.xi   u32Temp&=~VBUS_OFF;
2377*53ee8cc1Swenshuai.xi   hcd_reg_writel(u32Temp,(U32)&ehci->op_regs->bus_control);       //set intr high active
2378*53ee8cc1Swenshuai.xi   hcd_reg_writel (ehci->tPeriodicDma, (U32)&ehci->op_regs->periodiclistbase);
2379*53ee8cc1Swenshuai.xi 
2380*53ee8cc1Swenshuai.xi   ehci->stAsync->qh_next.qh = 0;
2381*53ee8cc1Swenshuai.xi   ehci->stAsync->hw_next_qh = QH_NEXT (ehci->stAsync->qh_dma_addr);
2382*53ee8cc1Swenshuai.xi   ehci->stAsync->hw_ep_state1 = QH_H_BIT;
2383*53ee8cc1Swenshuai.xi   ehci->stAsync->hw_token = QTD_STS_HALT;
2384*53ee8cc1Swenshuai.xi   ehci->stAsync->hw_next_qtd = EHCI_LIST_END;
2385*53ee8cc1Swenshuai.xi   ehci->stAsync->qh_status = QH_STS_LINKED;
2386*53ee8cc1Swenshuai.xi   ehci->stAsync->hw_alt_next_qtd = (U32)(ehci->stAsync->pDummyQtd->qtd_dma_addr);
2387*53ee8cc1Swenshuai.xi   ms_debug_msg("qh dma addr: %p\n", (void *)ehci->stAsync->qh_dma_addr);
2388*53ee8cc1Swenshuai.xi   hcd_reg_writel ((U32)ehci->stAsync->qh_dma_addr, (U32)&ehci->op_regs->asynclistaddr);
2389*53ee8cc1Swenshuai.xi 
2390*53ee8cc1Swenshuai.xi   if (HCC_64BIT_ADDR_CAP (u32HccParams))
2391*53ee8cc1Swenshuai.xi   {
2392*53ee8cc1Swenshuai.xi     hcd_reg_writel (0, (U32)&ehci->op_regs->ctrldssegment);
2393*53ee8cc1Swenshuai.xi   }
2394*53ee8cc1Swenshuai.xi 
2395*53ee8cc1Swenshuai.xi   u32Temp = hcd_reg_readl ((U32)&ehci->op_regs->usbcmd) & 0x0fff;
2396*53ee8cc1Swenshuai.xi   if (log2_irq_thresh < 0 || log2_irq_thresh > 6)
2397*53ee8cc1Swenshuai.xi     log2_irq_thresh = 0;
2398*53ee8cc1Swenshuai.xi   u32Temp |= 1 << (16 + log2_irq_thresh);
2399*53ee8cc1Swenshuai.xi 
2400*53ee8cc1Swenshuai.xi #if defined(CHIP_K2)
2401*53ee8cc1Swenshuai.xi   // K2 U02 & Newer IC
2402*53ee8cc1Swenshuai.xi   if (MDrv_SYS_GetChipRev() >= 0x01)
2403*53ee8cc1Swenshuai.xi   {
2404*53ee8cc1Swenshuai.xi     park_eco = 3;
2405*53ee8cc1Swenshuai.xi   }
2406*53ee8cc1Swenshuai.xi #endif
2407*53ee8cc1Swenshuai.xi 
2408*53ee8cc1Swenshuai.xi   if (park_eco && HCC_ASPC(u32HccParams))
2409*53ee8cc1Swenshuai.xi   {
2410*53ee8cc1Swenshuai.xi     ms_debug_msg("[EHCI] Enable Park Mode: %d\n", (int)park_eco);
2411*53ee8cc1Swenshuai.xi     u32Temp |= USBCMD_PARK;
2412*53ee8cc1Swenshuai.xi     u32Temp |= park_eco << 8;
2413*53ee8cc1Swenshuai.xi   }
2414*53ee8cc1Swenshuai.xi 
2415*53ee8cc1Swenshuai.xi   if (HCC_PFLF (u32HccParams))
2416*53ee8cc1Swenshuai.xi   {
2417*53ee8cc1Swenshuai.xi     u32Temp &= ~(3 << 2);
2418*53ee8cc1Swenshuai.xi     u32Temp |= (EHCI_PERIODIC_FLS << 2);
2419*53ee8cc1Swenshuai.xi     switch (EHCI_PERIODIC_FLS)
2420*53ee8cc1Swenshuai.xi     {
2421*53ee8cc1Swenshuai.xi     case 0: ehci->u32PeriodicSize = 1024; break;
2422*53ee8cc1Swenshuai.xi     case 1: ehci->u32PeriodicSize = 512; break;
2423*53ee8cc1Swenshuai.xi     case 2: ehci->u32PeriodicSize = 256; break;
2424*53ee8cc1Swenshuai.xi     default:  USB_ASSERT(0, "Not alllowed periodic frame list size\n");
2425*53ee8cc1Swenshuai.xi     }
2426*53ee8cc1Swenshuai.xi   }
2427*53ee8cc1Swenshuai.xi   u32Temp &= ~(USBCMD_IAAD | USBCMD_ASE | USBCMD_PSE),
2428*53ee8cc1Swenshuai.xi 
2429*53ee8cc1Swenshuai.xi   // Only make HC run when device connects to bus
2430*53ee8cc1Swenshuai.xi   u32Temp |= USBCMD_RUN;
2431*53ee8cc1Swenshuai.xi   hcd_reg_writel (u32Temp, (U32)&ehci->op_regs->usbcmd);
2432*53ee8cc1Swenshuai.xi 
2433*53ee8cc1Swenshuai.xi   /* initialize watchdog timer function */
2434*53ee8cc1Swenshuai.xi 
2435*53ee8cc1Swenshuai.xi   ms_init_timer (&ehci->stWatchdog);
2436*53ee8cc1Swenshuai.xi   ehci->stWatchdog.function = ms_ehci_watchdog;
2437*53ee8cc1Swenshuai.xi   ehci->stWatchdog.data = (U32) ehci;
2438*53ee8cc1Swenshuai.xi 
2439*53ee8cc1Swenshuai.xi   ms_init_timer (&ehci->stiaa_Watchdog);
2440*53ee8cc1Swenshuai.xi   ehci->stiaa_Watchdog.function = ms_ehci_iaa_watchdog;
2441*53ee8cc1Swenshuai.xi   ehci->stiaa_Watchdog.data = (U32) ehci;
2442*53ee8cc1Swenshuai.xi 
2443*53ee8cc1Swenshuai.xi   pBus = (struct usb_bus *)(&hcd->self);
2444*53ee8cc1Swenshuai.xi   pBus->root_hub = pUdev = ms_usb_alloc_dev (NULL, pBus);
2445*53ee8cc1Swenshuai.xi   if (!pUdev)
2446*53ee8cc1Swenshuai.xi   {
2447*53ee8cc1Swenshuai.xi done2:
2448*53ee8cc1Swenshuai.xi     ms_ehci_mem_cleanup (ehci);
2449*53ee8cc1Swenshuai.xi     ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2450*53ee8cc1Swenshuai.xi     return -ENOMEM;
2451*53ee8cc1Swenshuai.xi   }
2452*53ee8cc1Swenshuai.xi 
2453*53ee8cc1Swenshuai.xi   ehci->hcd.state = HCD_STATE_RUNNING;
2454*53ee8cc1Swenshuai.xi   u32Temp = hcd_reg_readl ((U32)&ehci->op_regs->usbcmd);  /* unblock posted write */
2455*53ee8cc1Swenshuai.xi 
2456*53ee8cc1Swenshuai.xi   u32Temp = hcd_reg_readw ((U32)&ehci->cap_regs->hciversion);
2457*53ee8cc1Swenshuai.xi   ms_debug_msg ("EHCI %x.%02x, driver %s\n",
2458*53ee8cc1Swenshuai.xi     (unsigned int)u32Temp >> 8, (unsigned int)u32Temp & 0xff, DRIVER_VERSION);
2459*53ee8cc1Swenshuai.xi 
2460*53ee8cc1Swenshuai.xi   pUdev->eSpeed = USB_HIGH_SPEED;
2461*53ee8cc1Swenshuai.xi   if (ms_register_root_hub(hcd) != 0)
2462*53ee8cc1Swenshuai.xi   {
2463*53ee8cc1Swenshuai.xi     if (hcd->state == HCD_STATE_RUNNING)
2464*53ee8cc1Swenshuai.xi       ms_ehci_quiesce(ehci);
2465*53ee8cc1Swenshuai.xi     ms_ehci_reset (ehci);
2466*53ee8cc1Swenshuai.xi     pBus->root_hub = 0;
2467*53ee8cc1Swenshuai.xi     ms_usb_put_dev (pUdev);
2468*53ee8cc1Swenshuai.xi     iRetval = -ENODEV;
2469*53ee8cc1Swenshuai.xi     goto done2;
2470*53ee8cc1Swenshuai.xi   }
2471*53ee8cc1Swenshuai.xi 
2472*53ee8cc1Swenshuai.xi   ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2473*53ee8cc1Swenshuai.xi   return 0;
2474*53ee8cc1Swenshuai.xi }
2475*53ee8cc1Swenshuai.xi 
2476*53ee8cc1Swenshuai.xi  /*
2477*53ee8cc1Swenshuai.xi     * @brief             stop ehci controller
2478*53ee8cc1Swenshuai.xi     *
2479*53ee8cc1Swenshuai.xi     * @param          struct usb_hcd *hcd
2480*53ee8cc1Swenshuai.xi     *
2481*53ee8cc1Swenshuai.xi     * @return           none
2482*53ee8cc1Swenshuai.xi     */
2483*53ee8cc1Swenshuai.xi 
ms_ehci_end(struct usb_hcd * hcd)2484*53ee8cc1Swenshuai.xi  void ms_ehci_end (struct usb_hcd *hcd)
2485*53ee8cc1Swenshuai.xi {
2486*53ee8cc1Swenshuai.xi   struct ehci_hcd    *ehci = hcd_to_ehci (hcd);
2487*53ee8cc1Swenshuai.xi 
2488*53ee8cc1Swenshuai.xi   ms_debug_func("[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2489*53ee8cc1Swenshuai.xi 
2490*53ee8cc1Swenshuai.xi   ms_del_timer_sync (&ehci->stWatchdog);
2491*53ee8cc1Swenshuai.xi   ms_del_timer_sync (&ehci->stiaa_Watchdog);
2492*53ee8cc1Swenshuai.xi 
2493*53ee8cc1Swenshuai.xi   osapi_spin_lock_irq (&ehci->tHcdLock);
2494*53ee8cc1Swenshuai.xi   if (hcd->state == HCD_STATE_RUNNING)
2495*53ee8cc1Swenshuai.xi     ms_ehci_quiesce(ehci);
2496*53ee8cc1Swenshuai.xi   // need to turn off all ports?
2497*53ee8cc1Swenshuai.xi   ms_ehci_reset (ehci);
2498*53ee8cc1Swenshuai.xi   //osapi_spin_unlock_irq (&ehci->tHcdLock);
2499*53ee8cc1Swenshuai.xi 
2500*53ee8cc1Swenshuai.xi   //osapi_spin_lock_irq (&ehci->tHcdLock);
2501*53ee8cc1Swenshuai.xi   if (ehci->stAsync) // patch from Linux 3.1.10
2502*53ee8cc1Swenshuai.xi     ms_ehci_work(ehci, NULL);
2503*53ee8cc1Swenshuai.xi   osapi_spin_unlock_irq (&ehci->tHcdLock);
2504*53ee8cc1Swenshuai.xi   ms_ehci_mem_cleanup (ehci);
2505*53ee8cc1Swenshuai.xi 
2506*53ee8cc1Swenshuai.xi #ifdef  EHCI_STATS
2507*53ee8cc1Swenshuai.xi   ms_debug_msg ("[EHCI DEBUG] irq normal %ld err %ld reclaim %ld (lost %ld) ",
2508*53ee8cc1Swenshuai.xi     ehci->stats.u32Normal, ehci->stats.u32Error, ehci->stats.u32Reclaim,
2509*53ee8cc1Swenshuai.xi     ehci->stats.u32LostIAA);
2510*53ee8cc1Swenshuai.xi   ms_debug_msg ("complete %ld unlink %ld\n",
2511*53ee8cc1Swenshuai.xi     ehci->stats.u32Complete, ehci->stats.u32Unlink);
2512*53ee8cc1Swenshuai.xi #endif
2513*53ee8cc1Swenshuai.xi 
2514*53ee8cc1Swenshuai.xi }
2515*53ee8cc1Swenshuai.xi 
ms_ehci_get_frame_idx(struct usb_hcd * hcd)2516*53ee8cc1Swenshuai.xi  int ms_ehci_get_frame_idx (struct usb_hcd *hcd)
2517*53ee8cc1Swenshuai.xi {
2518*53ee8cc1Swenshuai.xi   struct ehci_hcd    *ehci = hcd_to_ehci (hcd);
2519*53ee8cc1Swenshuai.xi   ms_debug_func("[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2520*53ee8cc1Swenshuai.xi   return (hcd_reg_readl ((U32)&ehci->op_regs->frindex) >> 3) % ehci->u32PeriodicSize;
2521*53ee8cc1Swenshuai.xi }
2522*53ee8cc1Swenshuai.xi 
2523*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
2524*53ee8cc1Swenshuai.xi 
ms_ehci_suspend(struct usb_hcd * hcd,U32 state)2525*53ee8cc1Swenshuai.xi  int ms_ehci_suspend (struct usb_hcd *hcd, U32 state)
2526*53ee8cc1Swenshuai.xi {
2527*53ee8cc1Swenshuai.xi   struct ehci_hcd    *ehci = hcd_to_ehci (hcd);
2528*53ee8cc1Swenshuai.xi   int      iPorts;
2529*53ee8cc1Swenshuai.xi   int      i;
2530*53ee8cc1Swenshuai.xi 
2531*53ee8cc1Swenshuai.xi   ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2532*53ee8cc1Swenshuai.xi 
2533*53ee8cc1Swenshuai.xi   iPorts = HCS_N_PORTS (ehci->hcs_params);
2534*53ee8cc1Swenshuai.xi 
2535*53ee8cc1Swenshuai.xi   if (hcd->state == HCD_STATE_RUNNING)
2536*53ee8cc1Swenshuai.xi     ms_ehci_quiesce(ehci);
2537*53ee8cc1Swenshuai.xi   ms_debug_msg("ms_ehci_suspend\n");
2538*53ee8cc1Swenshuai.xi   hcd_reg_writel(hcd_reg_readl ((U32)&ehci->op_regs->usbcmd) & ~USBCMD_RUN, (U32)&ehci->op_regs->usbcmd);
2539*53ee8cc1Swenshuai.xi   while((hcd_reg_readl((U32)&ehci->op_regs->usbsts)&USBSTS_HALT) == 0);
2540*53ee8cc1Swenshuai.xi 
2541*53ee8cc1Swenshuai.xi   /* suspend each port, then stop the hc */
2542*53ee8cc1Swenshuai.xi   for (i = 0; i < iPorts; i++) {
2543*53ee8cc1Swenshuai.xi     int  temp = hcd_reg_readl ((U32)&ehci->op_regs->portsc [i]);
2544*53ee8cc1Swenshuai.xi     if ((temp & PORTSC_PE) == 0
2545*53ee8cc1Swenshuai.xi         /* || (temp & PORTSC_OWNER) != 0 */)
2546*53ee8cc1Swenshuai.xi       continue;
2547*53ee8cc1Swenshuai.xi     ms_debug_msg ("suspend port %d", i);
2548*53ee8cc1Swenshuai.xi     temp |= PORTSC_SUSPEND;
2549*53ee8cc1Swenshuai.xi     hcd_reg_writel (temp, (U32)&ehci->op_regs->portsc [i]);
2550*53ee8cc1Swenshuai.xi   }
2551*53ee8cc1Swenshuai.xi   ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2552*53ee8cc1Swenshuai.xi   return 0;
2553*53ee8cc1Swenshuai.xi }
2554*53ee8cc1Swenshuai.xi 
ms_ehci_resume(struct usb_hcd * hcd)2555*53ee8cc1Swenshuai.xi  int ms_ehci_resume (struct usb_hcd *hcd)
2556*53ee8cc1Swenshuai.xi {
2557*53ee8cc1Swenshuai.xi   struct ehci_hcd    *ehci = hcd_to_ehci (hcd);
2558*53ee8cc1Swenshuai.xi   int  iPorts;
2559*53ee8cc1Swenshuai.xi   int  i;
2560*53ee8cc1Swenshuai.xi   //U32  U32Tmp;
2561*53ee8cc1Swenshuai.xi 
2562*53ee8cc1Swenshuai.xi   ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2563*53ee8cc1Swenshuai.xi 
2564*53ee8cc1Swenshuai.xi   iPorts = HCS_N_PORTS (ehci->hcs_params);
2565*53ee8cc1Swenshuai.xi   hcd->state = HCD_STATE_RUNNING;
2566*53ee8cc1Swenshuai.xi   for (i = 0; i < iPorts; i++)
2567*53ee8cc1Swenshuai.xi   {
2568*53ee8cc1Swenshuai.xi     int  temp = hcd_reg_readl ((U32)&ehci->op_regs->portsc [i]);
2569*53ee8cc1Swenshuai.xi     if ((temp & PORTSC_PE) == 0
2570*53ee8cc1Swenshuai.xi         || (temp & PORTSC_SUSPEND) != 0)
2571*53ee8cc1Swenshuai.xi       continue;
2572*53ee8cc1Swenshuai.xi     ms_debug_msg ("resume port %d", i);
2573*53ee8cc1Swenshuai.xi     temp |= PORTSC_SUSPEND;
2574*53ee8cc1Swenshuai.xi     hcd_reg_writel (temp, (U32)&ehci->op_regs->portsc [i]);
2575*53ee8cc1Swenshuai.xi     /*U32Tmp = */hcd_reg_readl ((U32)&ehci->op_regs->usbcmd);  /* unblock posted writes */
2576*53ee8cc1Swenshuai.xi     wait_ms (20);
2577*53ee8cc1Swenshuai.xi     temp &= ~PORTSC_SUSPEND;
2578*53ee8cc1Swenshuai.xi     hcd_reg_writel (temp, (U32)&ehci->op_regs->portsc [i]);
2579*53ee8cc1Swenshuai.xi   }
2580*53ee8cc1Swenshuai.xi   /*U32Tmp = */hcd_reg_readl ((U32)&ehci->op_regs->usbcmd);  /* unblock posted writes */
2581*53ee8cc1Swenshuai.xi   ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2582*53ee8cc1Swenshuai.xi   return 0;
2583*53ee8cc1Swenshuai.xi }
2584*53ee8cc1Swenshuai.xi 
2585*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
2586*53ee8cc1Swenshuai.xi /*
2587*53ee8cc1Swenshuai.xi   * @brief          scan asynchronous qh chain and periodic frame list
2588*53ee8cc1Swenshuai.xi   *
2589*53ee8cc1Swenshuai.xi   * @param          struct ehci_hcd *pEhci
2590*53ee8cc1Swenshuai.xi   * @param          struct stPtRegs *regs
2591*53ee8cc1Swenshuai.xi   *
2592*53ee8cc1Swenshuai.xi   * @return         none
2593*53ee8cc1Swenshuai.xi   */
ms_ehci_work(struct ehci_hcd * pEhci,struct stPtRegs * regs)2594*53ee8cc1Swenshuai.xi static void ms_ehci_work(struct ehci_hcd *pEhci, struct stPtRegs *regs)
2595*53ee8cc1Swenshuai.xi {
2596*53ee8cc1Swenshuai.xi   ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2597*53ee8cc1Swenshuai.xi   ms_timer_action_done (pEhci, TIMER_IO_WATCHDOG);
2598*53ee8cc1Swenshuai.xi   Chip_Read_Memory(); // 20121218, 20121225
2599*53ee8cc1Swenshuai.xi 
2600*53ee8cc1Swenshuai.xi #if 0 // old reclaim flow
2601*53ee8cc1Swenshuai.xi   // This sequence will release Host task befor USB DSR complete.
2602*53ee8cc1Swenshuai.xi   if (pEhci->iReclaimReady)
2603*53ee8cc1Swenshuai.xi   {
2604*53ee8cc1Swenshuai.xi     ms_end_unlink_async (pEhci, regs);
2605*53ee8cc1Swenshuai.xi     ms_scan_async (pEhci, regs);
2606*53ee8cc1Swenshuai.xi     //ms_end_unlink_async (pEhci, regs); // move 2 lines ahead for IAA issue. 20140408
2607*53ee8cc1Swenshuai.xi   }
2608*53ee8cc1Swenshuai.xi #endif
2609*53ee8cc1Swenshuai.xi 
2610*53ee8cc1Swenshuai.xi   if (pEhci->iScanning)
2611*53ee8cc1Swenshuai.xi     return;
2612*53ee8cc1Swenshuai.xi   pEhci->iScanning = 1;
2613*53ee8cc1Swenshuai.xi   ms_scan_async (pEhci, regs);
2614*53ee8cc1Swenshuai.xi   if (pEhci->iNextUframe != -1)
2615*53ee8cc1Swenshuai.xi     ms_scan_periodic (pEhci, regs);
2616*53ee8cc1Swenshuai.xi   pEhci->iScanning = 0;
2617*53ee8cc1Swenshuai.xi 
2618*53ee8cc1Swenshuai.xi   if (HCD_IS_RUNNING(pEhci->hcd.state) &&
2619*53ee8cc1Swenshuai.xi     ((pEhci->stAsync->qh_next.ptr != 0) || (pEhci->u32PeriodicSched != 0)))
2620*53ee8cc1Swenshuai.xi     ms_timer_action (pEhci, TIMER_IO_WATCHDOG);
2621*53ee8cc1Swenshuai.xi   ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2622*53ee8cc1Swenshuai.xi }
2623*53ee8cc1Swenshuai.xi 
2624*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
2625*53ee8cc1Swenshuai.xi /*
2626*53ee8cc1Swenshuai.xi   * @brief          process ehci controller interrupt events
2627*53ee8cc1Swenshuai.xi   *
2628*53ee8cc1Swenshuai.xi   * @param          struct usb_hcd *pHcd
2629*53ee8cc1Swenshuai.xi   * @param          struct stPtRegs *pRegs
2630*53ee8cc1Swenshuai.xi   *
2631*53ee8cc1Swenshuai.xi   * @return         none
2632*53ee8cc1Swenshuai.xi   */
ms_ehci_irq(struct usb_hcd * pHcd,struct stPtRegs * pRegs)2633*53ee8cc1Swenshuai.xi void ms_ehci_irq (struct usb_hcd *pHcd, struct stPtRegs *pRegs)
2634*53ee8cc1Swenshuai.xi {
2635*53ee8cc1Swenshuai.xi   struct ehci_hcd    *pEhci= hcd_to_ehci (pHcd);
2636*53ee8cc1Swenshuai.xi   U32  u32Status, int_status;
2637*53ee8cc1Swenshuai.xi   int  bh;
2638*53ee8cc1Swenshuai.xi   U32 u32Cmd;
2639*53ee8cc1Swenshuai.xi 
2640*53ee8cc1Swenshuai.xi   osapi_spin_lock (&pEhci->tHcdLock);
2641*53ee8cc1Swenshuai.xi 
2642*53ee8cc1Swenshuai.xi   int_status = u32Status = hcd_reg_readl ((U32)&pEhci->op_regs->usbsts);
2643*53ee8cc1Swenshuai.xi 
2644*53ee8cc1Swenshuai.xi   if (u32Status == ~(U32) 0)
2645*53ee8cc1Swenshuai.xi   {
2646*53ee8cc1Swenshuai.xi     ms_debug_msg ("reg usbsts is 0xffff, device removed\n");
2647*53ee8cc1Swenshuai.xi     goto dead;
2648*53ee8cc1Swenshuai.xi   }
2649*53ee8cc1Swenshuai.xi 
2650*53ee8cc1Swenshuai.xi   u32Status &= INTR_MASK;
2651*53ee8cc1Swenshuai.xi   if (!u32Status)      /* No any our interrupt event */
2652*53ee8cc1Swenshuai.xi   {
2653*53ee8cc1Swenshuai.xi     diag_printf("ms_ehci_irq status: %x, intr_enable: %x\n", (unsigned int)int_status, hcd_reg_readw((U32)&pEhci->op_regs->usbintr));
2654*53ee8cc1Swenshuai.xi     goto done;
2655*53ee8cc1Swenshuai.xi   }
2656*53ee8cc1Swenshuai.xi 
2657*53ee8cc1Swenshuai.xi   hcd_reg_writel (u32Status, (U32)&pEhci->op_regs->usbsts);
2658*53ee8cc1Swenshuai.xi   u32Cmd = hcd_reg_readl ((U32)&pEhci->op_regs->usbcmd);
2659*53ee8cc1Swenshuai.xi   bh = 0;
2660*53ee8cc1Swenshuai.xi   //pEhci->uDontSendIAA = 0;
2661*53ee8cc1Swenshuai.xi 
2662*53ee8cc1Swenshuai.xi   /* Notify controller for advance async schedule */
2663*53ee8cc1Swenshuai.xi   /* USBSTS_INT for normal completion, see 4.15.1.2
2664*53ee8cc1Swenshuai.xi          USBSTS_ERR for error completion, see 4.15.1.1 */
2665*53ee8cc1Swenshuai.xi   if ((u32Status & (USBSTS_INT|USBSTS_ERR)) != 0)
2666*53ee8cc1Swenshuai.xi   {
2667*53ee8cc1Swenshuai.xi #if 0 // old reclaim flow
2668*53ee8cc1Swenshuai.xi     // Enable the interrupt for Async Advance Enable
2669*53ee8cc1Swenshuai.xi     pEhci->iReclaimReady = 0;
2670*53ee8cc1Swenshuai.xi     int    cmd = hcd_reg_readl ((U32)&pEhci->op_regs->usbcmd);
2671*53ee8cc1Swenshuai.xi     cmd |= USBCMD_IAAD;
2672*53ee8cc1Swenshuai.xi     hcd_reg_writel (cmd, (U32)&pEhci->op_regs->usbcmd);
2673*53ee8cc1Swenshuai.xi     (void) hcd_reg_readl ((U32)&pEhci->op_regs->usbcmd);
2674*53ee8cc1Swenshuai.xi     //pEhci->uDontSendIAA = 1;
2675*53ee8cc1Swenshuai.xi #endif
2676*53ee8cc1Swenshuai.xi     if ((u32Status & USBSTS_ERR) == 0)
2677*53ee8cc1Swenshuai.xi     {
2678*53ee8cc1Swenshuai.xi       INCREASE(pEhci->stats.u32Normal);
2679*53ee8cc1Swenshuai.xi     }
2680*53ee8cc1Swenshuai.xi     else
2681*53ee8cc1Swenshuai.xi     {
2682*53ee8cc1Swenshuai.xi       INCREASE(pEhci->stats.u32Error);
2683*53ee8cc1Swenshuai.xi       //bh = 1;	//Note, remove for command stall
2684*53ee8cc1Swenshuai.xi     }
2685*53ee8cc1Swenshuai.xi     bh = 1;
2686*53ee8cc1Swenshuai.xi   }
2687*53ee8cc1Swenshuai.xi 
2688*53ee8cc1Swenshuai.xi   /* IAA is used for complete the unlinking of qh */
2689*53ee8cc1Swenshuai.xi   if (u32Status & USBSTS_IAA)
2690*53ee8cc1Swenshuai.xi   {
2691*53ee8cc1Swenshuai.xi #if 0 // old reclaim flow
2692*53ee8cc1Swenshuai.xi     INCREASE(pEhci->stats.u32Reclaim);
2693*53ee8cc1Swenshuai.xi     pEhci->iReclaimReady = 1;
2694*53ee8cc1Swenshuai.xi     //pEhci->uDontSendIAA = 1;
2695*53ee8cc1Swenshuai.xi     bh = 1;
2696*53ee8cc1Swenshuai.xi #endif
2697*53ee8cc1Swenshuai.xi     if (u32Cmd & USBCMD_IAAD)
2698*53ee8cc1Swenshuai.xi     {
2699*53ee8cc1Swenshuai.xi         hcd_reg_writel (u32Cmd & ~USBCMD_IAAD, (U32)&pEhci->op_regs->usbcmd);
2700*53ee8cc1Swenshuai.xi         ms_debug_err("[EHCI] IAAD not clear?\n");
2701*53ee8cc1Swenshuai.xi     }
2702*53ee8cc1Swenshuai.xi     if (pEhci->stReclaim)
2703*53ee8cc1Swenshuai.xi     {
2704*53ee8cc1Swenshuai.xi         INCREASE(pEhci->stats.u32Reclaim);
2705*53ee8cc1Swenshuai.xi         ms_end_unlink_async(pEhci, pRegs);
2706*53ee8cc1Swenshuai.xi     }
2707*53ee8cc1Swenshuai.xi     else
2708*53ee8cc1Swenshuai.xi         ms_debug_err("reclaim but with nothing there!\n");
2709*53ee8cc1Swenshuai.xi   }
2710*53ee8cc1Swenshuai.xi 
2711*53ee8cc1Swenshuai.xi   /* See [4.3.1] */
2712*53ee8cc1Swenshuai.xi   if (u32Status & USBSTS_PCD)
2713*53ee8cc1Swenshuai.xi   {
2714*53ee8cc1Swenshuai.xi       // Only support one port
2715*53ee8cc1Swenshuai.xi       int iPsc/*, masked_psc*/;
2716*53ee8cc1Swenshuai.xi       int isHalt = 0;
2717*53ee8cc1Swenshuai.xi 
2718*53ee8cc1Swenshuai.xi       iPsc = hcd_reg_readl((U32)&pEhci->op_regs->portsc [0]);
2719*53ee8cc1Swenshuai.xi 
2720*53ee8cc1Swenshuai.xi       /* new patch, root hub not run */
2721*53ee8cc1Swenshuai.xi       if (iPsc == pHcd->saved_ehci_state.iPsc &&
2722*53ee8cc1Swenshuai.xi             pEhci->u32ResetEnd[0] == pHcd->saved_ehci_state.reset_done &&
2723*53ee8cc1Swenshuai.xi             u32Cmd == pHcd->saved_ehci_state.usbcmd &&
2724*53ee8cc1Swenshuai.xi             (u32Cmd & USBCMD_RUN) == 0)
2725*53ee8cc1Swenshuai.xi         {
2726*53ee8cc1Swenshuai.xi                 ++pEhci->ehci_port_not_change_cnt;
2727*53ee8cc1Swenshuai.xi                 if (pEhci->ehci_port_not_change_cnt > 7)
2728*53ee8cc1Swenshuai.xi                     isHalt = 1;
2729*53ee8cc1Swenshuai.xi         }
2730*53ee8cc1Swenshuai.xi       else
2731*53ee8cc1Swenshuai.xi         pEhci->ehci_port_not_change_cnt = 0;
2732*53ee8cc1Swenshuai.xi       pHcd->saved_ehci_state.iPsc = iPsc;
2733*53ee8cc1Swenshuai.xi       pHcd->saved_ehci_state.reset_done = pEhci->u32ResetEnd[0];
2734*53ee8cc1Swenshuai.xi       pHcd->saved_ehci_state.usbcmd = u32Cmd;
2735*53ee8cc1Swenshuai.xi       if (isHalt)
2736*53ee8cc1Swenshuai.xi       {
2737*53ee8cc1Swenshuai.xi         diag_printf("[EHCI] PCD not clear, reset UHC to get new CURRENT usbsts\n");
2738*53ee8cc1Swenshuai.xi         if(iPsc & PORTSC_CSC)
2739*53ee8cc1Swenshuai.xi         {
2740*53ee8cc1Swenshuai.xi           diag_printf("[EHCI] set more CSC\n");
2741*53ee8cc1Swenshuai.xi           pEhci->u32MoreCSC = true;
2742*53ee8cc1Swenshuai.xi         }
2743*53ee8cc1Swenshuai.xi         ms_ehci_softrst(pEhci);
2744*53ee8cc1Swenshuai.xi         goto done;
2745*53ee8cc1Swenshuai.xi       }
2746*53ee8cc1Swenshuai.xi 
2747*53ee8cc1Swenshuai.xi       // root hub not run
2748*53ee8cc1Swenshuai.xi #if 0 // NUSED
2749*53ee8cc1Swenshuai.xi       if ((u32Cmd & USBCMD_RUN) == 0)
2750*53ee8cc1Swenshuai.xi       {
2751*53ee8cc1Swenshuai.xi           //u32Cmd |= USBCMD_RUN;
2752*53ee8cc1Swenshuai.xi           //hcd_reg_writel(u32Cmd, (U32)&pEhci->op_regs->usbcmd);
2753*53ee8cc1Swenshuai.xi           //while(hcd_reg_readw ((U32)&pEhci->op_regs->usbsts) & USBSTS_HALT);
2754*53ee8cc1Swenshuai.xi           isHalt = 1;
2755*53ee8cc1Swenshuai.xi           //hcd_reg_writel (u32Status, (U32)&pEhci->op_regs->usbsts);
2756*53ee8cc1Swenshuai.xi           //diag_printf("clear USBSTS_PCD (0x%x) again\n", hcd_reg_readw ((U32)&pEhci->op_regs->usbsts));
2757*53ee8cc1Swenshuai.xi       }
2758*53ee8cc1Swenshuai.xi 
2759*53ee8cc1Swenshuai.xi       masked_psc = iPsc & 0xf;
2760*53ee8cc1Swenshuai.xi       //if ((masked_psc == 0xa /*|| masked_psc == 0xf */) && pEhci->u32ResetEnd[0] == 0)
2761*53ee8cc1Swenshuai.xi       if ((masked_psc == 0xb))
2762*53ee8cc1Swenshuai.xi       {
2763*53ee8cc1Swenshuai.xi           if (isHalt)
2764*53ee8cc1Swenshuai.xi           {
2765*53ee8cc1Swenshuai.xi             //ms_ehci_softrst(pEhci);
2766*53ee8cc1Swenshuai.xi             //diag_printf("PCD not clear, reset UHC to get new CURRENT usbsts = 0x%x\n", hcd_reg_readl ((U32)&pEhci->op_regs->usbsts));
2767*53ee8cc1Swenshuai.xi           }
2768*53ee8cc1Swenshuai.xi       }
2769*53ee8cc1Swenshuai.xi #endif
2770*53ee8cc1Swenshuai.xi 
2771*53ee8cc1Swenshuai.xi       /* Clear port enable bit when root device disconnect */
2772*53ee8cc1Swenshuai.xi       /* Patch for hub+device hot plug frequency then lost disconnect event */
2773*53ee8cc1Swenshuai.xi       if ((iPsc & PORTSC_CSC) && (iPsc & PORTSC_CONNECT)==0)
2774*53ee8cc1Swenshuai.xi       {
2775*53ee8cc1Swenshuai.xi             iPsc &= ~(PORTSC_PEC | PORTSC_PE | PORTSC_CSC);
2776*53ee8cc1Swenshuai.xi             hcd_reg_writel(iPsc, (U32)&pEhci->op_regs->portsc[0]);
2777*53ee8cc1Swenshuai.xi             //diag_printf("<irq> clear PORTSC_PE\n");
2778*53ee8cc1Swenshuai.xi       }
2779*53ee8cc1Swenshuai.xi       #if 0 // un-patch since not to support suspend
2780*53ee8cc1Swenshuai.xi       if ((((iPsc & PORTSC_RESUME) ||
2781*53ee8cc1Swenshuai.xi            !(iPsc & PORTSC_SUSPEND)) &&
2782*53ee8cc1Swenshuai.xi             (iPsc & PORTSC_PE) &&
2783*53ee8cc1Swenshuai.xi              pEhci->u32ResetEnd[0] == 0))
2784*53ee8cc1Swenshuai.xi       {
2785*53ee8cc1Swenshuai.xi           /* The root hub port active 20 msec resume signal,
2786*53ee8cc1Swenshuai.xi                     * PORTSC_SUSPEND to stop resume signal.
2787*53ee8cc1Swenshuai.xi                     */
2788*53ee8cc1Swenshuai.xi           pEhci->u32ResetEnd [0] = jiffies + ((20 /* msec */ * HZ) / 1000);
2789*53ee8cc1Swenshuai.xi           ms_debug_msg ("port 1 remote wakeup\n");
2790*53ee8cc1Swenshuai.xi           ms_update_timer(&pHcd->roothub_timer, pEhci->u32ResetEnd[0], 0);
2791*53ee8cc1Swenshuai.xi       }
2792*53ee8cc1Swenshuai.xi       #endif
2793*53ee8cc1Swenshuai.xi   }
2794*53ee8cc1Swenshuai.xi 
2795*53ee8cc1Swenshuai.xi 
2796*53ee8cc1Swenshuai.xi   /* See [4.15.2.4] */
2797*53ee8cc1Swenshuai.xi 
2798*53ee8cc1Swenshuai.xi   if ((u32Status & USBSTS_FATAL) != 0)
2799*53ee8cc1Swenshuai.xi   {
2800*53ee8cc1Swenshuai.xi      ms_debug_err ("[EHCI] fatal error\n");
2801*53ee8cc1Swenshuai.xi dead:
2802*53ee8cc1Swenshuai.xi      //ms_ehci_reset (pEhci);
2803*53ee8cc1Swenshuai.xi      ms_ehci_softrst(pEhci);
2804*53ee8cc1Swenshuai.xi      /* uses ms_ehci_end to clean up the rest */
2805*53ee8cc1Swenshuai.xi      bh = 1;
2806*53ee8cc1Swenshuai.xi   }
2807*53ee8cc1Swenshuai.xi 
2808*53ee8cc1Swenshuai.xi   if (bh ||
2809*53ee8cc1Swenshuai.xi     (pEhci->u32PeriodicSched != 0) //If we has periodic transactions in Schedule, we must scan periodic when USBSTS_INT
2810*53ee8cc1Swenshuai.xi     )
2811*53ee8cc1Swenshuai.xi     ms_ehci_work(pEhci, pRegs);
2812*53ee8cc1Swenshuai.xi done:
2813*53ee8cc1Swenshuai.xi   osapi_spin_unlock (&pEhci->tHcdLock);
2814*53ee8cc1Swenshuai.xi   if (u32Status & USBSTS_PCD)
2815*53ee8cc1Swenshuai.xi       ms_hcd_poll_rh_status(pHcd);
2816*53ee8cc1Swenshuai.xi 
2817*53ee8cc1Swenshuai.xi }
2818*53ee8cc1Swenshuai.xi 
2819*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
2820*53ee8cc1Swenshuai.xi /*
2821*53ee8cc1Swenshuai.xi   * @brief          transforms urb into qh+qtd list and submit to HCD hardware
2822*53ee8cc1Swenshuai.xi   *
2823*53ee8cc1Swenshuai.xi   * @param          struct usb_hcd  *pHcd
2824*53ee8cc1Swenshuai.xi   * @param          struct urb  *pUrb
2825*53ee8cc1Swenshuai.xi   * @param          int  iMem_flags
2826*53ee8cc1Swenshuai.xi   *
2827*53ee8cc1Swenshuai.xi   * @return         error code
2828*53ee8cc1Swenshuai.xi   */
ms_urb_enqueue(struct usb_hcd * pHcd,struct urb * pUrb,int iMem_flags)2829*53ee8cc1Swenshuai.xi  int ms_urb_enqueue (
2830*53ee8cc1Swenshuai.xi   struct usb_hcd  *pHcd,
2831*53ee8cc1Swenshuai.xi   struct urb  *pUrb,
2832*53ee8cc1Swenshuai.xi   int    iMem_flags
2833*53ee8cc1Swenshuai.xi )
2834*53ee8cc1Swenshuai.xi {
2835*53ee8cc1Swenshuai.xi   struct ehci_hcd    *pEhci = hcd_to_ehci (pHcd);
2836*53ee8cc1Swenshuai.xi   struct list_head  qtd_list;
2837*53ee8cc1Swenshuai.xi   int iRetVal;
2838*53ee8cc1Swenshuai.xi 
2839*53ee8cc1Swenshuai.xi   ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2840*53ee8cc1Swenshuai.xi #ifdef ENABLE_DISCONNECT_FAST_RESPONSE
2841*53ee8cc1Swenshuai.xi   if( (hcd_reg_readl ((U32)&pEhci->op_regs->portsc[0])&PORTSC_CONNECT) == 0 )
2842*53ee8cc1Swenshuai.xi   {
2843*53ee8cc1Swenshuai.xi     iRetVal = -ENODEV;
2844*53ee8cc1Swenshuai.xi     goto urb_enqueue_fail;
2845*53ee8cc1Swenshuai.xi   }
2846*53ee8cc1Swenshuai.xi #endif
2847*53ee8cc1Swenshuai.xi   ms_list_init (&qtd_list);
2848*53ee8cc1Swenshuai.xi 
2849*53ee8cc1Swenshuai.xi   switch (usb_pipetype (pUrb->u32Pipe))
2850*53ee8cc1Swenshuai.xi   {
2851*53ee8cc1Swenshuai.xi     case EP_CONTROL:
2852*53ee8cc1Swenshuai.xi     case EP_BULK:
2853*53ee8cc1Swenshuai.xi         if (!ms_qh_urb_process (pEhci, pUrb, &qtd_list, iMem_flags))
2854*53ee8cc1Swenshuai.xi         {
2855*53ee8cc1Swenshuai.xi             iRetVal = -ENOMEM;
2856*53ee8cc1Swenshuai.xi             goto urb_enqueue_fail;
2857*53ee8cc1Swenshuai.xi         }
2858*53ee8cc1Swenshuai.xi         iRetVal = ms_submit_async (pEhci, pUrb, &qtd_list);
2859*53ee8cc1Swenshuai.xi         break;
2860*53ee8cc1Swenshuai.xi 
2861*53ee8cc1Swenshuai.xi     case EP_INTERRUPT:
2862*53ee8cc1Swenshuai.xi         if (!ms_qh_urb_process (pEhci, pUrb, &qtd_list, iMem_flags))
2863*53ee8cc1Swenshuai.xi         {
2864*53ee8cc1Swenshuai.xi             iRetVal = -ENOMEM;
2865*53ee8cc1Swenshuai.xi             goto urb_enqueue_fail;
2866*53ee8cc1Swenshuai.xi         }
2867*53ee8cc1Swenshuai.xi         iRetVal = ms_intr_submit (pEhci, pUrb, &qtd_list);
2868*53ee8cc1Swenshuai.xi         break;
2869*53ee8cc1Swenshuai.xi 
2870*53ee8cc1Swenshuai.xi     default:
2871*53ee8cc1Swenshuai.xi         ms_debug_msg ("no support the transaction type!!\n");
2872*53ee8cc1Swenshuai.xi         iRetVal = -ENOSYS;
2873*53ee8cc1Swenshuai.xi   }
2874*53ee8cc1Swenshuai.xi 
2875*53ee8cc1Swenshuai.xi urb_enqueue_fail:
2876*53ee8cc1Swenshuai.xi   ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2877*53ee8cc1Swenshuai.xi   return iRetVal;
2878*53ee8cc1Swenshuai.xi }
2879*53ee8cc1Swenshuai.xi 
2880*53ee8cc1Swenshuai.xi /*
2881*53ee8cc1Swenshuai.xi   * @brief          remove qh from HW content
2882*53ee8cc1Swenshuai.xi   *                 will happen a  completion event
2883*53ee8cc1Swenshuai.xi   *
2884*53ee8cc1Swenshuai.xi   * @param          struct usb_hcd *pHcd
2885*53ee8cc1Swenshuai.xi   * @param          struct urb *pUrb
2886*53ee8cc1Swenshuai.xi   *
2887*53ee8cc1Swenshuai.xi   * @return         error code
2888*53ee8cc1Swenshuai.xi   */
ms_urb_dequeue(struct usb_hcd * pHcd,struct urb * pUrb)2889*53ee8cc1Swenshuai.xi  int ms_urb_dequeue (struct usb_hcd *pHcd, struct urb *pUrb)
2890*53ee8cc1Swenshuai.xi {
2891*53ee8cc1Swenshuai.xi   struct ehci_hcd    *pEhci = hcd_to_ehci (pHcd);
2892*53ee8cc1Swenshuai.xi   struct ehci_qh    *pQh = (struct ehci_qh *) pUrb->hcpriv;
2893*53ee8cc1Swenshuai.xi   U32    u32Flags;
2894*53ee8cc1Swenshuai.xi   int iStatus = 0;
2895*53ee8cc1Swenshuai.xi 
2896*53ee8cc1Swenshuai.xi   if (!pQh)
2897*53ee8cc1Swenshuai.xi       return 0;
2898*53ee8cc1Swenshuai.xi 
2899*53ee8cc1Swenshuai.xi   ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
2900*53ee8cc1Swenshuai.xi   osapi_spin_lock_irqsave (&pEhci->tHcdLock, u32Flags);
2901*53ee8cc1Swenshuai.xi   switch (usb_pipetype (pUrb->u32Pipe))
2902*53ee8cc1Swenshuai.xi   {
2903*53ee8cc1Swenshuai.xi   /*
2904*53ee8cc1Swenshuai.xi       // case EP_CONTROL:
2905*53ee8cc1Swenshuai.xi       // case EP_BULK:
2906*53ee8cc1Swenshuai.xi         */
2907*53ee8cc1Swenshuai.xi   default:
2908*53ee8cc1Swenshuai.xi     /* patch the old flow */
2909*53ee8cc1Swenshuai.xi     switch (pQh->qh_status) {
2910*53ee8cc1Swenshuai.xi         case QH_STS_LINKED:
2911*53ee8cc1Swenshuai.xi         case QH_STS_COMPLETING:
2912*53ee8cc1Swenshuai.xi #ifdef ENABLE_DISCONNECT_FAST_RESPONSE
2913*53ee8cc1Swenshuai.xi             /* remove (20150422) */
2914*53ee8cc1Swenshuai.xi             /* do fast unlink if HCD halt */
2915*53ee8cc1Swenshuai.xi             //if ( (hcd_reg_readw ((U32)&pEhci->op_regs->usbcmd)&USBCMD_RUN) == 0 )
2916*53ee8cc1Swenshuai.xi             //    pEhci->hcd.state = HCD_STATE_HALT;
2917*53ee8cc1Swenshuai.xi #endif
2918*53ee8cc1Swenshuai.xi             /* base on linux 2.6.28, 3.1.10 */
2919*53ee8cc1Swenshuai.xi             /*** unlink_async ***/
2920*53ee8cc1Swenshuai.xi             ms_unlink_async(pEhci, pQh);
2921*53ee8cc1Swenshuai.xi             break;
2922*53ee8cc1Swenshuai.xi         case QH_STS_UNLINK:
2923*53ee8cc1Swenshuai.xi         case QH_STS_UNLINK_WAIT:
2924*53ee8cc1Swenshuai.xi             /* had started */
2925*53ee8cc1Swenshuai.xi             break;
2926*53ee8cc1Swenshuai.xi         case QH_STS_IDLE:
2927*53ee8cc1Swenshuai.xi             diag_printf("[USB] dequeue idle qh\n");
2928*53ee8cc1Swenshuai.xi             break;
2929*53ee8cc1Swenshuai.xi     }
2930*53ee8cc1Swenshuai.xi     #if 0 // renewed old flow
2931*53ee8cc1Swenshuai.xi     /* if we need to use IAA and it's busy, defer */
2932*53ee8cc1Swenshuai.xi     if (pQh->qh_status == QH_STS_LINKED
2933*53ee8cc1Swenshuai.xi         && pEhci->stReclaim
2934*53ee8cc1Swenshuai.xi         && HCD_IS_RUNNING (pEhci->hcd.state)
2935*53ee8cc1Swenshuai.xi         )
2936*53ee8cc1Swenshuai.xi     {
2937*53ee8cc1Swenshuai.xi       struct ehci_qh    *pLast;
2938*53ee8cc1Swenshuai.xi 
2939*53ee8cc1Swenshuai.xi       for (pLast = pEhci->stReclaim;
2940*53ee8cc1Swenshuai.xi           pLast->pReclaimQh;
2941*53ee8cc1Swenshuai.xi           pLast = pLast->pReclaimQh)
2942*53ee8cc1Swenshuai.xi         continue;
2943*53ee8cc1Swenshuai.xi       pQh->qh_status = QH_STS_UNLINK_WAIT;
2944*53ee8cc1Swenshuai.xi       pLast->pReclaimQh = pQh;
2945*53ee8cc1Swenshuai.xi       /* bypass IAA if the hc can't care */
2946*53ee8cc1Swenshuai.xi     }
2947*53ee8cc1Swenshuai.xi     else if (!HCD_IS_RUNNING (pEhci->hcd.state) && pEhci->stReclaim)
2948*53ee8cc1Swenshuai.xi       ms_end_unlink_async (pEhci, NULL);
2949*53ee8cc1Swenshuai.xi 
2950*53ee8cc1Swenshuai.xi     /* something else might have unlinked the qh by now */
2951*53ee8cc1Swenshuai.xi     if (pQh->qh_status == QH_STS_LINKED)
2952*53ee8cc1Swenshuai.xi       ms_start_unlink_async (pEhci, pQh);
2953*53ee8cc1Swenshuai.xi     #endif
2954*53ee8cc1Swenshuai.xi     //FIXME: cover FOTG200 bug
2955*53ee8cc1Swenshuai.xi     // NUSED, not proper hardware patch
2956*53ee8cc1Swenshuai.xi     //if( (hcd_reg_readw ((U32)&pEhci->op_regs->portsc[0])&PORTSC_CONNECT) == 0 )
2957*53ee8cc1Swenshuai.xi     //{
2958*53ee8cc1Swenshuai.xi     //  diag_printf("[urb_dequeue] connect bit = 0 \n");
2959*53ee8cc1Swenshuai.xi     //  //Finish ullinking procedure
2960*53ee8cc1Swenshuai.xi     //  ms_end_unlink_async (pEhci, NULL);
2961*53ee8cc1Swenshuai.xi     //  //Reset HC to ensure FOTG200 work correctly at the next time
2962*53ee8cc1Swenshuai.xi     //  ms_hub_port_disable(pEhci->hcd.self.root_hub,0);
2963*53ee8cc1Swenshuai.xi     //}
2964*53ee8cc1Swenshuai.xi     //else if ( (hcd_reg_readw ((U32)&pEhci->op_regs->usbcmd)&USBCMD_RUN) == 0 )
2965*53ee8cc1Swenshuai.xi     //{
2966*53ee8cc1Swenshuai.xi     //  diag_printf("Something wrong (script auto running?) ==> Check it out\n");
2967*53ee8cc1Swenshuai.xi     //  //Finish ullinking procedure
2968*53ee8cc1Swenshuai.xi     //  ms_end_unlink_async (pEhci, NULL);
2969*53ee8cc1Swenshuai.xi     //  //Reset HC to ensure FOTG200 work correctly at the next time
2970*53ee8cc1Swenshuai.xi     //  ms_hub_port_disable(pEhci->hcd.self.root_hub,0);
2971*53ee8cc1Swenshuai.xi     //}
2972*53ee8cc1Swenshuai.xi     break;
2973*53ee8cc1Swenshuai.xi   case EP_INTERRUPT:
2974*53ee8cc1Swenshuai.xi     /* patch from Linux 2.6.28 */
2975*53ee8cc1Swenshuai.xi     switch (pQh->qh_status)
2976*53ee8cc1Swenshuai.xi     {
2977*53ee8cc1Swenshuai.xi         case QH_STS_LINKED:
2978*53ee8cc1Swenshuai.xi         //case QH_STS_COMPLETING:
2979*53ee8cc1Swenshuai.xi             ms_intr_deschedule (pEhci, pQh);
2980*53ee8cc1Swenshuai.xi             /* revise to fall through */
2981*53ee8cc1Swenshuai.xi             //break;
2982*53ee8cc1Swenshuai.xi         case QH_STS_IDLE:
2983*53ee8cc1Swenshuai.xi             ms_qh_completions (pEhci, pQh, NULL);
2984*53ee8cc1Swenshuai.xi             break;
2985*53ee8cc1Swenshuai.xi         default:
2986*53ee8cc1Swenshuai.xi             ms_debug_err("bogus qh %p state %d\n",
2987*53ee8cc1Swenshuai.xi                     pQh, pQh->qh_status);
2988*53ee8cc1Swenshuai.xi             goto done;
2989*53ee8cc1Swenshuai.xi     }
2990*53ee8cc1Swenshuai.xi     break;
2991*53ee8cc1Swenshuai.xi     #if 0 // renewed old one
2992*53ee8cc1Swenshuai.xi     if (pQh->qh_status == QH_STS_LINKED)
2993*53ee8cc1Swenshuai.xi     {
2994*53ee8cc1Swenshuai.xi       /* messy, can spin or block a microframe ... */
2995*53ee8cc1Swenshuai.xi       ms_intr_deschedule (pEhci, pQh, 1);
2996*53ee8cc1Swenshuai.xi       /* qh_state == IDLE */
2997*53ee8cc1Swenshuai.xi     }
2998*53ee8cc1Swenshuai.xi     ms_qh_completions (pEhci, pQh, NULL);
2999*53ee8cc1Swenshuai.xi     #endif
3000*53ee8cc1Swenshuai.xi 
3001*53ee8cc1Swenshuai.xi     /* reschedule QH iff another request is queued */
3002*53ee8cc1Swenshuai.xi     if (!ms_is_empty_list (&pQh->qtd_list)
3003*53ee8cc1Swenshuai.xi         && HCD_IS_RUNNING (pEhci->hcd.state))
3004*53ee8cc1Swenshuai.xi     {
3005*53ee8cc1Swenshuai.xi       //int iStatus;
3006*53ee8cc1Swenshuai.xi 
3007*53ee8cc1Swenshuai.xi       iStatus = ms_qh_schedule (pEhci, pQh);
3008*53ee8cc1Swenshuai.xi       //osapi_spin_unlock_irqrestore (&pEhci->tHcdLock, u32Flags);
3009*53ee8cc1Swenshuai.xi       if (iStatus != 0)
3010*53ee8cc1Swenshuai.xi       {
3011*53ee8cc1Swenshuai.xi         // Warning happened
3012*53ee8cc1Swenshuai.xi         ms_debug_err ("can't reschedule pQh %p, err %d", pQh, iStatus);
3013*53ee8cc1Swenshuai.xi       }
3014*53ee8cc1Swenshuai.xi       //ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
3015*53ee8cc1Swenshuai.xi       //return iStatus;
3016*53ee8cc1Swenshuai.xi     }
3017*53ee8cc1Swenshuai.xi     break;
3018*53ee8cc1Swenshuai.xi   }
3019*53ee8cc1Swenshuai.xi done:
3020*53ee8cc1Swenshuai.xi   osapi_spin_unlock_irqrestore (&pEhci->tHcdLock, u32Flags);
3021*53ee8cc1Swenshuai.xi   ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
3022*53ee8cc1Swenshuai.xi   return iStatus;
3023*53ee8cc1Swenshuai.xi }
3024*53ee8cc1Swenshuai.xi 
3025*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
3026*53ee8cc1Swenshuai.xi 
3027*53ee8cc1Swenshuai.xi /*
3028*53ee8cc1Swenshuai.xi   * @brief          wait qh unlink complete then free qtd list.
3029*53ee8cc1Swenshuai.xi   *
3030*53ee8cc1Swenshuai.xi   * @param          struct usb_hcd *pHcd
3031*53ee8cc1Swenshuai.xi   * @param          struct s_hcd_dev *pDev
3032*53ee8cc1Swenshuai.xi   * @param          int iEp
3033*53ee8cc1Swenshuai.xi   *
3034*53ee8cc1Swenshuai.xi   * @return         none
3035*53ee8cc1Swenshuai.xi   */
3036*53ee8cc1Swenshuai.xi 
3037*53ee8cc1Swenshuai.xi void
ms_ehci_disable_ep(struct usb_hcd * pHcd,struct s_hcd_dev * pDev,int iEp)3038*53ee8cc1Swenshuai.xi ms_ehci_disable_ep (struct usb_hcd *pHcd, struct s_hcd_dev *pDev, int iEp)
3039*53ee8cc1Swenshuai.xi {
3040*53ee8cc1Swenshuai.xi   struct ehci_hcd    *pEhci = hcd_to_ehci (pHcd);
3041*53ee8cc1Swenshuai.xi   int    iEpnum;
3042*53ee8cc1Swenshuai.xi   U32    u32Flags;
3043*53ee8cc1Swenshuai.xi   struct ehci_qh    *pQh, *tmp;
3044*53ee8cc1Swenshuai.xi   int numRescan = 100;
3045*53ee8cc1Swenshuai.xi 
3046*53ee8cc1Swenshuai.xi   ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
3047*53ee8cc1Swenshuai.xi   iEpnum = iEp & USB_ENDPOINT_NUMBER_MASK;
3048*53ee8cc1Swenshuai.xi   if (iEpnum != 0 && (iEp & USB_DIR_IN))
3049*53ee8cc1Swenshuai.xi     iEpnum |= 0x10;
3050*53ee8cc1Swenshuai.xi 
3051*53ee8cc1Swenshuai.xi rescan:
3052*53ee8cc1Swenshuai.xi   osapi_spin_lock_irqsave (&pEhci->tHcdLock, u32Flags);
3053*53ee8cc1Swenshuai.xi   pQh = (struct ehci_qh *) pDev->ep[iEpnum];
3054*53ee8cc1Swenshuai.xi   if (!pQh)
3055*53ee8cc1Swenshuai.xi     goto done;
3056*53ee8cc1Swenshuai.xi 
3057*53ee8cc1Swenshuai.xi   if (!HCD_IS_RUNNING (pEhci->hcd.state))
3058*53ee8cc1Swenshuai.xi     pQh->qh_status = QH_STS_IDLE;
3059*53ee8cc1Swenshuai.xi   switch (pQh->qh_status)
3060*53ee8cc1Swenshuai.xi   {
3061*53ee8cc1Swenshuai.xi       case QH_STS_LINKED:
3062*53ee8cc1Swenshuai.xi         for (tmp = pEhci->stAsync->qh_next.qh;
3063*53ee8cc1Swenshuai.xi           tmp && tmp != pQh; tmp = tmp->qh_next.qh)
3064*53ee8cc1Swenshuai.xi             continue;
3065*53ee8cc1Swenshuai.xi         if (!tmp)
3066*53ee8cc1Swenshuai.xi             goto bad;
3067*53ee8cc1Swenshuai.xi         /* base on linux 2.6.28, 3.1.10 */
3068*53ee8cc1Swenshuai.xi         /*** unlink_async ***/
3069*53ee8cc1Swenshuai.xi         ms_unlink_async(pEhci, pQh);
3070*53ee8cc1Swenshuai.xi         //break;
3071*53ee8cc1Swenshuai.xi         /* to disable endpoint, unlink continued */
3072*53ee8cc1Swenshuai.xi       case QH_STS_UNLINK:
3073*53ee8cc1Swenshuai.xi       case QH_STS_UNLINK_WAIT:
3074*53ee8cc1Swenshuai.xi         osapi_spin_unlock_irqrestore (&pEhci->tHcdLock, u32Flags);
3075*53ee8cc1Swenshuai.xi         osapi_schedule_timeout (1);
3076*53ee8cc1Swenshuai.xi         if (--numRescan)
3077*53ee8cc1Swenshuai.xi             goto rescan;
3078*53ee8cc1Swenshuai.xi         diag_printf("[UM-DEP] rescan 100 times, qh state %d, HCD state %x\n", pQh->qh_status, pEhci->hcd.state);
3079*53ee8cc1Swenshuai.xi         osapi_spin_lock_irqsave (&pEhci->tHcdLock, u32Flags);
3080*53ee8cc1Swenshuai.xi       case QH_STS_IDLE:
3081*53ee8cc1Swenshuai.xi         if (ms_is_empty_list (&pQh->qtd_list))
3082*53ee8cc1Swenshuai.xi         {
3083*53ee8cc1Swenshuai.xi           ms_qh_put (pEhci, pQh);
3084*53ee8cc1Swenshuai.xi           break;
3085*53ee8cc1Swenshuai.xi         }
3086*53ee8cc1Swenshuai.xi       default:
3087*53ee8cc1Swenshuai.xi bad:
3088*53ee8cc1Swenshuai.xi         //if ( !ms_is_empty_list (&pQh->qtd_list))
3089*53ee8cc1Swenshuai.xi         {
3090*53ee8cc1Swenshuai.xi             ms_debug_err ("<%s> pQh %p (ep#%d) state %d%s\n",
3091*53ee8cc1Swenshuai.xi                 __FUNCTION__, pQh, iEpnum, pQh->qh_status,
3092*53ee8cc1Swenshuai.xi                 ms_is_empty_list (&pQh->qtd_list) ? "" : "(has tds)");
3093*53ee8cc1Swenshuai.xi         }
3094*53ee8cc1Swenshuai.xi         break;
3095*53ee8cc1Swenshuai.xi   }
3096*53ee8cc1Swenshuai.xi   if (numRescan)
3097*53ee8cc1Swenshuai.xi         pDev->ep[iEpnum] = 0;
3098*53ee8cc1Swenshuai.xi done:
3099*53ee8cc1Swenshuai.xi   osapi_spin_unlock_irqrestore (&pEhci->tHcdLock, u32Flags);
3100*53ee8cc1Swenshuai.xi   ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
3101*53ee8cc1Swenshuai.xi   return;
3102*53ee8cc1Swenshuai.xi }
3103*53ee8cc1Swenshuai.xi 
3104*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
3105*53ee8cc1Swenshuai.xi 
ms_ehci_stoprun_setting(MS_U8 bOption,struct ehci_hcd * ehci)3106*53ee8cc1Swenshuai.xi void ms_ehci_stoprun_setting(MS_U8 bOption, struct ehci_hcd *ehci)
3107*53ee8cc1Swenshuai.xi {
3108*53ee8cc1Swenshuai.xi     U32 temp;
3109*53ee8cc1Swenshuai.xi 
3110*53ee8cc1Swenshuai.xi     ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
3111*53ee8cc1Swenshuai.xi     if (bOption==HOST20_Enable)
3112*53ee8cc1Swenshuai.xi     {
3113*53ee8cc1Swenshuai.xi         temp = hcd_reg_readl((U32)&ehci->op_regs->usbcmd);
3114*53ee8cc1Swenshuai.xi         if (temp & USBCMD_RUN)
3115*53ee8cc1Swenshuai.xi         {
3116*53ee8cc1Swenshuai.xi             ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
3117*53ee8cc1Swenshuai.xi             return;
3118*53ee8cc1Swenshuai.xi         }
3119*53ee8cc1Swenshuai.xi         temp |= USBCMD_RUN;
3120*53ee8cc1Swenshuai.xi         hcd_reg_writel(temp, (U32)&ehci->op_regs->usbcmd);
3121*53ee8cc1Swenshuai.xi         do
3122*53ee8cc1Swenshuai.xi         {
3123*53ee8cc1Swenshuai.xi             temp = hcd_reg_readl((U32)&ehci->op_regs->usbcmd);
3124*53ee8cc1Swenshuai.xi         } while ((temp & USBCMD_RUN) == 0);
3125*53ee8cc1Swenshuai.xi         ehci->hcd.state = HCD_STATE_RUNNING;
3126*53ee8cc1Swenshuai.xi     }
3127*53ee8cc1Swenshuai.xi     else if (bOption==HOST20_Disable)
3128*53ee8cc1Swenshuai.xi     {
3129*53ee8cc1Swenshuai.xi         temp = hcd_reg_readl((U32)&ehci->op_regs->usbcmd);
3130*53ee8cc1Swenshuai.xi         if ((temp & USBCMD_RUN) == 0)
3131*53ee8cc1Swenshuai.xi             return;
3132*53ee8cc1Swenshuai.xi 
3133*53ee8cc1Swenshuai.xi       temp &= ~USBCMD_RUN;
3134*53ee8cc1Swenshuai.xi       hcd_reg_writel(temp, (U32)&ehci->op_regs->usbcmd);
3135*53ee8cc1Swenshuai.xi       do {
3136*53ee8cc1Swenshuai.xi           temp = hcd_reg_readl((U32)&ehci->op_regs->usbcmd);
3137*53ee8cc1Swenshuai.xi       } while ((temp & USBCMD_RUN) > 0);
3138*53ee8cc1Swenshuai.xi       ehci->hcd.state = HCD_STATE_HALT;
3139*53ee8cc1Swenshuai.xi     }
3140*53ee8cc1Swenshuai.xi     else
3141*53ee8cc1Swenshuai.xi       USB_ASSERT(0, "??? Input Error 'ms_ehci_stoprun_setting'...");
3142*53ee8cc1Swenshuai.xi 
3143*53ee8cc1Swenshuai.xi     ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
3144*53ee8cc1Swenshuai.xi }
3145*53ee8cc1Swenshuai.xi 
ms_qh_ehci_reinit(struct usb_hcd * pHcd,int not_fix)3146*53ee8cc1Swenshuai.xi void ms_qh_ehci_reinit(struct usb_hcd *pHcd, int not_fix)
3147*53ee8cc1Swenshuai.xi {
3148*53ee8cc1Swenshuai.xi     struct ehci_hcd  *pEhci = hcd_to_ehci (pHcd);
3149*53ee8cc1Swenshuai.xi     U32    u32Temp;
3150*53ee8cc1Swenshuai.xi     int is_empty_qtd = 0;
3151*53ee8cc1Swenshuai.xi 
3152*53ee8cc1Swenshuai.xi     if( pEhci->stAsync->qh_next.qh != 0 )
3153*53ee8cc1Swenshuai.xi     {
3154*53ee8cc1Swenshuai.xi         ms_debug_err("[reinit] MAY Not only cantain one qHD in asyn. scheduler (%p)\n", pEhci->stAsync);
3155*53ee8cc1Swenshuai.xi         ms_debug_err("[reinit] async hw_next_qh %x\n", pEhci->stAsync->hw_next_qh);
3156*53ee8cc1Swenshuai.xi #if 0
3157*53ee8cc1Swenshuai.xi         struct ehci_qh *pQh = pEhci->stAsync->qh_next.qh;
3158*53ee8cc1Swenshuai.xi         while(pQh) {
3159*53ee8cc1Swenshuai.xi           ms_debug_err("qh %p\n=============\n", pQh);
3160*53ee8cc1Swenshuai.xi           ms_debug_err("[UM] status %d\n", pQh->qh_status);
3161*53ee8cc1Swenshuai.xi           ms_debug_err("[UM] hw ep %d\n", (pQh->hw_ep_state1 >> 8) & 0xf);
3162*53ee8cc1Swenshuai.xi           ms_debug_err("[UM] qtd_list %s\n", !ms_is_empty_list (&pQh->qtd_list) ? "there": "none");
3163*53ee8cc1Swenshuai.xi           ms_debug_err("[UM] refcnt %d\n", pQh->tRefCnt);
3164*53ee8cc1Swenshuai.xi           if (ms_is_empty_list (&pQh->qtd_list))
3165*53ee8cc1Swenshuai.xi             is_empty_qtd = 1;
3166*53ee8cc1Swenshuai.xi           pQh = pQh->qh_next.qh;
3167*53ee8cc1Swenshuai.xi         }
3168*53ee8cc1Swenshuai.xi         ms_debug_err("=============\n");
3169*53ee8cc1Swenshuai.xi #endif
3170*53ee8cc1Swenshuai.xi     }
3171*53ee8cc1Swenshuai.xi 
3172*53ee8cc1Swenshuai.xi     if (not_fix || is_empty_qtd)
3173*53ee8cc1Swenshuai.xi         return;
3174*53ee8cc1Swenshuai.xi 
3175*53ee8cc1Swenshuai.xi     u32Temp = hcd_reg_readl ((U32)&pEhci->op_regs->portsc [0]);
3176*53ee8cc1Swenshuai.xi     u32Temp = u32Temp & ~PORTSC_RWC_BITS;
3177*53ee8cc1Swenshuai.xi     hcd_reg_writel (u32Temp & ~PORTSC_PE, (U32)&pEhci->op_regs->portsc [0]);
3178*53ee8cc1Swenshuai.xi     //�˸m�Q�������ɭ� ����scheduler
3179*53ee8cc1Swenshuai.xi     hcd_reg_writel(hcd_reg_readl((U32)&pEhci->op_regs->usbcmd)&(~(USBCMD_ASE|USBCMD_PSE|USBCMD_IAAD)),(U32)&pEhci->op_regs->usbcmd);
3180*53ee8cc1Swenshuai.xi     /* recover periodic size setting at STR off/on  */
3181*53ee8cc1Swenshuai.xi     u32Temp = hcd_reg_readl((U32)&pEhci->op_regs->usbcmd);
3182*53ee8cc1Swenshuai.xi     u32Temp &= ~(3 << 2);
3183*53ee8cc1Swenshuai.xi     u32Temp |= (EHCI_PERIODIC_FLS << 2);
3184*53ee8cc1Swenshuai.xi     hcd_reg_writel(u32Temp,(U32)&pEhci->op_regs->usbcmd);
3185*53ee8cc1Swenshuai.xi 
3186*53ee8cc1Swenshuai.xi     if( pEhci->stAsync->qh_next.qh != 0 )
3187*53ee8cc1Swenshuai.xi     {
3188*53ee8cc1Swenshuai.xi         struct ehci_qh *pQh = pEhci->stAsync->qh_next.qh;
3189*53ee8cc1Swenshuai.xi 
3190*53ee8cc1Swenshuai.xi         do {
3191*53ee8cc1Swenshuai.xi           struct ehci_qh *qh_rm;
3192*53ee8cc1Swenshuai.xi 
3193*53ee8cc1Swenshuai.xi           qh_rm = pQh;
3194*53ee8cc1Swenshuai.xi           pQh = pQh->qh_next.qh;
3195*53ee8cc1Swenshuai.xi           qh_rm->qh_next.qh = NULL;
3196*53ee8cc1Swenshuai.xi           qh_rm->tRefCnt = 1; // forced to be 1
3197*53ee8cc1Swenshuai.xi           ms_qh_put(pEhci, qh_rm);
3198*53ee8cc1Swenshuai.xi         } while(pQh);
3199*53ee8cc1Swenshuai.xi 
3200*53ee8cc1Swenshuai.xi         /* re-init head QH */
3201*53ee8cc1Swenshuai.xi         pEhci->stAsync->qh_next.qh = NULL;
3202*53ee8cc1Swenshuai.xi         pEhci->stAsync->hw_next_qh = QH_NEXT (pEhci->stAsync->qh_dma_addr);
3203*53ee8cc1Swenshuai.xi         pEhci->stAsync->hw_ep_state1 = QH_H_BIT;
3204*53ee8cc1Swenshuai.xi         pEhci->stAsync->hw_token = QTD_STS_HALT;
3205*53ee8cc1Swenshuai.xi         pEhci->stAsync->hw_next_qtd = EHCI_LIST_END;
3206*53ee8cc1Swenshuai.xi         pEhci->stAsync->qh_status = QH_STS_LINKED;
3207*53ee8cc1Swenshuai.xi         pEhci->stAsync->hw_alt_next_qtd = (U32)(pEhci->stAsync->pDummyQtd->qtd_dma_addr);
3208*53ee8cc1Swenshuai.xi     }
3209*53ee8cc1Swenshuai.xi }
3210*53ee8cc1Swenshuai.xi 
3211*53ee8cc1Swenshuai.xi #ifdef USB_SYSTEM_STR_SUPPORT
ms_ehci_periodic_size_init(struct usb_hcd * hcd)3212*53ee8cc1Swenshuai.xi void ms_ehci_periodic_size_init (struct usb_hcd *hcd)
3213*53ee8cc1Swenshuai.xi {
3214*53ee8cc1Swenshuai.xi     struct ehci_hcd  *pEhci = hcd_to_ehci (hcd);
3215*53ee8cc1Swenshuai.xi     U32    u32Temp;
3216*53ee8cc1Swenshuai.xi 
3217*53ee8cc1Swenshuai.xi     /* recover periodic size setting at STR off/on  */
3218*53ee8cc1Swenshuai.xi     u32Temp = hcd_reg_readl((U32)&pEhci->op_regs->usbcmd);
3219*53ee8cc1Swenshuai.xi     u32Temp &= ~(3 << 2);
3220*53ee8cc1Swenshuai.xi     u32Temp |= (EHCI_PERIODIC_FLS << 2);
3221*53ee8cc1Swenshuai.xi     hcd_reg_writel(u32Temp,(U32)&pEhci->op_regs->usbcmd);
3222*53ee8cc1Swenshuai.xi }
3223*53ee8cc1Swenshuai.xi #endif
3224*53ee8cc1Swenshuai.xi 
3225*53ee8cc1Swenshuai.xi #if USB_IF_EHSET_SUPPORT // Embedded host electrical test procedure
3226*53ee8cc1Swenshuai.xi struct list_head *
ms_qh_urb_transaction_EHSET(struct ehci_hcd * ehci,struct urb * urb,struct list_head * head,int iFlags,int iStage)3227*53ee8cc1Swenshuai.xi ms_qh_urb_transaction_EHSET (
3228*53ee8cc1Swenshuai.xi   struct ehci_hcd    *ehci,
3229*53ee8cc1Swenshuai.xi   struct urb    *urb,
3230*53ee8cc1Swenshuai.xi   struct list_head  *head,
3231*53ee8cc1Swenshuai.xi   int      iFlags,
3232*53ee8cc1Swenshuai.xi   int      iStage
3233*53ee8cc1Swenshuai.xi )
3234*53ee8cc1Swenshuai.xi {
3235*53ee8cc1Swenshuai.xi     struct ehci_qtd    *pQtd, *pQtdPrev;
3236*53ee8cc1Swenshuai.xi     dma_addr_t    tBufAddr;
3237*53ee8cc1Swenshuai.xi     int      iLen, iMaxpkt;
3238*53ee8cc1Swenshuai.xi     int      iIsInput;
3239*53ee8cc1Swenshuai.xi     U32      u32Token;
3240*53ee8cc1Swenshuai.xi 
3241*53ee8cc1Swenshuai.xi     ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
3242*53ee8cc1Swenshuai.xi     pQtd = ms_ehci_qtd_alloc (ehci, iFlags);
3243*53ee8cc1Swenshuai.xi     if (!pQtd)
3244*53ee8cc1Swenshuai.xi     {
3245*53ee8cc1Swenshuai.xi         ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
3246*53ee8cc1Swenshuai.xi         return 0;
3247*53ee8cc1Swenshuai.xi     }
3248*53ee8cc1Swenshuai.xi     ms_insert_list_before (&pQtd->qtd_list, head);
3249*53ee8cc1Swenshuai.xi     pQtd->urb = urb;
3250*53ee8cc1Swenshuai.xi 
3251*53ee8cc1Swenshuai.xi     u32Token = QTD_STS_ACT;
3252*53ee8cc1Swenshuai.xi     u32Token |= (MAX_CERR_CNT << 10);
3253*53ee8cc1Swenshuai.xi 
3254*53ee8cc1Swenshuai.xi     iLen = urb->u32TransferBufferLength;
3255*53ee8cc1Swenshuai.xi     iIsInput = usb_pipein (urb->u32Pipe);
3256*53ee8cc1Swenshuai.xi     if (!iStage)
3257*53ee8cc1Swenshuai.xi     {
3258*53ee8cc1Swenshuai.xi         if (usb_pipecontrol (urb->u32Pipe))
3259*53ee8cc1Swenshuai.xi         {
3260*53ee8cc1Swenshuai.xi           ms_qtd_pack (pQtd, urb->tSetupDma, sizeof (struct usb_ctrlrequest),
3261*53ee8cc1Swenshuai.xi           u32Token | (2 /* "setup" */ << 8), 8);
3262*53ee8cc1Swenshuai.xi           pQtd->hw_alt_next_qtd = EHCI_LIST_END; // EHSET
3263*53ee8cc1Swenshuai.xi           u32Token ^= QTD_TOGGLE;
3264*53ee8cc1Swenshuai.xi         }
3265*53ee8cc1Swenshuai.xi 
3266*53ee8cc1Swenshuai.xi         if (!(urb->u32TransferFlags & MS_FLAG_URB_NO_INTERRUPT))
3267*53ee8cc1Swenshuai.xi           pQtd->hw_token |= QTD_IOC; // EHSET
3268*53ee8cc1Swenshuai.xi         return head;
3269*53ee8cc1Swenshuai.xi     }
3270*53ee8cc1Swenshuai.xi     else
3271*53ee8cc1Swenshuai.xi         u32Token ^= QTD_TOGGLE;
3272*53ee8cc1Swenshuai.xi 
3273*53ee8cc1Swenshuai.xi   tBufAddr = (iLen > 0) ? urb->tTransferDma : 0;
3274*53ee8cc1Swenshuai.xi 
3275*53ee8cc1Swenshuai.xi   if (!tBufAddr || iIsInput)
3276*53ee8cc1Swenshuai.xi     u32Token |= (1 /* "in" */ << 8);
3277*53ee8cc1Swenshuai.xi   if (usb_pipebulk(urb->u32Pipe))
3278*53ee8cc1Swenshuai.xi   {
3279*53ee8cc1Swenshuai.xi     switch (urb->dev->eSpeed)
3280*53ee8cc1Swenshuai.xi     {
3281*53ee8cc1Swenshuai.xi       case USB_FULL_SPEED:
3282*53ee8cc1Swenshuai.xi         iMaxpkt = max_packet(usb_maxpacket(urb->dev, urb->u32Pipe, !iIsInput));
3283*53ee8cc1Swenshuai.xi         break;
3284*53ee8cc1Swenshuai.xi       case USB_HIGH_SPEED:
3285*53ee8cc1Swenshuai.xi       default:
3286*53ee8cc1Swenshuai.xi         iMaxpkt = 512;
3287*53ee8cc1Swenshuai.xi         break;
3288*53ee8cc1Swenshuai.xi     }
3289*53ee8cc1Swenshuai.xi   }
3290*53ee8cc1Swenshuai.xi   else
3291*53ee8cc1Swenshuai.xi   {
3292*53ee8cc1Swenshuai.xi     iMaxpkt = max_packet(usb_maxpacket(urb->dev, urb->u32Pipe, !iIsInput));
3293*53ee8cc1Swenshuai.xi   }
3294*53ee8cc1Swenshuai.xi 
3295*53ee8cc1Swenshuai.xi   for (;;)
3296*53ee8cc1Swenshuai.xi   {
3297*53ee8cc1Swenshuai.xi     int iThisQtdLen;
3298*53ee8cc1Swenshuai.xi 
3299*53ee8cc1Swenshuai.xi     iThisQtdLen = ms_qtd_pack (pQtd, tBufAddr, iLen, u32Token, iMaxpkt);
3300*53ee8cc1Swenshuai.xi     iLen -= iThisQtdLen;
3301*53ee8cc1Swenshuai.xi     tBufAddr += iThisQtdLen;
3302*53ee8cc1Swenshuai.xi     if (iIsInput)
3303*53ee8cc1Swenshuai.xi       pQtd->hw_alt_next_qtd = ehci->stAsync->hw_alt_next_qtd;
3304*53ee8cc1Swenshuai.xi 
3305*53ee8cc1Swenshuai.xi     if ((iMaxpkt & (iThisQtdLen + (iMaxpkt - 1))) == 0)
3306*53ee8cc1Swenshuai.xi       u32Token ^= QTD_TOGGLE;
3307*53ee8cc1Swenshuai.xi 
3308*53ee8cc1Swenshuai.xi     if (iLen <= 0)
3309*53ee8cc1Swenshuai.xi       break;
3310*53ee8cc1Swenshuai.xi 
3311*53ee8cc1Swenshuai.xi     pQtdPrev = pQtd;
3312*53ee8cc1Swenshuai.xi     pQtd = ms_ehci_qtd_alloc (ehci, iFlags);
3313*53ee8cc1Swenshuai.xi     if (!pQtd)
3314*53ee8cc1Swenshuai.xi       goto cleanup;
3315*53ee8cc1Swenshuai.xi     pQtd->urb = urb;
3316*53ee8cc1Swenshuai.xi     pQtdPrev->hw_next_qtd = (U32)(pQtd->qtd_dma_addr);
3317*53ee8cc1Swenshuai.xi     ms_insert_list_before (&pQtd->qtd_list, head);
3318*53ee8cc1Swenshuai.xi   }
3319*53ee8cc1Swenshuai.xi 
3320*53ee8cc1Swenshuai.xi   if ((urb->u32TransferFlags & MS_FLAG_URB_SHORT_NOT_OK) == 0
3321*53ee8cc1Swenshuai.xi         || usb_pipecontrol (urb->u32Pipe))
3322*53ee8cc1Swenshuai.xi     pQtd->hw_alt_next_qtd = EHCI_LIST_END;
3323*53ee8cc1Swenshuai.xi 
3324*53ee8cc1Swenshuai.xi   if (tBufAddr != 0)
3325*53ee8cc1Swenshuai.xi   {
3326*53ee8cc1Swenshuai.xi     int  iOneMore = 0;
3327*53ee8cc1Swenshuai.xi 
3328*53ee8cc1Swenshuai.xi     if (usb_pipecontrol (urb->u32Pipe))
3329*53ee8cc1Swenshuai.xi     {
3330*53ee8cc1Swenshuai.xi       iOneMore = 1;
3331*53ee8cc1Swenshuai.xi       u32Token ^= 0x0100;  /* "in" <--> "out"  */
3332*53ee8cc1Swenshuai.xi       u32Token |= QTD_TOGGLE;  /* force DATA1 */
3333*53ee8cc1Swenshuai.xi     }
3334*53ee8cc1Swenshuai.xi     else if (usb_pipebulk (urb->u32Pipe)
3335*53ee8cc1Swenshuai.xi         && (urb->u32TransferFlags & MS_FLAG_URB_ZERO_PACKET)
3336*53ee8cc1Swenshuai.xi         && !(urb->u32TransferBufferLength % iMaxpkt)) {
3337*53ee8cc1Swenshuai.xi       iOneMore = 1;
3338*53ee8cc1Swenshuai.xi     }
3339*53ee8cc1Swenshuai.xi     if (iOneMore)
3340*53ee8cc1Swenshuai.xi     {
3341*53ee8cc1Swenshuai.xi       pQtdPrev = pQtd;
3342*53ee8cc1Swenshuai.xi       pQtd = ms_ehci_qtd_alloc (ehci, iFlags);
3343*53ee8cc1Swenshuai.xi       if (!pQtd)
3344*53ee8cc1Swenshuai.xi         goto cleanup;
3345*53ee8cc1Swenshuai.xi       pQtd->urb = urb;
3346*53ee8cc1Swenshuai.xi       pQtdPrev->hw_next_qtd = (U32)(pQtd->qtd_dma_addr);
3347*53ee8cc1Swenshuai.xi       ms_insert_list_before (&pQtd->qtd_list, head);
3348*53ee8cc1Swenshuai.xi 
3349*53ee8cc1Swenshuai.xi       ms_qtd_pack (pQtd, 0, 0, u32Token, 0);
3350*53ee8cc1Swenshuai.xi     }
3351*53ee8cc1Swenshuai.xi   }
3352*53ee8cc1Swenshuai.xi 
3353*53ee8cc1Swenshuai.xi   if (!(urb->u32TransferFlags & MS_FLAG_URB_NO_INTERRUPT))
3354*53ee8cc1Swenshuai.xi     pQtd->hw_token |= QTD_IOC;
3355*53ee8cc1Swenshuai.xi 
3356*53ee8cc1Swenshuai.xi   ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
3357*53ee8cc1Swenshuai.xi   return head;
3358*53ee8cc1Swenshuai.xi 
3359*53ee8cc1Swenshuai.xi cleanup:
3360*53ee8cc1Swenshuai.xi 
3361*53ee8cc1Swenshuai.xi   ms_qtd_register_free (ehci, head);
3362*53ee8cc1Swenshuai.xi   ms_debug_func("--[%s] line:[%d]\n", __FUNCTION__, __LINE__);
3363*53ee8cc1Swenshuai.xi   return 0;
3364*53ee8cc1Swenshuai.xi }
3365*53ee8cc1Swenshuai.xi 
ms_submit_async_EHSET(struct ehci_hcd * ehci,struct urb * urb,struct list_head * qtd_list,int mem_flags)3366*53ee8cc1Swenshuai.xi inline int ms_submit_async_EHSET (
3367*53ee8cc1Swenshuai.xi   struct ehci_hcd    *ehci,
3368*53ee8cc1Swenshuai.xi   struct urb    *urb,
3369*53ee8cc1Swenshuai.xi   struct list_head  *qtd_list,
3370*53ee8cc1Swenshuai.xi   int      mem_flags
3371*53ee8cc1Swenshuai.xi ) {
3372*53ee8cc1Swenshuai.xi     ms_debug_func("++[%s] line:[%d]\n", __FUNCTION__, __LINE__);
3373*53ee8cc1Swenshuai.xi     return ms_submit_async(ehci, urb, qtd_list);
3374*53ee8cc1Swenshuai.xi }
3375*53ee8cc1Swenshuai.xi #endif
3376