diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2006-07-01 22:12:19 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-09-27 14:58:50 -0400 |
commit | 2bf4086d7a7722b470aa24e1be725cc58619c6fe (patch) | |
tree | 26724ce626c7b522311d7f9993527a8d2a0268fd /drivers/usb/core/driver.c | |
parent | 4d064c080265a41324d108fccc26b72106d43db3 (diff) |
usbcore: set device and power states properly
This patch (as733) fixes up the places where device states and power
states are set in usbcore. Right now things are duplicated or missing;
this should straighten things out.
The idea is that udev->state is USB_STATE_SUSPENDED exactly when the
device's upstream port has been suspended, whereas
udev->dev.power.power_state.event reflects the result of the last call
to the suspend/resume routines (which might not actually change the
device state, especially if CONFIG_USB_SUSPEND isn't set).
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/core/driver.c')
-rw-r--r-- | drivers/usb/core/driver.c | 71 |
1 files changed, 42 insertions, 29 deletions
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index eefc98584eac..92ecc4eb1e88 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c | |||
@@ -755,48 +755,57 @@ EXPORT_SYMBOL_GPL_FUTURE(usb_deregister); | |||
755 | static int suspend_device(struct usb_device *udev, pm_message_t msg) | 755 | static int suspend_device(struct usb_device *udev, pm_message_t msg) |
756 | { | 756 | { |
757 | struct usb_device_driver *udriver; | 757 | struct usb_device_driver *udriver; |
758 | int status = 0; | ||
758 | 759 | ||
759 | if (udev->dev.driver == NULL) | 760 | if (udev->dev.driver == NULL) |
760 | return 0; | 761 | goto done; |
761 | udriver = to_usb_device_driver(udev->dev.driver); | 762 | udriver = to_usb_device_driver(udev->dev.driver); |
762 | if (udev->dev.power.power_state.event == msg.event) | 763 | if (udev->dev.power.power_state.event == msg.event) |
763 | return 0; | 764 | goto done; |
764 | return udriver->suspend(udev, msg); | 765 | status = udriver->suspend(udev, msg); |
766 | |||
767 | done: | ||
768 | if (status == 0) | ||
769 | udev->dev.power.power_state.event = msg.event; | ||
770 | return status; | ||
765 | } | 771 | } |
766 | 772 | ||
767 | /* Caller has locked udev */ | 773 | /* Caller has locked udev */ |
768 | static int resume_device(struct usb_device *udev) | 774 | static int resume_device(struct usb_device *udev) |
769 | { | 775 | { |
770 | struct usb_device_driver *udriver; | 776 | struct usb_device_driver *udriver; |
777 | int status = 0; | ||
771 | 778 | ||
772 | if (udev->dev.power.power_state.event == PM_EVENT_ON) | 779 | if (udev->dev.power.power_state.event == PM_EVENT_ON) |
773 | return 0; | 780 | goto done; |
774 | |||
775 | /* mark things as "on" immediately, no matter what errors crop up */ | ||
776 | udev->dev.power.power_state.event = PM_EVENT_ON; | ||
777 | 781 | ||
778 | if (udev->dev.driver == NULL) | 782 | if (udev->dev.driver == NULL) |
779 | return 0; | 783 | goto done; |
780 | udriver = to_usb_device_driver(udev->dev.driver); | 784 | udriver = to_usb_device_driver(udev->dev.driver); |
781 | if (udev->state == USB_STATE_NOTATTACHED) | 785 | if (udev->state == USB_STATE_NOTATTACHED) |
782 | return 0; | 786 | goto done; |
783 | return udriver->resume(udev); | 787 | status = udriver->resume(udev); |
788 | |||
789 | done: | ||
790 | if (status == 0) | ||
791 | udev->dev.power.power_state.event = PM_EVENT_ON; | ||
792 | return status; | ||
784 | } | 793 | } |
785 | 794 | ||
786 | /* Caller has locked intf's usb_device */ | 795 | /* Caller has locked intf's usb_device */ |
787 | static int suspend_interface(struct usb_interface *intf, pm_message_t msg) | 796 | static int suspend_interface(struct usb_interface *intf, pm_message_t msg) |
788 | { | 797 | { |
789 | struct usb_driver *driver; | 798 | struct usb_driver *driver; |
790 | int status; | 799 | int status = 0; |
791 | 800 | ||
792 | if (intf->dev.driver == NULL) | 801 | if (intf->dev.driver == NULL) |
793 | return 0; | 802 | goto done; |
794 | 803 | ||
795 | driver = to_usb_driver(intf->dev.driver); | 804 | driver = to_usb_driver(intf->dev.driver); |
796 | 805 | ||
797 | /* with no hardware, USB interfaces only use FREEZE and ON states */ | 806 | /* with no hardware, USB interfaces only use FREEZE and ON states */ |
798 | if (!is_active(intf)) | 807 | if (!is_active(intf)) |
799 | return 0; | 808 | goto done; |
800 | 809 | ||
801 | if (driver->suspend && driver->resume) { | 810 | if (driver->suspend && driver->resume) { |
802 | status = driver->suspend(intf, msg); | 811 | status = driver->suspend(intf, msg); |
@@ -810,8 +819,11 @@ static int suspend_interface(struct usb_interface *intf, pm_message_t msg) | |||
810 | dev_warn(&intf->dev, "no suspend for driver %s?\n", | 819 | dev_warn(&intf->dev, "no suspend for driver %s?\n", |
811 | driver->name); | 820 | driver->name); |
812 | mark_quiesced(intf); | 821 | mark_quiesced(intf); |
813 | status = 0; | ||
814 | } | 822 | } |
823 | |||
824 | done: | ||
825 | if (status == 0) | ||
826 | intf->dev.power.power_state.event = msg.event; | ||
815 | return status; | 827 | return status; |
816 | } | 828 | } |
817 | 829 | ||
@@ -820,24 +832,19 @@ static int resume_interface(struct usb_interface *intf) | |||
820 | { | 832 | { |
821 | struct usb_driver *driver; | 833 | struct usb_driver *driver; |
822 | struct usb_device *udev; | 834 | struct usb_device *udev; |
823 | int status; | 835 | int status = 0; |
824 | 836 | ||
825 | if (intf->dev.power.power_state.event == PM_EVENT_ON) | 837 | if (intf->dev.power.power_state.event == PM_EVENT_ON) |
826 | return 0; | 838 | goto done; |
827 | |||
828 | /* mark things as "on" immediately, no matter what errors crop up */ | ||
829 | intf->dev.power.power_state.event = PM_EVENT_ON; | ||
830 | 839 | ||
831 | if (intf->dev.driver == NULL) { | 840 | if (intf->dev.driver == NULL) |
832 | intf->dev.power.power_state.event = PM_EVENT_FREEZE; | 841 | goto done; |
833 | return 0; | ||
834 | } | ||
835 | 842 | ||
836 | driver = to_usb_driver(intf->dev.driver); | 843 | driver = to_usb_driver(intf->dev.driver); |
837 | 844 | ||
838 | udev = interface_to_usbdev(intf); | 845 | udev = interface_to_usbdev(intf); |
839 | if (udev->state == USB_STATE_NOTATTACHED) | 846 | if (udev->state == USB_STATE_NOTATTACHED) |
840 | return 0; | 847 | goto done; |
841 | 848 | ||
842 | /* if driver was suspended, it has a resume method; | 849 | /* if driver was suspended, it has a resume method; |
843 | * however, sysfs can wrongly mark things as suspended | 850 | * however, sysfs can wrongly mark things as suspended |
@@ -845,15 +852,21 @@ static int resume_interface(struct usb_interface *intf) | |||
845 | */ | 852 | */ |
846 | if (driver->resume) { | 853 | if (driver->resume) { |
847 | status = driver->resume(intf); | 854 | status = driver->resume(intf); |
848 | if (status) { | 855 | if (status) |
849 | dev_err(&intf->dev, "%s error %d\n", | 856 | dev_err(&intf->dev, "%s error %d\n", |
850 | "resume", status); | 857 | "resume", status); |
851 | mark_quiesced(intf); | 858 | else |
852 | } | 859 | mark_active(intf); |
853 | } else | 860 | } else { |
854 | dev_warn(&intf->dev, "no resume for driver %s?\n", | 861 | dev_warn(&intf->dev, "no resume for driver %s?\n", |
855 | driver->name); | 862 | driver->name); |
856 | return 0; | 863 | mark_active(intf); |
864 | } | ||
865 | |||
866 | done: | ||
867 | if (status == 0) | ||
868 | intf->dev.power.power_state.event = PM_EVENT_ON; | ||
869 | return status; | ||
857 | } | 870 | } |
858 | 871 | ||
859 | /* Caller has locked udev */ | 872 | /* Caller has locked udev */ |