diff options
| author | Alan Stern <stern@rowland.harvard.edu> | 2008-12-31 11:31:33 -0500 | 
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-01-07 10:00:13 -0800 | 
| commit | 2caf7fcdb8532045680f06b67b9e63f0c9613aaa (patch) | |
| tree | d9faee328532a3badd73d20e175259e8bdea271a /drivers/usb/core/message.c | |
| parent | df718962bf91c7bd345060aadaa24b03f6140b07 (diff) | |
USB: re-enable interface after driver unbinds
This patch (as1197) fixes an error introduced recently.  Since a
significant number of devices can't handle Set-Interface requests, we
no longer call usb_set_interface() when a driver unbinds from an
interface, provided the interface is already in altsetting 0.  However
the interface still does get disabled, and the call to
usb_set_interface() was the only thing re-enabling it.  Since the
interface doesn't get re-enabled, further attempts to use it fail.
So the patch adds a call to usb_enable_interface() when a driver
unbinds and the interface is in altsetting 0.  For this to work
right, the interface's endpoints have to be re-enabled but their
toggles have to be left alone.  Therefore an additional argument is
added to usb_enable_endpoint() and usb_enable_interface(), a flag
indicating whether or not the endpoint toggles should be reset.
This is a forward-ported version of a patch which fixes Bugzilla
#12301.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Reported-by: David Roka <roka@dawid.hu>
Reported-by: Erik Ekman <erik@kryo.se>
Tested-by: Erik Ekman <erik@kryo.se>
Tested-by: Alon Bar-Lev <alon.barlev@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/core/message.c')
| -rw-r--r-- | drivers/usb/core/message.c | 25 | 
1 files changed, 15 insertions, 10 deletions
| diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 5589686981f..de51667dd64 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1143,22 +1143,26 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0)   * usb_enable_endpoint - Enable an endpoint for USB communications   * @dev: the device whose interface is being enabled   * @ep: the endpoint + * @reset_toggle: flag to set the endpoint's toggle back to 0   * - * Resets the endpoint toggle, and sets dev->ep_{in,out} pointers. + * Resets the endpoint toggle if asked, and sets dev->ep_{in,out} pointers.   * For control endpoints, both the input and output sides are handled.   */ -void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep) +void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep, +		bool reset_toggle)  {  	int epnum = usb_endpoint_num(&ep->desc);  	int is_out = usb_endpoint_dir_out(&ep->desc);  	int is_control = usb_endpoint_xfer_control(&ep->desc);  	if (is_out || is_control) { -		usb_settoggle(dev, epnum, 1, 0); +		if (reset_toggle) +			usb_settoggle(dev, epnum, 1, 0);  		dev->ep_out[epnum] = ep;  	}  	if (!is_out || is_control) { -		usb_settoggle(dev, epnum, 0, 0); +		if (reset_toggle) +			usb_settoggle(dev, epnum, 0, 0);  		dev->ep_in[epnum] = ep;  	}  	ep->enabled = 1; @@ -1168,17 +1172,18 @@ void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep)   * usb_enable_interface - Enable all the endpoints for an interface   * @dev: the device whose interface is being enabled   * @intf: pointer to the interface descriptor + * @reset_toggles: flag to set the endpoints' toggles back to 0   *   * Enables all the endpoints for the interface's current altsetting.   */ -static void usb_enable_interface(struct usb_device *dev, -				 struct usb_interface *intf) +void usb_enable_interface(struct usb_device *dev, +		struct usb_interface *intf, bool reset_toggles)  {  	struct usb_host_interface *alt = intf->cur_altsetting;  	int i;  	for (i = 0; i < alt->desc.bNumEndpoints; ++i) -		usb_enable_endpoint(dev, &alt->endpoint[i]); +		usb_enable_endpoint(dev, &alt->endpoint[i], reset_toggles);  }  /** @@ -1303,7 +1308,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)  	 * during the SETUP stage - hence EP0 toggles are "don't care" here.  	 * (Likewise, EP0 never "halts" on well designed devices.)  	 */ -	usb_enable_interface(dev, iface); +	usb_enable_interface(dev, iface, true);  	if (device_is_registered(&iface->dev)) {  		usb_create_sysfs_intf_files(iface);  		create_intf_ep_devs(iface); @@ -1382,7 +1387,7 @@ int usb_reset_configuration(struct usb_device *dev)  			usb_remove_sysfs_intf_files(intf);  		}  		intf->cur_altsetting = alt; -		usb_enable_interface(dev, intf); +		usb_enable_interface(dev, intf, true);  		if (device_is_registered(&intf->dev)) {  			usb_create_sysfs_intf_files(intf);  			create_intf_ep_devs(intf); @@ -1685,7 +1690,7 @@ free_interfaces:  			alt = &intf->altsetting[0];  		intf->cur_altsetting = alt; -		usb_enable_interface(dev, intf); +		usb_enable_interface(dev, intf, true);  		intf->dev.parent = &dev->dev;  		intf->dev.driver = NULL;  		intf->dev.bus = &usb_bus_type; | 
