diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2014-03-12 11:30:38 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-03-17 16:08:27 -0700 |
commit | 6aec044cc2f5670cf3b143c151c8be846499bd15 (patch) | |
tree | a2d0c9ba0e26e9029a0f62948540799ed53703bf /drivers/usb/core/hub.c | |
parent | ead5178bf442dbae4008ee54bf4f66a1f6a317c9 (diff) | |
download | linux-6aec044cc2f5670cf3b143c151c8be846499bd15.tar.gz linux-6aec044cc2f5670cf3b143c151c8be846499bd15.tar.bz2 linux-6aec044cc2f5670cf3b143c151c8be846499bd15.zip |
USB: unbind all interfaces before rebinding any
When a driver doesn't have pre_reset, post_reset, or reset_resume
methods, the USB core unbinds that driver when its device undergoes a
reset or a reset-resume, and then rebinds it afterward.
The existing straightforward implementation can lead to problems,
because each interface gets unbound and rebound before the next
interface is handled. If a driver claims additional interfaces, the
claim may fail because the old binding instance may still own the
additional interface when the new instance tries to claim it.
This patch fixes the problem by first unbinding all the interfaces
that are marked (i.e., their needs_binding flag is set) and then
rebinding all of them.
The patch also makes the helper functions in driver.c a little more
uniform and adjusts some out-of-date comments.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Reported-and-tested-by: "Poulain, Loic" <loic.poulain@intel.com>
Cc: stable <stable@vger.kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/core/hub.c')
-rw-r--r-- | drivers/usb/core/hub.c | 5 |
1 files changed, 3 insertions, 2 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 5da5394127e9..2d74dfb9c989 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -5380,10 +5380,11 @@ int usb_reset_device(struct usb_device *udev) else if (cintf->condition == USB_INTERFACE_BOUND) rebind = 1; + if (rebind) + cintf->needs_binding = 1; } - if (ret == 0 && rebind) - usb_rebind_intf(cintf); } + usb_unbind_and_rebind_marked_interfaces(udev); } usb_autosuspend_device(udev); |