aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/core/driver.c122
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
754static int usb_suspend(struct device *dev, pm_message_t message) 754/* Caller has locked udev */
755static 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 */
768static 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 */
787static 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
797static int usb_resume(struct device *dev) 818/* Caller has locked intf */
819static 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
859static 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
870static 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
851struct bus_type usb_bus_type = { 883struct bus_type usb_bus_type = {