diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2007-02-08 16:40:43 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-02-16 18:32:21 -0500 |
commit | 3f141e2aed586c41c2666d49c70c1c1bbb6d6abd (patch) | |
tree | d7308c465ec658fd09b5f6969ccf8a8e9b48f131 | |
parent | d1bbb60007597b920beca72cd0b413d10290310a (diff) |
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: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | drivers/usb/core/devio.c | 4 | ||||
-rw-r--r-- | drivers/usb/core/generic.c | 2 | ||||
-rw-r--r-- | drivers/usb/core/message.c | 22 | ||||
-rw-r--r-- | drivers/usb/core/sysfs.c | 2 |
4 files changed, 22 insertions, 8 deletions
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 2087766f9e88..274f14f1633e 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c | |||
@@ -857,11 +857,11 @@ static int proc_setintf(struct dev_state *ps, void __user *arg) | |||
857 | 857 | ||
858 | static int proc_setconfig(struct dev_state *ps, void __user *arg) | 858 | static int proc_setconfig(struct dev_state *ps, void __user *arg) |
859 | { | 859 | { |
860 | unsigned int u; | 860 | int u; |
861 | int status = 0; | 861 | int status = 0; |
862 | struct usb_host_config *actconfig; | 862 | struct usb_host_config *actconfig; |
863 | 863 | ||
864 | if (get_user(u, (unsigned int __user *)arg)) | 864 | if (get_user(u, (int __user *)arg)) |
865 | return -EFAULT; | 865 | return -EFAULT; |
866 | 866 | ||
867 | actconfig = ps->dev->actconfig; | 867 | actconfig = ps->dev->actconfig; |
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index b531a4fd30c2..9bbcb20e2d94 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c | |||
@@ -184,7 +184,7 @@ static void generic_disconnect(struct usb_device *udev) | |||
184 | /* if this is only an unbind, not a physical disconnect, then | 184 | /* if this is only an unbind, not a physical disconnect, then |
185 | * unconfigure the device */ | 185 | * unconfigure the device */ |
186 | if (udev->actconfig) | 186 | if (udev->actconfig) |
187 | usb_set_configuration(udev, 0); | 187 | usb_set_configuration(udev, -1); |
188 | 188 | ||
189 | usb_remove_sysfs_dev_files(udev); | 189 | usb_remove_sysfs_dev_files(udev); |
190 | } | 190 | } |
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 8aca3574c2b5..74edaea5665d 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c | |||
@@ -1316,6 +1316,14 @@ static void release_interface(struct device *dev) | |||
1316 | * use this kind of configurability; many devices only have one | 1316 | * use this kind of configurability; many devices only have one |
1317 | * configuration. | 1317 | * configuration. |
1318 | * | 1318 | * |
1319 | * @configuration is the value of the configuration to be installed. | ||
1320 | * According to the USB spec (e.g. section 9.1.1.5), configuration values | ||
1321 | * must be non-zero; a value of zero indicates that the device in | ||
1322 | * unconfigured. However some devices erroneously use 0 as one of their | ||
1323 | * configuration values. To help manage such devices, this routine will | ||
1324 | * accept @configuration = -1 as indicating the device should be put in | ||
1325 | * an unconfigured state. | ||
1326 | * | ||
1319 | * USB device configurations may affect Linux interoperability, | 1327 | * USB device configurations may affect Linux interoperability, |
1320 | * power consumption and the functionality available. For example, | 1328 | * power consumption and the functionality available. For example, |
1321 | * the default configuration is limited to using 100mA of bus power, | 1329 | * 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 | struct usb_interface **new_interfaces = NULL; | 1355 | struct usb_interface **new_interfaces = NULL; |
1348 | int n, nintf; | 1356 | int n, nintf; |
1349 | 1357 | ||
1350 | for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { | 1358 | if (configuration == -1) |
1351 | if (dev->config[i].desc.bConfigurationValue == configuration) { | 1359 | configuration = 0; |
1352 | cp = &dev->config[i]; | 1360 | else { |
1353 | break; | 1361 | for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { |
1362 | if (dev->config[i].desc.bConfigurationValue == | ||
1363 | configuration) { | ||
1364 | cp = &dev->config[i]; | ||
1365 | break; | ||
1366 | } | ||
1354 | } | 1367 | } |
1355 | } | 1368 | } |
1356 | if ((!cp && configuration != 0)) | 1369 | if ((!cp && configuration != 0)) |
@@ -1359,6 +1372,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration) | |||
1359 | /* The USB spec says configuration 0 means unconfigured. | 1372 | /* The USB spec says configuration 0 means unconfigured. |
1360 | * But if a device includes a configuration numbered 0, | 1373 | * But if a device includes a configuration numbered 0, |
1361 | * we will accept it as a correctly configured state. | 1374 | * we will accept it as a correctly configured state. |
1375 | * Use -1 if you really want to unconfigure the device. | ||
1362 | */ | 1376 | */ |
1363 | if (cp && configuration == 0) | 1377 | if (cp && configuration == 0) |
1364 | dev_warn(&dev->dev, "config 0 descriptor??\n"); | 1378 | dev_warn(&dev->dev, "config 0 descriptor??\n"); |
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 4eaa0ee8e72f..0edfbafd702c 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c | |||
@@ -63,7 +63,7 @@ set_bConfigurationValue(struct device *dev, struct device_attribute *attr, | |||
63 | struct usb_device *udev = to_usb_device(dev); | 63 | struct usb_device *udev = to_usb_device(dev); |
64 | int config, value; | 64 | int config, value; |
65 | 65 | ||
66 | if (sscanf(buf, "%u", &config) != 1 || config > 255) | 66 | if (sscanf(buf, "%d", &config) != 1 || config < -1 || config > 255) |
67 | return -EINVAL; | 67 | return -EINVAL; |
68 | usb_lock_device(udev); | 68 | usb_lock_device(udev); |
69 | value = usb_set_configuration(udev, config); | 69 | value = usb_set_configuration(udev, config); |