----- Original Message -----
> From: "CAI Qian" <[email protected]>
> To: "Greg Kroah-Hartman" <[email protected]>
> Cc: [email protected], "Alan Stern" <[email protected]>,
> "Matthias Schniedermeyer" <[email protected]>, "Sarah
> Sharp" <[email protected]>
> Sent: Friday, January 11, 2013 11:12:31 AM
> Subject: [PATCH 3.0.x] USB: fix endpoint-disabling for failed config changes
>
> Hi Greg,
>
> Since you are also the maintainer for the USB subsystem here, it is
> up
> to you to take/drop this now. :)
Sorry, forgot to mention that this version is also applied for the 3.4.y stable.
>
> Thanks,
> CAI Qian
>
> From 36caff5d795429c572443894e8789c2150dd796b Mon Sep 17 00:00:00
> 2001
> From: Alan Stern <[email protected]>
> Date: Wed, 7 Nov 2012 10:31:30 -0500
> Subject: [PATCH] USB: fix endpoint-disabling for failed config
> changes
>
> This patch (as1631) fixes a bug that shows up when a config change
> fails for a device under an xHCI controller. The controller needs to
> be told to disable the endpoints that have been enabled for the new
> config. The existing code does this, but before storing the
> information about which endpoints were enabled! As a result, any
> second attempt to install the new config is doomed to fail because
> xhci-hcd will refuse to enable an endpoint that is already enabled.
>
> The patch optimistically initializes the new endpoints' device
> structures before asking the device to switch to the new config. If
> the request fails then the endpoint information is already stored, so
> we can use usb_hcd_alloc_bandwidth() to disable the endpoints with no
> trouble. The rest of the error path is slightly more complex now; we
> have to disable the new interfaces and call put_device() rather than
> simply deallocating them.
>
> Signed-off-by: Alan Stern <[email protected]>
> Reported-and-tested-by: Matthias Schniedermeyer <[email protected]>
> CC: Sarah Sharp <[email protected]>
> CC: <[email protected]>
> Signed-off-by: Greg Kroah-Hartman <[email protected]>
> Signed-off-by: CAI Qian <[email protected]>
>
> diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
> index 806060c..3c84a03 100644
> --- a/drivers/usb/core/message.c
> +++ b/drivers/usb/core/message.c
> @@ -1770,28 +1770,8 @@ free_interfaces:
> goto free_interfaces;
> }
>
> - ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
> - USB_REQ_SET_CONFIGURATION, 0, configuration, 0,
> - NULL, 0, USB_CTRL_SET_TIMEOUT);
> - if (ret < 0) {
> - /* All the old state is gone, so what else can we do?
> - * The device is probably useless now anyway.
> - */
> - cp = NULL;
> - }
> -
> - dev->actconfig = cp;
> - if (!cp) {
> - usb_set_device_state(dev, USB_STATE_ADDRESS);
> - usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL);
> - mutex_unlock(hcd->bandwidth_mutex);
> - usb_autosuspend_device(dev);
> - goto free_interfaces;
> - }
> - mutex_unlock(hcd->bandwidth_mutex);
> - usb_set_device_state(dev, USB_STATE_CONFIGURED);
> -
> - /* Initialize the new interface structures and the
> + /*
> + * Initialize the new interface structures and the
> * hc/hcd/usbcore interface/endpoint state.
> */
> for (i = 0; i < nintf; ++i) {
> @@ -1835,6 +1815,35 @@ free_interfaces:
> }
> kfree(new_interfaces);
>
> + ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
> + USB_REQ_SET_CONFIGURATION, 0, configuration, 0,
> + NULL, 0, USB_CTRL_SET_TIMEOUT);
> + if (ret < 0 && cp) {
> + /*
> + * All the old state is gone, so what else can we do?
> + * The device is probably useless now anyway.
> + */
> + usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL);
> + for (i = 0; i < nintf; ++i) {
> + usb_disable_interface(dev, cp->interface[i], true);
> + put_device(&cp->interface[i]->dev);
> + cp->interface[i] = NULL;
> + }
> + cp = NULL;
> + }
> +
> + dev->actconfig = cp;
> + mutex_unlock(hcd->bandwidth_mutex);
> +
> + if (!cp) {
> + usb_set_device_state(dev, USB_STATE_ADDRESS);
> +
> + /* Leave LPM disabled while the device is unconfigured. */
> + usb_autosuspend_device(dev);
> + return ret;
> + }
> + usb_set_device_state(dev, USB_STATE_CONFIGURED);
> +
> if (cp->string == NULL &&
> !(dev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS))
> cp->string = usb_cache_string(dev, cp->desc.iConfiguration);
> --
> To unsubscribe from this list: send the line "unsubscribe stable" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
To unsubscribe from this list: send the line "unsubscribe stable" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html