aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/core
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2008-12-31 11:31:33 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2009-01-07 13:00:13 -0500
commit2caf7fcdb8532045680f06b67b9e63f0c9613aaa (patch)
treed9faee328532a3badd73d20e175259e8bdea271a /drivers/usb/core
parentdf718962bf91c7bd345060aadaa24b03f6140b07 (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')
-rw-r--r--drivers/usb/core/driver.c9
-rw-r--r--drivers/usb/core/hub.c2
-rw-r--r--drivers/usb/core/message.c25
-rw-r--r--drivers/usb/core/usb.c2
-rw-r--r--drivers/usb/core/usb.h4
5 files changed, 26 insertions, 16 deletions
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 41c06025506e..98760553bc95 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -295,9 +295,12 @@ static int usb_unbind_interface(struct device *dev)
295 * altsetting means creating new endpoint device entries). 295 * altsetting means creating new endpoint device entries).
296 * When either of these happens, defer the Set-Interface. 296 * When either of these happens, defer the Set-Interface.
297 */ 297 */
298 if (intf->cur_altsetting->desc.bAlternateSetting == 0) 298 if (intf->cur_altsetting->desc.bAlternateSetting == 0) {
299 ; /* Already in altsetting 0 so skip Set-Interface */ 299 /* Already in altsetting 0 so skip Set-Interface.
300 else if (!error && intf->dev.power.status == DPM_ON) 300 * Just re-enable it without affecting the endpoint toggles.
301 */
302 usb_enable_interface(udev, intf, false);
303 } else if (!error && intf->dev.power.status == DPM_ON)
301 usb_set_interface(udev, intf->altsetting[0]. 304 usb_set_interface(udev, intf->altsetting[0].
302 desc.bInterfaceNumber, 0); 305 desc.bInterfaceNumber, 0);
303 else 306 else
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 756b8d9993fc..d5d0e40b1e2d 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -2384,7 +2384,7 @@ void usb_ep0_reinit(struct usb_device *udev)
2384{ 2384{
2385 usb_disable_endpoint(udev, 0 + USB_DIR_IN); 2385 usb_disable_endpoint(udev, 0 + USB_DIR_IN);
2386 usb_disable_endpoint(udev, 0 + USB_DIR_OUT); 2386 usb_disable_endpoint(udev, 0 + USB_DIR_OUT);
2387 usb_enable_endpoint(udev, &udev->ep0); 2387 usb_enable_endpoint(udev, &udev->ep0, true);
2388} 2388}
2389EXPORT_SYMBOL_GPL(usb_ep0_reinit); 2389EXPORT_SYMBOL_GPL(usb_ep0_reinit);
2390 2390
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 5589686981f1..de51667dd64d 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)
1143 * usb_enable_endpoint - Enable an endpoint for USB communications 1143 * usb_enable_endpoint - Enable an endpoint for USB communications
1144 * @dev: the device whose interface is being enabled 1144 * @dev: the device whose interface is being enabled
1145 * @ep: the endpoint 1145 * @ep: the endpoint
1146 * @reset_toggle: flag to set the endpoint's toggle back to 0
1146 * 1147 *
1147 * Resets the endpoint toggle, and sets dev->ep_{in,out} pointers. 1148 * Resets the endpoint toggle if asked, and sets dev->ep_{in,out} pointers.
1148 * For control endpoints, both the input and output sides are handled. 1149 * For control endpoints, both the input and output sides are handled.
1149 */ 1150 */
1150void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep) 1151void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep,
1152 bool reset_toggle)
1151{ 1153{
1152 int epnum = usb_endpoint_num(&ep->desc); 1154 int epnum = usb_endpoint_num(&ep->desc);
1153 int is_out = usb_endpoint_dir_out(&ep->desc); 1155 int is_out = usb_endpoint_dir_out(&ep->desc);
1154 int is_control = usb_endpoint_xfer_control(&ep->desc); 1156 int is_control = usb_endpoint_xfer_control(&ep->desc);
1155 1157
1156 if (is_out || is_control) { 1158 if (is_out || is_control) {
1157 usb_settoggle(dev, epnum, 1, 0); 1159 if (reset_toggle)
1160 usb_settoggle(dev, epnum, 1, 0);
1158 dev->ep_out[epnum] = ep; 1161 dev->ep_out[epnum] = ep;
1159 } 1162 }
1160 if (!is_out || is_control) { 1163 if (!is_out || is_control) {
1161 usb_settoggle(dev, epnum, 0, 0); 1164 if (reset_toggle)
1165 usb_settoggle(dev, epnum, 0, 0);
1162 dev->ep_in[epnum] = ep; 1166 dev->ep_in[epnum] = ep;
1163 } 1167 }
1164 ep->enabled = 1; 1168 ep->enabled = 1;
@@ -1168,17 +1172,18 @@ void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep)
1168 * usb_enable_interface - Enable all the endpoints for an interface 1172 * usb_enable_interface - Enable all the endpoints for an interface
1169 * @dev: the device whose interface is being enabled 1173 * @dev: the device whose interface is being enabled
1170 * @intf: pointer to the interface descriptor 1174 * @intf: pointer to the interface descriptor
1175 * @reset_toggles: flag to set the endpoints' toggles back to 0
1171 * 1176 *
1172 * Enables all the endpoints for the interface's current altsetting. 1177 * Enables all the endpoints for the interface's current altsetting.
1173 */ 1178 */
1174static void usb_enable_interface(struct usb_device *dev, 1179void usb_enable_interface(struct usb_device *dev,
1175 struct usb_interface *intf) 1180 struct usb_interface *intf, bool reset_toggles)
1176{ 1181{
1177 struct usb_host_interface *alt = intf->cur_altsetting; 1182 struct usb_host_interface *alt = intf->cur_altsetting;
1178 int i; 1183 int i;
1179 1184
1180 for (i = 0; i < alt->desc.bNumEndpoints; ++i) 1185 for (i = 0; i < alt->desc.bNumEndpoints; ++i)
1181 usb_enable_endpoint(dev, &alt->endpoint[i]); 1186 usb_enable_endpoint(dev, &alt->endpoint[i], reset_toggles);
1182} 1187}
1183 1188
1184/** 1189/**
@@ -1303,7 +1308,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
1303 * during the SETUP stage - hence EP0 toggles are "don't care" here. 1308 * during the SETUP stage - hence EP0 toggles are "don't care" here.
1304 * (Likewise, EP0 never "halts" on well designed devices.) 1309 * (Likewise, EP0 never "halts" on well designed devices.)
1305 */ 1310 */
1306 usb_enable_interface(dev, iface); 1311 usb_enable_interface(dev, iface, true);
1307 if (device_is_registered(&iface->dev)) { 1312 if (device_is_registered(&iface->dev)) {
1308 usb_create_sysfs_intf_files(iface); 1313 usb_create_sysfs_intf_files(iface);
1309 create_intf_ep_devs(iface); 1314 create_intf_ep_devs(iface);
@@ -1382,7 +1387,7 @@ int usb_reset_configuration(struct usb_device *dev)
1382 usb_remove_sysfs_intf_files(intf); 1387 usb_remove_sysfs_intf_files(intf);
1383 } 1388 }
1384 intf->cur_altsetting = alt; 1389 intf->cur_altsetting = alt;
1385 usb_enable_interface(dev, intf); 1390 usb_enable_interface(dev, intf, true);
1386 if (device_is_registered(&intf->dev)) { 1391 if (device_is_registered(&intf->dev)) {
1387 usb_create_sysfs_intf_files(intf); 1392 usb_create_sysfs_intf_files(intf);
1388 create_intf_ep_devs(intf); 1393 create_intf_ep_devs(intf);
@@ -1685,7 +1690,7 @@ free_interfaces:
1685 alt = &intf->altsetting[0]; 1690 alt = &intf->altsetting[0];
1686 1691
1687 intf->cur_altsetting = alt; 1692 intf->cur_altsetting = alt;
1688 usb_enable_interface(dev, intf); 1693 usb_enable_interface(dev, intf, true);
1689 intf->dev.parent = &dev->dev; 1694 intf->dev.parent = &dev->dev;
1690 intf->dev.driver = NULL; 1695 intf->dev.driver = NULL;
1691 intf->dev.bus = &usb_bus_type; 1696 intf->dev.bus = &usb_bus_type;
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index c0821564a3fe..dcfc072630c1 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -362,7 +362,7 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
362 dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE; 362 dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE;
363 dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT; 363 dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT;
364 /* ep0 maxpacket comes later, from device descriptor */ 364 /* ep0 maxpacket comes later, from device descriptor */
365 usb_enable_endpoint(dev, &dev->ep0); 365 usb_enable_endpoint(dev, &dev->ep0, true);
366 dev->can_submit = 1; 366 dev->can_submit = 1;
367 367
368 /* Save readable and stable topology id, distinguishing devices 368 /* Save readable and stable topology id, distinguishing devices
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index 381eae90c3b7..386177867a8a 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -12,7 +12,9 @@ extern int usb_create_ep_devs(struct device *parent,
12extern void usb_remove_ep_devs(struct usb_host_endpoint *endpoint); 12extern void usb_remove_ep_devs(struct usb_host_endpoint *endpoint);
13 13
14extern void usb_enable_endpoint(struct usb_device *dev, 14extern void usb_enable_endpoint(struct usb_device *dev,
15 struct usb_host_endpoint *ep); 15 struct usb_host_endpoint *ep, bool reset_toggle);
16extern void usb_enable_interface(struct usb_device *dev,
17 struct usb_interface *intf, bool reset_toggles);
16extern void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr); 18extern void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr);
17extern void usb_disable_interface(struct usb_device *dev, 19extern void usb_disable_interface(struct usb_device *dev,
18 struct usb_interface *intf); 20 struct usb_interface *intf);