ChangeSet 1.1337.3.6, 2003/10/23 17:03:25-07:00, david-b@pacbell.net [PATCH] USB: usbcore, better heuristic for choosing configs Until now, the Linux-USB core has always chosen the first device configuration, even when there was a choice. In 2.4 kernels, device driver probe() routines were allowed to override that initial policy decisions. But 2.6 kernels can't do that from probe() routines, causing problems with some CDC-ACM modems where the first config uses MSFT-proprietary protocols. This patch switches to a smarter heuristic: Linux now prefers standard interface classes when there's a choice. So those CDC-ACM modems don't need a "write bConfigurationValue in sysfs" step when they are connected; they act just like on 2.4 kernels. (And sysfs can still be used to handle any problem cases.) drivers/usb/core/usb.c | 21 +++++++++++++++++---- 1 files changed, 17 insertions(+), 4 deletions(-) diff -Nru a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c --- a/drivers/usb/core/usb.c Mon Dec 29 14:27:37 2003 +++ b/drivers/usb/core/usb.c Mon Dec 29 14:27:37 2003 @@ -991,6 +991,7 @@ int err = -EINVAL; int i; int j; + int config; /* * Set the driver for the usb device to point to the "generic" driver. @@ -1105,18 +1106,30 @@ /* choose and set the configuration. that registers the interfaces * with the driver core, and lets usb device drivers bind to them. + * NOTE: should interact with hub power budgeting. */ + config = dev->config[0].desc.bConfigurationValue; if (dev->descriptor.bNumConfigurations != 1) { + for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { + /* heuristic: Linux is more likely to have class + * drivers, so avoid vendor-specific interfaces. + */ + if (dev->config[i].interface[0]->altsetting + ->desc.bInterfaceClass + == USB_CLASS_VENDOR_SPEC) + continue; + config = dev->config[i].desc.bConfigurationValue; + break; + } dev_info(&dev->dev, "configuration #%d chosen from %d choices\n", - dev->config[0].desc.bConfigurationValue, + config, dev->descriptor.bNumConfigurations); } - err = usb_set_configuration(dev, - dev->config[0].desc.bConfigurationValue); + err = usb_set_configuration(dev, config); if (err) { dev_err(&dev->dev, "can't set config #%d, error %d\n", - dev->config[0].desc.bConfigurationValue, err); + config, err); goto fail; }