diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2007-05-30 15:38:16 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-07-12 19:34:30 -0400 |
commit | f07600cf9eb3ee92777b2001e564faa413144a99 (patch) | |
tree | e48f2e3051fde642e80269bf9c54b289d4abdb44 /drivers/usb/core/driver.c | |
parent | 624d6c0732d2c4ac00945ad79dbb6ff39ba90ee3 (diff) |
USB: add reset_resume method
This patch (as918) introduces a new USB driver method: reset_resume.
It is called when a device needs to be reset as part of a resume
procedure (whether because of a device quirk or because of the
USB-Persist facility), thereby taking over a role formerly assigned to
the post_reset method. As a consequence, post_reset no longer needs
an argument indicating whether it is being called as part of a
reset-resume. This separation of functions makes the code clearer.
In addition, the pre_reset and post_reset method return types are
changed; they now must return an error code. The return value is
unused at present, but at some later time we may unbind drivers and
re-probe if they encounter an error during reset handling.
The existing pre_reset and post_reset methods in the usbhid,
usb-storage, and hub drivers are updated to match the new
requirements. For usbhid the post_reset routine is also used for
reset_resume (duplicate method pointers); for the other drivers a new
reset_resume routine is added. The change to hub.c looks bigger than
it really is, because mark_children_for_reset_resume() gets moved down
next to the new hub_reset_resume() routine.
A minor change to usb-storage makes the usb_stor_report_bus_reset()
routine acquire the host lock instead of requiring the caller to hold
it already.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
CC: Matthew Dharm <mdharm-usb@one-eyed-alien.net>
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 | 51 |
1 files changed, 40 insertions, 11 deletions
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 6c62a6d91484..3cd9af2638fc 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c | |||
@@ -915,21 +915,37 @@ static int usb_resume_interface(struct usb_interface *intf, int reset_resume) | |||
915 | } | 915 | } |
916 | driver = to_usb_driver(intf->dev.driver); | 916 | driver = to_usb_driver(intf->dev.driver); |
917 | 917 | ||
918 | if (reset_resume && driver->post_reset) | 918 | if (reset_resume) { |
919 | driver->post_reset(intf, reset_resume); | 919 | if (driver->reset_resume) { |
920 | else if (driver->resume) { | 920 | status = driver->reset_resume(intf); |
921 | status = driver->resume(intf); | 921 | if (status) |
922 | if (status) | 922 | dev_err(&intf->dev, "%s error %d\n", |
923 | dev_err(&intf->dev, "%s error %d\n", | 923 | "reset_resume", status); |
924 | "resume", status); | 924 | } else { |
925 | } else | 925 | // status = -EOPNOTSUPP; |
926 | dev_warn(&intf->dev, "no resume for driver %s?\n", | 926 | dev_warn(&intf->dev, "no %s for driver %s?\n", |
927 | driver->name); | 927 | "reset_resume", driver->name); |
928 | } | ||
929 | } else { | ||
930 | if (driver->resume) { | ||
931 | status = driver->resume(intf); | ||
932 | if (status) | ||
933 | dev_err(&intf->dev, "%s error %d\n", | ||
934 | "resume", status); | ||
935 | } else { | ||
936 | // status = -EOPNOTSUPP; | ||
937 | dev_warn(&intf->dev, "no %s for driver %s?\n", | ||
938 | "resume", driver->name); | ||
939 | } | ||
940 | } | ||
928 | 941 | ||
929 | done: | 942 | done: |
930 | dev_vdbg(&intf->dev, "%s: status %d\n", __FUNCTION__, status); | 943 | dev_vdbg(&intf->dev, "%s: status %d\n", __FUNCTION__, status); |
931 | if (status == 0) | 944 | if (status == 0) |
932 | mark_active(intf); | 945 | mark_active(intf); |
946 | |||
947 | /* FIXME: Unbind the driver and reprobe if the resume failed | ||
948 | * (not possible if auto_pm is set) */ | ||
933 | return status; | 949 | return status; |
934 | } | 950 | } |
935 | 951 | ||
@@ -966,6 +982,18 @@ static int autosuspend_check(struct usb_device *udev) | |||
966 | "for autosuspend\n"); | 982 | "for autosuspend\n"); |
967 | return -EOPNOTSUPP; | 983 | return -EOPNOTSUPP; |
968 | } | 984 | } |
985 | |||
986 | /* Don't allow autosuspend if the device will need | ||
987 | * a reset-resume and any of its interface drivers | ||
988 | * doesn't include support. | ||
989 | */ | ||
990 | if (udev->quirks & USB_QUIRK_RESET_RESUME) { | ||
991 | struct usb_driver *driver; | ||
992 | |||
993 | driver = to_usb_driver(intf->dev.driver); | ||
994 | if (!driver->reset_resume) | ||
995 | return -EOPNOTSUPP; | ||
996 | } | ||
969 | } | 997 | } |
970 | } | 998 | } |
971 | 999 | ||
@@ -1146,7 +1174,8 @@ static int usb_resume_both(struct usb_device *udev) | |||
1146 | status = usb_autoresume_device(parent); | 1174 | status = usb_autoresume_device(parent); |
1147 | if (status == 0) { | 1175 | if (status == 0) { |
1148 | status = usb_resume_device(udev); | 1176 | status = usb_resume_device(udev); |
1149 | if (status) { | 1177 | if (status || udev->state == |
1178 | USB_STATE_NOTATTACHED) { | ||
1150 | usb_autosuspend_device(parent); | 1179 | usb_autosuspend_device(parent); |
1151 | 1180 | ||
1152 | /* It's possible usb_resume_device() | 1181 | /* It's possible usb_resume_device() |