usb: Add USB_QUIRK_RESET_RESUME for all Logitech UVC webcams (Closes: #668211)
svn path=/dists/sid/linux/; revision=19350
This commit is contained in:
parent
872731beb7
commit
05990430e6
|
@ -102,6 +102,8 @@ linux (3.2.28-1) UNRELEASED; urgency=low
|
|||
* PCI/PM/Runtime: make PCI traces quieter (Closes: #684049)
|
||||
* rc: ite-cir: Initialise ite_dev::rdev earlier (Closes: #684441)
|
||||
* input: Enable TOUCHSCREEN_ATMEL_MXT as module (Closes: #685123)
|
||||
* usb: Add USB_QUIRK_RESET_RESUME for all Logitech UVC webcams
|
||||
(Closes: #668211)
|
||||
|
||||
[ Bastian Blank ]
|
||||
* Make xen-linux-system meta-packages depend on xen-system. This allows
|
||||
|
|
99
debian/patches/bugfix/all/usb-Add-USB_QUIRK_RESET_RESUME-for-all-Logitech-UVC-.patch
vendored
Normal file
99
debian/patches/bugfix/all/usb-Add-USB_QUIRK_RESET_RESUME-for-all-Logitech-UVC-.patch
vendored
Normal file
|
@ -0,0 +1,99 @@
|
|||
From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
||||
Date: Thu, 19 Jul 2012 12:39:14 +0200
|
||||
Subject: usb: Add USB_QUIRK_RESET_RESUME for all Logitech UVC webcams
|
||||
|
||||
commit e387ef5c47ddeaeaa3cbdc54424cdb7a28dae2c0 upstream.
|
||||
|
||||
Most Logitech UVC webcams (both early models that don't advertise UVC
|
||||
compatibility and newer UVC-advertised devices) require the RESET_RESUME
|
||||
quirk. Instead of listing each and every model, match the devices based
|
||||
on the UVC interface information.
|
||||
|
||||
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
||||
Acked-by: Alan Stern <stern@rowland.harvard.edu>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||
---
|
||||
drivers/usb/core/quirks.c | 58 +++++++++++++--------------------------------
|
||||
1 file changed, 16 insertions(+), 42 deletions(-)
|
||||
|
||||
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
|
||||
index cbd15d1..f15501f4c 100644
|
||||
--- a/drivers/usb/core/quirks.c
|
||||
+++ b/drivers/usb/core/quirks.c
|
||||
@@ -43,53 +43,23 @@ static const struct usb_device_id usb_quirk_list[] = {
|
||||
/* Creative SB Audigy 2 NX */
|
||||
{ USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME },
|
||||
|
||||
- /* Logitech Webcam C200 */
|
||||
- { USB_DEVICE(0x046d, 0x0802), .driver_info = USB_QUIRK_RESET_RESUME },
|
||||
+ /* Logitech Quickcam Fusion */
|
||||
+ { USB_DEVICE(0x046d, 0x08c1), .driver_info = USB_QUIRK_RESET_RESUME },
|
||||
|
||||
- /* Logitech Webcam C250 */
|
||||
- { USB_DEVICE(0x046d, 0x0804), .driver_info = USB_QUIRK_RESET_RESUME },
|
||||
+ /* Logitech Quickcam Orbit MP */
|
||||
+ { USB_DEVICE(0x046d, 0x08c2), .driver_info = USB_QUIRK_RESET_RESUME },
|
||||
|
||||
- /* Logitech Webcam C300 */
|
||||
- { USB_DEVICE(0x046d, 0x0805), .driver_info = USB_QUIRK_RESET_RESUME },
|
||||
+ /* Logitech Quickcam Pro for Notebook */
|
||||
+ { USB_DEVICE(0x046d, 0x08c3), .driver_info = USB_QUIRK_RESET_RESUME },
|
||||
|
||||
- /* Logitech Webcam B/C500 */
|
||||
- { USB_DEVICE(0x046d, 0x0807), .driver_info = USB_QUIRK_RESET_RESUME },
|
||||
+ /* Logitech Quickcam Pro 5000 */
|
||||
+ { USB_DEVICE(0x046d, 0x08c5), .driver_info = USB_QUIRK_RESET_RESUME },
|
||||
|
||||
- /* Logitech Webcam C600 */
|
||||
- { USB_DEVICE(0x046d, 0x0808), .driver_info = USB_QUIRK_RESET_RESUME },
|
||||
+ /* Logitech Quickcam OEM Dell Notebook */
|
||||
+ { USB_DEVICE(0x046d, 0x08c6), .driver_info = USB_QUIRK_RESET_RESUME },
|
||||
|
||||
- /* Logitech Webcam Pro 9000 */
|
||||
- { USB_DEVICE(0x046d, 0x0809), .driver_info = USB_QUIRK_RESET_RESUME },
|
||||
-
|
||||
- /* Logitech Webcam C905 */
|
||||
- { USB_DEVICE(0x046d, 0x080a), .driver_info = USB_QUIRK_RESET_RESUME },
|
||||
-
|
||||
- /* Logitech Webcam C210 */
|
||||
- { USB_DEVICE(0x046d, 0x0819), .driver_info = USB_QUIRK_RESET_RESUME },
|
||||
-
|
||||
- /* Logitech Webcam C260 */
|
||||
- { USB_DEVICE(0x046d, 0x081a), .driver_info = USB_QUIRK_RESET_RESUME },
|
||||
-
|
||||
- /* Logitech Webcam C310 */
|
||||
- { USB_DEVICE(0x046d, 0x081b), .driver_info = USB_QUIRK_RESET_RESUME },
|
||||
-
|
||||
- /* Logitech Webcam C910 */
|
||||
- { USB_DEVICE(0x046d, 0x0821), .driver_info = USB_QUIRK_RESET_RESUME },
|
||||
-
|
||||
- /* Logitech Webcam C160 */
|
||||
- { USB_DEVICE(0x046d, 0x0824), .driver_info = USB_QUIRK_RESET_RESUME },
|
||||
-
|
||||
- /* Logitech Webcam C270 */
|
||||
- { USB_DEVICE(0x046d, 0x0825), .driver_info = USB_QUIRK_RESET_RESUME },
|
||||
-
|
||||
- /* Logitech Quickcam Pro 9000 */
|
||||
- { USB_DEVICE(0x046d, 0x0990), .driver_info = USB_QUIRK_RESET_RESUME },
|
||||
-
|
||||
- /* Logitech Quickcam E3500 */
|
||||
- { USB_DEVICE(0x046d, 0x09a4), .driver_info = USB_QUIRK_RESET_RESUME },
|
||||
-
|
||||
- /* Logitech Quickcam Vision Pro */
|
||||
- { USB_DEVICE(0x046d, 0x09a6), .driver_info = USB_QUIRK_RESET_RESUME },
|
||||
+ /* Logitech Quickcam OEM Cisco VT Camera II */
|
||||
+ { USB_DEVICE(0x046d, 0x08c7), .driver_info = USB_QUIRK_RESET_RESUME },
|
||||
|
||||
/* Logitech Harmony 700-series */
|
||||
{ USB_DEVICE(0x046d, 0xc122), .driver_info = USB_QUIRK_DELAY_INIT },
|
||||
@@ -162,6 +132,10 @@ static const struct usb_device_id usb_quirk_list[] = {
|
||||
};
|
||||
|
||||
static const struct usb_device_id usb_interface_quirk_list[] = {
|
||||
+ /* Logitech UVC Cameras */
|
||||
+ { USB_VENDOR_AND_INTERFACE_INFO(0x046d, USB_CLASS_VIDEO, 1, 0),
|
||||
+ .driver_info = USB_QUIRK_RESET_RESUME },
|
||||
+
|
||||
{ } /* terminating entry must be last */
|
||||
};
|
||||
|
250
debian/patches/bugfix/all/usb-Add-quirk-detection-based-on-interface-informati.patch
vendored
Normal file
250
debian/patches/bugfix/all/usb-Add-quirk-detection-based-on-interface-informati.patch
vendored
Normal file
|
@ -0,0 +1,250 @@
|
|||
From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
||||
Date: Thu, 19 Jul 2012 12:39:13 +0200
|
||||
Subject: usb: Add quirk detection based on interface information
|
||||
|
||||
commit 80da2e0df5af700518611b7d1cc4fc9945bcaf95 upstream.
|
||||
|
||||
When a whole class of devices (possibly from a specific vendor, or
|
||||
across multiple vendors) require a quirk, explictly listing all devices
|
||||
in the class make the quirks table unnecessarily large. Fix this by
|
||||
allowing matching devices based on interface information.
|
||||
|
||||
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
||||
Acked-by: Alan Stern <stern@rowland.harvard.edu>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||
---
|
||||
drivers/usb/core/driver.c | 38 ++++++++++--------
|
||||
drivers/usb/core/hub.c | 10 +++--
|
||||
drivers/usb/core/quirks.c | 93 +++++++++++++++++++++++++++++++++++----------
|
||||
drivers/usb/core/usb.h | 4 ++
|
||||
4 files changed, 106 insertions(+), 39 deletions(-)
|
||||
|
||||
--- a/drivers/usb/core/driver.c
|
||||
+++ b/drivers/usb/core/driver.c
|
||||
@@ -541,22 +541,10 @@ int usb_match_device(struct usb_device *
|
||||
}
|
||||
|
||||
/* returns 0 if no match, 1 if match */
|
||||
-int usb_match_one_id(struct usb_interface *interface,
|
||||
- const struct usb_device_id *id)
|
||||
+int usb_match_one_id_intf(struct usb_device *dev,
|
||||
+ struct usb_host_interface *intf,
|
||||
+ const struct usb_device_id *id)
|
||||
{
|
||||
- struct usb_host_interface *intf;
|
||||
- struct usb_device *dev;
|
||||
-
|
||||
- /* proc_connectinfo in devio.c may call us with id == NULL. */
|
||||
- if (id == NULL)
|
||||
- return 0;
|
||||
-
|
||||
- intf = interface->cur_altsetting;
|
||||
- dev = interface_to_usbdev(interface);
|
||||
-
|
||||
- if (!usb_match_device(dev, id))
|
||||
- return 0;
|
||||
-
|
||||
/* The interface class, subclass, and protocol should never be
|
||||
* checked for a match if the device class is Vendor Specific,
|
||||
* unless the match record specifies the Vendor ID. */
|
||||
@@ -581,6 +569,26 @@ int usb_match_one_id(struct usb_interfac
|
||||
|
||||
return 1;
|
||||
}
|
||||
+
|
||||
+/* returns 0 if no match, 1 if match */
|
||||
+int usb_match_one_id(struct usb_interface *interface,
|
||||
+ const struct usb_device_id *id)
|
||||
+{
|
||||
+ struct usb_host_interface *intf;
|
||||
+ struct usb_device *dev;
|
||||
+
|
||||
+ /* proc_connectinfo in devio.c may call us with id == NULL. */
|
||||
+ if (id == NULL)
|
||||
+ return 0;
|
||||
+
|
||||
+ intf = interface->cur_altsetting;
|
||||
+ dev = interface_to_usbdev(interface);
|
||||
+
|
||||
+ if (!usb_match_device(dev, id))
|
||||
+ return 0;
|
||||
+
|
||||
+ return usb_match_one_id_intf(dev, intf, id);
|
||||
+}
|
||||
EXPORT_SYMBOL_GPL(usb_match_one_id);
|
||||
|
||||
/**
|
||||
--- a/drivers/usb/core/hub.c
|
||||
+++ b/drivers/usb/core/hub.c
|
||||
@@ -1821,7 +1821,7 @@ static int usb_enumerate_device(struct u
|
||||
if (err < 0) {
|
||||
dev_err(&udev->dev, "can't read configurations, error %d\n",
|
||||
err);
|
||||
- goto fail;
|
||||
+ return err;
|
||||
}
|
||||
}
|
||||
if (udev->wusb == 1 && udev->authorized == 0) {
|
||||
@@ -1837,8 +1837,12 @@ static int usb_enumerate_device(struct u
|
||||
udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);
|
||||
}
|
||||
err = usb_enumerate_device_otg(udev);
|
||||
-fail:
|
||||
- return err;
|
||||
+ if (err < 0)
|
||||
+ return err;
|
||||
+
|
||||
+ usb_detect_interface_quirks(udev);
|
||||
+
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
|
||||
--- a/drivers/usb/core/quirks.c
|
||||
+++ b/drivers/usb/core/quirks.c
|
||||
@@ -15,17 +15,22 @@
|
||||
#include <linux/usb/quirks.h>
|
||||
#include "usb.h"
|
||||
|
||||
-/* List of quirky USB devices. Please keep this list ordered by:
|
||||
+/* Lists of quirky USB devices, split in device quirks and interface quirks.
|
||||
+ * Device quirks are applied at the very beginning of the enumeration process,
|
||||
+ * right after reading the device descriptor. They can thus only match on device
|
||||
+ * information.
|
||||
+ *
|
||||
+ * Interface quirks are applied after reading all the configuration descriptors.
|
||||
+ * They can match on both device and interface information.
|
||||
+ *
|
||||
+ * Note that the DELAY_INIT and HONOR_BNUMINTERFACES quirks do not make sense as
|
||||
+ * interface quirks, as they only influence the enumeration process which is run
|
||||
+ * before processing the interface quirks.
|
||||
+ *
|
||||
+ * Please keep the lists ordered by:
|
||||
* 1) Vendor ID
|
||||
* 2) Product ID
|
||||
* 3) Class ID
|
||||
- *
|
||||
- * as we want specific devices to be overridden first, and only after that, any
|
||||
- * class specific quirks.
|
||||
- *
|
||||
- * Right now the logic aborts if it finds a valid device in the table, we might
|
||||
- * want to change that in the future if it turns out that a whole class of
|
||||
- * devices is broken...
|
||||
*/
|
||||
static const struct usb_device_id usb_quirk_list[] = {
|
||||
/* CBM - Flash disk */
|
||||
@@ -156,16 +161,53 @@ static const struct usb_device_id usb_qu
|
||||
{ } /* terminating entry must be last */
|
||||
};
|
||||
|
||||
-static const struct usb_device_id *find_id(struct usb_device *udev)
|
||||
+static const struct usb_device_id usb_interface_quirk_list[] = {
|
||||
+ { } /* terminating entry must be last */
|
||||
+};
|
||||
+
|
||||
+static bool usb_match_any_interface(struct usb_device *udev,
|
||||
+ const struct usb_device_id *id)
|
||||
+{
|
||||
+ unsigned int i;
|
||||
+
|
||||
+ for (i = 0; i < udev->descriptor.bNumConfigurations; ++i) {
|
||||
+ struct usb_host_config *cfg = &udev->config[i];
|
||||
+ unsigned int j;
|
||||
+
|
||||
+ for (j = 0; j < cfg->desc.bNumInterfaces; ++j) {
|
||||
+ struct usb_interface_cache *cache;
|
||||
+ struct usb_host_interface *intf;
|
||||
+
|
||||
+ cache = cfg->intf_cache[j];
|
||||
+ if (cache->num_altsetting == 0)
|
||||
+ continue;
|
||||
+
|
||||
+ intf = &cache->altsetting[0];
|
||||
+ if (usb_match_one_id_intf(udev, intf, id))
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
+static u32 __usb_detect_quirks(struct usb_device *udev,
|
||||
+ const struct usb_device_id *id)
|
||||
{
|
||||
- const struct usb_device_id *id = usb_quirk_list;
|
||||
+ u32 quirks = 0;
|
||||
|
||||
- for (; id->idVendor || id->bDeviceClass || id->bInterfaceClass ||
|
||||
- id->driver_info; id++) {
|
||||
- if (usb_match_device(udev, id))
|
||||
- return id;
|
||||
+ for (; id->match_flags; id++) {
|
||||
+ if (!usb_match_device(udev, id))
|
||||
+ continue;
|
||||
+
|
||||
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_INFO) &&
|
||||
+ !usb_match_any_interface(udev, id))
|
||||
+ continue;
|
||||
+
|
||||
+ quirks |= (u32)(id->driver_info);
|
||||
}
|
||||
- return NULL;
|
||||
+
|
||||
+ return quirks;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -173,14 +215,10 @@ static const struct usb_device_id *find_
|
||||
*/
|
||||
void usb_detect_quirks(struct usb_device *udev)
|
||||
{
|
||||
- const struct usb_device_id *id = usb_quirk_list;
|
||||
-
|
||||
- id = find_id(udev);
|
||||
- if (id)
|
||||
- udev->quirks = (u32)(id->driver_info);
|
||||
+ udev->quirks = __usb_detect_quirks(udev, usb_quirk_list);
|
||||
if (udev->quirks)
|
||||
dev_dbg(&udev->dev, "USB quirks for this device: %x\n",
|
||||
- udev->quirks);
|
||||
+ udev->quirks);
|
||||
|
||||
/* For the present, all devices default to USB-PERSIST enabled */
|
||||
#if 0 /* was: #ifdef CONFIG_PM */
|
||||
@@ -197,3 +235,16 @@ void usb_detect_quirks(struct usb_device
|
||||
udev->persist_enabled = 1;
|
||||
#endif /* CONFIG_PM */
|
||||
}
|
||||
+
|
||||
+void usb_detect_interface_quirks(struct usb_device *udev)
|
||||
+{
|
||||
+ u32 quirks;
|
||||
+
|
||||
+ quirks = __usb_detect_quirks(udev, usb_interface_quirk_list);
|
||||
+ if (quirks == 0)
|
||||
+ return;
|
||||
+
|
||||
+ dev_dbg(&udev->dev, "USB interface quirks for this device: %x\n",
|
||||
+ quirks);
|
||||
+ udev->quirks |= quirks;
|
||||
+}
|
||||
--- a/drivers/usb/core/usb.h
|
||||
+++ b/drivers/usb/core/usb.h
|
||||
@@ -24,6 +24,7 @@ extern void usb_disable_device(struct us
|
||||
extern int usb_deauthorize_device(struct usb_device *);
|
||||
extern int usb_authorize_device(struct usb_device *);
|
||||
extern void usb_detect_quirks(struct usb_device *udev);
|
||||
+extern void usb_detect_interface_quirks(struct usb_device *udev);
|
||||
extern int usb_remove_device(struct usb_device *udev);
|
||||
|
||||
extern int usb_get_device_descriptor(struct usb_device *dev,
|
||||
@@ -35,6 +36,9 @@ extern int usb_set_configuration(struct
|
||||
extern int usb_choose_configuration(struct usb_device *udev);
|
||||
|
||||
extern void usb_kick_khubd(struct usb_device *dev);
|
||||
+extern int usb_match_one_id_intf(struct usb_device *dev,
|
||||
+ struct usb_host_interface *intf,
|
||||
+ const struct usb_device_id *id);
|
||||
extern int usb_match_device(struct usb_device *dev,
|
||||
const struct usb_device_id *id);
|
||||
extern void usb_forced_unbind_intf(struct usb_interface *intf);
|
56
debian/patches/features/all/USB-add-USB_VENDOR_AND_INTERFACE_INFO-macro.patch
vendored
Normal file
56
debian/patches/features/all/USB-add-USB_VENDOR_AND_INTERFACE_INFO-macro.patch
vendored
Normal file
|
@ -0,0 +1,56 @@
|
|||
From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
|
||||
Date: Tue, 10 Jul 2012 19:10:06 -0300
|
||||
Subject: USB: add USB_VENDOR_AND_INTERFACE_INFO() macro
|
||||
|
||||
commit d81a5d1956731c453b85c141458d4ff5d6cc5366 upstream.
|
||||
|
||||
A lot of Broadcom Bluetooth devices provides vendor specific interface
|
||||
class and we are getting flooded by patches adding new device support.
|
||||
This change will help us enable support for any other Broadcom with vendor
|
||||
specific device that arrives in the future.
|
||||
|
||||
Only the product id changes for those devices, so this macro would be
|
||||
perfect for us:
|
||||
|
||||
{ USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) }
|
||||
|
||||
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
|
||||
Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
|
||||
Acked-by: Henrik Rydberg <rydberg@bitmath.se>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||
---
|
||||
include/linux/usb.h | 21 +++++++++++++++++++++
|
||||
1 file changed, 21 insertions(+)
|
||||
|
||||
diff --git a/include/linux/usb.h b/include/linux/usb.h
|
||||
index 873956b..30d1ae3 100644
|
||||
--- a/include/linux/usb.h
|
||||
+++ b/include/linux/usb.h
|
||||
@@ -861,6 +861,27 @@ static inline int usb_make_path(struct usb_device *dev, char *buf, size_t size)
|
||||
.bInterfaceSubClass = (sc), \
|
||||
.bInterfaceProtocol = (pr)
|
||||
|
||||
+/**
|
||||
+ * USB_VENDOR_AND_INTERFACE_INFO - describe a specific usb vendor with a class of usb interfaces
|
||||
+ * @vend: the 16 bit USB Vendor ID
|
||||
+ * @cl: bInterfaceClass value
|
||||
+ * @sc: bInterfaceSubClass value
|
||||
+ * @pr: bInterfaceProtocol value
|
||||
+ *
|
||||
+ * This macro is used to create a struct usb_device_id that matches a
|
||||
+ * specific vendor with a specific class of interfaces.
|
||||
+ *
|
||||
+ * This is especially useful when explicitly matching devices that have
|
||||
+ * vendor specific bDeviceClass values, but standards-compliant interfaces.
|
||||
+ */
|
||||
+#define USB_VENDOR_AND_INTERFACE_INFO(vend, cl, sc, pr) \
|
||||
+ .match_flags = USB_DEVICE_ID_MATCH_INT_INFO \
|
||||
+ | USB_DEVICE_ID_MATCH_VENDOR, \
|
||||
+ .idVendor = (vend), \
|
||||
+ .bInterfaceClass = (cl), \
|
||||
+ .bInterfaceSubClass = (sc), \
|
||||
+ .bInterfaceProtocol = (pr)
|
||||
+
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
/* Stuff for dynamic usb ids */
|
|
@ -389,3 +389,6 @@ features/all/bql/skge-add-byte-queue-limit-support.patch
|
|||
bugfix/all/rds-set-correct-msg_namelen.patch
|
||||
bugfix/all/PCI-PM-Runtime-make-PCI-traces-quieter.patch
|
||||
bugfix/all/media-rc-ite-cir-Initialise-ite_dev-rdev-earlier.patch
|
||||
features/all/USB-add-USB_VENDOR_AND_INTERFACE_INFO-macro.patch
|
||||
bugfix/all/usb-Add-quirk-detection-based-on-interface-informati.patch
|
||||
bugfix/all/usb-Add-USB_QUIRK_RESET_RESUME-for-all-Logitech-UVC-.patch
|
||||
|
|
Loading…
Reference in New Issue