diff options
Diffstat (limited to 'drivers/usb/core')
| -rw-r--r-- | drivers/usb/core/driver.c | 96 | ||||
| -rw-r--r-- | drivers/usb/core/hcd.c | 9 | ||||
| -rw-r--r-- | drivers/usb/core/hcd.h | 4 | ||||
| -rw-r--r-- | drivers/usb/core/hub.c | 9 | ||||
| -rw-r--r-- | drivers/usb/core/urb.c | 9 | ||||
| -rw-r--r-- | drivers/usb/core/usb.c | 73 | ||||
| -rw-r--r-- | drivers/usb/core/usb.h | 3 |
7 files changed, 126 insertions, 77 deletions
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 2be37fe466f2..5a7fa6f09958 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c | |||
| @@ -230,6 +230,13 @@ static int usb_probe_interface(struct device *dev) | |||
| 230 | */ | 230 | */ |
| 231 | intf->pm_usage_cnt = !(driver->supports_autosuspend); | 231 | intf->pm_usage_cnt = !(driver->supports_autosuspend); |
| 232 | 232 | ||
| 233 | /* Carry out a deferred switch to altsetting 0 */ | ||
| 234 | if (intf->needs_altsetting0) { | ||
| 235 | usb_set_interface(udev, intf->altsetting[0]. | ||
| 236 | desc.bInterfaceNumber, 0); | ||
| 237 | intf->needs_altsetting0 = 0; | ||
| 238 | } | ||
| 239 | |||
| 233 | error = driver->probe(intf, id); | 240 | error = driver->probe(intf, id); |
| 234 | if (error) { | 241 | if (error) { |
| 235 | mark_quiesced(intf); | 242 | mark_quiesced(intf); |
| @@ -266,8 +273,17 @@ static int usb_unbind_interface(struct device *dev) | |||
| 266 | 273 | ||
| 267 | driver->disconnect(intf); | 274 | driver->disconnect(intf); |
| 268 | 275 | ||
| 269 | /* reset other interface state */ | 276 | /* Reset other interface state. |
| 270 | usb_set_interface(udev, intf->altsetting[0].desc.bInterfaceNumber, 0); | 277 | * We cannot do a Set-Interface if the device is suspended or |
| 278 | * if it is prepared for a system sleep (since installing a new | ||
| 279 | * altsetting means creating new endpoint device entries). | ||
| 280 | * When either of these happens, defer the Set-Interface. | ||
| 281 | */ | ||
| 282 | if (!error && intf->dev.power.status == DPM_ON) | ||
| 283 | usb_set_interface(udev, intf->altsetting[0]. | ||
| 284 | desc.bInterfaceNumber, 0); | ||
| 285 | else | ||
| 286 | intf->needs_altsetting0 = 1; | ||
| 271 | usb_set_intfdata(intf, NULL); | 287 | usb_set_intfdata(intf, NULL); |
| 272 | 288 | ||
| 273 | intf->condition = USB_INTERFACE_UNBOUND; | 289 | intf->condition = USB_INTERFACE_UNBOUND; |
| @@ -798,7 +814,8 @@ void usb_forced_unbind_intf(struct usb_interface *intf) | |||
| 798 | * The caller must hold @intf's device's lock, but not its pm_mutex | 814 | * The caller must hold @intf's device's lock, but not its pm_mutex |
| 799 | * and not @intf->dev.sem. | 815 | * and not @intf->dev.sem. |
| 800 | * | 816 | * |
| 801 | * FIXME: The caller must block system sleep transitions. | 817 | * Note: Rebinds will be skipped if a system sleep transition is in |
| 818 | * progress and the PM "complete" callback hasn't occurred yet. | ||
| 802 | */ | 819 | */ |
| 803 | void usb_rebind_intf(struct usb_interface *intf) | 820 | void usb_rebind_intf(struct usb_interface *intf) |
| 804 | { | 821 | { |
| @@ -814,10 +831,12 @@ void usb_rebind_intf(struct usb_interface *intf) | |||
| 814 | } | 831 | } |
| 815 | 832 | ||
| 816 | /* Try to rebind the interface */ | 833 | /* Try to rebind the interface */ |
| 817 | intf->needs_binding = 0; | 834 | if (intf->dev.power.status == DPM_ON) { |
| 818 | rc = device_attach(&intf->dev); | 835 | intf->needs_binding = 0; |
| 819 | if (rc < 0) | 836 | rc = device_attach(&intf->dev); |
| 820 | dev_warn(&intf->dev, "rebind failed: %d\n", rc); | 837 | if (rc < 0) |
| 838 | dev_warn(&intf->dev, "rebind failed: %d\n", rc); | ||
| 839 | } | ||
| 821 | } | 840 | } |
| 822 | 841 | ||
| 823 | #ifdef CONFIG_PM | 842 | #ifdef CONFIG_PM |
| @@ -829,7 +848,6 @@ void usb_rebind_intf(struct usb_interface *intf) | |||
| 829 | * or rebind interfaces that have been unbound, according to @action. | 848 | * or rebind interfaces that have been unbound, according to @action. |
| 830 | * | 849 | * |
| 831 | * The caller must hold @udev's device lock. | 850 | * The caller must hold @udev's device lock. |
| 832 | * FIXME: For rebinds, the caller must block system sleep transitions. | ||
| 833 | */ | 851 | */ |
| 834 | static void do_unbind_rebind(struct usb_device *udev, int action) | 852 | static void do_unbind_rebind(struct usb_device *udev, int action) |
| 835 | { | 853 | { |
| @@ -851,22 +869,8 @@ static void do_unbind_rebind(struct usb_device *udev, int action) | |||
| 851 | } | 869 | } |
| 852 | break; | 870 | break; |
| 853 | case DO_REBIND: | 871 | case DO_REBIND: |
| 854 | if (intf->needs_binding) { | 872 | if (intf->needs_binding) |
| 855 | |||
| 856 | /* FIXME: The next line is needed because we are going to probe | ||
| 857 | * the interface, but as far as the PM core is concerned the | ||
| 858 | * interface is still suspended. The problem wouldn't exist | ||
| 859 | * if we could rebind the interface during the interface's own | ||
| 860 | * resume() call, but at the time the usb_device isn't locked! | ||
| 861 | * | ||
| 862 | * The real solution will be to carry this out during the device's | ||
| 863 | * complete() callback. Until that is implemented, we have to | ||
| 864 | * use this hack. | ||
| 865 | */ | ||
| 866 | // intf->dev.power.sleeping = 0; | ||
| 867 | |||
| 868 | usb_rebind_intf(intf); | 873 | usb_rebind_intf(intf); |
| 869 | } | ||
| 870 | break; | 874 | break; |
| 871 | } | 875 | } |
| 872 | } | 876 | } |
| @@ -926,14 +930,14 @@ static int usb_resume_device(struct usb_device *udev) | |||
| 926 | } | 930 | } |
| 927 | 931 | ||
| 928 | /* Caller has locked intf's usb_device's pm mutex */ | 932 | /* Caller has locked intf's usb_device's pm mutex */ |
| 929 | static int usb_suspend_interface(struct usb_interface *intf, pm_message_t msg) | 933 | static int usb_suspend_interface(struct usb_device *udev, |
| 934 | struct usb_interface *intf, pm_message_t msg) | ||
| 930 | { | 935 | { |
| 931 | struct usb_driver *driver; | 936 | struct usb_driver *driver; |
| 932 | int status = 0; | 937 | int status = 0; |
| 933 | 938 | ||
| 934 | /* with no hardware, USB interfaces only use FREEZE and ON states */ | 939 | /* with no hardware, USB interfaces only use FREEZE and ON states */ |
| 935 | if (interface_to_usbdev(intf)->state == USB_STATE_NOTATTACHED || | 940 | if (udev->state == USB_STATE_NOTATTACHED || !is_active(intf)) |
| 936 | !is_active(intf)) | ||
| 937 | goto done; | 941 | goto done; |
| 938 | 942 | ||
| 939 | if (intf->condition == USB_INTERFACE_UNBOUND) /* This can't happen */ | 943 | if (intf->condition == USB_INTERFACE_UNBOUND) /* This can't happen */ |
| @@ -944,7 +948,7 @@ static int usb_suspend_interface(struct usb_interface *intf, pm_message_t msg) | |||
| 944 | status = driver->suspend(intf, msg); | 948 | status = driver->suspend(intf, msg); |
| 945 | if (status == 0) | 949 | if (status == 0) |
| 946 | mark_quiesced(intf); | 950 | mark_quiesced(intf); |
| 947 | else if (!interface_to_usbdev(intf)->auto_pm) | 951 | else if (!udev->auto_pm) |
| 948 | dev_err(&intf->dev, "%s error %d\n", | 952 | dev_err(&intf->dev, "%s error %d\n", |
| 949 | "suspend", status); | 953 | "suspend", status); |
| 950 | } else { | 954 | } else { |
| @@ -961,13 +965,13 @@ static int usb_suspend_interface(struct usb_interface *intf, pm_message_t msg) | |||
| 961 | } | 965 | } |
| 962 | 966 | ||
| 963 | /* Caller has locked intf's usb_device's pm_mutex */ | 967 | /* Caller has locked intf's usb_device's pm_mutex */ |
| 964 | static int usb_resume_interface(struct usb_interface *intf, int reset_resume) | 968 | static int usb_resume_interface(struct usb_device *udev, |
| 969 | struct usb_interface *intf, int reset_resume) | ||
| 965 | { | 970 | { |
| 966 | struct usb_driver *driver; | 971 | struct usb_driver *driver; |
| 967 | int status = 0; | 972 | int status = 0; |
| 968 | 973 | ||
| 969 | if (interface_to_usbdev(intf)->state == USB_STATE_NOTATTACHED || | 974 | if (udev->state == USB_STATE_NOTATTACHED || is_active(intf)) |
| 970 | is_active(intf)) | ||
| 971 | goto done; | 975 | goto done; |
| 972 | 976 | ||
| 973 | /* Don't let autoresume interfere with unbinding */ | 977 | /* Don't let autoresume interfere with unbinding */ |
| @@ -975,8 +979,17 @@ static int usb_resume_interface(struct usb_interface *intf, int reset_resume) | |||
| 975 | goto done; | 979 | goto done; |
| 976 | 980 | ||
| 977 | /* Can't resume it if it doesn't have a driver. */ | 981 | /* Can't resume it if it doesn't have a driver. */ |
| 978 | if (intf->condition == USB_INTERFACE_UNBOUND) | 982 | if (intf->condition == USB_INTERFACE_UNBOUND) { |
| 983 | |||
| 984 | /* Carry out a deferred switch to altsetting 0 */ | ||
| 985 | if (intf->needs_altsetting0 && | ||
| 986 | intf->dev.power.status == DPM_ON) { | ||
| 987 | usb_set_interface(udev, intf->altsetting[0]. | ||
| 988 | desc.bInterfaceNumber, 0); | ||
| 989 | intf->needs_altsetting0 = 0; | ||
| 990 | } | ||
| 979 | goto done; | 991 | goto done; |
| 992 | } | ||
| 980 | 993 | ||
| 981 | /* Don't resume if the interface is marked for rebinding */ | 994 | /* Don't resume if the interface is marked for rebinding */ |
| 982 | if (intf->needs_binding) | 995 | if (intf->needs_binding) |
| @@ -1151,7 +1164,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) | |||
| 1151 | if (udev->actconfig) { | 1164 | if (udev->actconfig) { |
| 1152 | for (; i < udev->actconfig->desc.bNumInterfaces; i++) { | 1165 | for (; i < udev->actconfig->desc.bNumInterfaces; i++) { |
| 1153 | intf = udev->actconfig->interface[i]; | 1166 | intf = udev->actconfig->interface[i]; |
| 1154 | status = usb_suspend_interface(intf, msg); | 1167 | status = usb_suspend_interface(udev, intf, msg); |
| 1155 | if (status != 0) | 1168 | if (status != 0) |
| 1156 | break; | 1169 | break; |
| 1157 | } | 1170 | } |
| @@ -1163,7 +1176,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) | |||
| 1163 | if (status != 0) { | 1176 | if (status != 0) { |
| 1164 | while (--i >= 0) { | 1177 | while (--i >= 0) { |
| 1165 | intf = udev->actconfig->interface[i]; | 1178 | intf = udev->actconfig->interface[i]; |
| 1166 | usb_resume_interface(intf, 0); | 1179 | usb_resume_interface(udev, intf, 0); |
| 1167 | } | 1180 | } |
| 1168 | 1181 | ||
| 1169 | /* Try another autosuspend when the interfaces aren't busy */ | 1182 | /* Try another autosuspend when the interfaces aren't busy */ |
| @@ -1276,7 +1289,7 @@ static int usb_resume_both(struct usb_device *udev) | |||
| 1276 | if (status == 0 && udev->actconfig) { | 1289 | if (status == 0 && udev->actconfig) { |
| 1277 | for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { | 1290 | for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { |
| 1278 | intf = udev->actconfig->interface[i]; | 1291 | intf = udev->actconfig->interface[i]; |
| 1279 | usb_resume_interface(intf, udev->reset_resume); | 1292 | usb_resume_interface(udev, intf, udev->reset_resume); |
| 1280 | } | 1293 | } |
| 1281 | } | 1294 | } |
| 1282 | 1295 | ||
| @@ -1605,12 +1618,10 @@ int usb_external_resume_device(struct usb_device *udev) | |||
| 1605 | return status; | 1618 | return status; |
| 1606 | } | 1619 | } |
| 1607 | 1620 | ||
| 1608 | static int usb_suspend(struct device *dev, pm_message_t message) | 1621 | int usb_suspend(struct device *dev, pm_message_t message) |
| 1609 | { | 1622 | { |
| 1610 | struct usb_device *udev; | 1623 | struct usb_device *udev; |
| 1611 | 1624 | ||
| 1612 | if (!is_usb_device(dev)) /* Ignore PM for interfaces */ | ||
| 1613 | return 0; | ||
| 1614 | udev = to_usb_device(dev); | 1625 | udev = to_usb_device(dev); |
| 1615 | 1626 | ||
| 1616 | /* If udev is already suspended, we can skip this suspend and | 1627 | /* If udev is already suspended, we can skip this suspend and |
| @@ -1629,12 +1640,10 @@ static int usb_suspend(struct device *dev, pm_message_t message) | |||
| 1629 | return usb_external_suspend_device(udev, message); | 1640 | return usb_external_suspend_device(udev, message); |
| 1630 | } | 1641 | } |
| 1631 | 1642 | ||
| 1632 | static int usb_resume(struct device *dev) | 1643 | int usb_resume(struct device *dev) |
| 1633 | { | 1644 | { |
| 1634 | struct usb_device *udev; | 1645 | struct usb_device *udev; |
| 1635 | 1646 | ||
| 1636 | if (!is_usb_device(dev)) /* Ignore PM for interfaces */ | ||
| 1637 | return 0; | ||
| 1638 | udev = to_usb_device(dev); | 1647 | udev = to_usb_device(dev); |
| 1639 | 1648 | ||
| 1640 | /* If udev->skip_sys_resume is set then udev was already suspended | 1649 | /* If udev->skip_sys_resume is set then udev was already suspended |
| @@ -1646,17 +1655,10 @@ static int usb_resume(struct device *dev) | |||
| 1646 | return usb_external_resume_device(udev); | 1655 | return usb_external_resume_device(udev); |
| 1647 | } | 1656 | } |
| 1648 | 1657 | ||
| 1649 | #else | ||
| 1650 | |||
| 1651 | #define usb_suspend NULL | ||
| 1652 | #define usb_resume NULL | ||
| 1653 | |||
| 1654 | #endif /* CONFIG_PM */ | 1658 | #endif /* CONFIG_PM */ |
| 1655 | 1659 | ||
| 1656 | struct bus_type usb_bus_type = { | 1660 | struct bus_type usb_bus_type = { |
| 1657 | .name = "usb", | 1661 | .name = "usb", |
| 1658 | .match = usb_device_match, | 1662 | .match = usb_device_match, |
| 1659 | .uevent = usb_uevent, | 1663 | .uevent = usb_uevent, |
| 1660 | .suspend = usb_suspend, | ||
| 1661 | .resume = usb_resume, | ||
| 1662 | }; | 1664 | }; |
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index f7bfd72ef115..8abd4e59bf4a 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c | |||
| @@ -924,15 +924,6 @@ static int register_root_hub(struct usb_hcd *hcd) | |||
| 924 | return retval; | 924 | return retval; |
| 925 | } | 925 | } |
| 926 | 926 | ||
| 927 | void usb_enable_root_hub_irq (struct usb_bus *bus) | ||
| 928 | { | ||
| 929 | struct usb_hcd *hcd; | ||
| 930 | |||
| 931 | hcd = container_of (bus, struct usb_hcd, self); | ||
| 932 | if (hcd->driver->hub_irq_enable && hcd->state != HC_STATE_HALT) | ||
| 933 | hcd->driver->hub_irq_enable (hcd); | ||
| 934 | } | ||
| 935 | |||
| 936 | 927 | ||
| 937 | /*-------------------------------------------------------------------------*/ | 928 | /*-------------------------------------------------------------------------*/ |
| 938 | 929 | ||
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 5b0b59b0d89b..e710ce04e228 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h | |||
| @@ -212,8 +212,6 @@ struct hc_driver { | |||
| 212 | int (*bus_suspend)(struct usb_hcd *); | 212 | int (*bus_suspend)(struct usb_hcd *); |
| 213 | int (*bus_resume)(struct usb_hcd *); | 213 | int (*bus_resume)(struct usb_hcd *); |
| 214 | int (*start_port_reset)(struct usb_hcd *, unsigned port_num); | 214 | int (*start_port_reset)(struct usb_hcd *, unsigned port_num); |
| 215 | void (*hub_irq_enable)(struct usb_hcd *); | ||
| 216 | /* Needed only if port-change IRQs are level-triggered */ | ||
| 217 | 215 | ||
| 218 | /* force handover of high-speed port to full-speed companion */ | 216 | /* force handover of high-speed port to full-speed companion */ |
| 219 | void (*relinquish_port)(struct usb_hcd *, int); | 217 | void (*relinquish_port)(struct usb_hcd *, int); |
| @@ -379,8 +377,6 @@ extern struct list_head usb_bus_list; | |||
| 379 | extern struct mutex usb_bus_list_lock; | 377 | extern struct mutex usb_bus_list_lock; |
| 380 | extern wait_queue_head_t usb_kill_urb_queue; | 378 | extern wait_queue_head_t usb_kill_urb_queue; |
| 381 | 379 | ||
| 382 | extern void usb_enable_root_hub_irq(struct usb_bus *bus); | ||
| 383 | |||
| 384 | extern int usb_find_interface_driver(struct usb_device *dev, | 380 | extern int usb_find_interface_driver(struct usb_device *dev, |
| 385 | struct usb_interface *interface); | 381 | struct usb_interface *interface); |
| 386 | 382 | ||
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 107e1d25ddec..6a5cb018383d 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c | |||
| @@ -2102,8 +2102,6 @@ int usb_port_resume(struct usb_device *udev) | |||
| 2102 | } | 2102 | } |
| 2103 | 2103 | ||
| 2104 | clear_bit(port1, hub->busy_bits); | 2104 | clear_bit(port1, hub->busy_bits); |
| 2105 | if (!hub->hdev->parent && !hub->busy_bits[0]) | ||
| 2106 | usb_enable_root_hub_irq(hub->hdev->bus); | ||
| 2107 | 2105 | ||
| 2108 | status = check_port_resume_type(udev, | 2106 | status = check_port_resume_type(udev, |
| 2109 | hub, port1, status, portchange, portstatus); | 2107 | hub, port1, status, portchange, portstatus); |
| @@ -3081,11 +3079,6 @@ static void hub_events(void) | |||
| 3081 | } | 3079 | } |
| 3082 | } | 3080 | } |
| 3083 | 3081 | ||
| 3084 | /* If this is a root hub, tell the HCD it's okay to | ||
| 3085 | * re-enable port-change interrupts now. */ | ||
| 3086 | if (!hdev->parent && !hub->busy_bits[0]) | ||
| 3087 | usb_enable_root_hub_irq(hdev->bus); | ||
| 3088 | |||
| 3089 | loop_autopm: | 3082 | loop_autopm: |
| 3090 | /* Allow autosuspend if we're not going to run again */ | 3083 | /* Allow autosuspend if we're not going to run again */ |
| 3091 | if (list_empty(&hub->event_list)) | 3084 | if (list_empty(&hub->event_list)) |
| @@ -3311,8 +3304,6 @@ static int usb_reset_and_verify_device(struct usb_device *udev) | |||
| 3311 | break; | 3304 | break; |
| 3312 | } | 3305 | } |
| 3313 | clear_bit(port1, parent_hub->busy_bits); | 3306 | clear_bit(port1, parent_hub->busy_bits); |
| 3314 | if (!parent_hdev->parent && !parent_hub->busy_bits[0]) | ||
| 3315 | usb_enable_root_hub_irq(parent_hdev->bus); | ||
| 3316 | 3307 | ||
| 3317 | if (ret < 0) | 3308 | if (ret < 0) |
| 3318 | goto re_enumerate; | 3309 | goto re_enumerate; |
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index c0b1ae25ae2a..47111e88f791 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c | |||
| @@ -601,15 +601,20 @@ EXPORT_SYMBOL_GPL(usb_kill_anchored_urbs); | |||
| 601 | void usb_unlink_anchored_urbs(struct usb_anchor *anchor) | 601 | void usb_unlink_anchored_urbs(struct usb_anchor *anchor) |
| 602 | { | 602 | { |
| 603 | struct urb *victim; | 603 | struct urb *victim; |
| 604 | unsigned long flags; | ||
| 604 | 605 | ||
| 605 | spin_lock_irq(&anchor->lock); | 606 | spin_lock_irqsave(&anchor->lock, flags); |
| 606 | while (!list_empty(&anchor->urb_list)) { | 607 | while (!list_empty(&anchor->urb_list)) { |
| 607 | victim = list_entry(anchor->urb_list.prev, struct urb, | 608 | victim = list_entry(anchor->urb_list.prev, struct urb, |
| 608 | anchor_list); | 609 | anchor_list); |
| 610 | usb_get_urb(victim); | ||
| 611 | spin_unlock_irqrestore(&anchor->lock, flags); | ||
| 609 | /* this will unanchor the URB */ | 612 | /* this will unanchor the URB */ |
| 610 | usb_unlink_urb(victim); | 613 | usb_unlink_urb(victim); |
| 614 | usb_put_urb(victim); | ||
| 615 | spin_lock_irqsave(&anchor->lock, flags); | ||
| 611 | } | 616 | } |
| 612 | spin_unlock_irq(&anchor->lock); | 617 | spin_unlock_irqrestore(&anchor->lock, flags); |
| 613 | } | 618 | } |
| 614 | EXPORT_SYMBOL_GPL(usb_unlink_anchored_urbs); | 619 | EXPORT_SYMBOL_GPL(usb_unlink_anchored_urbs); |
| 615 | 620 | ||
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 84fcaa6a21ec..be1fa0723f2c 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c | |||
| @@ -219,12 +219,6 @@ static int usb_dev_uevent(struct device *dev, struct kobj_uevent_env *env) | |||
| 219 | } | 219 | } |
| 220 | #endif /* CONFIG_HOTPLUG */ | 220 | #endif /* CONFIG_HOTPLUG */ |
| 221 | 221 | ||
| 222 | struct device_type usb_device_type = { | ||
| 223 | .name = "usb_device", | ||
| 224 | .release = usb_release_dev, | ||
| 225 | .uevent = usb_dev_uevent, | ||
| 226 | }; | ||
| 227 | |||
| 228 | #ifdef CONFIG_PM | 222 | #ifdef CONFIG_PM |
| 229 | 223 | ||
| 230 | static int ksuspend_usb_init(void) | 224 | static int ksuspend_usb_init(void) |
| @@ -244,13 +238,80 @@ static void ksuspend_usb_cleanup(void) | |||
| 244 | destroy_workqueue(ksuspend_usb_wq); | 238 | destroy_workqueue(ksuspend_usb_wq); |
| 245 | } | 239 | } |
| 246 | 240 | ||
| 241 | /* USB device Power-Management thunks. | ||
| 242 | * There's no need to distinguish here between quiescing a USB device | ||
| 243 | * and powering it down; the generic_suspend() routine takes care of | ||
| 244 | * it by skipping the usb_port_suspend() call for a quiesce. And for | ||
| 245 | * USB interfaces there's no difference at all. | ||
| 246 | */ | ||
| 247 | |||
| 248 | static int usb_dev_prepare(struct device *dev) | ||
| 249 | { | ||
| 250 | return 0; /* Implement eventually? */ | ||
| 251 | } | ||
| 252 | |||
| 253 | static void usb_dev_complete(struct device *dev) | ||
| 254 | { | ||
| 255 | /* Currently used only for rebinding interfaces */ | ||
| 256 | usb_resume(dev); /* Implement eventually? */ | ||
| 257 | } | ||
| 258 | |||
| 259 | static int usb_dev_suspend(struct device *dev) | ||
| 260 | { | ||
| 261 | return usb_suspend(dev, PMSG_SUSPEND); | ||
| 262 | } | ||
| 263 | |||
| 264 | static int usb_dev_resume(struct device *dev) | ||
| 265 | { | ||
| 266 | return usb_resume(dev); | ||
| 267 | } | ||
| 268 | |||
| 269 | static int usb_dev_freeze(struct device *dev) | ||
| 270 | { | ||
| 271 | return usb_suspend(dev, PMSG_FREEZE); | ||
| 272 | } | ||
| 273 | |||
| 274 | static int usb_dev_thaw(struct device *dev) | ||
| 275 | { | ||
| 276 | return usb_resume(dev); | ||
| 277 | } | ||
| 278 | |||
| 279 | static int usb_dev_poweroff(struct device *dev) | ||
| 280 | { | ||
| 281 | return usb_suspend(dev, PMSG_HIBERNATE); | ||
| 282 | } | ||
| 283 | |||
| 284 | static int usb_dev_restore(struct device *dev) | ||
| 285 | { | ||
| 286 | return usb_resume(dev); | ||
| 287 | } | ||
| 288 | |||
| 289 | static struct pm_ops usb_device_pm_ops = { | ||
| 290 | .prepare = usb_dev_prepare, | ||
| 291 | .complete = usb_dev_complete, | ||
| 292 | .suspend = usb_dev_suspend, | ||
| 293 | .resume = usb_dev_resume, | ||
| 294 | .freeze = usb_dev_freeze, | ||
| 295 | .thaw = usb_dev_thaw, | ||
| 296 | .poweroff = usb_dev_poweroff, | ||
| 297 | .restore = usb_dev_restore, | ||
| 298 | }; | ||
| 299 | |||
| 247 | #else | 300 | #else |
| 248 | 301 | ||
| 249 | #define ksuspend_usb_init() 0 | 302 | #define ksuspend_usb_init() 0 |
| 250 | #define ksuspend_usb_cleanup() do {} while (0) | 303 | #define ksuspend_usb_cleanup() do {} while (0) |
| 304 | #define usb_device_pm_ops (*(struct pm_ops *)0) | ||
| 251 | 305 | ||
| 252 | #endif /* CONFIG_PM */ | 306 | #endif /* CONFIG_PM */ |
| 253 | 307 | ||
| 308 | struct device_type usb_device_type = { | ||
| 309 | .name = "usb_device", | ||
| 310 | .release = usb_release_dev, | ||
| 311 | .uevent = usb_dev_uevent, | ||
| 312 | .pm = &usb_device_pm_ops, | ||
| 313 | }; | ||
| 314 | |||
| 254 | 315 | ||
| 255 | /* Returns 1 if @usb_bus is WUSB, 0 otherwise */ | 316 | /* Returns 1 if @usb_bus is WUSB, 0 otherwise */ |
| 256 | static unsigned usb_bus_is_wusb(struct usb_bus *bus) | 317 | static unsigned usb_bus_is_wusb(struct usb_bus *bus) |
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index d9a6e16dbf84..9a1a45ac3add 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h | |||
| @@ -41,6 +41,9 @@ extern void usb_host_cleanup(void); | |||
| 41 | 41 | ||
| 42 | #ifdef CONFIG_PM | 42 | #ifdef CONFIG_PM |
| 43 | 43 | ||
| 44 | extern int usb_suspend(struct device *dev, pm_message_t msg); | ||
| 45 | extern int usb_resume(struct device *dev); | ||
| 46 | |||
| 44 | extern void usb_autosuspend_work(struct work_struct *work); | 47 | extern void usb_autosuspend_work(struct work_struct *work); |
| 45 | extern int usb_port_suspend(struct usb_device *dev); | 48 | extern int usb_port_suspend(struct usb_device *dev); |
| 46 | extern int usb_port_resume(struct usb_device *dev); | 49 | extern int usb_port_resume(struct usb_device *dev); |
