On 06/04/2017 03:41 PM, Alexandre Macabies wrote:
> Hello,
I forgot to Cc: the full list of maintainers for this patch. This follow-up
includes them. Sorry for the noise! My original email & patch is quoted below.
Best,
Alexandre
> This thread comes after two others[1][2] about a similar issue.
>
> I own a USB video microscope[3] from Dino-Lite. Even if the constructor does
> not advertise it as being supported on Linux, it is mostly a "good citizen"
> camera: it registers as a standard USB video device and as such, it is
> properly
> recognized by uvcvideo.
>
> This device is equipped with an integrated illuminator/lamp -- a set of LEDs.
> After some research (using a USB sniffer) I managed to identify the
> non-standard XU control used to switch this lamp on and off: one shall send
> either 80 01 f0 (off) or 80 01 f1 (on) to XU control unit 4 selector 3.
>
> So at first I tried to send a raw ctrl_set using:
>
> $ uvcdynctrl -S 4:3 8001f0
> [...]
> query control size of : 1
> [...]
> ERROR: Unable to set the control value: Invalid argument. (Code: 3)
>
> Indeed, the device reports this XU as being only 1 in length, but the payload
> has to be 3 bytes. So I assume there is a bug (or deliberate inaccuracy) in
> the
> GET_LEN reply from the device firmware. To overcome this issue, I compiled
> a patched version of uvcvideo in which uvc_query_ctrl[4] returns an hardcoded
> size of 3 for this specific device & UX control. I was finally able to switch
> the lamp on and off:
>
> $ uvcdynctrl -S 4:3 8001f0
> [39252.854261] uvcvideo: Fixing USB a168:0870 UX control 4/3 len: 1 -> 3
> [...]
> query control size of : 3
> [...]
> set value of : (LE)0x8001f0 (BE)0xf00180
> [lamp goes off]
>
> You can find the patch below. I abstracted it in the spirit of
> uvc_ctrl_fixup_xu_info[5] so we can add more entries to the table in the
> future. What do you think, would it be relevant to merge? AFAICT there is no
> API in uvcvideo or v4l for controlling this kind of illuminator/lamp features,
> so giving userland the ability to control the devices via XU by lying seems to
> be the only solution.
>
> Best,
>
> Alexandre
>
> [1] "Dino-Lite uvc support", 2008,
> https://sourceforge.net/p/linux-uvc/mailman/message/29831153/
> [2] "switching light on device Dino-Lite Premier", 2013,
> https://sourceforge.net/p/linux-uvc/mailman/message/31219122/
> [3] https://www.dinolite.us/products/digital-microscopes/usb/basic/am4111t
> [4]
> http://elixir.free-electrons.com/linux/v4.11/source/drivers/media/usb/uvc/uvc_video.c#L72
> [5]
> http://elixir.free-electrons.com/linux/v4.11/source/drivers/media/usb/uvc/uvc_ctrl.c#L1593
>
> Signed-off-by: Alexandre Macabies
>
> ---
> drivers/media/usb/uvc/uvc_video.c | 37 +
> 1 file changed, 37 insertions(+)
>
> diff --git a/drivers/media/usb/uvc/uvc_video.c
> b/drivers/media/usb/uvc/uvc_video.c
> index 07a6c833ef7b..839dc02b4f33 100644
> --- a/drivers/media/usb/uvc/uvc_video.c
> +++ b/drivers/media/usb/uvc/uvc_video.c
> @@ -69,6 +69,40 @@ static const char *uvc_query_name(__u8 query)
> }
> }
>
> +static void uvc_fixup_query_ctrl_len(const struct uvc_device *dev, __u8 unit,
> + __u8 cs, void *data)
> +{
> + struct uvc_ctrl_fixup {
> + struct usb_device_id id;
> + u8 unit;
> + u8 selector;
> + u16 len;
> + };
> +
> + static const struct uvc_ctrl_fixup fixups[] = {
> + // Dino-Lite Premier (AM4111T)
> + { { USB_DEVICE(0xa168, 0x0870) }, 4, 3, 3 },
> + };
> +
> + unsigned int i;
> +
> + for (i = 0; i < ARRAY_SIZE(fixups); ++i) {
> + if (!usb_match_one_id(dev->intf, &fixups[i].id))
> + continue;
> +
> + if (!(fixups[i].unit == unit && fixups[i].selector == cs))
> + continue;
> +
> + uvc_trace(UVC_TRACE_CONTROL,
> + "Fixing USB %04x:%04x %u/%u GET_LEN: %u -> %u",
> + fixups[i].id.idVendor, fixups[i].id.idProduct,
> + unit, cs,
> + le16_to_cpup((__le16 *)data), fixups[i].len);
> + *((__le16 *)data) = cpu_to_le16(fixups[i].len);
> + break;
> + }
> +}
> +
> int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
> __u8 intfnum, __u8 cs, void *data, __u16 size)
> {
> @@ -83,6 +117,9 @@ int uvc_query_ctrl(struct uvc_device *dev, __u8 query,
> __u8 unit,
> return -EIO;
> }
>
> + if (query == UVC_GET_LEN && size == 2)
> + uvc_fixup_query_ctrl_len(dev, unit, cs, data);
> +
> return 0;
> }
>
>
> --
> 2.13.0
>