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