V4L/DVB (9810): uvcvideo: Add a device quirk to prune bogus controls.
authorLaurent Pinchart <laurent.pinchart@skynet.be>
Sat, 6 Dec 2008 20:43:40 +0000 (17:43 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Tue, 30 Dec 2008 11:38:34 +0000 (09:38 -0200)
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.

Signed-off-by: Laurent Pinchart <laurent.pinchart@skynet.be>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/video/uvc/uvc_ctrl.c
drivers/media/video/uvc/uvc_driver.c
drivers/media/video/uvc/uvcvideo.h

index f16aafe9cf145a6cbbdc44af3451649939573968..77b92e67953da67f03f1f9e4584aa3cb5a42812f 100644 (file)
@@ -543,11 +543,16 @@ static inline __u8 *uvc_ctrl_data(struct uvc_control *ctrl, int id)
        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
  * from the little-endian data stored at 'data' and return the result as
  * a signed 32bit integer. Sign extension will be performed if the mapping
@@ -1305,6 +1310,51 @@ end:
        return ret;
 }
 
+/*
+ * 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.
  */
@@ -1331,6 +1381,9 @@ int uvc_ctrl_init_device(struct uvc_device *dev)
                        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]);
 
@@ -1345,7 +1398,7 @@ int uvc_ctrl_init_device(struct uvc_device *dev)
 
                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;
index a67533f11f2ecf0693f0c93c775fcc6a03a2df8e..1054c7656aefb78e59c9340853835b12f0b1d5dc 100644 (file)
@@ -1894,7 +1894,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) },
        {}
index 437df60e0daebf04b701ca225052a4fc1b2b05c7..00d593776b86093a2d915308dec4788945b8adff 100644 (file)
@@ -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