diff options
| -rw-r--r-- | drivers/usb/core/driver.c | 122 |
1 files changed, 77 insertions, 45 deletions
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index a62de0a85406..b0db1583c522 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c | |||
| @@ -751,81 +751,89 @@ EXPORT_SYMBOL_GPL_FUTURE(usb_deregister); | |||
| 751 | 751 | ||
| 752 | #ifdef CONFIG_PM | 752 | #ifdef CONFIG_PM |
| 753 | 753 | ||
| 754 | static int usb_suspend(struct device *dev, pm_message_t message) | 754 | /* Caller has locked udev */ |
| 755 | static int suspend_device(struct usb_device *udev, pm_message_t msg) | ||
| 755 | { | 756 | { |
| 756 | struct usb_device *udev; | ||
| 757 | struct usb_device_driver *udriver; | 757 | struct usb_device_driver *udriver; |
| 758 | struct usb_interface *intf; | ||
| 759 | struct usb_driver *driver; | ||
| 760 | int status; | ||
| 761 | 758 | ||
| 762 | if (is_usb_device(dev)) { | 759 | if (udev->dev.driver == NULL) |
| 763 | if (dev->driver == NULL) | 760 | return 0; |
| 764 | return 0; | 761 | udriver = to_usb_device_driver(udev->dev.driver); |
| 765 | udev = to_usb_device(dev); | 762 | if (udev->dev.power.power_state.event == msg.event) |
| 766 | udriver = to_usb_device_driver(dev->driver); | 763 | return 0; |
| 767 | if (dev->power.power_state.event == message.event) | 764 | return udriver->suspend(udev, msg); |
| 768 | return 0; | 765 | } |
| 769 | return udriver->suspend(udev, message); | 766 | |
| 770 | } | 767 | /* Caller has locked udev */ |
| 768 | static int resume_device(struct usb_device *udev) | ||
| 769 | { | ||
| 770 | struct usb_device_driver *udriver; | ||
| 771 | 771 | ||
| 772 | if (dev->driver == NULL) | 772 | if (udev->dev.power.power_state.event == PM_EVENT_ON) |
| 773 | return 0; | 773 | return 0; |
| 774 | 774 | ||
| 775 | intf = to_usb_interface(dev); | 775 | /* mark things as "on" immediately, no matter what errors crop up */ |
| 776 | driver = to_usb_driver(dev->driver); | 776 | udev->dev.power.power_state.event = PM_EVENT_ON; |
| 777 | |||
| 778 | if (udev->dev.driver == NULL) | ||
| 779 | return 0; | ||
| 780 | udriver = to_usb_device_driver(udev->dev.driver); | ||
| 781 | if (udev->state == USB_STATE_NOTATTACHED) | ||
| 782 | return 0; | ||
| 783 | return udriver->resume(udev); | ||
| 784 | } | ||
| 785 | |||
| 786 | /* Caller has locked intf */ | ||
| 787 | static int suspend_interface(struct usb_interface *intf, pm_message_t msg) | ||
| 788 | { | ||
| 789 | struct usb_driver *driver; | ||
| 790 | int status; | ||
| 791 | |||
| 792 | if (intf->dev.driver == NULL) | ||
| 793 | return 0; | ||
| 794 | |||
| 795 | driver = to_usb_driver(intf->dev.driver); | ||
| 777 | 796 | ||
| 778 | /* with no hardware, USB interfaces only use FREEZE and ON states */ | 797 | /* with no hardware, USB interfaces only use FREEZE and ON states */ |
| 779 | if (!is_active(intf)) | 798 | if (!is_active(intf)) |
| 780 | return 0; | 799 | return 0; |
| 781 | 800 | ||
| 782 | if (driver->suspend && driver->resume) { | 801 | if (driver->suspend && driver->resume) { |
| 783 | status = driver->suspend(intf, message); | 802 | status = driver->suspend(intf, msg); |
| 784 | if (status) | 803 | if (status) |
| 785 | dev_err(dev, "%s error %d\n", "suspend", status); | 804 | dev_err(&intf->dev, "%s error %d\n", |
| 805 | "suspend", status); | ||
| 786 | else | 806 | else |
| 787 | mark_quiesced(intf); | 807 | mark_quiesced(intf); |
| 788 | } else { | 808 | } else { |
| 789 | // FIXME else if there's no suspend method, disconnect... | 809 | // FIXME else if there's no suspend method, disconnect... |
| 790 | dev_warn(dev, "no suspend for driver %s?\n", driver->name); | 810 | dev_warn(&intf->dev, "no suspend for driver %s?\n", |
| 811 | driver->name); | ||
| 791 | mark_quiesced(intf); | 812 | mark_quiesced(intf); |
| 792 | status = 0; | 813 | status = 0; |
| 793 | } | 814 | } |
| 794 | return status; | 815 | return status; |
| 795 | } | 816 | } |
| 796 | 817 | ||
| 797 | static int usb_resume(struct device *dev) | 818 | /* Caller has locked intf */ |
| 819 | static int resume_interface(struct usb_interface *intf) | ||
| 798 | { | 820 | { |
| 799 | struct usb_device *udev; | 821 | struct usb_driver *driver; |
| 800 | struct usb_device_driver *udriver; | 822 | struct usb_device *udev; |
| 801 | struct usb_interface *intf; | 823 | int status; |
| 802 | struct usb_driver *driver; | ||
| 803 | int status; | ||
| 804 | 824 | ||
| 805 | if (dev->power.power_state.event == PM_EVENT_ON) | 825 | if (intf->dev.power.power_state.event == PM_EVENT_ON) |
| 806 | return 0; | 826 | return 0; |
| 807 | 827 | ||
| 808 | /* mark things as "on" immediately, no matter what errors crop up */ | 828 | /* mark things as "on" immediately, no matter what errors crop up */ |
| 809 | dev->power.power_state.event = PM_EVENT_ON; | 829 | intf->dev.power.power_state.event = PM_EVENT_ON; |
| 810 | 830 | ||
| 811 | /* devices resume through their hubs */ | 831 | if (intf->dev.driver == NULL) { |
| 812 | if (is_usb_device(dev)) { | 832 | intf->dev.power.power_state.event = PM_EVENT_FREEZE; |
| 813 | if (dev->driver == NULL) | ||
| 814 | return 0; | ||
| 815 | udev = to_usb_device(dev); | ||
| 816 | udriver = to_usb_device_driver(dev->driver); | ||
| 817 | if (udev->state == USB_STATE_NOTATTACHED) | ||
| 818 | return 0; | ||
| 819 | return udriver->resume(udev); | ||
| 820 | } | ||
| 821 | |||
| 822 | if (dev->driver == NULL) { | ||
| 823 | dev->power.power_state.event = PM_EVENT_FREEZE; | ||
| 824 | return 0; | 833 | return 0; |
| 825 | } | 834 | } |
| 826 | 835 | ||
| 827 | intf = to_usb_interface(dev); | 836 | driver = to_usb_driver(intf->dev.driver); |
| 828 | driver = to_usb_driver(dev->driver); | ||
| 829 | 837 | ||
| 830 | udev = interface_to_usbdev(intf); | 838 | udev = interface_to_usbdev(intf); |
| 831 | if (udev->state == USB_STATE_NOTATTACHED) | 839 | if (udev->state == USB_STATE_NOTATTACHED) |
| @@ -838,14 +846,38 @@ static int usb_resume(struct device *dev) | |||
| 838 | if (driver->resume) { | 846 | if (driver->resume) { |
| 839 | status = driver->resume(intf); | 847 | status = driver->resume(intf); |
| 840 | if (status) { | 848 | if (status) { |
| 841 | dev_err(dev, "%s error %d\n", "resume", status); | 849 | dev_err(&intf->dev, "%s error %d\n", |
| 850 | "resume", status); | ||
| 842 | mark_quiesced(intf); | 851 | mark_quiesced(intf); |
| 843 | } | 852 | } |
| 844 | } else | 853 | } else |
| 845 | dev_warn(dev, "no resume for driver %s?\n", driver->name); | 854 | dev_warn(&intf->dev, "no resume for driver %s?\n", |
| 855 | driver->name); | ||
| 846 | return 0; | 856 | return 0; |
| 847 | } | 857 | } |
| 848 | 858 | ||
| 859 | static int usb_suspend(struct device *dev, pm_message_t message) | ||
| 860 | { | ||
| 861 | int status; | ||
| 862 | |||
| 863 | if (is_usb_device(dev)) | ||
| 864 | status = suspend_device(to_usb_device(dev), message); | ||
| 865 | else | ||
| 866 | status = suspend_interface(to_usb_interface(dev), message); | ||
| 867 | return status; | ||
| 868 | } | ||
| 869 | |||
| 870 | static int usb_resume(struct device *dev) | ||
| 871 | { | ||
| 872 | int status; | ||
| 873 | |||
| 874 | if (is_usb_device(dev)) | ||
| 875 | status = resume_device(to_usb_device(dev)); | ||
| 876 | else | ||
| 877 | status = resume_interface(to_usb_interface(dev)); | ||
| 878 | return status; | ||
| 879 | } | ||
| 880 | |||
| 849 | #endif /* CONFIG_PM */ | 881 | #endif /* CONFIG_PM */ |
| 850 | 882 | ||
| 851 | struct bus_type usb_bus_type = { | 883 | struct bus_type usb_bus_type = { |
