diff options
author | Hans de Goede <hdegoede@redhat.com> | 2010-03-29 06:03:17 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-05-20 16:21:32 -0400 |
commit | 317149c655defedfaf432143b86a720cfc12a424 (patch) | |
tree | c9834f9813e14b595c93da5d7ceb718af39d1c5d | |
parent | 7f0ae3a8eeb7f231dc99cee7c871ba64e07ebefe (diff) |
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@redhat.com>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | drivers/usb/core/config.c | 16 | ||||
-rw-r--r-- | drivers/usb/core/quirks.c | 4 | ||||
-rw-r--r-- | 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 @@ | |||
1 | #include <linux/usb.h> | 1 | #include <linux/usb.h> |
2 | #include <linux/usb/ch9.h> | 2 | #include <linux/usb/ch9.h> |
3 | #include <linux/usb/hcd.h> | 3 | #include <linux/usb/hcd.h> |
4 | #include <linux/usb/quirks.h> | ||
4 | #include <linux/module.h> | 5 | #include <linux/module.h> |
5 | #include <linux/init.h> | 6 | #include <linux/init.h> |
6 | #include <linux/slab.h> | 7 | #include <linux/slab.h> |
@@ -479,9 +480,10 @@ skip_to_next_interface_descriptor: | |||
479 | return buffer - buffer0 + i; | 480 | return buffer - buffer0 + i; |
480 | } | 481 | } |
481 | 482 | ||
482 | static int usb_parse_configuration(struct device *ddev, int cfgidx, | 483 | static int usb_parse_configuration(struct usb_device *dev, int cfgidx, |
483 | struct usb_host_config *config, unsigned char *buffer, int size) | 484 | struct usb_host_config *config, unsigned char *buffer, int size) |
484 | { | 485 | { |
486 | struct device *ddev = &dev->dev; | ||
485 | unsigned char *buffer0 = buffer; | 487 | unsigned char *buffer0 = buffer; |
486 | int cfgno; | 488 | int cfgno; |
487 | int nintf, nintf_orig; | 489 | int nintf, nintf_orig; |
@@ -550,6 +552,16 @@ static int usb_parse_configuration(struct device *ddev, int cfgidx, | |||
550 | } | 552 | } |
551 | 553 | ||
552 | inum = d->bInterfaceNumber; | 554 | inum = d->bInterfaceNumber; |
555 | |||
556 | if ((dev->quirks & USB_QUIRK_HONOR_BNUMINTERFACES) && | ||
557 | n >= nintf_orig) { | ||
558 | dev_warn(ddev, "config %d has more interface " | ||
559 | "descriptors, than it declares in " | ||
560 | "bNumInterfaces, ignoring interface " | ||
561 | "number: %d\n", cfgno, inum); | ||
562 | continue; | ||
563 | } | ||
564 | |||
553 | if (inum >= nintf_orig) | 565 | if (inum >= nintf_orig) |
554 | dev_warn(ddev, "config %d has an invalid " | 566 | dev_warn(ddev, "config %d has an invalid " |
555 | "interface number: %d but max is %d\n", | 567 | "interface number: %d but max is %d\n", |
@@ -801,7 +813,7 @@ int usb_get_configuration(struct usb_device *dev) | |||
801 | 813 | ||
802 | dev->rawdescriptors[cfgno] = bigbuffer; | 814 | dev->rawdescriptors[cfgno] = bigbuffer; |
803 | 815 | ||
804 | result = usb_parse_configuration(&dev->dev, cfgno, | 816 | result = usb_parse_configuration(dev, cfgno, |
805 | &dev->config[cfgno], bigbuffer, length); | 817 | &dev->config[cfgno], bigbuffer, length); |
806 | if (result < 0) { | 818 | if (result < 0) { |
807 | ++cfgno; | 819 | ++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[] = { | |||
71 | /* SKYMEDI USB_DRIVE */ | 71 | /* SKYMEDI USB_DRIVE */ |
72 | { USB_DEVICE(0x1516, 0x8628), .driver_info = USB_QUIRK_RESET_RESUME }, | 72 | { USB_DEVICE(0x1516, 0x8628), .driver_info = USB_QUIRK_RESET_RESUME }, |
73 | 73 | ||
74 | /* BUILDWIN Photo Frame */ | ||
75 | { USB_DEVICE(0x1908, 0x1315), .driver_info = | ||
76 | USB_QUIRK_HONOR_BNUMINTERFACES }, | ||
77 | |||
74 | /* INTEL VALUE SSD */ | 78 | /* INTEL VALUE SSD */ |
75 | { USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME }, | 79 | { USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME }, |
76 | 80 | ||
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 @@ | |||
22 | /*device will morph if reset, don't use reset for handling errors */ | 22 | /*device will morph if reset, don't use reset for handling errors */ |
23 | #define USB_QUIRK_RESET_MORPHS 0x00000010 | 23 | #define USB_QUIRK_RESET_MORPHS 0x00000010 |
24 | 24 | ||
25 | /* device has more interface descriptions than the bNumInterfaces count, | ||
26 | and can't handle talking to these interfaces */ | ||
27 | #define USB_QUIRK_HONOR_BNUMINTERFACES 0x00000020 | ||
28 | |||
25 | #endif /* __LINUX_USB_QUIRKS_H */ | 29 | #endif /* __LINUX_USB_QUIRKS_H */ |