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>
This commit is contained in:
Alan Stern
2007-05-30 15:38:16 -04:00
committed by Greg Kroah-Hartman
parent 624d6c0732
commit f07600cf9e
6 changed files with 140 additions and 80 deletions

View File

@ -915,21 +915,37 @@ static int usb_resume_interface(struct usb_interface *intf, int reset_resume)
}
driver = to_usb_driver(intf->dev.driver);
if (reset_resume && driver->post_reset)
driver->post_reset(intf, reset_resume);
else if (driver->resume) {
status = driver->resume(intf);
if (status)
dev_err(&intf->dev, "%s error %d\n",
"resume", status);
} else
dev_warn(&intf->dev, "no resume for driver %s?\n",
driver->name);
if (reset_resume) {
if (driver->reset_resume) {
status = driver->reset_resume(intf);
if (status)
dev_err(&intf->dev, "%s error %d\n",
"reset_resume", status);
} else {
// status = -EOPNOTSUPP;
dev_warn(&intf->dev, "no %s for driver %s?\n",
"reset_resume", driver->name);
}
} else {
if (driver->resume) {
status = driver->resume(intf);
if (status)
dev_err(&intf->dev, "%s error %d\n",
"resume", status);
} else {
// status = -EOPNOTSUPP;
dev_warn(&intf->dev, "no %s for driver %s?\n",
"resume", driver->name);
}
}
done:
dev_vdbg(&intf->dev, "%s: status %d\n", __FUNCTION__, status);
if (status == 0)
mark_active(intf);
/* FIXME: Unbind the driver and reprobe if the resume failed
* (not possible if auto_pm is set) */
return status;
}
@ -966,6 +982,18 @@ static int autosuspend_check(struct usb_device *udev)
"for autosuspend\n");
return -EOPNOTSUPP;
}
/* Don't allow autosuspend if the device will need
* a reset-resume and any of its interface drivers
* doesn't include support.
*/
if (udev->quirks & USB_QUIRK_RESET_RESUME) {
struct usb_driver *driver;
driver = to_usb_driver(intf->dev.driver);
if (!driver->reset_resume)
return -EOPNOTSUPP;
}
}
}
@ -1146,7 +1174,8 @@ static int usb_resume_both(struct usb_device *udev)
status = usb_autoresume_device(parent);
if (status == 0) {
status = usb_resume_device(udev);
if (status) {
if (status || udev->state ==
USB_STATE_NOTATTACHED) {
usb_autosuspend_device(parent);
/* It's possible usb_resume_device()