The patch number 9810 was added via Laurent Pinchart 
<laurent.pinch...@skynet.be>
to http://linuxtv.org/hg/v4l-dvb master development tree.

Kernel patches in this development tree may be modified to be backward
compatible with older kernels. Compatibility modifications will be
removed before inclusion into the mainstream Kernel

If anyone has any objections, please let us know by sending a message to:
        v4l-dvb-maintai...@linuxtv.org

------

From: Laurent Pinchart  <laurent.pinch...@skynet.be>
uvcvideo: Add a device quirk to prune bogus controls.


Bogus controls currently include processing unit auto controls for which no
corresponding manual control is available. Such auto controls make little
sense if any, and are known to crash at least the SiGma Micro webcam.

Priority: normal

Signed-off-by: Laurent Pinchart <laurent.pinch...@skynet.be>


---

 linux/drivers/media/video/uvc/uvc_ctrl.c   |   57 ++++++++++++++++++++-
 linux/drivers/media/video/uvc/uvc_driver.c |    3 -
 linux/drivers/media/video/uvc/uvcvideo.h   |    1 
 3 files changed, 58 insertions(+), 3 deletions(-)

diff -r 07d965b42627 -r ecb8f0350435 linux/drivers/media/video/uvc/uvc_ctrl.c
--- a/linux/drivers/media/video/uvc/uvc_ctrl.c  Sat Dec 06 20:25:14 2008 +0100
+++ b/linux/drivers/media/video/uvc/uvc_ctrl.c  Sat Dec 06 21:43:40 2008 +0100
@@ -545,9 +545,14 @@ static inline __u8 *uvc_ctrl_data(struct
        return ctrl->data + id * ctrl->info->size;
 }
 
-static inline int uvc_get_bit(const __u8 *data, int bit)
+static inline int uvc_test_bit(const __u8 *data, int bit)
 {
        return (data[bit >> 3] >> (bit & 7)) & 1;
+}
+
+static inline void uvc_clear_bit(__u8 *data, int bit)
+{
+       data[bit >> 3] &= ~(1 << (bit & 7));
 }
 
 /* Extract the bit string specified by mapping->offset and mapping->size
@@ -1308,6 +1313,51 @@ end:
 }
 
 /*
+ * Prune an entity of its bogus controls. This currently includes processing
+ * unit auto controls for which no corresponding manual control is available.
+ * Such auto controls make little sense if any, and are known to crash at
+ * least the SiGma Micro webcam.
+ */
+static void
+uvc_ctrl_prune_entity(struct uvc_entity *entity)
+{
+       static const struct {
+               u8 idx_manual;
+               u8 idx_auto;
+       } blacklist[] = {
+               { 2, 11 }, /* Hue */
+               { 6, 12 }, /* White Balance Temperature */
+               { 7, 13 }, /* White Balance Component */
+       };
+
+       u8 *controls;
+       unsigned int size;
+       unsigned int i;
+
+       if (UVC_ENTITY_TYPE(entity) != VC_PROCESSING_UNIT)
+               return;
+
+       controls = entity->processing.bmControls;
+       size = entity->processing.bControlSize;
+
+       for (i = 0; i < ARRAY_SIZE(blacklist); ++i) {
+               if (blacklist[i].idx_auto >= 8 * size ||
+                   blacklist[i].idx_manual >= 8 * size)
+                       continue;
+
+               if (!uvc_test_bit(controls, blacklist[i].idx_auto) ||
+                    uvc_test_bit(controls, blacklist[i].idx_manual))
+                       continue;
+
+               uvc_trace(UVC_TRACE_CONTROL, "Auto control %u/%u has no "
+                       "matching manual control, removing it.\n", entity->id,
+                       blacklist[i].idx_auto);
+
+               uvc_clear_bit(controls, blacklist[i].idx_auto);
+       }
+}
+
+/*
  * Initialize device controls.
  */
 int uvc_ctrl_init_device(struct uvc_device *dev)
@@ -1333,6 +1383,9 @@ int uvc_ctrl_init_device(struct uvc_devi
                        bControlSize = entity->camera.bControlSize;
                }
 
+               if (dev->quirks & UVC_QUIRK_PRUNE_CONTROLS)
+                       uvc_ctrl_prune_entity(entity);
+
                for (i = 0; i < bControlSize; ++i)
                        ncontrols += hweight8(bmControls[i]);
 
@@ -1347,7 +1400,7 @@ int uvc_ctrl_init_device(struct uvc_devi
 
                ctrl = entity->controls;
                for (i = 0; i < bControlSize * 8; ++i) {
-                       if (uvc_get_bit(bmControls, i) == 0)
+                       if (uvc_test_bit(bmControls, i) == 0)
                                continue;
 
                        ctrl->entity = entity;
diff -r 07d965b42627 -r ecb8f0350435 linux/drivers/media/video/uvc/uvc_driver.c
--- a/linux/drivers/media/video/uvc/uvc_driver.c        Sat Dec 06 20:25:14 
2008 +0100
+++ b/linux/drivers/media/video/uvc/uvc_driver.c        Sat Dec 06 21:43:40 
2008 +0100
@@ -1896,7 +1896,8 @@ static struct usb_device_id uvc_ids[] = 
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
          .driver_info          = UVC_QUIRK_PROBE_MINMAX
-                               | UVC_QUIRK_IGNORE_SELECTOR_UNIT},
+                               | UVC_QUIRK_IGNORE_SELECTOR_UNIT
+                               | UVC_QUIRK_PRUNE_CONTROLS },
        /* Generic USB Video Class */
        { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) },
        {}
diff -r 07d965b42627 -r ecb8f0350435 linux/drivers/media/video/uvc/uvcvideo.h
--- a/linux/drivers/media/video/uvc/uvcvideo.h  Sat Dec 06 20:25:14 2008 +0100
+++ b/linux/drivers/media/video/uvc/uvcvideo.h  Sat Dec 06 21:43:40 2008 +0100
@@ -316,6 +316,7 @@ struct uvc_xu_control {
 #define UVC_QUIRK_BUILTIN_ISIGHT       0x00000008
 #define UVC_QUIRK_STREAM_NO_FID                0x00000010
 #define UVC_QUIRK_IGNORE_SELECTOR_UNIT 0x00000020
+#define UVC_QUIRK_PRUNE_CONTROLS       0x00000040
 
 /* Format flags */
 #define UVC_FMT_FLAG_COMPRESSED                0x00000001


---

Patch is available at: 
http://linuxtv.org/hg/v4l-dvb/rev/ecb8f0350435fc4ecbe46b24cfe58f6b155d8517

_______________________________________________
linuxtv-commits mailing list
linuxtv-commits@linuxtv.org
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linuxtv-commits

Reply via email to