From d08ad5434259f6c4ec0f6e6391a31e4c5484c0ea Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 22 Jan 2009 12:00:44 -0800 Subject: [PATCH] .28 patch --- queue-2.6.28/series | 1 + ...nable-interface-after-driver-unbinds.patch | 177 ++++++++++++++++++ 2 files changed, 178 insertions(+) create mode 100644 queue-2.6.28/usb-re-enable-interface-after-driver-unbinds.patch diff --git a/queue-2.6.28/series b/queue-2.6.28/series index 797aaa845f7..c108c4f094c 100644 --- a/queue-2.6.28/series +++ b/queue-2.6.28/series @@ -24,3 +24,4 @@ r6040-fix-wrong-logic-in-mdio-code.patch r6040-save-and-restore-mier-correctly-in-the-interrupt-routine.patch r6040-bump-release-number-to-0.19.patch tcp-don-t-mask-eof-and-socket-errors-on-nonblocking-splice-receive.patch +usb-re-enable-interface-after-driver-unbinds.patch diff --git a/queue-2.6.28/usb-re-enable-interface-after-driver-unbinds.patch b/queue-2.6.28/usb-re-enable-interface-after-driver-unbinds.patch new file mode 100644 index 00000000000..a934f2a14db --- /dev/null +++ b/queue-2.6.28/usb-re-enable-interface-after-driver-unbinds.patch @@ -0,0 +1,177 @@ +From 2caf7fcdb8532045680f06b67b9e63f0c9613aaa Mon Sep 17 00:00:00 2001 +From: Alan Stern +Date: Wed, 31 Dec 2008 11:31:33 -0500 +Subject: USB: re-enable interface after driver unbinds + +From: Alan Stern + +commit 2caf7fcdb8532045680f06b67b9e63f0c9613aaa upstream. + +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 +Reported-by: David Roka +Reported-by: Erik Ekman +Tested-by: Erik Ekman +Tested-by: Alon Bar-Lev +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/core/driver.c | 9 ++++++--- + drivers/usb/core/hub.c | 2 +- + drivers/usb/core/message.c | 25 +++++++++++++++---------- + drivers/usb/core/usb.c | 2 +- + drivers/usb/core/usb.h | 4 +++- + 5 files changed, 26 insertions(+), 16 deletions(-) + +--- a/drivers/usb/core/driver.c ++++ b/drivers/usb/core/driver.c +@@ -279,9 +279,12 @@ static int usb_unbind_interface(struct d + * altsetting means creating new endpoint device entries). + * When either of these happens, defer the Set-Interface. + */ +- if (intf->cur_altsetting->desc.bAlternateSetting == 0) +- ; /* Already in altsetting 0 so skip Set-Interface */ +- else if (!error && intf->dev.power.status == DPM_ON) ++ if (intf->cur_altsetting->desc.bAlternateSetting == 0) { ++ /* Already in altsetting 0 so skip Set-Interface. ++ * Just re-enable it without affecting the endpoint toggles. ++ */ ++ usb_enable_interface(udev, intf, false); ++ } else if (!error && intf->dev.power.status == DPM_ON) + usb_set_interface(udev, intf->altsetting[0]. + desc.bInterfaceNumber, 0); + else +--- a/drivers/usb/core/hub.c ++++ b/drivers/usb/core/hub.c +@@ -2385,7 +2385,7 @@ void usb_ep0_reinit(struct usb_device *u + { + usb_disable_endpoint(udev, 0 + USB_DIR_IN); + usb_disable_endpoint(udev, 0 + USB_DIR_OUT); +- usb_enable_endpoint(udev, &udev->ep0); ++ usb_enable_endpoint(udev, &udev->ep0, true); + } + EXPORT_SYMBOL_GPL(usb_ep0_reinit); + +--- a/drivers/usb/core/message.c ++++ b/drivers/usb/core/message.c +@@ -1113,22 +1113,26 @@ void usb_disable_device(struct usb_devic + * 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; +@@ -1138,17 +1142,18 @@ void usb_enable_endpoint(struct usb_devi + * 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); + } + + /** +@@ -1271,7 +1276,7 @@ int usb_set_interface(struct usb_device + * 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); + +@@ -1346,7 +1351,7 @@ int usb_reset_configuration(struct usb_d + alt = &intf->altsetting[0]; + + 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); + } +@@ -1604,7 +1609,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; +--- a/drivers/usb/core/usb.c ++++ b/drivers/usb/core/usb.c +@@ -362,7 +362,7 @@ struct usb_device *usb_alloc_dev(struct + dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE; + dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT; + /* ep0 maxpacket comes later, from device descriptor */ +- usb_enable_endpoint(dev, &dev->ep0); ++ usb_enable_endpoint(dev, &dev->ep0, true); + dev->can_submit = 1; + + /* Save readable and stable topology id, distinguishing devices +--- a/drivers/usb/core/usb.h ++++ b/drivers/usb/core/usb.h +@@ -10,7 +10,9 @@ extern int usb_create_ep_files(struct de + extern void usb_remove_ep_files(struct usb_host_endpoint *endpoint); + + extern void usb_enable_endpoint(struct usb_device *dev, +- struct usb_host_endpoint *ep); ++ struct usb_host_endpoint *ep, bool reset_toggle); ++extern void usb_enable_interface(struct usb_device *dev, ++ struct usb_interface *intf, bool reset_toggles); + extern void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr); + extern void usb_disable_interface(struct usb_device *dev, + struct usb_interface *intf); -- 2.47.3