lkml.org 
[lkml]   [2009]   [Jan]   [22]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[patch 26/46] USB: re-enable interface after driver unbinds
    2.6.28-stable review patch.  If anyone has any objections, please let us know.

    ------------------

    From: Alan Stern <stern@rowland.harvard.edu>

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

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


    \
     
     \ /
      Last update: 2009-01-23 02:25    [W:0.033 / U:0.048 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site