diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2006-11-09 14:44:33 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-12-01 17:25:52 -0500 |
commit | 40f122f343797d02390c5a157372cac0c5b50bb7 (patch) | |
tree | 87f7b3f5b6fc347466668a4b9d8b67d32f5bb014 /drivers/usb | |
parent | 8c03356a559ced6fa78931f498193f776d67e445 (diff) |
USB: Add autosuspend support to the hub driver
This patch (as742b) adds autosuspend/autoresume support to the USB hub
driver. The largest aspect of the change is that we no longer need a
special flag for root hubs that want to be resumed. Now every hub is
autoresumed whenever khubd needs to access it.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/core/hub.c | 45 |
1 files changed, 26 insertions, 19 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index f6e692180587..55812a5ac661 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c | |||
@@ -65,7 +65,6 @@ struct usb_hub { | |||
65 | unsigned limited_power:1; | 65 | unsigned limited_power:1; |
66 | unsigned quiescing:1; | 66 | unsigned quiescing:1; |
67 | unsigned activating:1; | 67 | unsigned activating:1; |
68 | unsigned resume_root_hub:1; | ||
69 | 68 | ||
70 | unsigned has_indicators:1; | 69 | unsigned has_indicators:1; |
71 | u8 indicator[USB_MAXCHILDREN]; | 70 | u8 indicator[USB_MAXCHILDREN]; |
@@ -328,6 +327,9 @@ static void kick_khubd(struct usb_hub *hub) | |||
328 | { | 327 | { |
329 | unsigned long flags; | 328 | unsigned long flags; |
330 | 329 | ||
330 | /* Suppress autosuspend until khubd runs */ | ||
331 | to_usb_interface(hub->intfdev)->pm_usage_cnt = 1; | ||
332 | |||
331 | spin_lock_irqsave(&hub_event_lock, flags); | 333 | spin_lock_irqsave(&hub_event_lock, flags); |
332 | if (list_empty(&hub->event_list)) { | 334 | if (list_empty(&hub->event_list)) { |
333 | list_add_tail(&hub->event_list, &hub_event_list); | 335 | list_add_tail(&hub->event_list, &hub_event_list); |
@@ -509,7 +511,6 @@ static void hub_quiesce(struct usb_hub *hub) | |||
509 | /* (nonblocking) khubd and related activity won't re-trigger */ | 511 | /* (nonblocking) khubd and related activity won't re-trigger */ |
510 | hub->quiescing = 1; | 512 | hub->quiescing = 1; |
511 | hub->activating = 0; | 513 | hub->activating = 0; |
512 | hub->resume_root_hub = 0; | ||
513 | 514 | ||
514 | /* (blocking) stop khubd and related activity */ | 515 | /* (blocking) stop khubd and related activity */ |
515 | usb_kill_urb(hub->urb); | 516 | usb_kill_urb(hub->urb); |
@@ -525,7 +526,7 @@ static void hub_activate(struct usb_hub *hub) | |||
525 | 526 | ||
526 | hub->quiescing = 0; | 527 | hub->quiescing = 0; |
527 | hub->activating = 1; | 528 | hub->activating = 1; |
528 | hub->resume_root_hub = 0; | 529 | |
529 | status = usb_submit_urb(hub->urb, GFP_NOIO); | 530 | status = usb_submit_urb(hub->urb, GFP_NOIO); |
530 | if (status < 0) | 531 | if (status < 0) |
531 | dev_err(hub->intfdev, "activate --> %d\n", status); | 532 | dev_err(hub->intfdev, "activate --> %d\n", status); |
@@ -940,6 +941,7 @@ descriptor_error: | |||
940 | INIT_WORK(&hub->leds, led_work, hub); | 941 | INIT_WORK(&hub->leds, led_work, hub); |
941 | 942 | ||
942 | usb_set_intfdata (intf, hub); | 943 | usb_set_intfdata (intf, hub); |
944 | intf->needs_remote_wakeup = 1; | ||
943 | 945 | ||
944 | if (hdev->speed == USB_SPEED_HIGH) | 946 | if (hdev->speed == USB_SPEED_HIGH) |
945 | highspeed_hubs++; | 947 | highspeed_hubs++; |
@@ -1938,6 +1940,8 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) | |||
1938 | } | 1940 | } |
1939 | } | 1941 | } |
1940 | 1942 | ||
1943 | dev_dbg(&intf->dev, "%s\n", __FUNCTION__); | ||
1944 | |||
1941 | /* "global suspend" of the downstream HC-to-USB interface */ | 1945 | /* "global suspend" of the downstream HC-to-USB interface */ |
1942 | if (!hdev->parent) { | 1946 | if (!hdev->parent) { |
1943 | struct usb_bus *bus = hdev->bus; | 1947 | struct usb_bus *bus = hdev->bus; |
@@ -1960,10 +1964,12 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) | |||
1960 | 1964 | ||
1961 | static int hub_resume(struct usb_interface *intf) | 1965 | static int hub_resume(struct usb_interface *intf) |
1962 | { | 1966 | { |
1963 | struct usb_device *hdev = interface_to_usbdev(intf); | ||
1964 | struct usb_hub *hub = usb_get_intfdata (intf); | 1967 | struct usb_hub *hub = usb_get_intfdata (intf); |
1968 | struct usb_device *hdev = hub->hdev; | ||
1965 | int status; | 1969 | int status; |
1966 | 1970 | ||
1971 | dev_dbg(&intf->dev, "%s\n", __FUNCTION__); | ||
1972 | |||
1967 | /* "global resume" of the downstream HC-to-USB interface */ | 1973 | /* "global resume" of the downstream HC-to-USB interface */ |
1968 | if (!hdev->parent) { | 1974 | if (!hdev->parent) { |
1969 | struct usb_bus *bus = hdev->bus; | 1975 | struct usb_bus *bus = hdev->bus; |
@@ -2002,7 +2008,6 @@ void usb_resume_root_hub(struct usb_device *hdev) | |||
2002 | { | 2008 | { |
2003 | struct usb_hub *hub = hdev_to_hub(hdev); | 2009 | struct usb_hub *hub = hdev_to_hub(hdev); |
2004 | 2010 | ||
2005 | hub->resume_root_hub = 1; | ||
2006 | kick_khubd(hub); | 2011 | kick_khubd(hub); |
2007 | } | 2012 | } |
2008 | 2013 | ||
@@ -2639,16 +2644,13 @@ static void hub_events(void) | |||
2639 | intf = to_usb_interface(hub->intfdev); | 2644 | intf = to_usb_interface(hub->intfdev); |
2640 | hub_dev = &intf->dev; | 2645 | hub_dev = &intf->dev; |
2641 | 2646 | ||
2642 | i = hub->resume_root_hub; | 2647 | dev_dbg(hub_dev, "state %d ports %d chg %04x evt %04x\n", |
2643 | |||
2644 | dev_dbg(hub_dev, "state %d ports %d chg %04x evt %04x%s\n", | ||
2645 | hdev->state, hub->descriptor | 2648 | hdev->state, hub->descriptor |
2646 | ? hub->descriptor->bNbrPorts | 2649 | ? hub->descriptor->bNbrPorts |
2647 | : 0, | 2650 | : 0, |
2648 | /* NOTE: expects max 15 ports... */ | 2651 | /* NOTE: expects max 15 ports... */ |
2649 | (u16) hub->change_bits[0], | 2652 | (u16) hub->change_bits[0], |
2650 | (u16) hub->event_bits[0], | 2653 | (u16) hub->event_bits[0]); |
2651 | i ? ", resume root" : ""); | ||
2652 | 2654 | ||
2653 | usb_get_intf(intf); | 2655 | usb_get_intf(intf); |
2654 | spin_unlock_irq(&hub_event_lock); | 2656 | spin_unlock_irq(&hub_event_lock); |
@@ -2669,16 +2671,16 @@ static void hub_events(void) | |||
2669 | goto loop; | 2671 | goto loop; |
2670 | } | 2672 | } |
2671 | 2673 | ||
2672 | /* Is this is a root hub wanting to reactivate the downstream | 2674 | /* Autoresume */ |
2673 | * ports? If so, be sure the interface resumes even if its | 2675 | ret = usb_autopm_get_interface(intf); |
2674 | * stub "device" node was never suspended. | 2676 | if (ret) { |
2675 | */ | 2677 | dev_dbg(hub_dev, "Can't autoresume: %d\n", ret); |
2676 | if (i) | 2678 | goto loop; |
2677 | usb_autoresume_device(hdev, 0); | 2679 | } |
2678 | 2680 | ||
2679 | /* If this is an inactive or suspended hub, do nothing */ | 2681 | /* If this is an inactive hub, do nothing */ |
2680 | if (hub->quiescing) | 2682 | if (hub->quiescing) |
2681 | goto loop; | 2683 | goto loop_autopm; |
2682 | 2684 | ||
2683 | if (hub->error) { | 2685 | if (hub->error) { |
2684 | dev_dbg (hub_dev, "resetting for error %d\n", | 2686 | dev_dbg (hub_dev, "resetting for error %d\n", |
@@ -2688,7 +2690,7 @@ static void hub_events(void) | |||
2688 | if (ret) { | 2690 | if (ret) { |
2689 | dev_dbg (hub_dev, | 2691 | dev_dbg (hub_dev, |
2690 | "error resetting hub: %d\n", ret); | 2692 | "error resetting hub: %d\n", ret); |
2691 | goto loop; | 2693 | goto loop_autopm; |
2692 | } | 2694 | } |
2693 | 2695 | ||
2694 | hub->nerrors = 0; | 2696 | hub->nerrors = 0; |
@@ -2816,6 +2818,10 @@ static void hub_events(void) | |||
2816 | if (!hdev->parent && !hub->busy_bits[0]) | 2818 | if (!hdev->parent && !hub->busy_bits[0]) |
2817 | usb_enable_root_hub_irq(hdev->bus); | 2819 | usb_enable_root_hub_irq(hdev->bus); |
2818 | 2820 | ||
2821 | loop_autopm: | ||
2822 | /* Allow autosuspend if we're not going to run again */ | ||
2823 | if (list_empty(&hub->event_list)) | ||
2824 | usb_autopm_enable(intf); | ||
2819 | loop: | 2825 | loop: |
2820 | usb_unlock_device(hdev); | 2826 | usb_unlock_device(hdev); |
2821 | usb_put_intf(intf); | 2827 | usb_put_intf(intf); |
@@ -2857,6 +2863,7 @@ static struct usb_driver hub_driver = { | |||
2857 | .post_reset = hub_post_reset, | 2863 | .post_reset = hub_post_reset, |
2858 | .ioctl = hub_ioctl, | 2864 | .ioctl = hub_ioctl, |
2859 | .id_table = hub_id_table, | 2865 | .id_table = hub_id_table, |
2866 | .supports_autosuspend = 1, | ||
2860 | }; | 2867 | }; |
2861 | 2868 | ||
2862 | int usb_hub_init(void) | 2869 | int usb_hub_init(void) |