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 16:34:30 -0700 |
commit | f07600cf9eb3ee92777b2001e564faa413144a99 (patch) | |
tree | e48f2e3051fde642e80269bf9c54b289d4abdb44 /drivers/usb/core/hub.c | |
parent | 624d6c0732d2c4ac00945ad79dbb6ff39ba90ee3 (diff) | |
download | linux-f07600cf9eb3ee92777b2001e564faa413144a99.tar.gz |
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/hub.c')
-rw-r--r-- | drivers/usb/core/hub.c | 117 |
1 files changed, 63 insertions, 54 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index ca3dbf84e800..0b8ed414d5cf 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -605,73 +605,26 @@ static void disconnect_all_children(struct usb_hub *hub, int logical) } } -#ifdef CONFIG_USB_PERSIST - -#define USB_PERSIST 1 - -/* For "persistent-device" resets we must mark the child devices for reset - * and turn off a possible connect-change status (so khubd won't disconnect - * them later). - */ -static void mark_children_for_reset_resume(struct usb_hub *hub) -{ - struct usb_device *hdev = hub->hdev; - int port1; - - for (port1 = 1; port1 <= hdev->maxchild; ++port1) { - struct usb_device *child = hdev->children[port1-1]; - - if (child) { - child->reset_resume = 1; - clear_port_feature(hdev, port1, - USB_PORT_FEAT_C_CONNECTION); - } - } -} - -#else - -#define USB_PERSIST 0 - -static inline void mark_children_for_reset_resume(struct usb_hub *hub) -{ } - -#endif /* CONFIG_USB_PERSIST */ - /* caller has locked the hub device */ -static void hub_pre_reset(struct usb_interface *intf) +static int hub_pre_reset(struct usb_interface *intf) { struct usb_hub *hub = usb_get_intfdata(intf); - /* This routine doesn't run as part of a reset-resume, so it's safe - * to disconnect all the drivers below the hub. - */ disconnect_all_children(hub, 0); hub_quiesce(hub); + return 0; } /* caller has locked the hub device */ -static void hub_post_reset(struct usb_interface *intf, int reset_resume) +static int hub_post_reset(struct usb_interface *intf) { struct usb_hub *hub = usb_get_intfdata(intf); hub_power_on(hub); - if (reset_resume) { - if (USB_PERSIST) - mark_children_for_reset_resume(hub); - else { - /* Reset-resume doesn't call pre_reset, so we have to - * disconnect the children here. But we may not lock - * the child devices, so we have to do a "logical" - * disconnect. - */ - disconnect_all_children(hub, 1); - } - } hub_activate(hub); + return 0; } - static int hub_configure(struct usb_hub *hub, struct usb_endpoint_descriptor *endpoint) { @@ -1931,6 +1884,58 @@ static int hub_resume(struct usb_interface *intf) return 0; } +#ifdef CONFIG_USB_PERSIST + +#define USB_PERSIST 1 + +/* For "persistent-device" resets we must mark the child devices for reset + * and turn off a possible connect-change status (so khubd won't disconnect + * them later). + */ +static void mark_children_for_reset_resume(struct usb_hub *hub) +{ + struct usb_device *hdev = hub->hdev; + int port1; + + for (port1 = 1; port1 <= hdev->maxchild; ++port1) { + struct usb_device *child = hdev->children[port1-1]; + + if (child) { + child->reset_resume = 1; + clear_port_feature(hdev, port1, + USB_PORT_FEAT_C_CONNECTION); + } + } +} + +#else + +#define USB_PERSIST 0 + +static inline void mark_children_for_reset_resume(struct usb_hub *hub) +{ } + +#endif /* CONFIG_USB_PERSIST */ + +static int hub_reset_resume(struct usb_interface *intf) +{ + struct usb_hub *hub = usb_get_intfdata(intf); + + hub_power_on(hub); + if (USB_PERSIST) + mark_children_for_reset_resume(hub); + else { + /* Reset-resume doesn't call pre_reset, so we have to + * disconnect the children here. But we may not lock + * the child devices, so we have to do a "logical" + * disconnect. + */ + disconnect_all_children(hub, 1); + } + hub_activate(hub); + return 0; +} + #else /* CONFIG_PM */ static inline int remote_wakeup(struct usb_device *udev) @@ -1938,8 +1943,9 @@ static inline int remote_wakeup(struct usb_device *udev) return 0; } -#define hub_suspend NULL -#define hub_resume NULL +#define hub_suspend NULL +#define hub_resume NULL +#define hub_reset_resume NULL #endif @@ -2768,6 +2774,7 @@ static struct usb_driver hub_driver = { .disconnect = hub_disconnect, .suspend = hub_suspend, .resume = hub_resume, + .reset_resume = hub_reset_resume, .pre_reset = hub_pre_reset, .post_reset = hub_post_reset, .ioctl = hub_ioctl, @@ -3021,6 +3028,7 @@ int usb_reset_composite_device(struct usb_device *udev, drv = to_usb_driver(cintf->dev.driver); if (drv->pre_reset) (drv->pre_reset)(cintf); + /* FIXME: Unbind if pre_reset returns an error or isn't defined */ } } } @@ -3038,7 +3046,8 @@ int usb_reset_composite_device(struct usb_device *udev, cintf->dev.driver) { drv = to_usb_driver(cintf->dev.driver); if (drv->post_reset) - (drv->post_reset)(cintf, 0); + (drv->post_reset)(cintf); + /* FIXME: Unbind if post_reset returns an error or isn't defined */ } if (cintf != iface) up(&cintf->dev.sem); |