From 05990430e652e89cfbb0cd87e24620482113e54f Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Tue, 21 Aug 2012 03:50:56 +0000 Subject: [PATCH] usb: Add USB_QUIRK_RESET_RESUME for all Logitech UVC webcams (Closes: #668211) svn path=/dists/sid/linux/; revision=19350 --- debian/changelog | 2 + ...K_RESET_RESUME-for-all-Logitech-UVC-.patch | 99 +++++++ ...tection-based-on-interface-informati.patch | 250 ++++++++++++++++++ ...-USB_VENDOR_AND_INTERFACE_INFO-macro.patch | 56 ++++ debian/patches/series | 3 + 5 files changed, 410 insertions(+) create mode 100644 debian/patches/bugfix/all/usb-Add-USB_QUIRK_RESET_RESUME-for-all-Logitech-UVC-.patch create mode 100644 debian/patches/bugfix/all/usb-Add-quirk-detection-based-on-interface-informati.patch create mode 100644 debian/patches/features/all/USB-add-USB_VENDOR_AND_INTERFACE_INFO-macro.patch diff --git a/debian/changelog b/debian/changelog index 74ba645a1..4293a0263 100644 --- a/debian/changelog +++ b/debian/changelog @@ -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 diff --git a/debian/patches/bugfix/all/usb-Add-USB_QUIRK_RESET_RESUME-for-all-Logitech-UVC-.patch b/debian/patches/bugfix/all/usb-Add-USB_QUIRK_RESET_RESUME-for-all-Logitech-UVC-.patch new file mode 100644 index 000000000..ec538738c --- /dev/null +++ b/debian/patches/bugfix/all/usb-Add-USB_QUIRK_RESET_RESUME-for-all-Logitech-UVC-.patch @@ -0,0 +1,99 @@ +From: Laurent Pinchart +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 +Acked-by: Alan Stern +Signed-off-by: Greg Kroah-Hartman +--- + 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 */ + }; + diff --git a/debian/patches/bugfix/all/usb-Add-quirk-detection-based-on-interface-informati.patch b/debian/patches/bugfix/all/usb-Add-quirk-detection-based-on-interface-informati.patch new file mode 100644 index 000000000..c40b51554 --- /dev/null +++ b/debian/patches/bugfix/all/usb-Add-quirk-detection-based-on-interface-informati.patch @@ -0,0 +1,250 @@ +From: Laurent Pinchart +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 +Acked-by: Alan Stern +Signed-off-by: Greg Kroah-Hartman +--- + 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 + #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); diff --git a/debian/patches/features/all/USB-add-USB_VENDOR_AND_INTERFACE_INFO-macro.patch b/debian/patches/features/all/USB-add-USB_VENDOR_AND_INTERFACE_INFO-macro.patch new file mode 100644 index 000000000..8cb1db9d6 --- /dev/null +++ b/debian/patches/features/all/USB-add-USB_VENDOR_AND_INTERFACE_INFO-macro.patch @@ -0,0 +1,56 @@ +From: Gustavo Padovan +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 +Signed-off-by: Gustavo Padovan +Acked-by: Henrik Rydberg +Signed-off-by: Greg Kroah-Hartman +--- + 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 */ diff --git a/debian/patches/series b/debian/patches/series index cb5688191..28683101e 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -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