aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2010-09-30 15:16:23 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2010-10-22 13:22:01 -0400
commit80f0cf3947889014d3a3dc0ad60fb87cfda4b12a (patch)
treedf1a1b880c7c13b68c1e368668e00b4d7e3e75b5
parentcf7d3c8e579a643ff81ff95d51babdaf4c55f5f4 (diff)
USB: disable endpoints after unbinding interfaces, not before
This patch (as1430) fixes a bug in usbcore. When a device configuration change occurs or a device is removed, the endpoints for the old config should be completely disabled. However it turns out they aren't; this is because usb_unbind_interface() calls usb_enable_interface() or usb_set_interface() to put interfaces back in altsetting 0, which re-enables the interfaces' endpoints. As a result, when a device goes through a config change or is unconfigured, the ep_in[] and ep_out[] arrays may be left holding old pointers to usb_host_endpoint structures. If the device is deauthorized these structures get freed, and the stale pointers cause errors when the the device is eventually unplugged. The solution is to disable the endpoints after unbinding the interfaces instead of before. This isn't as large a change as it sounds, since usb_unbind_interface() disables all the interface's endpoints anyway before calling the driver's disconnect routine, unless the driver claims to support "soft" unbind. This fixes Bugzilla #19192. Thanks to "Tom" Lei Ming for diagnosing the underlying cause of the problem. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Tested-by: Carsten Sommer <carsten_sommer@ymail.com> CC: stable <stable@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/usb/core/message.c14
1 files changed, 7 insertions, 7 deletions
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 9f0ce7de0e36..d6e3e410477e 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -1140,13 +1140,6 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0)
1140{ 1140{
1141 int i; 1141 int i;
1142 1142
1143 dev_dbg(&dev->dev, "%s nuking %s URBs\n", __func__,
1144 skip_ep0 ? "non-ep0" : "all");
1145 for (i = skip_ep0; i < 16; ++i) {
1146 usb_disable_endpoint(dev, i, true);
1147 usb_disable_endpoint(dev, i + USB_DIR_IN, true);
1148 }
1149
1150 /* getting rid of interfaces will disconnect 1143 /* getting rid of interfaces will disconnect
1151 * any drivers bound to them (a key side effect) 1144 * any drivers bound to them (a key side effect)
1152 */ 1145 */
@@ -1176,6 +1169,13 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0)
1176 if (dev->state == USB_STATE_CONFIGURED) 1169 if (dev->state == USB_STATE_CONFIGURED)
1177 usb_set_device_state(dev, USB_STATE_ADDRESS); 1170 usb_set_device_state(dev, USB_STATE_ADDRESS);
1178 } 1171 }
1172
1173 dev_dbg(&dev->dev, "%s nuking %s URBs\n", __func__,
1174 skip_ep0 ? "non-ep0" : "all");
1175 for (i = skip_ep0; i < 16; ++i) {
1176 usb_disable_endpoint(dev, i, true);
1177 usb_disable_endpoint(dev, i + USB_DIR_IN, true);
1178 }
1179} 1179}
1180 1180
1181/** 1181/**