The Dino-Lite cameras are equipped with LED lights that can be switched
on and off by setting a proprietary control. For this control, the
camera reports a length of 1 byte, but actually the value set by the
original Windows driver is 3 byte long. This makes it impossible to
toggle the camera lights from uvcvideo, as the length from GET_LEN is
trusted as being the right one.

This is to make GET_LEN indicate a length of 3 instead of 1 for this
specific device.

Signed-off-by: Alexandre Macabies <web+...@zopieux.com>
---
 drivers/media/usb/uvc/uvc_driver.c |  9 +++++++++
 drivers/media/usb/uvc/uvc_video.c  | 10 ++++++++++
 drivers/media/usb/uvc/uvcvideo.h   |  1 +
 3 files changed, 20 insertions(+)

diff --git a/drivers/media/usb/uvc/uvc_driver.c 
b/drivers/media/usb/uvc/uvc_driver.c
index 28b91b7d7..17689a242 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -2734,6 +2734,15 @@ static const struct usb_device_id uvc_ids[] = {
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
          .driver_info          = UVC_QUIRK_FORCE_Y8 },
+       /* Dino-Lite Premier AM4111T */
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+                               | USB_DEVICE_ID_MATCH_INT_INFO,
+         .idVendor             = 0xa168,
+         .idProduct            = 0x0870,
+         .bInterfaceClass      = USB_CLASS_VIDEO,
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info          = UVC_QUIRK_LIGHT_CTRL_LEN },
        /* Generic USB Video Class */
        { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_UNDEFINED) },
        { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_15) },
diff --git a/drivers/media/usb/uvc/uvc_video.c 
b/drivers/media/usb/uvc/uvc_video.c
index fb86d6af3..702bf03c7 100644
--- a/drivers/media/usb/uvc/uvc_video.c
+++ b/drivers/media/usb/uvc/uvc_video.c
@@ -83,6 +83,16 @@ int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 
unit,
                return -EIO;
        }
 
+       /* The Dino-Lite Premier camera lies about a specific query length:
+        * control 3 unit 4 (LED light on/off) expects a 3 byte payload but
+        * the camera reports only 1 byte when queried for GET_LEN.
+        */
+       if ((dev->quirks & UVC_QUIRK_LIGHT_CTRL_LEN) && query == UVC_GET_LEN
+               && cs == 3 && unit == 4 && size == 2) {
+               put_unaligned_le16(3, data);
+               return 0;
+       }
+
        return 0;
 }
 
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index 05398784d..bb6a74920 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -186,6 +186,7 @@
 #define UVC_QUIRK_RESTRICT_FRAME_RATE  0x00000200
 #define UVC_QUIRK_RESTORE_CTRLS_ON_INIT        0x00000400
 #define UVC_QUIRK_FORCE_Y8             0x00000800
+#define UVC_QUIRK_LIGHT_CTRL_LEN       0x00001000
 
 /* Format flags */
 #define UVC_FMT_FLAG_COMPRESSED                0x00000001
-- 
2.15.1

Reply via email to