1 /*
2 *******************************************************************************
3 *                                              usb host module
4 *
5 *                             Copyright(C), 2006-2008, SoftWinners Co., Ltd.
6 *                                                  All Rights Reserved
7 *
8 * File Name :
9 *
10 * Author : GLHuang(HoLiGun)
11 *
12 * Version : 1.0
13 *
14 * Date : 2008.07.xx
15 *
16 * Description :
17 *
18 * History :
19 *******************************************************************************
20 */
21 //#include "usb_host_config.h"
22 
23 //#include "usb_os_platform.h"
24 #include <usb_host_common.h>
25 
26 //#include "usb_host_base_types.h"
27 //#include "usb_list.h"
28 #include <usb_host_hub.h>
29 #include <usb_utils_find_zero_bit.h>
30 #include "usb_core_base.h"
31 #include "usb_msg.h"
32 
33 #include "usb_virt_bus.h"
34 #include <usb_gen_dev_mod.h>
35 
36 #include "usb_gen_hub_base.h"
37 #include "urb.h"
38 
39 
40 
41 
42 /*
43  * USB 2.0 spec Section 11.24.2.7
44  */
45 
46 /*
47 ********************************************************************************
48 *                     get_port_status
49 * Description:
50 *     获得hub端口的状态
51 * Arguments:
52 *     hdev  : input.  hub
53 *     port1 : input.  端口号
54 *     data  : output. 用来记录端口状态
55 * Return value:
56 *     void
57 * note:
58 *     void
59 *********************************************************************************
60 */
get_port_status(struct usb_host_virt_dev * hdev,int port1,struct usb_port_status * data)61 static int get_port_status(struct usb_host_virt_dev *hdev, int port1,
62                            struct usb_port_status *data)
63 {
64     int i, status = -ETIMEDOUT;
65 
66     for (i = 0; i < USB_STS_RETRIES && status == -ETIMEDOUT; i++)
67     {
68         status = usb_control_msg(hdev,
69                                  usb_rcvctrlpipe(hdev, 0),
70                                  USB_REQ_GET_STATUS,
71                                  USB_DIR_IN | USB_RT_PORT,
72                                  0,
73                                  port1,
74                                  (void *)data,
75                                  sizeof(*data),
76                                  USB_STS_TIMEOUT);
77     }
78 
79     return status;
80 }
81 
82 /*
83 ********************************************************************************
84 *                     get_port_status
85 * Description:
86 *     获得hub端口的状态
87 * Arguments:
88 *     hdev    : input.  hub
89 *     port1   : input.  端口号
90 *     status  : output. 用来记录端口状态
91 *     change  : output. 用来记录端口的变化
92 * Return value:
93 *     void
94 * note:
95 *     void
96 *********************************************************************************
97 */
hub_port_status(struct usb_hub * hub,s32 port1,u16 * status,u16 * change)98 s32 hub_port_status(struct usb_hub *hub, s32 port1, u16 *status, u16 *change)
99 {
100     int ret;
101 
102     ret = get_port_status(hub->hdev, port1, &hub->status->port);
103 
104     if (ret < 0)
105     {
106         hal_log_err("hub_port_status() : failed (err = %d)\n",  ret);
107     }
108     else
109     {
110         *status = le16_to_cpu(hub->status->port.wPortStatus);
111         *change = le16_to_cpu(hub->status->port.wPortChange);
112         ret = 0;
113     }
114 
115     return ret;
116 }
117 
118 
119 
120 
121 
122 #ifdef  CONFIG_USB_SUSPEND
123 
124 /*
125  * Selective port suspend reduces power; most suspended devices draw
126  * less than 500 uA.  It's also used in OTG, along with remote wakeup.
127  * All devices below the suspended port are also suspended.
128  *
129  * Devices leave suspend state when the host wakes them up.  Some devices
130  * also support "remote wakeup", where the device can activate the USB
131  * tree above them to deliver data, such as a keypress or packet.  In
132  * some cases, this wakes the USB host.
133  */
134 /*
135 ********************************************************************************
136 *                     hub_port_suspend
137 * Description:
138 *     获得hub端口的状态
139 * Arguments:
140 *     hdev    : input.  hub
141 *     port1   : input.  端口号
142 *     status  : output. 用来记录端口状态
143 *     change  : output. 用来记录端口的变化
144 * Return value:
145 *     void
146 * note:
147 *     void
148 *********************************************************************************
149 */
hub_port_suspend(struct usb_hub * hub,int port1,struct usb_device * udev)150 static int hub_port_suspend(struct usb_hub *hub, int port1, struct usb_device *udev)
151 {
152     int status;
153 
154     // dev_dbg(hub->intfdev, "suspend port %d\n", port1);
155 
156     /* enable remote wakeup when appropriate; this lets the device
157      * wake up the upstream hub (including maybe the root hub).
158      *
159      * NOTE:  OTG devices may issue remote wakeup (or SRP) even when
160      * we don't explicitly enable it here.
161      */
162     if (udev->actconfig
163         // && FIXME (remote wakeup enabled on this bus)
164         // ... currently assuming it's always appropriate
165         && (udev->actconfig->desc.bmAttributes
166             & USB_CONFIG_ATT_WAKEUP) != 0)
167     {
168         status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
169                                  USB_REQ_SET_FEATURE, USB_RECIP_DEVICE,
170                                  USB_DEVICE_REMOTE_WAKEUP, 0,
171                                  NULL, 0,
172                                  USB_CTRL_SET_TIMEOUT);
173 
174         if (status)
175             dev_dbg(&udev->dev,
176                     "won't remote wakeup, status %d\n",
177                     status);
178     }
179 
180     /* see 7.1.7.6 */
181     status = set_port_feature(hub->hdev, port1, USB_PORT_FEAT_SUSPEND);
182 
183     if (status)
184     {
185         dev_dbg(hub->intfdev,
186                 "can't suspend port %d, status %d\n",
187                 port1, status);
188         /* paranoia:  "should not happen" */
189         (void) usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
190                                USB_REQ_CLEAR_FEATURE, USB_RECIP_DEVICE,
191                                USB_DEVICE_REMOTE_WAKEUP, 0,
192                                NULL, 0,
193                                USB_CTRL_SET_TIMEOUT);
194     }
195     else
196     {
197         /* device has up to 10 msec to fully suspend */
198         dev_dbg(&udev->dev, "usb suspend\n");
199         usb_set_device_state(udev, USB_STATE_SUSPENDED);
200         msleep(10);
201     }
202 
203     return status;
204 }
205 
206 /*
207  * Devices on USB hub ports have only one "suspend" state, corresponding
208  * to ACPI D2, "may cause the device to lose some context".
209  * State transitions include:
210  *
211  *   - suspend, resume ... when the VBUS power link stays live
212  *   - suspend, disconnect ... VBUS lost
213  *
214  * Once VBUS drop breaks the circuit, the port it's using has to go through
215  * normal re-enumeration procedures, starting with enabling VBUS power.
216  * Other than re-initializing the hub (plug/unplug, except for root hubs),
217  * Linux (2.6) currently has NO mechanisms to initiate that:  no khubd
218  * timer, no SRP, no requests through sysfs.
219  */
__usb_suspend_device(struct usb_device * udev,int port1,pm_message_t state)220 static int __usb_suspend_device(struct usb_device *udev, int port1,
221                                 pm_message_t state)
222 {
223     int status;
224 
225     /* caller owns the udev device lock */
226     if (port1 < 0)
227     {
228         return port1;
229     }
230 
231     if (udev->state == USB_STATE_SUSPENDED
232         || udev->state == USB_STATE_NOTATTACHED)
233     {
234         return 0;
235     }
236 
237     /* suspend interface drivers; if this is a hub, it
238      * suspends the child devices
239      */
240     if (udev->actconfig)
241     {
242         int i;
243 
244         for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++)
245         {
246             struct usb_interface    *intf;
247             struct usb_driver   *driver;
248             intf = udev->actconfig->interface[i];
249 
250             if (state <= intf->dev.power.power_state)
251             {
252                 continue;
253             }
254 
255             if (!intf->dev.driver)
256             {
257                 continue;
258             }
259 
260             driver = to_usb_driver(intf->dev.driver);
261 
262             if (driver->suspend)
263             {
264                 status = driver->suspend(intf, state);
265 
266                 if (intf->dev.power.power_state != state
267                     || status)
268                     dev_err(&intf->dev,
269                             "suspend %d fail, code %d\n",
270                             state, status);
271             }
272 
273             /* only drivers with suspend() can ever resume();
274              * and after power loss, even they won't.
275              * bus_rescan_devices() can rebind drivers later.
276              *
277              * FIXME the PM core self-deadlocks when unbinding
278              * drivers during suspend/resume ... everything grabs
279              * dpm_sem (not a spinlock, ugh).  we want to unbind,
280              * since we know every driver's probe/disconnect works
281              * even for drivers that can't suspend.
282              */
283             if (!driver->suspend || state > PM_SUSPEND_MEM)
284             {
285 #if 1
286                 dev_warn(&intf->dev, "resume is unsafe!\n");
287 #else
288                 down_write(&usb_bus_type.rwsem);
289                 device_release_driver(&intf->dev);
290                 up_write(&usb_bus_type.rwsem);
291 #endif
292             }
293         }
294     }
295 
296     /*
297      * FIXME this needs port power off call paths too, to help force
298      * USB into the "generic" PM model.  At least for devices on
299      * ports that aren't using ganged switching (usually root hubs).
300      *
301      * NOTE: SRP-capable links should adopt more aggressive poweroff
302      * policies (when HNP doesn't apply) once we have mechanisms to
303      * turn power back on!  (Likely not before 2.7...)
304      */
305     if (state > PM_SUSPEND_MEM)
306     {
307         dev_warn(&udev->dev, "no poweroff yet, suspending instead\n");
308     }
309 
310     /* "global suspend" of the HC-to-USB interface (root hub), or
311      * "selective suspend" of just one hub-device link.
312      */
313     if (!udev->parent)
314     {
315         struct usb_bus  *bus = udev->bus;
316 
317         if (bus && bus->op->hub_suspend)
318         {
319             status = bus->op->hub_suspend(bus);
320 
321             if (status == 0)
322             {
323                 dev_dbg(&udev->dev, "usb suspend\n");
324                 usb_set_device_state(udev,
325                                      USB_STATE_SUSPENDED);
326             }
327         }
328         else
329         {
330             status = -EOPNOTSUPP;
331         }
332     }
333     else
334         status = hub_port_suspend(hdev_to_hub(udev->parent), port1,
335                                   udev);
336 
337     if (status == 0)
338     {
339         udev->dev.power.power_state = state;
340     }
341 
342     return status;
343 }
344 
345 /**
346  * usb_suspend_device - suspend a usb device
347  * @udev: device that's no longer in active use
348  * @state: PMSG_SUSPEND to suspend
349  * Context: must be able to sleep; device not locked
350  *
351  * Suspends a USB device that isn't in active use, conserving power.
352  * Devices may wake out of a suspend, if anything important happens,
353  * using the remote wakeup mechanism.  They may also be taken out of
354  * suspend by the host, using usb_resume_device().  It's also routine
355  * to disconnect devices while they are suspended.
356  *
357  * Suspending OTG devices may trigger HNP, if that's been enabled
358  * between a pair of dual-role devices.  That will change roles, such
359  * as from A-Host to A-Peripheral or from B-Host back to B-Peripheral.
360  *
361  * Returns 0 on success, else negative errno.
362  */
usb_suspend_device(struct usb_device * udev,pm_message_t state)363 int usb_suspend_device(struct usb_device *udev, pm_message_t state)
364 {
365     int port1, status;
366     port1 = locktree(udev);
367 
368     if (port1 < 0)
369     {
370         return port1;
371     }
372 
373     status = __usb_suspend_device(udev, port1, state);
374     // usb_unlock_device(udev);
375     return status;
376 }
377 
378 /*
379  * hardware resume signaling is finished, either because of selective
380  * resume (by host) or remote wakeup (by device) ... now see what changed
381  * in the tree that's rooted at this device.
382  */
finish_port_resume(struct usb_device * udev)383 static int finish_port_resume(struct usb_device *udev)
384 {
385     int status;
386     u16 devstatus;
387     /* caller owns the udev device lock */
388     dev_dbg(&udev->dev, "usb resume\n");
389     /* usb ch9 identifies four variants of SUSPENDED, based on what
390      * state the device resumes to.  Linux currently won't see the
391      * first two on the host side; they'd be inside hub_port_init()
392      * during many timeouts, but khubd can't suspend until later.
393      */
394     usb_set_device_state(udev, udev->actconfig
395                          ? USB_STATE_CONFIGURED
396                          : USB_STATE_ADDRESS);
397     udev->dev.power.power_state = PMSG_ON;
398     /* 10.5.4.5 says be sure devices in the tree are still there.
399      * For now let's assume the device didn't go crazy on resume,
400      * and device drivers will know about any resume quirks.
401      */
402     status = usb_get_status(udev, USB_RECIP_DEVICE, 0, &devstatus);
403 
404     if (status < 0)
405         dev_dbg(&udev->dev,
406                 "gone after usb resume? status %d\n",
407                 status);
408     else if (udev->actconfig)
409     {
410         unsigned    i;
411         le16_to_cpus(&devstatus);
412 
413         if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP))
414         {
415             status = usb_control_msg(udev,
416                                      usb_sndctrlpipe(udev, 0),
417                                      USB_REQ_CLEAR_FEATURE,
418                                      USB_RECIP_DEVICE,
419                                      USB_DEVICE_REMOTE_WAKEUP, 0,
420                                      NULL, 0,
421                                      USB_CTRL_SET_TIMEOUT);
422 
423             if (status)
424             {
425                 dev_dbg(&udev->dev, "disable remote "
426                         "wakeup, status %d\n", status);
427                 status = 0;
428             }
429         }
430 
431         /* resume interface drivers; if this is a hub, it
432          * resumes the child devices
433          */
434         for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++)
435         {
436             struct usb_interface    *intf;
437             struct usb_driver   *driver;
438             intf = udev->actconfig->interface[i];
439 
440             if (intf->dev.power.power_state == PMSG_ON)
441             {
442                 continue;
443             }
444 
445             if (!intf->dev.driver)
446             {
447                 /* FIXME maybe force to alt 0 */
448                 continue;
449             }
450 
451             driver = to_usb_driver(intf->dev.driver);
452 
453             /* bus_rescan_devices() may rebind drivers */
454             if (!driver->resume)
455             {
456                 continue;
457             }
458 
459             /* can we do better than just logging errors? */
460             status = driver->resume(intf);
461 
462             if (intf->dev.power.power_state != PMSG_ON
463                 || status)
464                 dev_dbg(&intf->dev,
465                         "resume fail, state %d code %d\n",
466                         intf->dev.power.power_state, status);
467         }
468 
469         status = 0;
470     }
471     else if (udev->devnum <= 0)
472     {
473         dev_dbg(&udev->dev, "bogus resume!\n");
474         status = -EINVAL;
475     }
476 
477     return status;
478 }
479 
hub_port_resume(struct usb_hub * hub,int port1,struct usb_device * udev)480 static int hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
481 {
482     int status;
483     // dev_dbg(hub->intfdev, "resume port %d\n", port1);
484     /* see 7.1.7.7; affects power usage, but not budgeting */
485     status = clear_port_feature(hub->hdev,
486                                 port1, USB_PORT_FEAT_SUSPEND);
487 
488     if (status)
489     {
490         dev_dbg(hub->intfdev,
491                 "can't resume port %d, status %d\n",
492                 port1, status);
493     }
494     else
495     {
496         u16     devstatus;
497         u16     portchange;
498 
499         /* drive resume for at least 20 msec */
500         if (udev)
501         {
502             dev_dbg(&udev->dev, "RESUME\n");
503         }
504 
505         msleep(25);
506 #define LIVE_FLAGS  ( USB_PORT_STAT_POWER \
507                       | USB_PORT_STAT_ENABLE \
508                       | USB_PORT_STAT_CONNECTION)
509         /* Virtual root hubs can trigger on GET_PORT_STATUS to
510          * stop resume signaling.  Then finish the resume
511          * sequence.
512          */
513         devstatus = portchange = 0;
514         status = hub_port_status(hub, port1,
515                                  &devstatus, &portchange);
516 
517         if (status < 0
518             || (devstatus & LIVE_FLAGS) != LIVE_FLAGS
519             || (devstatus & USB_PORT_STAT_SUSPEND) != 0
520            )
521         {
522             dev_dbg(hub->intfdev,
523                     "port %d status %04x.%04x after resume, %d\n",
524                     port1, portchange, devstatus, status);
525         }
526         else
527         {
528             /* TRSMRCY = 10 msec */
529             msleep(10);
530 
531             if (udev)
532             {
533                 status = finish_port_resume(udev);
534             }
535         }
536     }
537 
538     if (status < 0)
539     {
540         hub_port_logical_disconnect(hub, port1);
541     }
542 
543     return status;
544 }
545 
546 static int hub_resume(struct usb_interface *intf);
547 
548 /**
549  * usb_resume_device - re-activate a suspended usb device
550  * @udev: device to re-activate
551  * Context: must be able to sleep; device not locked
552  *
553  * This will re-activate the suspended device, increasing power usage
554  * while letting drivers communicate again with its endpoints.
555  * USB resume explicitly guarantees that the power session between
556  * the host and the device is the same as it was when the device
557  * suspended.
558  *
559  * Returns 0 on success, else negative errno.
560  */
usb_resume_device(struct usb_device * udev)561 int usb_resume_device(struct usb_device *udev)
562 {
563     int port1, status;
564     port1 = locktree(udev);
565 
566     if (port1 < 0)
567     {
568         return port1;
569     }
570 
571     /* "global resume" of the HC-to-USB interface (root hub), or
572      * selective resume of one hub-to-device port
573      */
574     if (!udev->parent)
575     {
576         struct usb_bus  *bus = udev->bus;
577 
578         if (bus && bus->op->hub_resume)
579         {
580             status = bus->op->hub_resume(bus);
581         }
582         else
583         {
584             status = -EOPNOTSUPP;
585         }
586 
587         if (status == 0)
588         {
589             dev_dbg(&udev->dev, "usb resume\n");
590             /* TRSMRCY = 10 msec */
591             msleep(10);
592             usb_set_device_state(udev, USB_STATE_CONFIGURED);
593             udev->dev.power.power_state = PMSG_ON;
594             status = hub_resume(udev
595                                 ->actconfig->interface[0]);
596         }
597     }
598     else if (udev->state == USB_STATE_SUSPENDED)
599     {
600         // NOTE this fails if parent is also suspended...
601         status = hub_port_resume(hdev_to_hub(udev->parent),
602                                  port1, udev);
603     }
604     else
605     {
606         status = 0;
607     }
608 
609     if (status < 0)
610     {
611         dev_dbg(&udev->dev, "can't resume, status %d\n",
612                 status);
613     }
614 
615     // usb_unlock_device(udev);
616 
617     /* rebind drivers that had no suspend() */
618     if (status == 0)
619     {
620         usb_lock_all_devices();
621         bus_rescan_devices(&usb_bus_type);
622         usb_unlock_all_devices();
623     }
624 
625     return status;
626 }
627 
remote_wakeup(struct usb_device * udev)628 static int remote_wakeup(struct usb_device *udev)
629 {
630     int status = 0;
631     /* don't repeat RESUME sequence if this device
632      * was already woken up by some other task
633      */
634     down(&udev->serialize);
635 
636     if (udev->state == USB_STATE_SUSPENDED)
637     {
638         dev_dbg(&udev->dev, "RESUME (wakeup)\n");
639         /* TRSMRCY = 10 msec */
640         msleep(10);
641         status = finish_port_resume(udev);
642     }
643 
644     up(&udev->serialize);
645     return status;
646 }
647 
hub_suspend(struct usb_interface * intf,pm_message_t state)648 static __s32 hub_suspend(struct usb_interface *intf, pm_message_t state)
649 {
650     struct usb_hub      *hub = usb_mod_usb_get_intf_priv_data(intf);
651     struct usb_device   *hdev = hub->hdev;
652     unsigned        port1;
653     int         status;
654     /* stop khubd and related activity */
655     hub_quiesce(hub);
656 
657     /* then suspend every port */
658     for (port1 = 1; port1 <= hdev->maxchild; port1++)
659     {
660         struct usb_device   *udev;
661         udev = hdev->children [port1 - 1];
662 
663         if (!udev)
664         {
665             continue;
666         }
667 
668         down(&udev->serialize);
669         status = __usb_suspend_device(udev, port1, state);
670         up(&udev->serialize);
671 
672         if (status < 0)
673             dev_dbg(&intf->dev, "suspend port %d --> %d\n",
674                     port1, status);
675     }
676 
677     intf->dev.power.power_state = state;
678     return 0;
679 }
680 
hub_resume(struct usb_interface * intf)681 static int hub_resume(struct usb_interface *intf)
682 {
683     struct usb_device   *hdev = usb_mod_interface_to_usbdev(intf);
684     struct usb_hub      *hub = usb_mod_usb_get_intf_priv_data(intf);
685     unsigned        port1;
686     int         status;
687 
688     if (intf->dev.power.power_state == PM_SUSPEND_ON)
689     {
690         return 0;
691     }
692 
693     for (port1 = 1; port1 <= hdev->maxchild; port1++)
694     {
695         struct usb_device   *udev;
696         u16         portstat, portchange;
697         udev = hdev->children [port1 - 1];
698         status = hub_port_status(hub, port1, &portstat, &portchange);
699 
700         if (status == 0)
701         {
702             if (portchange & USB_PORT_STAT_C_SUSPEND)
703             {
704                 clear_port_feature(hdev, port1,
705                                    USB_PORT_FEAT_C_SUSPEND);
706                 portchange &= ~USB_PORT_STAT_C_SUSPEND;
707             }
708 
709             /* let khubd handle disconnects etc */
710             if (portchange)
711             {
712                 continue;
713             }
714         }
715 
716         if (!udev || status < 0)
717         {
718             continue;
719         }
720 
721         down(&udev->serialize);
722 
723         if (portstat & USB_PORT_STAT_SUSPEND)
724         {
725             status = hub_port_resume(hub, port1, udev);
726         }
727         else
728         {
729             status = finish_port_resume(udev);
730 
731             if (status < 0)
732             {
733                 dev_dbg(&intf->dev, "resume port %d --> %d\n",
734                         port1, status);
735                 hub_port_logical_disconnect(hub, port1);
736             }
737         }
738 
739         up(&udev->serialize);
740     }
741 
742     intf->dev.power.power_state = PMSG_ON;
743     hub->resume_root_hub = 0;
744     hub_activate(hub);
745     return 0;
746 }
747 
usb_resume_root_hub(struct usb_device * hdev)748 void usb_resume_root_hub(struct usb_device *hdev)
749 {
750     struct usb_hub *hub = hdev_to_hub(hdev);
751     hub->resume_root_hub = 1;
752     kick_khubd(hub);
753 }
754 
755 #else   /* !CONFIG_USB_SUSPEND */
756 
usb_suspend_device(struct usb_host_virt_dev * virt_dev)757 s32 usb_suspend_device(struct usb_host_virt_dev *virt_dev)
758 {
759     return 0;
760 }
761 
usb_resume_device(struct usb_host_virt_dev * virt_dev)762 s32 usb_resume_device(struct usb_host_virt_dev *virt_dev)
763 {
764     return 0;
765 }
766 
767 
768 
hub_suspend(struct usb_interface * intf)769 __s32 hub_suspend(struct usb_interface *intf)
770 {
771     return 0;
772 }
773 
hub_resume(struct usb_interface * intf)774 int hub_resume(struct usb_interface *intf)
775 {
776     return 0;
777 }
778 
779 
remote_wakeup(struct usb_host_virt_dev * udev)780 int remote_wakeup(struct usb_host_virt_dev *udev)
781 {
782     return 0;
783 }
784 
785 #endif  /* CONFIG_USB_SUSPEND */
786 
787 
788 
789 
790 
791 
792 
hub_quiesce(struct usb_hub * hub)793 void hub_quiesce(struct usb_hub *hub)
794 {
795     if (hub == NULL)
796     {
797         __err("ERR: hub_quiesce: input error\n");
798         return;
799     }
800 
801     /* stop khubd and related activity */
802     hub->quiescing = 1;
803     usb_kill_urb(hub->urb);
804     /*
805         if (hub->has_indicators)
806             cancel_delayed_work(&hub->leds);
807         if (hub->has_indicators || hub->tt.hub)
808             flush_scheduled_work();
809     */
810 }
811 
812 /*
813  * USB 2.0 spec Section 11.24.2.6
814  */
get_hub_status(struct usb_host_virt_dev * hdev,struct usb_hub_status * data)815 static int get_hub_status(struct usb_host_virt_dev *hdev,
816                           struct usb_hub_status *data)
817 {
818     int i, status = -ETIMEDOUT;
819 
820     for (i = 0; i < USB_STS_RETRIES && status == -ETIMEDOUT; i++)
821     {
822         status = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
823                                  USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_HUB, 0, 0,
824                                  (void *)data, sizeof(*data), USB_STS_TIMEOUT);
825     }
826 
827     return status;
828 }
829 
hub_hub_status(struct usb_hub * hub,u16 * status,u16 * change)830 int hub_hub_status(struct usb_hub *hub,
831                    u16 *status, u16 *change)
832 {
833     int ret;
834     ret = get_hub_status(hub->hdev, &hub->status->hub);
835 
836     if (ret < 0)
837     {
838         __err("PANIC : hub_hub_status()  failed (err = %d)\n", ret);
839     }
840     else
841     {
842         *status = le16_to_cpu(hub->status->hub.wHubStatus);
843         *change = le16_to_cpu(hub->status->hub.wHubChange);
844         ret = 0;
845     }
846 
847     return ret;
848 }
849 
850 
851 
852 //限制: 只能在thread环境中使用,isr中是禁止的
hub_thread_sleep(struct hub_thread_context * thread_cont)853 int hub_thread_sleep(struct hub_thread_context *thread_cont)
854 {
855     u8  ret = 0;
856     //USB_OS_SEMI_PEND(thread_cont->hub_thread_event, 0, &ret);
857     hal_sem_wait(thread_cont->hub_thread_event);
858 
859     //if (ret != USB_OS_NO_ERR)
860     if (ret != 0)
861     {
862         __err("PANIC : hub_thread_sleep() : ret = %d\n", ret);
863         return -1;
864     }
865 
866     return (ret ? -EINTR : 0);
867 }
868 
869 //可以在thead,isr中使用
hub_thread_wakeup(struct hub_thread_context * thread_cont)870 void hub_thread_wakeup(struct hub_thread_context *thread_cont)
871 {
872     //USB_OS_SEMI_POST(thread_cont->hub_thread_event);
873     hal_sem_post(thread_cont->hub_thread_event);
874 }
875 
876 
877