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