From patchwork Sun Jun 4 13:41:19 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandre Macabies X-Patchwork-Id: 41638 X-Patchwork-Delegate: laurent.pinchart@ideasonboard.com Received: from mail.tu-berlin.de ([130.149.7.33]) by www.linuxtv.org with esmtp (Exim 4.84_2) (envelope-from ) id 1dHW3I-0007Vi-Ry; Sun, 04 Jun 2017 13:58:44 +0000 X-tubIT-Incoming-IP: 209.132.180.67 Received: from vger.kernel.org ([209.132.180.67]) by mail.tu-berlin.de (exim-4.89/mailfrontend-7) with esmtp id 1dHW3G-00053i-16; Sun, 04 Jun 2017 15:58:44 +0200 Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751201AbdFDN6k (ORCPT + 1 other); Sun, 4 Jun 2017 09:58:40 -0400 Received: from r0.smtpout1.alwaysdata.com ([176.31.58.0]:34874 "EHLO r0.smtpout1.alwaysdata.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751159AbdFDN6j (ORCPT ); Sun, 4 Jun 2017 09:58:39 -0400 X-Greylist: delayed 974 seconds by postgrey-1.27 at vger.kernel.org; Sun, 04 Jun 2017 09:58:39 EDT DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=alwaysdata.net; s=zopieux; h=Message-Id:Date:Subject:Cc:To:From:Sender: Reply-To:MIME-Version:Content-Type:Content-Transfer-Encoding:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=E1Hgmu+yTTiBJYj57+XhUpGGzNqrVIzwdZrv/R4VX8c=; b=EpSe7Od4ZW9TejAmrKw3eVq24V agXJSX1WC1JYULf4XycBFh182SjLQOJ5yWdLiWYnI+TPwuY18A77QdWZERR+hu84Y5GwpSioZ8kGr 5nlLVJCmc8FbbBz1sSFwhDZ8pdr9B8r5JIlJntDDuohssKL2Dlmxr8SK3QwB1IpLwgh8=; Received: from 116.104.88.79.rev.sfr.net ([79.88.104.116] helo=laptop.numericable.fr) by smtpout1.roubaix1.alwaysdata.com with esmtpsa (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.88) (envelope-from ) id 1dHVnS-0003uq-Ay; Sun, 04 Jun 2017 15:42:22 +0200 From: Alexandre Macabies To: linux-media@vger.kernel.org Cc: Laurent Pinchart , Alexandre Macabies Subject: [PATCH] uvcvideo: Hardcoded CTRL_QUERY GET_LEN for a lying device Date: Sun, 4 Jun 2017 15:41:19 +0200 Message-Id: <20170604134119.16936-1-web+oss@zopieux.com> X-Mailer: git-send-email 2.13.0 X-alwaysdata-ID: 236141273 Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org X-PMX-Version: 6.0.0.2142326, Antispam-Engine: 2.7.2.2107409, Antispam-Data: 2017.6.4.134815 X-PMX-Spam: Gauge=IIIIIIII, Probability=8%, Report=' MULTIPLE_RCPTS 0.1, HTML_00_01 0.05, HTML_00_10 0.05, BODY_SIZE_4000_4999 0, BODY_SIZE_5000_LESS 0, BODY_SIZE_7000_LESS 0, DKIM_SIGNATURE 0, LEGITIMATE_SIGNS 0, MULTIPLE_REAL_RCPTS 0, URI_WITH_PATH_ONLY 0, __ANY_URI 0, __CC_NAME 0, __CC_NAME_DIFF_FROM_ACC 0, __CC_REAL_NAMES 0, __CP_MEDIA_BODY 0, __CP_URI_IN_BODY 0, __FRAUD_MONEY_CURRENCY 0, __FRAUD_MONEY_CURRENCY_DOLLAR 0, __FROM_DOMAIN_IN_ANY_CC2 0, __FROM_DOMAIN_IN_RCPT 0, __HAS_CC_HDR 0, __HAS_FROM 0, __HAS_LIST_ID 0, __HAS_MSGID 0, __HAS_X_MAILER 0, __HAS_X_MAILING_LIST 0, __HTTPS_URI 0, __MIME_TEXT_ONLY 0, __MIME_TEXT_P 0, __MIME_TEXT_P1 0, __MULTIPLE_RCPTS_CC_X2 0, __MULTIPLE_URI_TEXT 0, __NO_HTML_TAG_RAW 0, __SANE_MSGID 0, __STOCK_PHRASE_7 0, __SUBJ_ALPHA_END 0, __TO_MALFORMED_2 0, __TO_NO_NAME 0, __URI_IN_BODY 0, __URI_NOT_IMG 0, __URI_NS , __URI_WITH_PATH 0' Hello, I sent this patch on the linux-uvc ML but it seems effectively dead nowadays. 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; }