From 317149c655defedfaf432143b86a720cfc12a424 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 29 Mar 2010 12:03:17 +0200 Subject: [PATCH] USB: Add a new quirk: USB_QUIRK_HONOR_BNUMINTERFACES Add a new quirk USB_QUIRK_HONOR_BNUMINTERFACES, when this quirk is set and a device has more interface descriptors in a configuration then it claims to have in config->bNumInterfaces, ignore all additional interfaces. This is needed for devices which try to hide unused interfaces by only lowering config->bNumInterfaces, and which can't handle if you try to talk to the "hidden" interfaces. Signed-off-by: Hans de Goede Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/config.c | 16 ++++++++++++++-- drivers/usb/core/quirks.c | 4 ++++ include/linux/usb/quirks.h | 4 ++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 77e0dda3a2fb..16c1157be3fc 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -479,9 +480,10 @@ skip_to_next_interface_descriptor: return buffer - buffer0 + i; } -static int usb_parse_configuration(struct device *ddev, int cfgidx, +static int usb_parse_configuration(struct usb_device *dev, int cfgidx, struct usb_host_config *config, unsigned char *buffer, int size) { + struct device *ddev = &dev->dev; unsigned char *buffer0 = buffer; int cfgno; int nintf, nintf_orig; @@ -550,6 +552,16 @@ static int usb_parse_configuration(struct device *ddev, int cfgidx, } inum = d->bInterfaceNumber; + + if ((dev->quirks & USB_QUIRK_HONOR_BNUMINTERFACES) && + n >= nintf_orig) { + dev_warn(ddev, "config %d has more interface " + "descriptors, than it declares in " + "bNumInterfaces, ignoring interface " + "number: %d\n", cfgno, inum); + continue; + } + if (inum >= nintf_orig) dev_warn(ddev, "config %d has an invalid " "interface number: %d but max is %d\n", @@ -801,7 +813,7 @@ int usb_get_configuration(struct usb_device *dev) dev->rawdescriptors[cfgno] = bigbuffer; - result = usb_parse_configuration(&dev->dev, cfgno, + result = usb_parse_configuration(dev, cfgno, &dev->config[cfgno], bigbuffer, length); if (result < 0) { ++cfgno; diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index f073c5cb4e7b..f22d03df8b17 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -71,6 +71,10 @@ static const struct usb_device_id usb_quirk_list[] = { /* SKYMEDI USB_DRIVE */ { USB_DEVICE(0x1516, 0x8628), .driver_info = USB_QUIRK_RESET_RESUME }, + /* BUILDWIN Photo Frame */ + { USB_DEVICE(0x1908, 0x1315), .driver_info = + USB_QUIRK_HONOR_BNUMINTERFACES }, + /* INTEL VALUE SSD */ { USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME }, diff --git a/include/linux/usb/quirks.h b/include/linux/usb/quirks.h index 0a555dd131fc..16b7f3347545 100644 --- a/include/linux/usb/quirks.h +++ b/include/linux/usb/quirks.h @@ -22,4 +22,8 @@ /*device will morph if reset, don't use reset for handling errors */ #define USB_QUIRK_RESET_MORPHS 0x00000010 +/* device has more interface descriptions than the bNumInterfaces count, + and can't handle talking to these interfaces */ +#define USB_QUIRK_HONOR_BNUMINTERFACES 0x00000020 + #endif /* __LINUX_USB_QUIRKS_H */ -- 2.20.1