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 = { |