xref: /utopia/UTPA2-700.0.x/modules/usb/drv/usb_ecos/newhost/drvHub.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 //#include <MsCommon.h> // NUSED
79*53ee8cc1Swenshuai.xi 
80*53ee8cc1Swenshuai.xi #include  "include/drvConfig.h"
81*53ee8cc1Swenshuai.xi //#include  "include/drvCompiler.h" // NUSED
82*53ee8cc1Swenshuai.xi //#include  "include/drvTypes.h" // NUSED
83*53ee8cc1Swenshuai.xi #include  "include/drvErrno.h"
84*53ee8cc1Swenshuai.xi //#include  "include/drvPorts.h" // NUSED
85*53ee8cc1Swenshuai.xi //#include  "include/drvPCIMEM.h" // NUSED
86*53ee8cc1Swenshuai.xi //#include  "include/drvTimer.h" // NUSED
87*53ee8cc1Swenshuai.xi //#include  "include/drvList.h" // NUSED
88*53ee8cc1Swenshuai.xi #include  "include/drvKernel.h"
89*53ee8cc1Swenshuai.xi //#include  "include/drvBitops.h" // NUSED
90*53ee8cc1Swenshuai.xi //#include "include/drvCPE_AMBA.h" // NUSED
91*53ee8cc1Swenshuai.xi 
92*53ee8cc1Swenshuai.xi // USB related header files
93*53ee8cc1Swenshuai.xi //#include "include/drvUSBHost.h" // NUSED
94*53ee8cc1Swenshuai.xi #include "drvUSBCore.h"
95*53ee8cc1Swenshuai.xi //#include "drvUsbd.h" // NUSED
96*53ee8cc1Swenshuai.xi //#include "drvHub.h" // NUSED
97*53ee8cc1Swenshuai.xi #include "drvEHCI.h"
98*53ee8cc1Swenshuai.xi #include "drvUSBHwCtl.h"
99*53ee8cc1Swenshuai.xi /* applying drvUsbHostConfig.h (inside drvUSBHwCtl.h) */
100*53ee8cc1Swenshuai.xi 
101*53ee8cc1Swenshuai.xi //#define DBG_DBG
102*53ee8cc1Swenshuai.xi #ifdef DBG_DBG
103*53ee8cc1Swenshuai.xi #undef ms_usbhost_debug
104*53ee8cc1Swenshuai.xi #define ms_usbhost_debug(fmt, arg...)    \
105*53ee8cc1Swenshuai.xi         do {diag_printf(fmt, ##arg);} while(0)
106*53ee8cc1Swenshuai.xi #endif
107*53ee8cc1Swenshuai.xi 
108*53ee8cc1Swenshuai.xi //struct list_head hub_list =            { &(hub_list), &(hub_list) };
109*53ee8cc1Swenshuai.xi 
110*53ee8cc1Swenshuai.xi /**
111*53ee8cc1Swenshuai.xi      * @brief               Interpreting post speed by text
112*53ee8cc1Swenshuai.xi      *
113*53ee8cc1Swenshuai.xi      * @param           int portstatus
114*53ee8cc1Swenshuai.xi      *
115*53ee8cc1Swenshuai.xi      * @return          Speed description
116*53ee8cc1Swenshuai.xi      */
ms_portspeed(int portstatus)117*53ee8cc1Swenshuai.xi static __inline__ char *ms_portspeed (int portstatus)
118*53ee8cc1Swenshuai.xi {
119*53ee8cc1Swenshuai.xi     if (portstatus & USB_PORT_STAT_HIGH_SPEED)
120*53ee8cc1Swenshuai.xi         return "480 Mb/s";
121*53ee8cc1Swenshuai.xi     else if (portstatus & USB_PORT_STAT_LOW_SPEED)
122*53ee8cc1Swenshuai.xi         return "1.5 Mb/s";
123*53ee8cc1Swenshuai.xi     else
124*53ee8cc1Swenshuai.xi         return "12 Mb/s";
125*53ee8cc1Swenshuai.xi }
126*53ee8cc1Swenshuai.xi 
127*53ee8cc1Swenshuai.xi /**
128*53ee8cc1Swenshuai.xi      * @brief               retrieving  generic device pointer from usb device
129*53ee8cc1Swenshuai.xi      *
130*53ee8cc1Swenshuai.xi      * @param           struct usb_device *ms_dev
131*53ee8cc1Swenshuai.xi      *
132*53ee8cc1Swenshuai.xi      * @return          generic device pointer
133*53ee8cc1Swenshuai.xi      */
ms_hubdev(struct usb_device * ms_dev)134*53ee8cc1Swenshuai.xi static __inline__ struct device_s *ms_hubdev (struct usb_device *ms_dev)
135*53ee8cc1Swenshuai.xi {
136*53ee8cc1Swenshuai.xi     return &ms_dev->actconfig->interface[0]->dev;
137*53ee8cc1Swenshuai.xi }
138*53ee8cc1Swenshuai.xi 
139*53ee8cc1Swenshuai.xi /**
140*53ee8cc1Swenshuai.xi      * @brief               hub driver complete function
141*53ee8cc1Swenshuai.xi      *
142*53ee8cc1Swenshuai.xi      * @param           struct urb *urb
143*53ee8cc1Swenshuai.xi      * @param           struct stPtRegs *regs
144*53ee8cc1Swenshuai.xi      *
145*53ee8cc1Swenshuai.xi      * @return          none
146*53ee8cc1Swenshuai.xi      */
ms_hub_irq(struct urb * urb,struct stPtRegs * regs)147*53ee8cc1Swenshuai.xi static void ms_hub_irq(struct urb *urb, struct stPtRegs *regs)
148*53ee8cc1Swenshuai.xi {
149*53ee8cc1Swenshuai.xi     struct usb_hub *pHub = (struct usb_hub *)urb->pContext;
150*53ee8cc1Swenshuai.xi     U32 flags;
151*53ee8cc1Swenshuai.xi     int status;
152*53ee8cc1Swenshuai.xi     int ms_rtval = ENOENT;
153*53ee8cc1Swenshuai.xi     struct usb_hcd    *hcd = (struct usb_hcd*) urb->dev->bus->hcpriv;
154*53ee8cc1Swenshuai.xi 
155*53ee8cc1Swenshuai.xi     switch (urb->s32Status)
156*53ee8cc1Swenshuai.xi     {
157*53ee8cc1Swenshuai.xi         case -ENOENT:
158*53ee8cc1Swenshuai.xi         case -ECONNRESET:
159*53ee8cc1Swenshuai.xi         case -ESHUTDOWN:
160*53ee8cc1Swenshuai.xi             ms_usbhost_debug("<%s> urb->status : %d \n", __FUNCTION__, (int)urb->s32Status);
161*53ee8cc1Swenshuai.xi             return;
162*53ee8cc1Swenshuai.xi 
163*53ee8cc1Swenshuai.xi         default:
164*53ee8cc1Swenshuai.xi             ms_usbhost_debug ("transfer --> %d\n", urb->s32Status);
165*53ee8cc1Swenshuai.xi             ms_rtval = urb->s32Status;
166*53ee8cc1Swenshuai.xi             if ((++pHub->nerrors < 10) || pHub->error)
167*53ee8cc1Swenshuai.xi                 goto resubmit;
168*53ee8cc1Swenshuai.xi             pHub->error = urb->s32Status;
169*53ee8cc1Swenshuai.xi 
170*53ee8cc1Swenshuai.xi         case 0:
171*53ee8cc1Swenshuai.xi             break;
172*53ee8cc1Swenshuai.xi     }
173*53ee8cc1Swenshuai.xi 
174*53ee8cc1Swenshuai.xi     pHub->nerrors = 0;
175*53ee8cc1Swenshuai.xi 
176*53ee8cc1Swenshuai.xi     osapi_spin_lock_irqsave(&hub_event_lock, flags);
177*53ee8cc1Swenshuai.xi     if (!pHub->disconnected && ms_is_empty_list(&pHub->event_list))
178*53ee8cc1Swenshuai.xi     {
179*53ee8cc1Swenshuai.xi         //list_add(&pHub->event_list, &hub_event_list);
180*53ee8cc1Swenshuai.xi         ms_insert_list_after(&pHub->event_list, hcd->phub_event); // new, link to the right hcd
181*53ee8cc1Swenshuai.xi 
182*53ee8cc1Swenshuai.xi         ms_usbhost_debug("%s:%s >>> Add HUB EVENT!\n", hcd->product_desc, interface_to_usbdev(pHub->intf)->devpath);
183*53ee8cc1Swenshuai.xi     }
184*53ee8cc1Swenshuai.xi     osapi_spin_unlock_irqrestore(&hub_event_lock, flags);
185*53ee8cc1Swenshuai.xi 
186*53ee8cc1Swenshuai.xi resubmit:
187*53ee8cc1Swenshuai.xi     if ((status = ms_usb_submit_urb (pHub->urb, GFP_ATOMIC)) != 0
188*53ee8cc1Swenshuai.xi         /* ENODEV means we raced disconnect() */
189*53ee8cc1Swenshuai.xi         && status != -ENODEV)
190*53ee8cc1Swenshuai.xi     {
191*53ee8cc1Swenshuai.xi         diag_printf ("previous urb status is %d, resubmit --> %d\n", ms_rtval, status);
192*53ee8cc1Swenshuai.xi         diag_printf ("hcd->state=%d\n",hcd->state);
193*53ee8cc1Swenshuai.xi     }
194*53ee8cc1Swenshuai.xi }
195*53ee8cc1Swenshuai.xi 
196*53ee8cc1Swenshuai.xi /**
197*53ee8cc1Swenshuai.xi      * @brief               hub power on function
198*53ee8cc1Swenshuai.xi      *
199*53ee8cc1Swenshuai.xi      * @param           struct usb_hub *hub
200*53ee8cc1Swenshuai.xi      *
201*53ee8cc1Swenshuai.xi      * @return          none
202*53ee8cc1Swenshuai.xi      */
ms_hub_power_on(struct usb_hub * hub)203*53ee8cc1Swenshuai.xi void ms_hub_power_on(struct usb_hub *hub)
204*53ee8cc1Swenshuai.xi {
205*53ee8cc1Swenshuai.xi     struct usb_device *ms_dev;
206*53ee8cc1Swenshuai.xi     int i;
207*53ee8cc1Swenshuai.xi 
208*53ee8cc1Swenshuai.xi     ms_usbhost_debug("enabling power on all ports, delay %d\n", hub->descriptor.bPwrOn2PwrGood * 2);
209*53ee8cc1Swenshuai.xi     ms_dev = interface_to_usbdev(hub->intf);
210*53ee8cc1Swenshuai.xi     for (i = 0; i < hub->descriptor.bNbrPorts; i++)
211*53ee8cc1Swenshuai.xi         // (USB_PORT_FEAT_POWER)
212*53ee8cc1Swenshuai.xi         ms_usb_control_cmd(ms_dev, usb_sndctrlpipe(ms_dev, 0),
213*53ee8cc1Swenshuai.xi             USB_REQ_SET_FEATURE, USB_RT_PORT, USB_PORT_FEAT_POWER, i + 1, NULL, 0, HZ);
214*53ee8cc1Swenshuai.xi 
215*53ee8cc1Swenshuai.xi     wait_ms(hub->descriptor.bPwrOn2PwrGood * 2);
216*53ee8cc1Swenshuai.xi }
217*53ee8cc1Swenshuai.xi 
218*53ee8cc1Swenshuai.xi /**
219*53ee8cc1Swenshuai.xi      * @brief               retrieving hub current condition
220*53ee8cc1Swenshuai.xi      *
221*53ee8cc1Swenshuai.xi      * @param           struct usb_hub *hub
222*53ee8cc1Swenshuai.xi      * @param           U16 *status_r
223*53ee8cc1Swenshuai.xi      * @param           U16 *change_r
224*53ee8cc1Swenshuai.xi      *
225*53ee8cc1Swenshuai.xi      * @return          error code
226*53ee8cc1Swenshuai.xi      */
ms_hub_hub_status(struct usb_hub * hub,U16 * status_r,U16 * change_r)227*53ee8cc1Swenshuai.xi int ms_hub_hub_status(struct usb_hub *hub, U16 *status_r, U16 *change_r)
228*53ee8cc1Swenshuai.xi {
229*53ee8cc1Swenshuai.xi     struct usb_device *ms_dev = interface_to_usbdev (hub->intf);
230*53ee8cc1Swenshuai.xi     S32 s32Ret;
231*53ee8cc1Swenshuai.xi 
232*53ee8cc1Swenshuai.xi     // ms_get_hub_status
233*53ee8cc1Swenshuai.xi     s32Ret = ms_usb_control_cmd(ms_dev, usb_rcvctrlpipe(ms_dev, 0),
234*53ee8cc1Swenshuai.xi         USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_HUB, 0, 0,
235*53ee8cc1Swenshuai.xi         &hub->status.hub, sizeof(hub->status.hub), HZ * USB_CTRL_GET_TIMEOUT);
236*53ee8cc1Swenshuai.xi     if (s32Ret < 0)
237*53ee8cc1Swenshuai.xi     {
238*53ee8cc1Swenshuai.xi         ms_usbhost_err ("<%s> failed (err = %d)\n", __FUNCTION__, (int)s32Ret);
239*53ee8cc1Swenshuai.xi     }
240*53ee8cc1Swenshuai.xi     else
241*53ee8cc1Swenshuai.xi     {
242*53ee8cc1Swenshuai.xi         *status_r = hub->status.hub.wHubStatus;
243*53ee8cc1Swenshuai.xi         *change_r = hub->status.hub.wHubChange;
244*53ee8cc1Swenshuai.xi         s32Ret = 0;
245*53ee8cc1Swenshuai.xi     }
246*53ee8cc1Swenshuai.xi     return s32Ret;
247*53ee8cc1Swenshuai.xi }
248*53ee8cc1Swenshuai.xi 
249*53ee8cc1Swenshuai.xi /**
250*53ee8cc1Swenshuai.xi      * @brief               hub configure by hub descriptor
251*53ee8cc1Swenshuai.xi      *
252*53ee8cc1Swenshuai.xi      * @param           struct usb_hub *hub
253*53ee8cc1Swenshuai.xi      * @param           struct usb_endpoint_descriptor *endpoint
254*53ee8cc1Swenshuai.xi      *
255*53ee8cc1Swenshuai.xi      * @return          error code
256*53ee8cc1Swenshuai.xi      */
ms_hub_configure(struct usb_hub * hub,struct usb_endpoint_descriptor * endpoint)257*53ee8cc1Swenshuai.xi static int ms_hub_configure(struct usb_hub *hub,
258*53ee8cc1Swenshuai.xi   struct usb_endpoint_descriptor *endpoint)
259*53ee8cc1Swenshuai.xi {
260*53ee8cc1Swenshuai.xi     struct usb_device *ms_dev = interface_to_usbdev (hub->intf);
261*53ee8cc1Swenshuai.xi     //struct device_s *hub_dev;
262*53ee8cc1Swenshuai.xi     U16 hubstatus, hubchange;
263*53ee8cc1Swenshuai.xi     U32 pipe;
264*53ee8cc1Swenshuai.xi     S32 maxp, s32Ret;
265*53ee8cc1Swenshuai.xi     char *message;
266*53ee8cc1Swenshuai.xi 
267*53ee8cc1Swenshuai.xi     hub->buffer = (char (*)[3]) ms_usb_buffer_alloc(ms_dev, sizeof(*hub->buffer), GFP_KERNEL,
268*53ee8cc1Swenshuai.xi         &hub->buffer_dma);
269*53ee8cc1Swenshuai.xi     if (!hub->buffer)
270*53ee8cc1Swenshuai.xi     {
271*53ee8cc1Swenshuai.xi         message = "can't allocate hub irq buffer";
272*53ee8cc1Swenshuai.xi         s32Ret = -ENOMEM;
273*53ee8cc1Swenshuai.xi         goto fail;
274*53ee8cc1Swenshuai.xi     }
275*53ee8cc1Swenshuai.xi 
276*53ee8cc1Swenshuai.xi     // ms_get_hub_descriptor
277*53ee8cc1Swenshuai.xi     s32Ret = ms_usb_control_cmd(ms_dev, usb_rcvctrlpipe(ms_dev, 0),
278*53ee8cc1Swenshuai.xi         USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB,
279*53ee8cc1Swenshuai.xi         USB_DT_HUB << 8, 0, &hub->descriptor, sizeof(hub->descriptor), HZ * USB_CTRL_GET_TIMEOUT);
280*53ee8cc1Swenshuai.xi     if (s32Ret < 0)
281*53ee8cc1Swenshuai.xi     {
282*53ee8cc1Swenshuai.xi         message = "can't read hub descriptor";
283*53ee8cc1Swenshuai.xi         goto fail;
284*53ee8cc1Swenshuai.xi     }
285*53ee8cc1Swenshuai.xi     else if (hub->descriptor.bNbrPorts > USB_MAXCHILDREN)
286*53ee8cc1Swenshuai.xi     {
287*53ee8cc1Swenshuai.xi         message = "hub has too many ports!";
288*53ee8cc1Swenshuai.xi         s32Ret = -ENODEV;
289*53ee8cc1Swenshuai.xi         goto fail;
290*53ee8cc1Swenshuai.xi     }
291*53ee8cc1Swenshuai.xi 
292*53ee8cc1Swenshuai.xi     //hub_dev = ms_hubdev(ms_dev);
293*53ee8cc1Swenshuai.xi     ms_dev->u32MaxChild = hub->descriptor.bNbrPorts;
294*53ee8cc1Swenshuai.xi     ms_usbhost_msg ("%d port%s detected\n", ms_dev->u32MaxChild, (ms_dev->u32MaxChild == 1) ? "" : "s");
295*53ee8cc1Swenshuai.xi 
296*53ee8cc1Swenshuai.xi     hub->descriptor.wHubCharacteristics = hub->descriptor.wHubCharacteristics;
297*53ee8cc1Swenshuai.xi 
298*53ee8cc1Swenshuai.xi     if (hub->descriptor.wHubCharacteristics & HUB_CHAR_COMPOUND)
299*53ee8cc1Swenshuai.xi     {
300*53ee8cc1Swenshuai.xi         int  i;
301*53ee8cc1Swenshuai.xi         char  portstr [USB_MAXCHILDREN + 1];
302*53ee8cc1Swenshuai.xi 
303*53ee8cc1Swenshuai.xi         for (i = 0; i < ms_dev->u32MaxChild; i++)
304*53ee8cc1Swenshuai.xi           portstr[i] = hub->descriptor.DeviceRemovable[((i + 1) / 8)] & (1 << ((i + 1) % 8))
305*53ee8cc1Swenshuai.xi             ? 'F' : 'R';
306*53ee8cc1Swenshuai.xi         portstr[ms_dev->u32MaxChild] = 0;
307*53ee8cc1Swenshuai.xi         ms_usbhost_msg("compound device; port removable status: %s\n", portstr);
308*53ee8cc1Swenshuai.xi     }
309*53ee8cc1Swenshuai.xi     else
310*53ee8cc1Swenshuai.xi         ms_usbhost_debug("Standalone hub\n");
311*53ee8cc1Swenshuai.xi 
312*53ee8cc1Swenshuai.xi     switch (hub->descriptor.wHubCharacteristics & HUB_CHAR_LPSM)
313*53ee8cc1Swenshuai.xi     {
314*53ee8cc1Swenshuai.xi         case 0x00:
315*53ee8cc1Swenshuai.xi             ms_usbhost_debug("Ganged power switching\n");
316*53ee8cc1Swenshuai.xi             break;
317*53ee8cc1Swenshuai.xi         case 0x01:
318*53ee8cc1Swenshuai.xi             ms_usbhost_debug("Individual port power switching\n");
319*53ee8cc1Swenshuai.xi             break;
320*53ee8cc1Swenshuai.xi         case 0x02:
321*53ee8cc1Swenshuai.xi         case 0x03:
322*53ee8cc1Swenshuai.xi             ms_usbhost_debug("Unknown reserved power switching mode\n");
323*53ee8cc1Swenshuai.xi             break;
324*53ee8cc1Swenshuai.xi     }
325*53ee8cc1Swenshuai.xi 
326*53ee8cc1Swenshuai.xi     switch (hub->descriptor.wHubCharacteristics & HUB_CHAR_OCPM)
327*53ee8cc1Swenshuai.xi     {
328*53ee8cc1Swenshuai.xi         case 0x00:
329*53ee8cc1Swenshuai.xi           ms_usbhost_debug("Global over-current protection\n");
330*53ee8cc1Swenshuai.xi           break;
331*53ee8cc1Swenshuai.xi         case 0x08:
332*53ee8cc1Swenshuai.xi           ms_usbhost_debug("Individual port over-current protection\n");
333*53ee8cc1Swenshuai.xi           break;
334*53ee8cc1Swenshuai.xi         case 0x10:
335*53ee8cc1Swenshuai.xi         case 0x18:
336*53ee8cc1Swenshuai.xi           ms_usbhost_debug("No over-current protection\n");
337*53ee8cc1Swenshuai.xi           break;
338*53ee8cc1Swenshuai.xi     }
339*53ee8cc1Swenshuai.xi 
340*53ee8cc1Swenshuai.xi     osapi_spin_lock_init (&hub->tt.lock);
341*53ee8cc1Swenshuai.xi     ms_list_init (&hub->tt.clear_list);
342*53ee8cc1Swenshuai.xi     //INIT_WORK (&hub->tt.kevent, hub_tt_kevent, hub);
343*53ee8cc1Swenshuai.xi     switch (ms_dev->descriptor.bDeviceProtocol)
344*53ee8cc1Swenshuai.xi     {
345*53ee8cc1Swenshuai.xi         case 0:
346*53ee8cc1Swenshuai.xi           break;
347*53ee8cc1Swenshuai.xi         case 1:
348*53ee8cc1Swenshuai.xi           ms_usbhost_debug("Single TT\n");
349*53ee8cc1Swenshuai.xi           hub->tt.hub = ms_dev;
350*53ee8cc1Swenshuai.xi           break;
351*53ee8cc1Swenshuai.xi         case 2:
352*53ee8cc1Swenshuai.xi           ms_usbhost_debug("TT per port\n");
353*53ee8cc1Swenshuai.xi           hub->tt.hub = ms_dev;
354*53ee8cc1Swenshuai.xi           hub->tt.multi = 1;
355*53ee8cc1Swenshuai.xi           break;
356*53ee8cc1Swenshuai.xi         default:
357*53ee8cc1Swenshuai.xi           ms_usbhost_err("Unrecognized hub protocol %d\n", ms_dev->descriptor.bDeviceProtocol);
358*53ee8cc1Swenshuai.xi           break;
359*53ee8cc1Swenshuai.xi     }
360*53ee8cc1Swenshuai.xi 
361*53ee8cc1Swenshuai.xi     switch (hub->descriptor.wHubCharacteristics & HUB_CHAR_TTTT)
362*53ee8cc1Swenshuai.xi     {
363*53ee8cc1Swenshuai.xi         case 0x00:
364*53ee8cc1Swenshuai.xi             if (ms_dev->descriptor.bDeviceProtocol != 0)
365*53ee8cc1Swenshuai.xi             {
366*53ee8cc1Swenshuai.xi                 hub->tt.think_time = 666;
367*53ee8cc1Swenshuai.xi                 ms_usbhost_debug("TT requires at most 8 FS bit times\n");
368*53ee8cc1Swenshuai.xi             }
369*53ee8cc1Swenshuai.xi             break;
370*53ee8cc1Swenshuai.xi         case 0x20:
371*53ee8cc1Swenshuai.xi             hub->tt.think_time = 666 * 2;
372*53ee8cc1Swenshuai.xi             ms_usbhost_debug("TT requires at most 16 FS bit times\n");
373*53ee8cc1Swenshuai.xi             break;
374*53ee8cc1Swenshuai.xi         case 0x40:
375*53ee8cc1Swenshuai.xi             hub->tt.think_time = 666 * 3;
376*53ee8cc1Swenshuai.xi             ms_usbhost_debug("TT requires at most 24 FS bit times\n");
377*53ee8cc1Swenshuai.xi             break;
378*53ee8cc1Swenshuai.xi         case 0x60:
379*53ee8cc1Swenshuai.xi             hub->tt.think_time = 666 * 4;
380*53ee8cc1Swenshuai.xi             ms_usbhost_debug("TT requires at most 32 FS bit times\n");
381*53ee8cc1Swenshuai.xi             break;
382*53ee8cc1Swenshuai.xi     }
383*53ee8cc1Swenshuai.xi 
384*53ee8cc1Swenshuai.xi     ms_usbhost_debug("Port LEDs are %s supported\n",(hub->descriptor.wHubCharacteristics & HUB_CHAR_PORTIND)? "" : "not");
385*53ee8cc1Swenshuai.xi     ms_usbhost_debug("Power on to power good last time: %dms\n", hub->descriptor.bPwrOn2PwrGood * 2);
386*53ee8cc1Swenshuai.xi     ms_usbhost_debug("Hub current requirement: %dmA\n", hub->descriptor.bHubContrCurrent);
387*53ee8cc1Swenshuai.xi 
388*53ee8cc1Swenshuai.xi     s32Ret = ms_hub_hub_status(hub, &hubstatus, &hubchange);
389*53ee8cc1Swenshuai.xi     if (s32Ret < 0)
390*53ee8cc1Swenshuai.xi     {
391*53ee8cc1Swenshuai.xi         message = "can't get hub status";
392*53ee8cc1Swenshuai.xi         goto fail;
393*53ee8cc1Swenshuai.xi     }
394*53ee8cc1Swenshuai.xi 
395*53ee8cc1Swenshuai.xi     ms_usbhost_debug("Local power source is %s\n",(hubstatus & HUB_STATUS_LOCAL_POWER)? "lost (inactive)" : "good");
396*53ee8cc1Swenshuai.xi 
397*53ee8cc1Swenshuai.xi     ms_usbhost_debug("%s over-current exists\n",(hubstatus & HUB_STATUS_OVERCURRENT) ? "" : "No");
398*53ee8cc1Swenshuai.xi 
399*53ee8cc1Swenshuai.xi     pipe = usb_rcvintpipe(ms_dev, endpoint->bEndpointAddress);
400*53ee8cc1Swenshuai.xi     maxp = usb_maxpacket(ms_dev, pipe, usb_pipeout(pipe));
401*53ee8cc1Swenshuai.xi 
402*53ee8cc1Swenshuai.xi     if ((U32) maxp > sizeof(*hub->buffer))
403*53ee8cc1Swenshuai.xi         maxp = sizeof(*hub->buffer);
404*53ee8cc1Swenshuai.xi 
405*53ee8cc1Swenshuai.xi     hub->urb = ms_usb_alloc_urb(GFP_KERNEL);
406*53ee8cc1Swenshuai.xi     if (!hub->urb)
407*53ee8cc1Swenshuai.xi     {
408*53ee8cc1Swenshuai.xi         message = "couldn't allocate interrupt urb";
409*53ee8cc1Swenshuai.xi         s32Ret = -ENOMEM;
410*53ee8cc1Swenshuai.xi         goto fail;
411*53ee8cc1Swenshuai.xi     }
412*53ee8cc1Swenshuai.xi 
413*53ee8cc1Swenshuai.xi     ms_usb_stuff_intr_urb(hub->urb, ms_dev, pipe, *hub->buffer, maxp, ms_hub_irq,
414*53ee8cc1Swenshuai.xi         hub, endpoint->bInterval);
415*53ee8cc1Swenshuai.xi     hub->urb->tTransferDma = hub->buffer_dma;
416*53ee8cc1Swenshuai.xi     hub->urb->u32TransferFlags |= MS_FLAG_URB_NO_TRANSFER_DMA_MAP;
417*53ee8cc1Swenshuai.xi 
418*53ee8cc1Swenshuai.xi     /* power on hub before submit urb */
419*53ee8cc1Swenshuai.xi     ms_hub_power_on(hub);
420*53ee8cc1Swenshuai.xi 
421*53ee8cc1Swenshuai.xi     s32Ret = ms_usb_submit_urb(hub->urb, GFP_KERNEL);
422*53ee8cc1Swenshuai.xi     if (s32Ret)
423*53ee8cc1Swenshuai.xi     {
424*53ee8cc1Swenshuai.xi         message = "couldn't submit status urb";
425*53ee8cc1Swenshuai.xi         goto fail;
426*53ee8cc1Swenshuai.xi     }
427*53ee8cc1Swenshuai.xi 
428*53ee8cc1Swenshuai.xi     return 0;
429*53ee8cc1Swenshuai.xi 
430*53ee8cc1Swenshuai.xi fail:
431*53ee8cc1Swenshuai.xi     ms_usbhost_err("Hub config failed, %s (err %d)\n", message, s32Ret);
432*53ee8cc1Swenshuai.xi     return s32Ret;
433*53ee8cc1Swenshuai.xi }
434*53ee8cc1Swenshuai.xi 
435*53ee8cc1Swenshuai.xi /**
436*53ee8cc1Swenshuai.xi      * @brief           hub disconnect service
437*53ee8cc1Swenshuai.xi      *
438*53ee8cc1Swenshuai.xi      * @param           struct usb_interface *intf
439*53ee8cc1Swenshuai.xi      *
440*53ee8cc1Swenshuai.xi      * @return          none
441*53ee8cc1Swenshuai.xi      */
ms_hub_disconnect(struct usb_interface * intf)442*53ee8cc1Swenshuai.xi static void ms_hub_disconnect(struct usb_interface *intf)
443*53ee8cc1Swenshuai.xi {
444*53ee8cc1Swenshuai.xi     struct usb_hub *pHub = (struct usb_hub*) ms_usb_get_intfdata (intf);
445*53ee8cc1Swenshuai.xi     U32 flags;
446*53ee8cc1Swenshuai.xi 
447*53ee8cc1Swenshuai.xi     if (!pHub)
448*53ee8cc1Swenshuai.xi         return;
449*53ee8cc1Swenshuai.xi 
450*53ee8cc1Swenshuai.xi     osapi_spin_lock_irqsave(&hub_event_lock, flags);
451*53ee8cc1Swenshuai.xi     /* Delete it and then reset it */
452*53ee8cc1Swenshuai.xi     if (!ms_is_empty_list(&pHub->event_list))
453*53ee8cc1Swenshuai.xi     {
454*53ee8cc1Swenshuai.xi         ms_list_remove(&pHub->event_list);
455*53ee8cc1Swenshuai.xi         ms_list_init(&pHub->event_list);
456*53ee8cc1Swenshuai.xi     }
457*53ee8cc1Swenshuai.xi     //ms_list_remove(&pHub->hub_list);
458*53ee8cc1Swenshuai.xi     //ms_list_init(&pHub->hub_list);
459*53ee8cc1Swenshuai.xi     pHub->disconnected = 1;
460*53ee8cc1Swenshuai.xi     osapi_spin_unlock_irqrestore(&hub_event_lock, flags);
461*53ee8cc1Swenshuai.xi 
462*53ee8cc1Swenshuai.xi     /* All children disconnect  and cease the hub */
463*53ee8cc1Swenshuai.xi     pHub->error = 0;
464*53ee8cc1Swenshuai.xi     //ms_hub_quiesce(pHub, HUB_DISCONNECT);
465*53ee8cc1Swenshuai.xi 
466*53ee8cc1Swenshuai.xi     ms_usb_set_intfdata (intf, NULL);
467*53ee8cc1Swenshuai.xi 
468*53ee8cc1Swenshuai.xi     if (pHub->urb)
469*53ee8cc1Swenshuai.xi     {
470*53ee8cc1Swenshuai.xi         ms_usbhost_debug("hub_disconnect: unlink urb %p\n", pHub->urb);
471*53ee8cc1Swenshuai.xi         //ms_usb_unlink_urb(pHub->urb); // patch from Linux 2.6.28
472*53ee8cc1Swenshuai.xi         ms_usb_free_urb(pHub->urb);
473*53ee8cc1Swenshuai.xi         pHub->urb = NULL;
474*53ee8cc1Swenshuai.xi     }
475*53ee8cc1Swenshuai.xi 
476*53ee8cc1Swenshuai.xi     if (pHub->buffer)
477*53ee8cc1Swenshuai.xi     {
478*53ee8cc1Swenshuai.xi         ms_usb_buffer_free(interface_to_usbdev(intf),
479*53ee8cc1Swenshuai.xi             sizeof(*pHub->buffer), pHub->buffer, pHub->buffer_dma);
480*53ee8cc1Swenshuai.xi         pHub->buffer = NULL;
481*53ee8cc1Swenshuai.xi     }
482*53ee8cc1Swenshuai.xi 
483*53ee8cc1Swenshuai.xi     kfree(pHub);
484*53ee8cc1Swenshuai.xi }
485*53ee8cc1Swenshuai.xi 
486*53ee8cc1Swenshuai.xi /**
487*53ee8cc1Swenshuai.xi      * @brief               hub driver probe function
488*53ee8cc1Swenshuai.xi      *
489*53ee8cc1Swenshuai.xi      * @param           struct usb_interface *intf
490*53ee8cc1Swenshuai.xi      * @param           const struct usb_device_id *id
491*53ee8cc1Swenshuai.xi      *
492*53ee8cc1Swenshuai.xi      * @return          error code
493*53ee8cc1Swenshuai.xi      */
ms_hub_probe(struct usb_interface * pIntf,const struct usb_device_id * id)494*53ee8cc1Swenshuai.xi static int ms_hub_probe(struct usb_interface *pIntf, const struct usb_device_id *id)
495*53ee8cc1Swenshuai.xi {
496*53ee8cc1Swenshuai.xi     struct usb_host_interface *pHIdesc;
497*53ee8cc1Swenshuai.xi     struct usb_endpoint_descriptor *pEndpoint;
498*53ee8cc1Swenshuai.xi     struct usb_device *pUdev;
499*53ee8cc1Swenshuai.xi     struct usb_hub *pHub;
500*53ee8cc1Swenshuai.xi     //U32 flags;
501*53ee8cc1Swenshuai.xi 
502*53ee8cc1Swenshuai.xi     pHIdesc = pIntf->altsetting + pIntf->act_altsetting;
503*53ee8cc1Swenshuai.xi     pUdev = interface_to_usbdev(pIntf);
504*53ee8cc1Swenshuai.xi 
505*53ee8cc1Swenshuai.xi     if (pUdev->level == MAX_HUB_TOPO_LEVEL)
506*53ee8cc1Swenshuai.xi     {
507*53ee8cc1Swenshuai.xi         ms_usbhost_msg("hub nested too deep, level = %d\n", MAX_HUB_TOPO_LEVEL);
508*53ee8cc1Swenshuai.xi         return -MS_ERR_2BIG;
509*53ee8cc1Swenshuai.xi     }
510*53ee8cc1Swenshuai.xi 
511*53ee8cc1Swenshuai.xi     if ((pHIdesc->desc.bInterfaceSubClass != 0) && (pHIdesc->desc.bInterfaceSubClass != 1))
512*53ee8cc1Swenshuai.xi     {
513*53ee8cc1Swenshuai.xi descriptor_error:
514*53ee8cc1Swenshuai.xi         ms_usbhost_err("bad descriptor, ignoring hub\n");
515*53ee8cc1Swenshuai.xi         return -EIO;
516*53ee8cc1Swenshuai.xi     }
517*53ee8cc1Swenshuai.xi 
518*53ee8cc1Swenshuai.xi     if (pHIdesc->desc.bNumEndpoints != 1)
519*53ee8cc1Swenshuai.xi     {
520*53ee8cc1Swenshuai.xi         goto descriptor_error;
521*53ee8cc1Swenshuai.xi     }
522*53ee8cc1Swenshuai.xi 
523*53ee8cc1Swenshuai.xi     pEndpoint = &pHIdesc->endpoint[0].desc;
524*53ee8cc1Swenshuai.xi 
525*53ee8cc1Swenshuai.xi     // Determine hub endpoint attribute as interrupt IN
526*53ee8cc1Swenshuai.xi     if (!(pEndpoint->bEndpointAddress & USB_DIR_IN))
527*53ee8cc1Swenshuai.xi     {
528*53ee8cc1Swenshuai.xi         goto descriptor_error;
529*53ee8cc1Swenshuai.xi     }
530*53ee8cc1Swenshuai.xi     if ((pEndpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
531*53ee8cc1Swenshuai.xi         != USB_ENDPOINT_XFER_INT)
532*53ee8cc1Swenshuai.xi     {
533*53ee8cc1Swenshuai.xi         goto descriptor_error;
534*53ee8cc1Swenshuai.xi     }
535*53ee8cc1Swenshuai.xi 
536*53ee8cc1Swenshuai.xi     ms_usbhost_msg ("USB hub found\n");
537*53ee8cc1Swenshuai.xi 
538*53ee8cc1Swenshuai.xi     pHub = (struct usb_hub*) kmalloc(sizeof(*pHub), GFP_KERNEL);
539*53ee8cc1Swenshuai.xi     if (!pHub)
540*53ee8cc1Swenshuai.xi     {
541*53ee8cc1Swenshuai.xi         ms_usbhost_err("couldn't kmalloc hub struct\n");
542*53ee8cc1Swenshuai.xi         return -ENOMEM;
543*53ee8cc1Swenshuai.xi     }
544*53ee8cc1Swenshuai.xi 
545*53ee8cc1Swenshuai.xi     memset(pHub, 0, sizeof(*pHub));
546*53ee8cc1Swenshuai.xi 
547*53ee8cc1Swenshuai.xi     ms_list_init(&pHub->event_list);
548*53ee8cc1Swenshuai.xi     pHub->intf = pIntf;
549*53ee8cc1Swenshuai.xi 
550*53ee8cc1Swenshuai.xi     //osapi_spin_lock_irqsave(&hub_event_lock, flags);
551*53ee8cc1Swenshuai.xi     //ms_list_init(&pHub->hub_list);
552*53ee8cc1Swenshuai.xi     //ms_insert_list_after(&pHub->hub_list, &hub_list);
553*53ee8cc1Swenshuai.xi     //osapi_spin_unlock_irqrestore(&hub_event_lock, flags);
554*53ee8cc1Swenshuai.xi 
555*53ee8cc1Swenshuai.xi     ms_usb_set_intfdata (pIntf, pHub);
556*53ee8cc1Swenshuai.xi 
557*53ee8cc1Swenshuai.xi     if (ms_hub_configure(pHub, pEndpoint) >= 0)
558*53ee8cc1Swenshuai.xi         return 0;
559*53ee8cc1Swenshuai.xi 
560*53ee8cc1Swenshuai.xi     ms_hub_disconnect (pIntf);
561*53ee8cc1Swenshuai.xi     return -ENODEV;
562*53ee8cc1Swenshuai.xi }
563*53ee8cc1Swenshuai.xi 
564*53ee8cc1Swenshuai.xi /**
565*53ee8cc1Swenshuai.xi      * @brief               hub reset according to hub tree
566*53ee8cc1Swenshuai.xi      *
567*53ee8cc1Swenshuai.xi      * @param           struct usb_hub *hub
568*53ee8cc1Swenshuai.xi      *
569*53ee8cc1Swenshuai.xi      * @return          error code
570*53ee8cc1Swenshuai.xi      */
ms_hub_reset(struct usb_hub * hub)571*53ee8cc1Swenshuai.xi int ms_hub_reset(struct usb_hub *hub)
572*53ee8cc1Swenshuai.xi {
573*53ee8cc1Swenshuai.xi     struct usb_device *ms_dev = interface_to_usbdev(hub->intf);
574*53ee8cc1Swenshuai.xi     int i;
575*53ee8cc1Swenshuai.xi 
576*53ee8cc1Swenshuai.xi     ms_usbhost_msg("\nhub reset\n");
577*53ee8cc1Swenshuai.xi     for (i = 0; i < hub->descriptor.bNbrPorts; i++)
578*53ee8cc1Swenshuai.xi     {
579*53ee8cc1Swenshuai.xi         if (ms_dev->children[i])
580*53ee8cc1Swenshuai.xi             ms_usb_disconnect(&ms_dev->children[i]);
581*53ee8cc1Swenshuai.xi     }
582*53ee8cc1Swenshuai.xi 
583*53ee8cc1Swenshuai.xi     if (hub->urb)
584*53ee8cc1Swenshuai.xi     {
585*53ee8cc1Swenshuai.xi         ms_usb_unlink_urb(hub->urb);
586*53ee8cc1Swenshuai.xi         ms_usbhost_msg("hub_reset: unlink urb\n");
587*53ee8cc1Swenshuai.xi     }
588*53ee8cc1Swenshuai.xi     else
589*53ee8cc1Swenshuai.xi         return -1;
590*53ee8cc1Swenshuai.xi 
591*53ee8cc1Swenshuai.xi     if (ms_usb_reset_device(ms_dev))
592*53ee8cc1Swenshuai.xi         return -1;
593*53ee8cc1Swenshuai.xi 
594*53ee8cc1Swenshuai.xi     hub->urb->dev = ms_dev;
595*53ee8cc1Swenshuai.xi     if (ms_usb_submit_urb(hub->urb, GFP_KERNEL))
596*53ee8cc1Swenshuai.xi         return -1;
597*53ee8cc1Swenshuai.xi 
598*53ee8cc1Swenshuai.xi     ms_hub_power_on(hub);
599*53ee8cc1Swenshuai.xi 
600*53ee8cc1Swenshuai.xi     return 0;
601*53ee8cc1Swenshuai.xi }
602*53ee8cc1Swenshuai.xi 
603*53ee8cc1Swenshuai.xi /**
604*53ee8cc1Swenshuai.xi      * @brief               hub disconnect by hub tree
605*53ee8cc1Swenshuai.xi      *
606*53ee8cc1Swenshuai.xi      * @param           struct usb_device *ms_dev
607*53ee8cc1Swenshuai.xi      *
608*53ee8cc1Swenshuai.xi      * @return          none
609*53ee8cc1Swenshuai.xi      */
ms_hub_start_disconnect(struct usb_device * ms_dev)610*53ee8cc1Swenshuai.xi void ms_hub_start_disconnect(struct usb_device *ms_dev)
611*53ee8cc1Swenshuai.xi {
612*53ee8cc1Swenshuai.xi     struct usb_device *ms_parent = ms_dev->parent;
613*53ee8cc1Swenshuai.xi     int i;
614*53ee8cc1Swenshuai.xi 
615*53ee8cc1Swenshuai.xi     if (ms_parent)
616*53ee8cc1Swenshuai.xi     {
617*53ee8cc1Swenshuai.xi         for (i = 0; i < ms_parent->u32MaxChild; i++)
618*53ee8cc1Swenshuai.xi         {
619*53ee8cc1Swenshuai.xi             if (ms_parent->children[i] == ms_dev)
620*53ee8cc1Swenshuai.xi             {
621*53ee8cc1Swenshuai.xi                 ms_usb_disconnect(&ms_parent->children[i]);
622*53ee8cc1Swenshuai.xi                 return;
623*53ee8cc1Swenshuai.xi             }
624*53ee8cc1Swenshuai.xi         }
625*53ee8cc1Swenshuai.xi     }
626*53ee8cc1Swenshuai.xi 
627*53ee8cc1Swenshuai.xi     ms_usbhost_err("cannot disconnect hub %s\n", ms_dev->devpath);
628*53ee8cc1Swenshuai.xi }
629*53ee8cc1Swenshuai.xi 
630*53ee8cc1Swenshuai.xi /**
631*53ee8cc1Swenshuai.xi      * @brief               retrieving hub port current condition
632*53ee8cc1Swenshuai.xi      *
633*53ee8cc1Swenshuai.xi      * @param           struct usb_device *dev
634*53ee8cc1Swenshuai.xi      * @param           int port
635*53ee8cc1Swenshuai.xi      * @param           U16 *status_r
636*53ee8cc1Swenshuai.xi      * @param           U16 *change_r
637*53ee8cc1Swenshuai.xi      *
638*53ee8cc1Swenshuai.xi      * @return          error code
639*53ee8cc1Swenshuai.xi      */
ms_hub_port_status(struct usb_device * ms_dev,int port,U16 * status_r,U16 * change_r)640*53ee8cc1Swenshuai.xi int ms_hub_port_status(struct usb_device *ms_dev, int port,
641*53ee8cc1Swenshuai.xi              U16 *status_r, U16 *change_r)
642*53ee8cc1Swenshuai.xi {
643*53ee8cc1Swenshuai.xi     struct usb_hub *hub = (struct usb_hub*) ms_usb_get_intfdata(ms_dev->actconfig->interface[0]);
644*53ee8cc1Swenshuai.xi     S32 s32Err;
645*53ee8cc1Swenshuai.xi 
646*53ee8cc1Swenshuai.xi     // ms_get_port_status
647*53ee8cc1Swenshuai.xi     s32Err = ms_usb_control_cmd(ms_dev, usb_rcvctrlpipe(ms_dev, 0),
648*53ee8cc1Swenshuai.xi         USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port+1,
649*53ee8cc1Swenshuai.xi         &hub->status.port, sizeof(hub->status.port), HZ * USB_CTRL_GET_TIMEOUT);
650*53ee8cc1Swenshuai.xi     if (s32Err < 0)
651*53ee8cc1Swenshuai.xi     {
652*53ee8cc1Swenshuai.xi         ms_usbhost_err("%s failed (err = %d)\n", __FUNCTION__, (int)s32Err);
653*53ee8cc1Swenshuai.xi     }
654*53ee8cc1Swenshuai.xi     else
655*53ee8cc1Swenshuai.xi     {
656*53ee8cc1Swenshuai.xi         *status_r = hub->status.port.wPortStatus;
657*53ee8cc1Swenshuai.xi         *change_r = hub->status.port.wPortChange;
658*53ee8cc1Swenshuai.xi         s32Err = 0;
659*53ee8cc1Swenshuai.xi     }
660*53ee8cc1Swenshuai.xi     return s32Err;
661*53ee8cc1Swenshuai.xi }
662*53ee8cc1Swenshuai.xi 
663*53ee8cc1Swenshuai.xi /**
664*53ee8cc1Swenshuai.xi      * @brief               hub port reset waiting function
665*53ee8cc1Swenshuai.xi      *
666*53ee8cc1Swenshuai.xi      * @param           struct usb_device *hub
667*53ee8cc1Swenshuai.xi      * @param           int port
668*53ee8cc1Swenshuai.xi      * @param           struct usb_device *ms_dev
669*53ee8cc1Swenshuai.xi      * @param           U32 delay
670*53ee8cc1Swenshuai.xi      *
671*53ee8cc1Swenshuai.xi      * @return          error code, -1 on error, 0 on success, 1 on disconnect.
672*53ee8cc1Swenshuai.xi      */
ms_hub_port_wait_reset(struct usb_device * hub,int port,struct usb_device * ms_dev,U32 delay)673*53ee8cc1Swenshuai.xi static int ms_hub_port_wait_reset(struct usb_device *hub, int port,
674*53ee8cc1Swenshuai.xi         struct usb_device *ms_dev, U32 delay)
675*53ee8cc1Swenshuai.xi {
676*53ee8cc1Swenshuai.xi     S32 s32Dtime, s32Ret;
677*53ee8cc1Swenshuai.xi     U16 u16Portstatus;
678*53ee8cc1Swenshuai.xi     U16 u16Portchange;
679*53ee8cc1Swenshuai.xi 
680*53ee8cc1Swenshuai.xi     for (s32Dtime = 0; s32Dtime < HUB_RESET_TIMEOUT; s32Dtime += delay)
681*53ee8cc1Swenshuai.xi     {
682*53ee8cc1Swenshuai.xi         wait_ms(delay);
683*53ee8cc1Swenshuai.xi 
684*53ee8cc1Swenshuai.xi         s32Ret = ms_hub_port_status(hub, port, &u16Portstatus, &u16Portchange);
685*53ee8cc1Swenshuai.xi         if (s32Ret < 0) {
686*53ee8cc1Swenshuai.xi             if (s32Ret == -ENODEV)
687*53ee8cc1Swenshuai.xi                 return 1;
688*53ee8cc1Swenshuai.xi             else
689*53ee8cc1Swenshuai.xi                 return -1;
690*53ee8cc1Swenshuai.xi         }
691*53ee8cc1Swenshuai.xi 
692*53ee8cc1Swenshuai.xi         if (!(u16Portstatus & USB_PORT_STAT_CONNECTION))
693*53ee8cc1Swenshuai.xi             return 1;
694*53ee8cc1Swenshuai.xi 
695*53ee8cc1Swenshuai.xi         if ((u16Portchange & USB_PORT_STAT_C_CONNECTION))
696*53ee8cc1Swenshuai.xi             //return -1;
697*53ee8cc1Swenshuai.xi             return 1; // disconnect
698*53ee8cc1Swenshuai.xi 
699*53ee8cc1Swenshuai.xi         if (!(u16Portstatus & USB_PORT_STAT_RESET) &&
700*53ee8cc1Swenshuai.xi             (u16Portstatus & USB_PORT_STAT_ENABLE))
701*53ee8cc1Swenshuai.xi         {
702*53ee8cc1Swenshuai.xi             if (u16Portstatus & USB_PORT_STAT_HIGH_SPEED)
703*53ee8cc1Swenshuai.xi                 ms_dev->eSpeed = USB_HIGH_SPEED;
704*53ee8cc1Swenshuai.xi             else if (u16Portstatus & USB_PORT_STAT_LOW_SPEED)
705*53ee8cc1Swenshuai.xi                 ms_dev->eSpeed = USB_LOW_SPEED;
706*53ee8cc1Swenshuai.xi             else
707*53ee8cc1Swenshuai.xi                 ms_dev->eSpeed = USB_FULL_SPEED;
708*53ee8cc1Swenshuai.xi             ms_usbhost_msg("::Device Speed is %s\n", ms_portspeed(u16Portstatus));
709*53ee8cc1Swenshuai.xi             return 0;
710*53ee8cc1Swenshuai.xi         }
711*53ee8cc1Swenshuai.xi 
712*53ee8cc1Swenshuai.xi         if (s32Dtime >= 2 * HUB_SHORT_RESET_TIME)
713*53ee8cc1Swenshuai.xi             delay = HUB_LONG_RESET_TIME;
714*53ee8cc1Swenshuai.xi 
715*53ee8cc1Swenshuai.xi         ms_usbhost_debug ("port %d not reset yet, waiting %dms\n", port + 1, delay);
716*53ee8cc1Swenshuai.xi     }
717*53ee8cc1Swenshuai.xi 
718*53ee8cc1Swenshuai.xi     return -1;
719*53ee8cc1Swenshuai.xi }
720*53ee8cc1Swenshuai.xi 
721*53ee8cc1Swenshuai.xi /**
722*53ee8cc1Swenshuai.xi      * @brief               hub port reset command
723*53ee8cc1Swenshuai.xi      *
724*53ee8cc1Swenshuai.xi      * @param           struct usb_device *hub
725*53ee8cc1Swenshuai.xi      * @param           int port
726*53ee8cc1Swenshuai.xi      * @param           struct usb_device *ms_dev
727*53ee8cc1Swenshuai.xi      * @param           U32 delay
728*53ee8cc1Swenshuai.xi      *
729*53ee8cc1Swenshuai.xi      * @return          error code
730*53ee8cc1Swenshuai.xi      */
ms_hub_port_reset(struct usb_device * hub,int port,struct usb_device * ms_dev,U32 delay)731*53ee8cc1Swenshuai.xi static int ms_hub_port_reset(struct usb_device *hub, int port,
732*53ee8cc1Swenshuai.xi         struct usb_device *ms_dev, U32 delay)
733*53ee8cc1Swenshuai.xi {
734*53ee8cc1Swenshuai.xi     int i, status;
735*53ee8cc1Swenshuai.xi 
736*53ee8cc1Swenshuai.xi     /* patch for DM always keep high issue */
737*53ee8cc1Swenshuai.xi     #if (_USB_HS_CUR_DRIVE_DM_ALLWAYS_HIGH_PATCH)
738*53ee8cc1Swenshuai.xi     /* turn off overwrite mode */
739*53ee8cc1Swenshuai.xi     if (hub->parent == NULL)
740*53ee8cc1Swenshuai.xi     {
741*53ee8cc1Swenshuai.xi       struct usb_hcd *hcd = (struct usb_hcd*) hub->bus->hcpriv;
742*53ee8cc1Swenshuai.xi       struct cpe_dev *dev;
743*53ee8cc1Swenshuai.xi       const struct device_s *__mptr = hcd->controller;
744*53ee8cc1Swenshuai.xi       dev = (struct cpe_dev *)( (char *)__mptr - offsetof(struct cpe_dev,dev) );
745*53ee8cc1Swenshuai.xi       U32 regUTMI = dev->utmibase;
746*53ee8cc1Swenshuai.xi 
747*53ee8cc1Swenshuai.xi       usb_writeb(usb_readb((void*)(regUTMI+0x0*2)) & ~BIT1, (void*) (regUTMI+0x0*2)); //tern_ov = 0
748*53ee8cc1Swenshuai.xi     }
749*53ee8cc1Swenshuai.xi     #endif
750*53ee8cc1Swenshuai.xi 
751*53ee8cc1Swenshuai.xi     for (i = 0; i < HUB_RESET_TRIES; i++)
752*53ee8cc1Swenshuai.xi     {
753*53ee8cc1Swenshuai.xi         // (USB_PORT_FEAT_RESET)
754*53ee8cc1Swenshuai.xi         ms_usb_control_cmd(hub, usb_sndctrlpipe(hub, 0),
755*53ee8cc1Swenshuai.xi             USB_REQ_SET_FEATURE, USB_RT_PORT, USB_PORT_FEAT_RESET, port+1, NULL, 0, HZ);
756*53ee8cc1Swenshuai.xi 
757*53ee8cc1Swenshuai.xi         status = ms_hub_port_wait_reset(hub, port, ms_dev, delay);
758*53ee8cc1Swenshuai.xi         ms_usbhost_debug("<hub_port_reset> loop %d, status %d\n", i, status);
759*53ee8cc1Swenshuai.xi         if (status != -1)
760*53ee8cc1Swenshuai.xi         {
761*53ee8cc1Swenshuai.xi             // (USB_PORT_FEAT_C_RESET)
762*53ee8cc1Swenshuai.xi             ms_usb_control_cmd(hub, usb_sndctrlpipe(hub, 0),
763*53ee8cc1Swenshuai.xi                 USB_REQ_CLEAR_FEATURE, USB_RT_PORT, USB_PORT_FEAT_C_RESET, port+1, NULL, 0, HZ);
764*53ee8cc1Swenshuai.xi             // status: 0 on success, 1 on disconnect
765*53ee8cc1Swenshuai.xi             //ms_dev->eState = status ? USB_STATE_NOTATTACHED : USB_STATE_DEFAULT;
766*53ee8cc1Swenshuai.xi             ms_usb_set_device_state(ms_dev, status ? USB_STATE_NOTATTACHED : USB_STATE_DEFAULT);
767*53ee8cc1Swenshuai.xi             return status;
768*53ee8cc1Swenshuai.xi         }
769*53ee8cc1Swenshuai.xi 
770*53ee8cc1Swenshuai.xi         ms_usbhost_debug("port %d not enabled, trying reset again...\n", port + 1);
771*53ee8cc1Swenshuai.xi         delay = HUB_LONG_RESET_TIME; // increase reset waiting time
772*53ee8cc1Swenshuai.xi     }
773*53ee8cc1Swenshuai.xi 
774*53ee8cc1Swenshuai.xi     ms_usbhost_err("Cannot enable port %d.  Maybe the USB cable is bad?\n", port + 1);
775*53ee8cc1Swenshuai.xi 
776*53ee8cc1Swenshuai.xi     return -1;
777*53ee8cc1Swenshuai.xi }
778*53ee8cc1Swenshuai.xi 
779*53ee8cc1Swenshuai.xi /**
780*53ee8cc1Swenshuai.xi      * @brief               hub port disable command
781*53ee8cc1Swenshuai.xi      *
782*53ee8cc1Swenshuai.xi      * @param           struct usb_device *hub
783*53ee8cc1Swenshuai.xi      * @param           int port
784*53ee8cc1Swenshuai.xi      *
785*53ee8cc1Swenshuai.xi      * @return          error code
786*53ee8cc1Swenshuai.xi      */
ms_hub_port_disable(struct usb_device * hub,int port)787*53ee8cc1Swenshuai.xi int ms_hub_port_disable(struct usb_device *hub, int port)
788*53ee8cc1Swenshuai.xi {
789*53ee8cc1Swenshuai.xi     S32 s32Err;
790*53ee8cc1Swenshuai.xi 
791*53ee8cc1Swenshuai.xi     // (USB_PORT_FEAT_ENABLE)
792*53ee8cc1Swenshuai.xi     s32Err = ms_usb_control_cmd(hub, usb_sndctrlpipe(hub, 0),
793*53ee8cc1Swenshuai.xi         USB_REQ_CLEAR_FEATURE, USB_RT_PORT, USB_PORT_FEAT_ENABLE, port+1, NULL, 0, HZ);
794*53ee8cc1Swenshuai.xi     if (s32Err)
795*53ee8cc1Swenshuai.xi     {
796*53ee8cc1Swenshuai.xi         ms_usbhost_err("cannot disable port %d (err = %d)\n", port + 1, (int)s32Err);
797*53ee8cc1Swenshuai.xi     }
798*53ee8cc1Swenshuai.xi 
799*53ee8cc1Swenshuai.xi     return s32Err;
800*53ee8cc1Swenshuai.xi }
801*53ee8cc1Swenshuai.xi 
ms_recursively_NOTATTACHED(struct usb_device * udev)802*53ee8cc1Swenshuai.xi static void ms_recursively_NOTATTACHED(struct usb_device *udev)
803*53ee8cc1Swenshuai.xi {
804*53ee8cc1Swenshuai.xi 	int i;
805*53ee8cc1Swenshuai.xi 
806*53ee8cc1Swenshuai.xi 	for (i = 0; i < udev->u32MaxChild; ++i) {
807*53ee8cc1Swenshuai.xi 		if (udev->children[i])
808*53ee8cc1Swenshuai.xi 			ms_recursively_NOTATTACHED(udev->children[i]);
809*53ee8cc1Swenshuai.xi 	}
810*53ee8cc1Swenshuai.xi 	udev->eState = USB_STATE_NOTATTACHED;
811*53ee8cc1Swenshuai.xi }
812*53ee8cc1Swenshuai.xi 
ms_usb_set_device_state(struct usb_device * udev,enum usb_device_state new_state)813*53ee8cc1Swenshuai.xi void ms_usb_set_device_state(struct usb_device *udev,
814*53ee8cc1Swenshuai.xi     enum usb_device_state new_state)
815*53ee8cc1Swenshuai.xi {
816*53ee8cc1Swenshuai.xi 	unsigned long flags;
817*53ee8cc1Swenshuai.xi 
818*53ee8cc1Swenshuai.xi 	osapi_spin_lock_irqsave(&device_state_lock, flags);
819*53ee8cc1Swenshuai.xi 	if (udev->eState == USB_STATE_NOTATTACHED)
820*53ee8cc1Swenshuai.xi 		;	/* no action */
821*53ee8cc1Swenshuai.xi 	else if (new_state != USB_STATE_NOTATTACHED) {
822*53ee8cc1Swenshuai.xi 		udev->eState = new_state;
823*53ee8cc1Swenshuai.xi 	} else
824*53ee8cc1Swenshuai.xi 		ms_recursively_NOTATTACHED(udev);
825*53ee8cc1Swenshuai.xi 	osapi_spin_unlock_irqrestore(&device_state_lock, flags);
826*53ee8cc1Swenshuai.xi }
827*53ee8cc1Swenshuai.xi 
828*53ee8cc1Swenshuai.xi #define HUB_DEBOUNCE_TIMEOUT  1500 //400
829*53ee8cc1Swenshuai.xi //#define HUB_DEBOUNCE_STEP      25
830*53ee8cc1Swenshuai.xi //#define HUB_DEBOUNCE_STABLE   4 // # of counts
831*53ee8cc1Swenshuai.xi /**
832*53ee8cc1Swenshuai.xi      * @brief               hub port deboucing
833*53ee8cc1Swenshuai.xi      *
834*53ee8cc1Swenshuai.xi      * @param           struct usb_device *hub
835*53ee8cc1Swenshuai.xi      * @param           int port
836*53ee8cc1Swenshuai.xi      *
837*53ee8cc1Swenshuai.xi      * @return          error code
838*53ee8cc1Swenshuai.xi      */
ms_hub_port_debounce(struct usb_device * hub,int port)839*53ee8cc1Swenshuai.xi static int ms_hub_port_debounce(struct usb_device *hub, int port)
840*53ee8cc1Swenshuai.xi {
841*53ee8cc1Swenshuai.xi     S32 s32Err;
842*53ee8cc1Swenshuai.xi     S32 s32Dtime, s32Stable_count;
843*53ee8cc1Swenshuai.xi     U16 u16Portchange, u16Portstatus;
844*53ee8cc1Swenshuai.xi     U32 u32Connection;
845*53ee8cc1Swenshuai.xi 
846*53ee8cc1Swenshuai.xi     u32Connection = 0;
847*53ee8cc1Swenshuai.xi     s32Stable_count = 0;
848*53ee8cc1Swenshuai.xi     for (s32Dtime = 0; s32Dtime < HUB_DEBOUNCE_TIMEOUT; s32Dtime += HUB_DEBOUNCE_STEP)
849*53ee8cc1Swenshuai.xi     {
850*53ee8cc1Swenshuai.xi         wait_ms(HUB_DEBOUNCE_STEP);
851*53ee8cc1Swenshuai.xi 
852*53ee8cc1Swenshuai.xi         s32Err = ms_hub_port_status(hub, port, &u16Portstatus, &u16Portchange);
853*53ee8cc1Swenshuai.xi         if (s32Err < 0)
854*53ee8cc1Swenshuai.xi             return -1;
855*53ee8cc1Swenshuai.xi 
856*53ee8cc1Swenshuai.xi         if ((U16) (u16Portstatus & USB_PORT_STAT_CONNECTION) == u32Connection)
857*53ee8cc1Swenshuai.xi         {
858*53ee8cc1Swenshuai.xi             if (u32Connection)
859*53ee8cc1Swenshuai.xi             {
860*53ee8cc1Swenshuai.xi                 if (++s32Stable_count == HUB_DEBOUNCE_STABLE)
861*53ee8cc1Swenshuai.xi                     break;
862*53ee8cc1Swenshuai.xi             }
863*53ee8cc1Swenshuai.xi         }
864*53ee8cc1Swenshuai.xi         else
865*53ee8cc1Swenshuai.xi         {
866*53ee8cc1Swenshuai.xi             s32Stable_count = 0;
867*53ee8cc1Swenshuai.xi         }
868*53ee8cc1Swenshuai.xi         u32Connection = u16Portstatus & USB_PORT_STAT_CONNECTION;
869*53ee8cc1Swenshuai.xi 
870*53ee8cc1Swenshuai.xi         if ((u16Portchange & USB_PORT_STAT_C_CONNECTION))
871*53ee8cc1Swenshuai.xi         {
872*53ee8cc1Swenshuai.xi             // (USB_PORT_FEAT_C_CONNECTION)
873*53ee8cc1Swenshuai.xi             ms_usb_control_cmd(hub, usb_sndctrlpipe(hub, 0),
874*53ee8cc1Swenshuai.xi                 USB_REQ_CLEAR_FEATURE, USB_RT_PORT, USB_PORT_FEAT_C_CONNECTION, port+1, NULL, 0, HZ);
875*53ee8cc1Swenshuai.xi         }
876*53ee8cc1Swenshuai.xi     }
877*53ee8cc1Swenshuai.xi 
878*53ee8cc1Swenshuai.xi     ms_usbhost_debug("debounce: port %d: delay %dms stable %d status 0x%x\n",
879*53ee8cc1Swenshuai.xi         port + 1, s32Dtime, s32Stable_count, u16Portstatus);
880*53ee8cc1Swenshuai.xi 
881*53ee8cc1Swenshuai.xi     return ((u16Portstatus & USB_PORT_STAT_CONNECTION)) ? 0 : 1;
882*53ee8cc1Swenshuai.xi }
883*53ee8cc1Swenshuai.xi 
884*53ee8cc1Swenshuai.xi /**
885*53ee8cc1Swenshuai.xi      * @brief           hub port connect change process
886*53ee8cc1Swenshuai.xi      *
887*53ee8cc1Swenshuai.xi      * @param           struct usb_hub *hubstate
888*53ee8cc1Swenshuai.xi      * @param           int port
889*53ee8cc1Swenshuai.xi      * @param           U16 portstatus
890*53ee8cc1Swenshuai.xi      * @param           U16 portchange
891*53ee8cc1Swenshuai.xi      *
892*53ee8cc1Swenshuai.xi      * @return          none
893*53ee8cc1Swenshuai.xi      */
ms_hub_port_connect_change(struct usb_hub * hubstate,int port,U16 portstatus,U16 portchange)894*53ee8cc1Swenshuai.xi static struct usb_device* ms_hub_port_connect_change(
895*53ee8cc1Swenshuai.xi 	struct usb_hub *hubstate, int port, U16 portstatus, U16 portchange)
896*53ee8cc1Swenshuai.xi {
897*53ee8cc1Swenshuai.xi     struct usb_device *pHub = interface_to_usbdev(hubstate->intf);
898*53ee8cc1Swenshuai.xi     struct usb_device *pUdev;
899*53ee8cc1Swenshuai.xi     //struct s_hcd_dev    *phcd_dev;
900*53ee8cc1Swenshuai.xi     struct usb_hcd    *pHcd = (struct usb_hcd*) pHub->bus->hcpriv;
901*53ee8cc1Swenshuai.xi     U32 u32Delay = HUB_SHORT_RESET_TIME;
902*53ee8cc1Swenshuai.xi     int i, sErr = 0;
903*53ee8cc1Swenshuai.xi 
904*53ee8cc1Swenshuai.xi     ms_usbhost_msg("hub_port_connect_change ===%s===>\t",
905*53ee8cc1Swenshuai.xi         ECOS_USB_HOST_LOCAL_VER);
906*53ee8cc1Swenshuai.xi     ms_usbhost_msg("port %d, status %x, change %x\n",
907*53ee8cc1Swenshuai.xi         port+1, portstatus, portchange);
908*53ee8cc1Swenshuai.xi 
909*53ee8cc1Swenshuai.xi     /* patch for DM always keep high issue */
910*53ee8cc1Swenshuai.xi     #if (_USB_HS_CUR_DRIVE_DM_ALLWAYS_HIGH_PATCH)
911*53ee8cc1Swenshuai.xi     /* turn on overwrite mode */
912*53ee8cc1Swenshuai.xi     if (pHub->parent == NULL)
913*53ee8cc1Swenshuai.xi     {
914*53ee8cc1Swenshuai.xi         struct cpe_dev *dev;
915*53ee8cc1Swenshuai.xi         const struct device_s *__mptr = pHcd->controller;
916*53ee8cc1Swenshuai.xi         dev = (struct cpe_dev *)( (char *)__mptr - offsetof(struct cpe_dev,dev) );
917*53ee8cc1Swenshuai.xi         U32 regUTMI = dev->utmibase;
918*53ee8cc1Swenshuai.xi 
919*53ee8cc1Swenshuai.xi         usb_writeb(usb_readb((void*)(regUTMI+0x0*2)) | BIT1, (void*) (regUTMI+0x0*2)); //tern_ov = 1
920*53ee8cc1Swenshuai.xi     }
921*53ee8cc1Swenshuai.xi     #endif
922*53ee8cc1Swenshuai.xi 
923*53ee8cc1Swenshuai.xi     /* move back to hub_events() */
924*53ee8cc1Swenshuai.xi     // (USB_PORT_FEAT_C_CONNECTION)
925*53ee8cc1Swenshuai.xi     //ms_usb_control_cmd(pHub, usb_sndctrlpipe(pHub, 0),
926*53ee8cc1Swenshuai.xi     //    USB_REQ_CLEAR_FEATURE, USB_RT_PORT, USB_PORT_FEAT_C_CONNECTION, port+1, NULL, 0, HZ);
927*53ee8cc1Swenshuai.xi 
928*53ee8cc1Swenshuai.xi     if (pHub->children[port])
929*53ee8cc1Swenshuai.xi         ms_usb_disconnect(&pHub->children[port]);
930*53ee8cc1Swenshuai.xi 
931*53ee8cc1Swenshuai.xi     if (!(portstatus & USB_PORT_STAT_CONNECTION))
932*53ee8cc1Swenshuai.xi     {
933*53ee8cc1Swenshuai.xi         if (portstatus & USB_PORT_STAT_ENABLE)
934*53ee8cc1Swenshuai.xi             ms_hub_port_disable(pHub, port);
935*53ee8cc1Swenshuai.xi         /* deal with HC abnormal state in fast plug in/out */
936*53ee8cc1Swenshuai.xi         else if (pHub->parent == NULL) // limited at roothub
937*53ee8cc1Swenshuai.xi             ms_roothub_disconn_reinit(pHcd);
938*53ee8cc1Swenshuai.xi         return NULL;
939*53ee8cc1Swenshuai.xi     }
940*53ee8cc1Swenshuai.xi 
941*53ee8cc1Swenshuai.xi     if (ms_hub_port_debounce(pHub, port))
942*53ee8cc1Swenshuai.xi     {
943*53ee8cc1Swenshuai.xi         ms_usbhost_err("connect-debounce failed, port %d disabled\n",
944*53ee8cc1Swenshuai.xi             port+1);
945*53ee8cc1Swenshuai.xi         ms_hub_port_disable(pHub, port);
946*53ee8cc1Swenshuai.xi         return NULL;
947*53ee8cc1Swenshuai.xi     }
948*53ee8cc1Swenshuai.xi 
949*53ee8cc1Swenshuai.xi     if (!pHub->parent)
950*53ee8cc1Swenshuai.xi         u32Delay = HUB_ROOT_RESET_TIME;
951*53ee8cc1Swenshuai.xi 
952*53ee8cc1Swenshuai.xi     if (portstatus & USB_PORT_STAT_LOW_SPEED)
953*53ee8cc1Swenshuai.xi         u32Delay = HUB_LONG_RESET_TIME;
954*53ee8cc1Swenshuai.xi 
955*53ee8cc1Swenshuai.xi   for (i = 0; i < HUB_PROBE_TRIES; i++) {
956*53ee8cc1Swenshuai.xi     struct usb_device *pdev;
957*53ee8cc1Swenshuai.xi     int  len;
958*53ee8cc1Swenshuai.xi 
959*53ee8cc1Swenshuai.xi     pUdev = ms_usb_alloc_dev(pHub, pHub->bus);
960*53ee8cc1Swenshuai.xi     if (!pUdev) {
961*53ee8cc1Swenshuai.xi       ms_usbhost_err("couldn't allocate usb_device\n");
962*53ee8cc1Swenshuai.xi       break;
963*53ee8cc1Swenshuai.xi     }
964*53ee8cc1Swenshuai.xi 
965*53ee8cc1Swenshuai.xi     pHub->children[port] = pUdev;
966*53ee8cc1Swenshuai.xi     //pUdev->eState = USB_STATE_POWERED;
967*53ee8cc1Swenshuai.xi     ms_usb_set_device_state(pUdev, USB_STATE_POWERED); // patch from Linux 2.6.28
968*53ee8cc1Swenshuai.xi 
969*53ee8cc1Swenshuai.xi     ms_usbhost_debug("pHcd->product_desc: (%s)\n", pHcd->product_desc);
970*53ee8cc1Swenshuai.xi     if ( (pHub->parent == NULL) && (pHcd->isBadDevice) )
971*53ee8cc1Swenshuai.xi     {
972*53ee8cc1Swenshuai.xi         if (pHcd->badDeviceCnt == 3)
973*53ee8cc1Swenshuai.xi             ms_RH_force_FSmode(pHcd, 1); //force enter FSmode
974*53ee8cc1Swenshuai.xi     }
975*53ee8cc1Swenshuai.xi     pHcd->isBadDevice = FALSE;
976*53ee8cc1Swenshuai.xi 
977*53ee8cc1Swenshuai.xi     if (pHub->parent == NULL && (pHcd->isBadDeviceRH == TRUE))
978*53ee8cc1Swenshuai.xi     {
979*53ee8cc1Swenshuai.xi         diag_printf("[USB] clear Bad Device on RH\n");
980*53ee8cc1Swenshuai.xi         pHcd->isBadDeviceRH = FALSE;
981*53ee8cc1Swenshuai.xi     }
982*53ee8cc1Swenshuai.xi 
983*53ee8cc1Swenshuai.xi     if (ms_hub_port_reset(pHub, port, pUdev, u32Delay)) {
984*53ee8cc1Swenshuai.xi         ms_usb_put_dev(pUdev);
985*53ee8cc1Swenshuai.xi         continue;
986*53ee8cc1Swenshuai.xi     }
987*53ee8cc1Swenshuai.xi 
988*53ee8cc1Swenshuai.xi     // device unexpected disconnected checking
989*53ee8cc1Swenshuai.xi     if (pHub->parent == NULL)
990*53ee8cc1Swenshuai.xi     {
991*53ee8cc1Swenshuai.xi         //struct ehci_hcd *ehci = hcd_to_ehci (pHcd);
992*53ee8cc1Swenshuai.xi         //U32 temp = hcd_reg_readl((U32)&ehci->op_regs->portsc[0]);
993*53ee8cc1Swenshuai.xi 
994*53ee8cc1Swenshuai.xi         //if (!(temp & PORTSC_CONNECT))
995*53ee8cc1Swenshuai.xi         if (!ms_RoothubPortConnected(pHcd))
996*53ee8cc1Swenshuai.xi         {
997*53ee8cc1Swenshuai.xi             diag_printf("[USB] no connect after bus reset\n");
998*53ee8cc1Swenshuai.xi             ms_usb_put_dev(pUdev);
999*53ee8cc1Swenshuai.xi             break;
1000*53ee8cc1Swenshuai.xi         }
1001*53ee8cc1Swenshuai.xi     }
1002*53ee8cc1Swenshuai.xi 
1003*53ee8cc1Swenshuai.xi     pUdev->level = pHub->level + 1;
1004*53ee8cc1Swenshuai.xi 
1005*53ee8cc1Swenshuai.xi     ms_usb_choose_address(pUdev);
1006*53ee8cc1Swenshuai.xi 
1007*53ee8cc1Swenshuai.xi     if (pHub->tt) {
1008*53ee8cc1Swenshuai.xi       pUdev->tt = pHub->tt;
1009*53ee8cc1Swenshuai.xi       pUdev->u32TTPort = pHub->u32TTPort;
1010*53ee8cc1Swenshuai.xi     }
1011*53ee8cc1Swenshuai.xi     else if (pUdev->eSpeed != USB_HIGH_SPEED
1012*53ee8cc1Swenshuai.xi         /* MStar patch to setup roothub tt record */
1013*53ee8cc1Swenshuai.xi         && (pHub->parent == NULL || pHub->eSpeed == USB_HIGH_SPEED)) {
1014*53ee8cc1Swenshuai.xi         //&& pHub->eSpeed == USB_HIGH_SPEED) {
1015*53ee8cc1Swenshuai.xi       pUdev->tt = &hubstate->tt;
1016*53ee8cc1Swenshuai.xi       pUdev->u32TTPort = port + 1;
1017*53ee8cc1Swenshuai.xi     }
1018*53ee8cc1Swenshuai.xi 
1019*53ee8cc1Swenshuai.xi     pdev = pUdev->parent;
1020*53ee8cc1Swenshuai.xi     if (pdev->devpath [0] != '0')
1021*53ee8cc1Swenshuai.xi       len = USB_sprintf (pUdev->devpath,"%s.%d", pdev->devpath, port + 1);
1022*53ee8cc1Swenshuai.xi     else
1023*53ee8cc1Swenshuai.xi       len = USB_sprintf (pUdev->devpath,"%d", port + 1);
1024*53ee8cc1Swenshuai.xi     if (len == sizeof pUdev->devpath) {
1025*53ee8cc1Swenshuai.xi       ms_usbhost_err("devpath size! usb/%03d/%03d path %s\n",
1026*53ee8cc1Swenshuai.xi         (int)pUdev->bus->busnum, (int)pUdev->u32DevNum, pUdev->devpath);
1027*53ee8cc1Swenshuai.xi     }
1028*53ee8cc1Swenshuai.xi 
1029*53ee8cc1Swenshuai.xi     ms_usbhost_msg("new USB device on path usb:%s, assigned address %d\n",
1030*53ee8cc1Swenshuai.xi       pUdev->devpath, (int)pUdev->u32DevNum);
1031*53ee8cc1Swenshuai.xi 
1032*53ee8cc1Swenshuai.xi     pUdev->dev.parent = pUdev->parent->dev.parent->parent;
1033*53ee8cc1Swenshuai.xi 
1034*53ee8cc1Swenshuai.xi     if (!(sErr = ms_usb_new_device(pUdev, &pHub->dev)))
1035*53ee8cc1Swenshuai.xi       goto done;
1036*53ee8cc1Swenshuai.xi 
1037*53ee8cc1Swenshuai.xi     ms_usbhost_msg("[HPCC] usb new device failed tier(%d)\n", i);
1038*53ee8cc1Swenshuai.xi     ms_hub_port_disable(pHub, port); // patch from Linux code
1039*53ee8cc1Swenshuai.xi 
1040*53ee8cc1Swenshuai.xi     /* Clean qh buffer through urb list of udev */
1041*53ee8cc1Swenshuai.xi     //ms_usb_disable_endpoint(pUdev, 0);
1042*53ee8cc1Swenshuai.xi     ms_usb_disable_endpoint(pUdev, 0+USB_DIR_OUT);
1043*53ee8cc1Swenshuai.xi     ms_usb_disable_endpoint(pUdev, 0+USB_DIR_IN);
1044*53ee8cc1Swenshuai.xi     //phcd_dev = (struct s_hcd_dev *)pUdev->hcpriv;
1045*53ee8cc1Swenshuai.xi     //ms_ehci_disable_ep(pHcd, phcd_dev, 0);
1046*53ee8cc1Swenshuai.xi 
1047*53ee8cc1Swenshuai.xi     ms_usb_put_dev(pUdev);
1048*53ee8cc1Swenshuai.xi 
1049*53ee8cc1Swenshuai.xi     if (sErr == -ESHUTDOWN || sErr == -ENODEV)
1050*53ee8cc1Swenshuai.xi     {
1051*53ee8cc1Swenshuai.xi         ms_usbhost_err("[HPCC] sErr %s!\n",
1052*53ee8cc1Swenshuai.xi 		(sErr == -ENODEV) ? "ENODEV" : "ESHUTDOWN");
1053*53ee8cc1Swenshuai.xi         break;
1054*53ee8cc1Swenshuai.xi     }
1055*53ee8cc1Swenshuai.xi     u32Delay = HUB_LONG_RESET_TIME; // increase hub reset period
1056*53ee8cc1Swenshuai.xi   }
1057*53ee8cc1Swenshuai.xi 
1058*53ee8cc1Swenshuai.xi 
1059*53ee8cc1Swenshuai.xi   diag_printf("HUB_PROBE_TRIES fail, #%d\n", i);
1060*53ee8cc1Swenshuai.xi   if (i >= HUB_PROBE_TRIES && pHub->parent == NULL) // 3 reset retries
1061*53ee8cc1Swenshuai.xi   {
1062*53ee8cc1Swenshuai.xi     ms_usbhost_err("HUB PROBE fail, set bad device on root hub!\n");
1063*53ee8cc1Swenshuai.xi     pHcd->isBadDeviceRH = TRUE;
1064*53ee8cc1Swenshuai.xi   }
1065*53ee8cc1Swenshuai.xi   pHub->children[port] = NULL;
1066*53ee8cc1Swenshuai.xi   ms_hub_port_disable(pHub, port);
1067*53ee8cc1Swenshuai.xi   pUdev = NULL;
1068*53ee8cc1Swenshuai.xi done:
1069*53ee8cc1Swenshuai.xi   osapi_up(&usb_address0_sem);
1070*53ee8cc1Swenshuai.xi   return pUdev;
1071*53ee8cc1Swenshuai.xi }
1072*53ee8cc1Swenshuai.xi 
1073*53ee8cc1Swenshuai.xi static struct usb_device_id hub_id_table [] = {
1074*53ee8cc1Swenshuai.xi     { USBDEV_MATCH_ID_DEV_CLASS,0,0,0,0,USB_CLASS_HUB,0,0,0,0,0,0},
1075*53ee8cc1Swenshuai.xi     { USBDEV_MATCH_ID_INT_CLASS,0,0,0,0,0,0,0,USB_CLASS_HUB,0,0,0},
1076*53ee8cc1Swenshuai.xi     { 0,0,0,0,0,0,0,0,0,0,0,0}
1077*53ee8cc1Swenshuai.xi 
1078*53ee8cc1Swenshuai.xi };
1079*53ee8cc1Swenshuai.xi 
1080*53ee8cc1Swenshuai.xi static struct usb_driver hub_driver = {
1081*53ee8cc1Swenshuai.xi     "hub",
1082*53ee8cc1Swenshuai.xi     ms_hub_probe,
1083*53ee8cc1Swenshuai.xi     ms_hub_disconnect,
1084*53ee8cc1Swenshuai.xi     hub_id_table
1085*53ee8cc1Swenshuai.xi };
1086*53ee8cc1Swenshuai.xi 
1087*53ee8cc1Swenshuai.xi /**
1088*53ee8cc1Swenshuai.xi      * @brief               hub driver installation
1089*53ee8cc1Swenshuai.xi      *
1090*53ee8cc1Swenshuai.xi      * @param           none
1091*53ee8cc1Swenshuai.xi      *
1092*53ee8cc1Swenshuai.xi      * @return          error code
1093*53ee8cc1Swenshuai.xi      */
ms_usb_hub_init(void)1094*53ee8cc1Swenshuai.xi int ms_usb_hub_init(void)
1095*53ee8cc1Swenshuai.xi {
1096*53ee8cc1Swenshuai.xi     if (ms_usb_register(&hub_driver) < 0)
1097*53ee8cc1Swenshuai.xi     {
1098*53ee8cc1Swenshuai.xi         ms_usbhost_err("Unable to register USB hub driver\n");
1099*53ee8cc1Swenshuai.xi         return -1;
1100*53ee8cc1Swenshuai.xi     }
1101*53ee8cc1Swenshuai.xi     // Start up hub thread here (if platform has OS support)
1102*53ee8cc1Swenshuai.xi 
1103*53ee8cc1Swenshuai.xi     return 0;
1104*53ee8cc1Swenshuai.xi }
1105*53ee8cc1Swenshuai.xi 
ms_usb_hub_uninit(void)1106*53ee8cc1Swenshuai.xi int ms_usb_hub_uninit(void)
1107*53ee8cc1Swenshuai.xi {
1108*53ee8cc1Swenshuai.xi     ms_usb_deregister(&hub_driver);
1109*53ee8cc1Swenshuai.xi     return 0;
1110*53ee8cc1Swenshuai.xi }
1111*53ee8cc1Swenshuai.xi /**
1112*53ee8cc1Swenshuai.xi      * @brief               usb reset function
1113*53ee8cc1Swenshuai.xi      *
1114*53ee8cc1Swenshuai.xi      * @param           struct usb_device *ms_dev
1115*53ee8cc1Swenshuai.xi      *
1116*53ee8cc1Swenshuai.xi      * @return          error code
1117*53ee8cc1Swenshuai.xi      */
ms_usb_physical_reset_device(struct usb_device * ms_dev)1118*53ee8cc1Swenshuai.xi int ms_usb_physical_reset_device(struct usb_device *ms_dev)
1119*53ee8cc1Swenshuai.xi {
1120*53ee8cc1Swenshuai.xi     struct usb_device *parent = ms_dev->parent;
1121*53ee8cc1Swenshuai.xi     struct usb_device_descriptor *d_desc;
1122*53ee8cc1Swenshuai.xi     S32 i, s32Err, port = -1;
1123*53ee8cc1Swenshuai.xi 
1124*53ee8cc1Swenshuai.xi     if (!parent)
1125*53ee8cc1Swenshuai.xi     {
1126*53ee8cc1Swenshuai.xi         ms_usbhost_err("attempting to reset root hub!\n");
1127*53ee8cc1Swenshuai.xi         return -EINVAL;
1128*53ee8cc1Swenshuai.xi     }
1129*53ee8cc1Swenshuai.xi 
1130*53ee8cc1Swenshuai.xi     for (i = 0; i < parent->u32MaxChild; i++)
1131*53ee8cc1Swenshuai.xi         if (parent->children[i] == ms_dev)
1132*53ee8cc1Swenshuai.xi         {
1133*53ee8cc1Swenshuai.xi             port = i;
1134*53ee8cc1Swenshuai.xi             break;
1135*53ee8cc1Swenshuai.xi         }
1136*53ee8cc1Swenshuai.xi 
1137*53ee8cc1Swenshuai.xi     if (port < 0)
1138*53ee8cc1Swenshuai.xi         return -ENOENT;
1139*53ee8cc1Swenshuai.xi 
1140*53ee8cc1Swenshuai.xi     d_desc = (struct usb_device_descriptor*) kmalloc(sizeof *d_desc, GFP_NOIO);
1141*53ee8cc1Swenshuai.xi     if (!d_desc)
1142*53ee8cc1Swenshuai.xi     {
1143*53ee8cc1Swenshuai.xi         ms_usbhost_err("[physical reset device] No available memory!\n");
1144*53ee8cc1Swenshuai.xi         return -ENOMEM;
1145*53ee8cc1Swenshuai.xi     }
1146*53ee8cc1Swenshuai.xi 
1147*53ee8cc1Swenshuai.xi     s32Err = ms_hub_port_reset(parent, port, ms_dev, HUB_SHORT_RESET_TIME);
1148*53ee8cc1Swenshuai.xi     if (s32Err)
1149*53ee8cc1Swenshuai.xi     {
1150*53ee8cc1Swenshuai.xi         ms_usbhost_err("hub port[%d] reset fail, to disable the port (error=%d)\n", (int)port, (int)s32Err);
1151*53ee8cc1Swenshuai.xi         ms_hub_port_disable(parent, port);
1152*53ee8cc1Swenshuai.xi         kfree(d_desc);
1153*53ee8cc1Swenshuai.xi         return -ENODEV;
1154*53ee8cc1Swenshuai.xi     }
1155*53ee8cc1Swenshuai.xi 
1156*53ee8cc1Swenshuai.xi     diag_printf("Re-enumerating...\n");
1157*53ee8cc1Swenshuai.xi     s32Err = ms_usb_set_address(ms_dev);
1158*53ee8cc1Swenshuai.xi     if (s32Err < 0)
1159*53ee8cc1Swenshuai.xi     {
1160*53ee8cc1Swenshuai.xi         ms_usbhost_err("USB device not accepting new address (error=%d)\n", (int)s32Err);
1161*53ee8cc1Swenshuai.xi         ms_hub_port_disable(parent, port);
1162*53ee8cc1Swenshuai.xi         kfree(d_desc);
1163*53ee8cc1Swenshuai.xi         /* prevent usb_port_reset to be submitted */
1164*53ee8cc1Swenshuai.xi         if (s32Err == -ETIMEDOUT)
1165*53ee8cc1Swenshuai.xi             s32Err = -ENODEV;
1166*53ee8cc1Swenshuai.xi         return s32Err;
1167*53ee8cc1Swenshuai.xi     }
1168*53ee8cc1Swenshuai.xi 
1169*53ee8cc1Swenshuai.xi     wait_ms(10);
1170*53ee8cc1Swenshuai.xi 
1171*53ee8cc1Swenshuai.xi     s32Err = ms_usb_get_descriptor(ms_dev, USB_DT_DEVICE, 0, d_desc, sizeof(*d_desc));
1172*53ee8cc1Swenshuai.xi     if (s32Err < 0)
1173*53ee8cc1Swenshuai.xi     {
1174*53ee8cc1Swenshuai.xi         ms_usbhost_err("USB device not getting device descriptor (error=%d)\n", (int)s32Err);
1175*53ee8cc1Swenshuai.xi         kfree(d_desc);
1176*53ee8cc1Swenshuai.xi         return s32Err;
1177*53ee8cc1Swenshuai.xi     }
1178*53ee8cc1Swenshuai.xi 
1179*53ee8cc1Swenshuai.xi     /* no need to do endien transform */
1180*53ee8cc1Swenshuai.xi     //d_desc->bcdUSB = d_desc->bcdUSB;
1181*53ee8cc1Swenshuai.xi     //d_desc->idVendor = d_desc->idVendor;
1182*53ee8cc1Swenshuai.xi     //d_desc->idProduct = d_desc->idProduct;
1183*53ee8cc1Swenshuai.xi     //d_desc->bcdDevice = d_desc->bcdDevice;
1184*53ee8cc1Swenshuai.xi 
1185*53ee8cc1Swenshuai.xi     /* this part is for re-enumeration, descriptor changed */
1186*53ee8cc1Swenshuai.xi     if (memcmp(&ms_dev->descriptor, d_desc, sizeof(*d_desc)))
1187*53ee8cc1Swenshuai.xi     {
1188*53ee8cc1Swenshuai.xi         kfree(d_desc);
1189*53ee8cc1Swenshuai.xi         ms_usb_destroy_config(ms_dev);
1190*53ee8cc1Swenshuai.xi 
1191*53ee8cc1Swenshuai.xi         s32Err = ms_usb_get_dev_descriptor(ms_dev);
1192*53ee8cc1Swenshuai.xi         if ((U32) s32Err < sizeof(ms_dev->descriptor))
1193*53ee8cc1Swenshuai.xi         {
1194*53ee8cc1Swenshuai.xi             if (s32Err < 0)
1195*53ee8cc1Swenshuai.xi             {
1196*53ee8cc1Swenshuai.xi                 ms_usbhost_err("unable to get device %s descriptor (error=%d)\n",
1197*53ee8cc1Swenshuai.xi                     ms_dev->devpath, (int)s32Err);
1198*53ee8cc1Swenshuai.xi             }
1199*53ee8cc1Swenshuai.xi             else
1200*53ee8cc1Swenshuai.xi                 ms_usbhost_msg("USB device %s descriptor short read "
1201*53ee8cc1Swenshuai.xi                     "(expected %i, got %i)\n",
1202*53ee8cc1Swenshuai.xi                     ms_dev->devpath, sizeof(ms_dev->descriptor), (int)s32Err);
1203*53ee8cc1Swenshuai.xi 
1204*53ee8cc1Swenshuai.xi             //ms_clear_bit(ms_dev->u32DevNum, ms_dev->bus->devmap.usb_devicemap,U32);
1205*53ee8cc1Swenshuai.xi             ms_devmap_clear_bit(ms_dev->u32DevNum, ms_dev->bus->devmap.usb_devicemap);
1206*53ee8cc1Swenshuai.xi             ms_dev->u32DevNum = -1;
1207*53ee8cc1Swenshuai.xi             return -EIO;
1208*53ee8cc1Swenshuai.xi         }
1209*53ee8cc1Swenshuai.xi 
1210*53ee8cc1Swenshuai.xi         s32Err = ms_usb_get_config(ms_dev);
1211*53ee8cc1Swenshuai.xi         if (s32Err < 0)
1212*53ee8cc1Swenshuai.xi         {
1213*53ee8cc1Swenshuai.xi             ms_usbhost_err("unable to get configuration (error=%d)\n", (int)s32Err);
1214*53ee8cc1Swenshuai.xi             ms_usb_destroy_config(ms_dev);
1215*53ee8cc1Swenshuai.xi             //ms_clear_bit(ms_dev->u32DevNum, ms_dev->bus->devmap.usb_devicemap,U32);
1216*53ee8cc1Swenshuai.xi             ms_devmap_clear_bit(ms_dev->u32DevNum, ms_dev->bus->devmap.usb_devicemap);
1217*53ee8cc1Swenshuai.xi             ms_dev->u32DevNum = -1;
1218*53ee8cc1Swenshuai.xi             return 1;
1219*53ee8cc1Swenshuai.xi         }
1220*53ee8cc1Swenshuai.xi 
1221*53ee8cc1Swenshuai.xi         //if(ms_dev->descriptor.bDeviceClass == USB_CLASS_COMM)
1222*53ee8cc1Swenshuai.xi         //    ms_usb_set_config(ms_dev, ms_dev->config[1].desc.bConfigurationValue);
1223*53ee8cc1Swenshuai.xi         //else
1224*53ee8cc1Swenshuai.xi             ms_usb_set_config(ms_dev, ms_dev->config[0].desc.bConfigurationValue);
1225*53ee8cc1Swenshuai.xi         return 1;
1226*53ee8cc1Swenshuai.xi     }
1227*53ee8cc1Swenshuai.xi 
1228*53ee8cc1Swenshuai.xi     kfree(d_desc);
1229*53ee8cc1Swenshuai.xi 
1230*53ee8cc1Swenshuai.xi     s32Err = ms_usb_set_config(ms_dev, ms_dev->actconfig->desc.bConfigurationValue);
1231*53ee8cc1Swenshuai.xi     diag_printf("usb_physical_reset_device done\n");
1232*53ee8cc1Swenshuai.xi     return 0;
1233*53ee8cc1Swenshuai.xi }
1234*53ee8cc1Swenshuai.xi 
1235*53ee8cc1Swenshuai.xi /**
1236*53ee8cc1Swenshuai.xi      * @brief               usb reset function
1237*53ee8cc1Swenshuai.xi      *
1238*53ee8cc1Swenshuai.xi      * @param           struct usb_device *ms_dev
1239*53ee8cc1Swenshuai.xi      *
1240*53ee8cc1Swenshuai.xi      * @return          error code
1241*53ee8cc1Swenshuai.xi      */
ms_usb_reset_device(struct usb_device * ms_dev)1242*53ee8cc1Swenshuai.xi int ms_usb_reset_device(struct usb_device *ms_dev)
1243*53ee8cc1Swenshuai.xi {
1244*53ee8cc1Swenshuai.xi     int retval;
1245*53ee8cc1Swenshuai.xi 
1246*53ee8cc1Swenshuai.xi     ms_usbhost_debug("ms_usb_reset_device\n");
1247*53ee8cc1Swenshuai.xi 
1248*53ee8cc1Swenshuai.xi 	if (ms_dev->eState == USB_STATE_NOTATTACHED ||
1249*53ee8cc1Swenshuai.xi 			ms_dev->eState == USB_STATE_SUSPENDED) {
1250*53ee8cc1Swenshuai.xi 		ms_usbhost_err("device reset not allowed in state %d\n",
1251*53ee8cc1Swenshuai.xi 				ms_dev->eState);
1252*53ee8cc1Swenshuai.xi 		return -EINVAL;
1253*53ee8cc1Swenshuai.xi 	}
1254*53ee8cc1Swenshuai.xi 
1255*53ee8cc1Swenshuai.xi     /* unbind interface */
1256*53ee8cc1Swenshuai.xi 
1257*53ee8cc1Swenshuai.xi     retval = ms_usb_physical_reset_device(ms_dev);
1258*53ee8cc1Swenshuai.xi 
1259*53ee8cc1Swenshuai.xi     /* rebind interface */
1260*53ee8cc1Swenshuai.xi 
1261*53ee8cc1Swenshuai.xi     return retval;
1262*53ee8cc1Swenshuai.xi }
1263*53ee8cc1Swenshuai.xi 
1264*53ee8cc1Swenshuai.xi /**
1265*53ee8cc1Swenshuai.xi      * @brief               hub events process
1266*53ee8cc1Swenshuai.xi      *
1267*53ee8cc1Swenshuai.xi      * @param           struct s_gVar4UsbPort *pRootHub
1268*53ee8cc1Swenshuai.xi      *
1269*53ee8cc1Swenshuai.xi      * @return          none
1270*53ee8cc1Swenshuai.xi      */
ms_hub_events(struct s_gVar4UsbPort * pRootHub)1271*53ee8cc1Swenshuai.xi static int ms_hub_events(struct s_gVar4UsbPort *pRootHub)
1272*53ee8cc1Swenshuai.xi {
1273*53ee8cc1Swenshuai.xi     U32 flags;
1274*53ee8cc1Swenshuai.xi     struct list_head *tmp_list = &pRootHub->hub_event;
1275*53ee8cc1Swenshuai.xi     struct list_head *list_t;
1276*53ee8cc1Swenshuai.xi     struct usb_device *ms_dev;
1277*53ee8cc1Swenshuai.xi     struct usb_hub *hub;
1278*53ee8cc1Swenshuai.xi     U16 hubstatus;
1279*53ee8cc1Swenshuai.xi     U16 hubchange;
1280*53ee8cc1Swenshuai.xi     U16 u16Portstatus;
1281*53ee8cc1Swenshuai.xi     U16 u16Portchange;
1282*53ee8cc1Swenshuai.xi     S32 i, s32Err;
1283*53ee8cc1Swenshuai.xi     S32 isHubConnEvent = 0;
1284*53ee8cc1Swenshuai.xi 
1285*53ee8cc1Swenshuai.xi     while (1)
1286*53ee8cc1Swenshuai.xi     {
1287*53ee8cc1Swenshuai.xi         osapi_spin_lock_irqsave(&hub_event_lock, flags);
1288*53ee8cc1Swenshuai.xi         if (ms_is_empty_list(tmp_list))
1289*53ee8cc1Swenshuai.xi         {
1290*53ee8cc1Swenshuai.xi             osapi_spin_unlock_irqrestore(&hub_event_lock, flags);
1291*53ee8cc1Swenshuai.xi             break;
1292*53ee8cc1Swenshuai.xi         }
1293*53ee8cc1Swenshuai.xi 
1294*53ee8cc1Swenshuai.xi         list_t = tmp_list->next;
1295*53ee8cc1Swenshuai.xi         hub = entry_to_container(list_t, struct usb_hub, event_list);
1296*53ee8cc1Swenshuai.xi         ms_dev = interface_to_usbdev(hub->intf);
1297*53ee8cc1Swenshuai.xi         ms_list_remove_and_init(list_t);
1298*53ee8cc1Swenshuai.xi         osapi_spin_unlock_irqrestore(&hub_event_lock, flags);
1299*53ee8cc1Swenshuai.xi 
1300*53ee8cc1Swenshuai.xi         if (hub->error)
1301*53ee8cc1Swenshuai.xi         {
1302*53ee8cc1Swenshuai.xi             ms_usbhost_debug ("resetting for error %d\n", hub->error);
1303*53ee8cc1Swenshuai.xi 
1304*53ee8cc1Swenshuai.xi             if (ms_hub_reset(hub))
1305*53ee8cc1Swenshuai.xi             {
1306*53ee8cc1Swenshuai.xi                 ms_usbhost_err("can't reset; disconnecting\n");
1307*53ee8cc1Swenshuai.xi                 ms_hub_start_disconnect(ms_dev);
1308*53ee8cc1Swenshuai.xi                 continue;
1309*53ee8cc1Swenshuai.xi             }
1310*53ee8cc1Swenshuai.xi 
1311*53ee8cc1Swenshuai.xi             hub->nerrors = 0;
1312*53ee8cc1Swenshuai.xi             hub->error = 0;
1313*53ee8cc1Swenshuai.xi         }
1314*53ee8cc1Swenshuai.xi 
1315*53ee8cc1Swenshuai.xi         ms_usbhost_debug("**EX** get hub event:%s at port %d\n",
1316*53ee8cc1Swenshuai.xi                 ms_dev->devpath, pRootHub->hostid);
1317*53ee8cc1Swenshuai.xi 
1318*53ee8cc1Swenshuai.xi         if (ms_dev->parent == NULL)
1319*53ee8cc1Swenshuai.xi             ms_usbhost_debug("<saved irq> portsc[0x%4x], usbcmd[%x]\n",
1320*53ee8cc1Swenshuai.xi                 pRootHub->p_UsbHcd->saved_ehci_state.iPsc,
1321*53ee8cc1Swenshuai.xi                 pRootHub->p_UsbHcd->saved_ehci_state.usbcmd);
1322*53ee8cc1Swenshuai.xi 
1323*53ee8cc1Swenshuai.xi         for (i = 0; i < hub->descriptor.bNbrPorts; i++)
1324*53ee8cc1Swenshuai.xi         {
1325*53ee8cc1Swenshuai.xi             int connect_change = 0;
1326*53ee8cc1Swenshuai.xi 
1327*53ee8cc1Swenshuai.xi             s32Err = ms_hub_port_status(ms_dev, i, &u16Portstatus, &u16Portchange);
1328*53ee8cc1Swenshuai.xi             if ((ms_dev->parent == NULL) &&
1329*53ee8cc1Swenshuai.xi                 (pRootHub->p_UsbHcd->saved_ehci_state.iPsc & 0x2) &&
1330*53ee8cc1Swenshuai.xi                 ((u16Portchange & USB_PORT_STAT_C_CONNECTION)==0) &&
1331*53ee8cc1Swenshuai.xi                 ((u16Portstatus & USB_PORT_STAT_CONNECTION)==0))
1332*53ee8cc1Swenshuai.xi             {
1333*53ee8cc1Swenshuai.xi                 diag_printf("current u16Portchange [0x%4x], u16Portstatus [0x%4x] s32Err %d\n", u16Portchange, u16Portstatus, s32Err);
1334*53ee8cc1Swenshuai.xi                 u16Portchange |= USB_PORT_STAT_C_CONNECTION;
1335*53ee8cc1Swenshuai.xi             }
1336*53ee8cc1Swenshuai.xi             if (s32Err < 0)
1337*53ee8cc1Swenshuai.xi             {
1338*53ee8cc1Swenshuai.xi                 continue;
1339*53ee8cc1Swenshuai.xi             }
1340*53ee8cc1Swenshuai.xi             if (u16Portchange & USB_PORT_STAT_C_CONNECTION)
1341*53ee8cc1Swenshuai.xi             {
1342*53ee8cc1Swenshuai.xi                 // (USB_PORT_FEAT_C_CONNECTION)
1343*53ee8cc1Swenshuai.xi                 ms_usb_control_cmd(ms_dev, usb_sndctrlpipe(ms_dev, 0),
1344*53ee8cc1Swenshuai.xi                     USB_REQ_CLEAR_FEATURE, USB_RT_PORT, USB_PORT_FEAT_C_CONNECTION, i + 1, NULL, 0, HZ);
1345*53ee8cc1Swenshuai.xi                 connect_change = 1;
1346*53ee8cc1Swenshuai.xi             }
1347*53ee8cc1Swenshuai.xi             if (u16Portchange & USB_PORT_STAT_C_ENABLE)
1348*53ee8cc1Swenshuai.xi             {
1349*53ee8cc1Swenshuai.xi                 ms_usbhost_debug ("port %d enable change, status %x\n", i + 1, u16Portstatus);
1350*53ee8cc1Swenshuai.xi                 // (USB_PORT_FEAT_C_ENABLE)
1351*53ee8cc1Swenshuai.xi                 ms_usb_control_cmd(ms_dev, usb_sndctrlpipe(ms_dev, 0),
1352*53ee8cc1Swenshuai.xi                     USB_REQ_CLEAR_FEATURE, USB_RT_PORT, USB_PORT_FEAT_C_ENABLE, i + 1, NULL, 0, HZ);
1353*53ee8cc1Swenshuai.xi 
1354*53ee8cc1Swenshuai.xi                 if (!(u16Portstatus & USB_PORT_STAT_ENABLE)
1355*53ee8cc1Swenshuai.xi                     && (u16Portstatus & USB_PORT_STAT_CONNECTION)
1356*53ee8cc1Swenshuai.xi                     && (ms_dev->children[i]))
1357*53ee8cc1Swenshuai.xi                 {
1358*53ee8cc1Swenshuai.xi                     ms_usbhost_err("port %d disabled by hub (EMI?), re-enabling...\n", (int)i + 1);
1359*53ee8cc1Swenshuai.xi                     connect_change = 1;
1360*53ee8cc1Swenshuai.xi                 }
1361*53ee8cc1Swenshuai.xi             }
1362*53ee8cc1Swenshuai.xi 
1363*53ee8cc1Swenshuai.xi             if (u16Portchange & USB_PORT_STAT_C_SUSPEND)
1364*53ee8cc1Swenshuai.xi             {
1365*53ee8cc1Swenshuai.xi                 ms_usbhost_debug ("suspend change on port %d\n", i + 1);
1366*53ee8cc1Swenshuai.xi                 // (USB_PORT_FEAT_C_SUSPEND)
1367*53ee8cc1Swenshuai.xi                 ms_usb_control_cmd(ms_dev, usb_sndctrlpipe(ms_dev, 0),
1368*53ee8cc1Swenshuai.xi                     USB_REQ_CLEAR_FEATURE, USB_RT_PORT, USB_PORT_FEAT_C_SUSPEND, i + 1, NULL, 0, HZ);
1369*53ee8cc1Swenshuai.xi             }
1370*53ee8cc1Swenshuai.xi 
1371*53ee8cc1Swenshuai.xi             if (u16Portchange & USB_PORT_STAT_C_OVERCURRENT)
1372*53ee8cc1Swenshuai.xi             {
1373*53ee8cc1Swenshuai.xi                 ms_usbhost_err("over-current change on port %d\n", (int)i + 1);
1374*53ee8cc1Swenshuai.xi                 // (USB_PORT_FEAT_C_OVER_CURRENT)
1375*53ee8cc1Swenshuai.xi                 ms_usb_control_cmd(ms_dev, usb_sndctrlpipe(ms_dev, 0),
1376*53ee8cc1Swenshuai.xi                     USB_REQ_CLEAR_FEATURE, USB_RT_PORT, USB_PORT_FEAT_C_OVER_CURRENT, i + 1, NULL, 0, HZ);
1377*53ee8cc1Swenshuai.xi                 ms_hub_power_on(hub);
1378*53ee8cc1Swenshuai.xi             }
1379*53ee8cc1Swenshuai.xi 
1380*53ee8cc1Swenshuai.xi             if (u16Portchange & USB_PORT_STAT_C_RESET)
1381*53ee8cc1Swenshuai.xi             {
1382*53ee8cc1Swenshuai.xi                 ms_usbhost_debug ("reset change on port %d\n", i + 1);
1383*53ee8cc1Swenshuai.xi                 // (USB_PORT_FEAT_C_RESET)
1384*53ee8cc1Swenshuai.xi                 ms_usb_control_cmd(ms_dev, usb_sndctrlpipe(ms_dev, 0),
1385*53ee8cc1Swenshuai.xi                     USB_REQ_CLEAR_FEATURE, USB_RT_PORT, USB_PORT_FEAT_C_RESET, i + 1, NULL, 0, HZ);
1386*53ee8cc1Swenshuai.xi             }
1387*53ee8cc1Swenshuai.xi             if (connect_change) {
1388*53ee8cc1Swenshuai.xi                 struct usb_device *pUdev;
1389*53ee8cc1Swenshuai.xi 
1390*53ee8cc1Swenshuai.xi                 pUdev = ms_hub_port_connect_change(hub, i, u16Portstatus, u16Portchange);
1391*53ee8cc1Swenshuai.xi                 if ((pUdev != NULL) && (u16Portstatus & USB_PORT_STAT_CONNECTION))
1392*53ee8cc1Swenshuai.xi                 {
1393*53ee8cc1Swenshuai.xi                     pRootHub->arConnDev[isHubConnEvent].connDev = pUdev;
1394*53ee8cc1Swenshuai.xi                     isHubConnEvent++;
1395*53ee8cc1Swenshuai.xi                     USB_ASSERT(isHubConnEvent<USB_MAXCHILDREN, "exceed the size of arConnDev!!!!\n");
1396*53ee8cc1Swenshuai.xi                 }
1397*53ee8cc1Swenshuai.xi             }
1398*53ee8cc1Swenshuai.xi         } /* end for i */
1399*53ee8cc1Swenshuai.xi 
1400*53ee8cc1Swenshuai.xi         if (ms_hub_hub_status(hub, &hubstatus, &hubchange) < 0)
1401*53ee8cc1Swenshuai.xi         {
1402*53ee8cc1Swenshuai.xi             ms_usbhost_err("get_hub_status failed\n");
1403*53ee8cc1Swenshuai.xi         }
1404*53ee8cc1Swenshuai.xi         else
1405*53ee8cc1Swenshuai.xi         {
1406*53ee8cc1Swenshuai.xi             if (hubchange & HUB_CHANGE_LOCAL_POWER)
1407*53ee8cc1Swenshuai.xi             {
1408*53ee8cc1Swenshuai.xi                 ms_usbhost_debug ("power change\n");
1409*53ee8cc1Swenshuai.xi                 // (C_HUB_LOCAL_POWER)
1410*53ee8cc1Swenshuai.xi                 ms_usb_control_cmd(ms_dev, usb_sndctrlpipe(ms_dev, 0),
1411*53ee8cc1Swenshuai.xi                     USB_REQ_CLEAR_FEATURE, USB_RT_HUB, C_HUB_LOCAL_POWER, 0, NULL, 0, HZ);
1412*53ee8cc1Swenshuai.xi             }
1413*53ee8cc1Swenshuai.xi 
1414*53ee8cc1Swenshuai.xi             if (hubchange & HUB_CHANGE_OVERCURRENT)
1415*53ee8cc1Swenshuai.xi             {
1416*53ee8cc1Swenshuai.xi                 ms_usbhost_debug ("overcurrent change\n");
1417*53ee8cc1Swenshuai.xi                 // (C_HUB_OVER_CURRENT)
1418*53ee8cc1Swenshuai.xi                 ms_usb_control_cmd(ms_dev, usb_sndctrlpipe(ms_dev, 0),
1419*53ee8cc1Swenshuai.xi                     USB_REQ_CLEAR_FEATURE, USB_RT_HUB, C_HUB_OVER_CURRENT, 0, NULL, 0, HZ);
1420*53ee8cc1Swenshuai.xi                 wait_ms(500); // to be cool down
1421*53ee8cc1Swenshuai.xi                 ms_hub_power_on(hub);
1422*53ee8cc1Swenshuai.xi             }
1423*53ee8cc1Swenshuai.xi         }
1424*53ee8cc1Swenshuai.xi     } /* end while (1) */
1425*53ee8cc1Swenshuai.xi 
1426*53ee8cc1Swenshuai.xi     return (isHubConnEvent);
1427*53ee8cc1Swenshuai.xi }
1428*53ee8cc1Swenshuai.xi 
1429*53ee8cc1Swenshuai.xi #ifdef USB_EHCI_TT
1430*53ee8cc1Swenshuai.xi static void ms_hub_tt_kevent(struct s_gVar4UsbPort *);
1431*53ee8cc1Swenshuai.xi #endif
1432*53ee8cc1Swenshuai.xi /**
1433*53ee8cc1Swenshuai.xi      * @brief               hub event polling from UsbTask
1434*53ee8cc1Swenshuai.xi      *
1435*53ee8cc1Swenshuai.xi      * @param           struct s_gVar4UsbPort *pRootHub
1436*53ee8cc1Swenshuai.xi      *
1437*53ee8cc1Swenshuai.xi      * @return          # of device connected
1438*53ee8cc1Swenshuai.xi      */
ms_hub_poll(struct s_gVar4UsbPort * pRootHub)1439*53ee8cc1Swenshuai.xi int ms_hub_poll(struct s_gVar4UsbPort *pRootHub)
1440*53ee8cc1Swenshuai.xi {
1441*53ee8cc1Swenshuai.xi     S32 isHubConnected = 0;
1442*53ee8cc1Swenshuai.xi     struct list_head *tmp_list = &pRootHub->hub_event;
1443*53ee8cc1Swenshuai.xi 
1444*53ee8cc1Swenshuai.xi     if (ms_is_empty_list(tmp_list))
1445*53ee8cc1Swenshuai.xi         return 0;
1446*53ee8cc1Swenshuai.xi 
1447*53ee8cc1Swenshuai.xi     ms_USBCriticalSectionIn(pRootHub->hostid);
1448*53ee8cc1Swenshuai.xi     isHubConnected = ms_hub_events(pRootHub);
1449*53ee8cc1Swenshuai.xi #ifdef USB_EHCI_TT
1450*53ee8cc1Swenshuai.xi     ms_hub_tt_kevent(pRootHub);
1451*53ee8cc1Swenshuai.xi #endif
1452*53ee8cc1Swenshuai.xi     ms_USBCriticalSectionOut(pRootHub->hostid);
1453*53ee8cc1Swenshuai.xi     return (isHubConnected);
1454*53ee8cc1Swenshuai.xi }
1455*53ee8cc1Swenshuai.xi 
1456*53ee8cc1Swenshuai.xi #ifdef USB_EHCI_TT
1457*53ee8cc1Swenshuai.xi /**
1458*53ee8cc1Swenshuai.xi      * @brief           high speed hub tt buffer clear
1459*53ee8cc1Swenshuai.xi      *
1460*53ee8cc1Swenshuai.xi      * @param           struct usb_device *ms_dev
1461*53ee8cc1Swenshuai.xi      * @param           int ms_pipe
1462*53ee8cc1Swenshuai.xi      *
1463*53ee8cc1Swenshuai.xi      * @return          none
1464*53ee8cc1Swenshuai.xi      */
ms_usb_hub_tt_clear_buffer(struct usb_device * ms_dev,int ms_pipe)1465*53ee8cc1Swenshuai.xi void ms_usb_hub_tt_clear_buffer (struct usb_device *ms_dev, int ms_pipe)
1466*53ee8cc1Swenshuai.xi {
1467*53ee8cc1Swenshuai.xi     struct usb_tt    *utt = ms_dev->tt;
1468*53ee8cc1Swenshuai.xi     U32    flags;
1469*53ee8cc1Swenshuai.xi     struct usb_tt_clear  *ms_clear;
1470*53ee8cc1Swenshuai.xi     struct usb_hcd *hcd = (struct usb_hcd*) ms_dev->bus->hcpriv;
1471*53ee8cc1Swenshuai.xi 
1472*53ee8cc1Swenshuai.xi     diag_printf("%s++\n",__FUNCTION__);
1473*53ee8cc1Swenshuai.xi     if ((ms_clear = kmalloc (sizeof *ms_clear, GFP_ATOMIC)) == 0)
1474*53ee8cc1Swenshuai.xi     {
1475*53ee8cc1Swenshuai.xi         ms_usbhost_err("can't allocate CLEAR_TT_BUFFER state for hub at usb-%s-%s\n",
1476*53ee8cc1Swenshuai.xi             ms_dev->bus->bus_name, utt->hub->devpath);
1477*53ee8cc1Swenshuai.xi         return;
1478*53ee8cc1Swenshuai.xi     }
1479*53ee8cc1Swenshuai.xi 
1480*53ee8cc1Swenshuai.xi     ms_clear->tt = utt->multi ? ms_dev->u32TTPort : 1;
1481*53ee8cc1Swenshuai.xi     ms_clear->devinfo = usb_pipeendpoint (ms_pipe);
1482*53ee8cc1Swenshuai.xi     ms_clear->devinfo |= ms_dev->u32DevNum << 4;
1483*53ee8cc1Swenshuai.xi     ms_clear->devinfo |= usb_pipecontrol (ms_pipe)
1484*53ee8cc1Swenshuai.xi         ? (USB_ENDPOINT_XFER_CONTROL << 11)
1485*53ee8cc1Swenshuai.xi         : (USB_ENDPOINT_XFER_BULK << 11);
1486*53ee8cc1Swenshuai.xi     if (usb_pipein (ms_pipe))
1487*53ee8cc1Swenshuai.xi         ms_clear->devinfo |= 1 << 15;
1488*53ee8cc1Swenshuai.xi 
1489*53ee8cc1Swenshuai.xi     osapi_spin_lock_irqsave (&utt->lock, flags);
1490*53ee8cc1Swenshuai.xi     ms_insert_list_before (&ms_clear->clear_list, &utt->clear_list);
1491*53ee8cc1Swenshuai.xi     //schedule_work (&utt->kevent);
1492*53ee8cc1Swenshuai.xi     ms_insert_list_after(&utt->clear_list, &hcd->tt_clear_list); // new, link to the right hcd
1493*53ee8cc1Swenshuai.xi     osapi_spin_unlock_irqrestore (&utt->lock, flags);
1494*53ee8cc1Swenshuai.xi }
1495*53ee8cc1Swenshuai.xi 
ms_hub_tt_kevent(struct s_gVar4UsbPort * pRootHub)1496*53ee8cc1Swenshuai.xi static void ms_hub_tt_kevent(struct s_gVar4UsbPort *pRootHub)
1497*53ee8cc1Swenshuai.xi {
1498*53ee8cc1Swenshuai.xi 	struct list_head	*tmp_list = &pRootHub->p_UsbHcd->tt_clear_list;
1499*53ee8cc1Swenshuai.xi 	struct list_head	*list_t;
1500*53ee8cc1Swenshuai.xi 	struct usb_hub		*hub;
1501*53ee8cc1Swenshuai.xi 	unsigned long		flags;
1502*53ee8cc1Swenshuai.xi 	int			limit = 100;
1503*53ee8cc1Swenshuai.xi 
1504*53ee8cc1Swenshuai.xi 	osapi_spin_lock_irqsave (&hub->tt.lock, flags);
1505*53ee8cc1Swenshuai.xi 	if (ms_is_empty_list(tmp_list)) {
1506*53ee8cc1Swenshuai.xi 		osapi_spin_unlock_irqrestore (&hub->tt.lock, flags);
1507*53ee8cc1Swenshuai.xi 		return;
1508*53ee8cc1Swenshuai.xi 	}
1509*53ee8cc1Swenshuai.xi 	list_t = tmp_list->next;
1510*53ee8cc1Swenshuai.xi 	hub = entry_to_container(list_t, struct usb_hub, event_list);
1511*53ee8cc1Swenshuai.xi 	while (--limit && !list_empty (&hub->tt.clear_list)) {
1512*53ee8cc1Swenshuai.xi 		struct list_head	*temp;
1513*53ee8cc1Swenshuai.xi 		struct usb_tt_clear	*clear;
1514*53ee8cc1Swenshuai.xi 		struct usb_device	*hdev = interface_to_usbdev(hub->intf);
1515*53ee8cc1Swenshuai.xi 		int			status;
1516*53ee8cc1Swenshuai.xi 
1517*53ee8cc1Swenshuai.xi 		temp = hub->tt.clear_list.next;
1518*53ee8cc1Swenshuai.xi 		clear = list_entry (temp, struct usb_tt_clear, clear_list);
1519*53ee8cc1Swenshuai.xi 		list_del (&clear->clear_list);
1520*53ee8cc1Swenshuai.xi 
1521*53ee8cc1Swenshuai.xi 		/* drop lock so HCD can concurrently report other TT errors */
1522*53ee8cc1Swenshuai.xi 		osapi_spin_unlock_irqrestore (&hub->tt.lock, flags);
1523*53ee8cc1Swenshuai.xi 		/* hub_clear_tt_buffer */
1524*53ee8cc1Swenshuai.xi 		status = ms_usb_control_cmd(hdev, usb_rcvctrlpipe(hdev, 0),
1525*53ee8cc1Swenshuai.xi 			       HUB_CLEAR_TT_BUFFER, USB_RT_PORT, clear->devinfo,
1526*53ee8cc1Swenshuai.xi 			       clear->tt, NULL, 0, 1000);
1527*53ee8cc1Swenshuai.xi 		osapi_spin_lock_irqsave (&hub->tt.lock, flags);
1528*53ee8cc1Swenshuai.xi 
1529*53ee8cc1Swenshuai.xi 		if (status)
1530*53ee8cc1Swenshuai.xi 			ms_usbhost_err ("clear tt %d (%04x) error %d\n",
1531*53ee8cc1Swenshuai.xi 				clear->tt, clear->devinfo, status);
1532*53ee8cc1Swenshuai.xi 		kfree(clear);
1533*53ee8cc1Swenshuai.xi 	}
1534*53ee8cc1Swenshuai.xi 	osapi_spin_unlock_irqrestore (&hub->tt.lock, flags);
1535*53ee8cc1Swenshuai.xi }
1536*53ee8cc1Swenshuai.xi 
1537*53ee8cc1Swenshuai.xi #endif
1538*53ee8cc1Swenshuai.xi 
1539