Commit 3f141e2a authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman

USB: unconfigure devices which have config 0

Some USB devices do have a configuration 0, in contravention of the
USB spec.  Normally 0 is supposed to indicate that a device is
unconfigured.

While we can't change what the device is doing, we can change usbcore.
This patch (as852) allows usb_set_configuration() to accept a config
value of -1 as indicating that the device should be unconfigured.  The
request actually sent to the device will still contain 0 as the value.
But even if the device does have a configuration 0, dev->actconfig
will be set to NULL and dev->state will be set to USB_STATE_ADDRESS.

Without some sort of special-case handling like this, there is no way
to unconfigure these non-compliant devices.
Signed-off-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent d1bbb600
...@@ -857,11 +857,11 @@ static int proc_setintf(struct dev_state *ps, void __user *arg) ...@@ -857,11 +857,11 @@ static int proc_setintf(struct dev_state *ps, void __user *arg)
static int proc_setconfig(struct dev_state *ps, void __user *arg) static int proc_setconfig(struct dev_state *ps, void __user *arg)
{ {
unsigned int u; int u;
int status = 0; int status = 0;
struct usb_host_config *actconfig; struct usb_host_config *actconfig;
if (get_user(u, (unsigned int __user *)arg)) if (get_user(u, (int __user *)arg))
return -EFAULT; return -EFAULT;
actconfig = ps->dev->actconfig; actconfig = ps->dev->actconfig;
......
...@@ -184,7 +184,7 @@ static void generic_disconnect(struct usb_device *udev) ...@@ -184,7 +184,7 @@ static void generic_disconnect(struct usb_device *udev)
/* if this is only an unbind, not a physical disconnect, then /* if this is only an unbind, not a physical disconnect, then
* unconfigure the device */ * unconfigure the device */
if (udev->actconfig) if (udev->actconfig)
usb_set_configuration(udev, 0); usb_set_configuration(udev, -1);
usb_remove_sysfs_dev_files(udev); usb_remove_sysfs_dev_files(udev);
} }
......
...@@ -1316,6 +1316,14 @@ static void release_interface(struct device *dev) ...@@ -1316,6 +1316,14 @@ static void release_interface(struct device *dev)
* use this kind of configurability; many devices only have one * use this kind of configurability; many devices only have one
* configuration. * configuration.
* *
* @configuration is the value of the configuration to be installed.
* According to the USB spec (e.g. section 9.1.1.5), configuration values
* must be non-zero; a value of zero indicates that the device in
* unconfigured. However some devices erroneously use 0 as one of their
* configuration values. To help manage such devices, this routine will
* accept @configuration = -1 as indicating the device should be put in
* an unconfigured state.
*
* USB device configurations may affect Linux interoperability, * USB device configurations may affect Linux interoperability,
* power consumption and the functionality available. For example, * power consumption and the functionality available. For example,
* the default configuration is limited to using 100mA of bus power, * the default configuration is limited to using 100mA of bus power,
...@@ -1347,10 +1355,15 @@ int usb_set_configuration(struct usb_device *dev, int configuration) ...@@ -1347,10 +1355,15 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
struct usb_interface **new_interfaces = NULL; struct usb_interface **new_interfaces = NULL;
int n, nintf; int n, nintf;
for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { if (configuration == -1)
if (dev->config[i].desc.bConfigurationValue == configuration) { configuration = 0;
cp = &dev->config[i]; else {
break; for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
if (dev->config[i].desc.bConfigurationValue ==
configuration) {
cp = &dev->config[i];
break;
}
} }
} }
if ((!cp && configuration != 0)) if ((!cp && configuration != 0))
...@@ -1359,6 +1372,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration) ...@@ -1359,6 +1372,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
/* The USB spec says configuration 0 means unconfigured. /* The USB spec says configuration 0 means unconfigured.
* But if a device includes a configuration numbered 0, * But if a device includes a configuration numbered 0,
* we will accept it as a correctly configured state. * we will accept it as a correctly configured state.
* Use -1 if you really want to unconfigure the device.
*/ */
if (cp && configuration == 0) if (cp && configuration == 0)
dev_warn(&dev->dev, "config 0 descriptor??\n"); dev_warn(&dev->dev, "config 0 descriptor??\n");
......
...@@ -63,7 +63,7 @@ set_bConfigurationValue(struct device *dev, struct device_attribute *attr, ...@@ -63,7 +63,7 @@ set_bConfigurationValue(struct device *dev, struct device_attribute *attr,
struct usb_device *udev = to_usb_device(dev); struct usb_device *udev = to_usb_device(dev);
int config, value; int config, value;
if (sscanf(buf, "%u", &config) != 1 || config > 255) if (sscanf(buf, "%d", &config) != 1 || config < -1 || config > 255)
return -EINVAL; return -EINVAL;
usb_lock_device(udev); usb_lock_device(udev);
value = usb_set_configuration(udev, config); value = usb_set_configuration(udev, config);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment