----- 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

Reply via email to