Hi, The attached patch adds a new usb device 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. This patch also adds a quirk table entry for one such device, which existence is the reason for this patch. Signed-off-by: Hans de Goede <hdegoede@xxxxxxxxxx> Regards, Hans
>From c4cdf657e56777ab0100e962450ca038f50e1aef Mon Sep 17 00:00:00 2001 From: Hans de Goede <hdegoede@xxxxxxxxxx> Date: Sun, 14 Mar 2010 09:39:42 +0100 Subject: [PATCH 1/2] 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 <hdegoede@xxxxxxxxxx> --- drivers/usb/core/config.c | 10 ++++++++-- drivers/usb/core/quirks.c | 4 ++++ include/linux/usb/quirks.h | 4 ++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 0d3af6a..07d38b6 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -1,5 +1,6 @@ #include <linux/usb.h> #include <linux/usb/ch9.h> +#include <linux/usb/quirks.h> #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> @@ -478,9 +479,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; @@ -540,6 +542,10 @@ static int usb_parse_configuration(struct device *ddev, int cfgidx, struct usb_interface_descriptor *d; int inum; + if ((dev->quirks & USB_QUIRK_HONOR_BNUMINTERFACES) && + n >= nintf_orig) + continue; + d = (struct usb_interface_descriptor *) header; if (d->bLength < USB_DT_INTERFACE_SIZE) { dev_warn(ddev, "config %d has an invalid " @@ -800,7 +806,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 ab93918..877a92c 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 2526f3b..383337e 100644 --- a/include/linux/usb/quirks.h +++ b/include/linux/usb/quirks.h @@ -19,4 +19,8 @@ /* device can't handle its Configuration or Interface strings */ #define USB_QUIRK_CONFIG_INTF_STRINGS 0x00000008 +/* device has more interface descriptions then the bNumInterfaces count, + and can't handle talking to these interfaces */ +#define USB_QUIRK_HONOR_BNUMINTERFACES 0x00000010 + #endif /* __LINUX_USB_QUIRKS_H */ -- 1.7.0