From patchwork Tue Feb 7 16:29:35 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Guennadi Liakhovetski X-Patchwork-Id: 39254 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 1cb8eS-00025M-3W; Tue, 07 Feb 2017 16:29:56 +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.84_2/mailfrontend-6) with esmtp id 1cb8eP-0006gS-65; Tue, 07 Feb 2017 17:29:55 +0100 Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932076AbdBGQ3t (ORCPT + 1 other); Tue, 7 Feb 2017 11:29:49 -0500 Received: from mout.gmx.net ([212.227.17.22]:52831 "EHLO mout.gmx.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754625AbdBGQ3r (ORCPT ); Tue, 7 Feb 2017 11:29:47 -0500 Received: from axis700.grange ([81.173.166.100]) by mail.gmx.com (mrgmx101 [212.227.17.168]) with ESMTPSA (Nemesis) id 0Lxt3Q-1cOmBY2TR6-015LHc for ; Tue, 07 Feb 2017 17:29:44 +0100 Received: from 200r.grange (200r.grange [192.168.1.16]) by axis700.grange (Postfix) with ESMTP id 53F448B119 for ; Tue, 7 Feb 2017 17:29:37 +0100 (CET) Received: from lyakh (uid 1000) (envelope-from g.liakhovetski@gmx.de) id 802184 by 200r.grange (DragonFly Mail Agent v0.9); Tue, 07 Feb 2017 17:29:37 +0100 From: Guennadi Liakhovetski To: linux-media@vger.kernel.org Cc: Laurent Pinchart , Hans Verkuil Subject: [PATCH v2 3/4] uvcvideo: handle control pipe protocol STALLs Date: Tue, 7 Feb 2017 17:29:35 +0100 Message-Id: <1486484976-17365-4-git-send-email-guennadi.liakhovetski@intel.com> X-Mailer: git-send-email 1.9.3 In-Reply-To: <1486484976-17365-1-git-send-email-guennadi.liakhovetski@intel.com> References: <1486484976-17365-1-git-send-email-guennadi.liakhovetski@intel.com> X-Provags-ID: V03:K0:1P7xhLVURnL/qX1BC+JPjGp7aQ0vYMmCku0pw/g4uZ2WshQPeFY f785Il9x91vzPRjdIAMxnDUpPunLD9UpU81m2B3lH/pinpDwwsFW3etJ2EHv06xzClNhntn ZpFv+MuuNAnMXsERDxUQA8sFYWoi69hXSr284nEK+8rR+XEa76EGjLT6RVD+RnAVK4JMiUr vpamKJzYvvK4odCAQ4REg== X-UI-Out-Filterresults: notjunk:1; V01:K0:w07Dybe9juo=:2EWyggGdYx2Tnp0LoAG3zl PRqNyAc+ROOUpoaBF7RwoKOdSQa1hzYCfebIO/zwdksxXsspzX0uvzRZECF0/sSFikPmETmY0 UXbl71xPeIJKNIBbqjgeAbaOLFrnDT7KfK9qFwHXzY9j/C4RpVEYUg7n+B9XTlSwtTwLuPTHl XzIzpRHvgBbaZT84RM23RlEfzg66CGgZ2grqruOKB5Oj98VKQOei/KaZRGjbbpmsgmta0v1pH JaocZOJPRqhdCLXuRaqKsp86uOXPr9v2qh4+nzMvnlULklWNOwHD1HJCGL89ha8UvuHkGSodL 2thKqUiUlZI99dvYWzv1lg+qVjz3oiuHT649pyCwSot3OyeMcQ0bpOaBOciUXK3tg1fXKJ1XH XMYm+p0QxrrB1ChX5+fp08V+igiXE0iB+ELLKW4T0Chv7iCaOkzz5GD5oMXmitty8DdsRm2Or +mv2BA2nddpKrgQxohD7tINq3A1F14lnf6ZbYzQ+Qb3J2SK4/9uJ+I127tPt4CLpKQk1RYX6J 7WwoWBvc9xWgpj+Mcy26G1QFU9hQkAK1eN8ATc/gkHXN9PlmbCJgv7epFivl77XF3/EFvjzGq 03jZUxKya/uIvv7LKptg0na0GdDwBQEFiZurVZlslIiQZmT9fQSa3PnrDTl+yfkyf5+p9WF4Y G3NBN3cel0gsK5wMuPZlkm3ZxPul2pDAvt2PmD/DZRXO/7Z4mHWzY5MyxfnMpM+petBjUSS+L Ti5qgZrBarN6ocNlroBqMvv5OMJDlanKqu/j7b4Cax3tN1W6Ym6G2zyf0t222XyI2pgfpIHoW HXCiVCV 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.2.7.162115 X-PMX-Spam: Gauge=IIIIIIII, Probability=8%, Report=' MULTIPLE_RCPTS 0.1, HTML_00_01 0.05, HTML_00_10 0.05, BODY_SIZE_3000_3999 0, BODY_SIZE_5000_LESS 0, BODY_SIZE_7000_LESS 0, IN_REP_TO 0, LEGITIMATE_SIGNS 0, MSG_THREAD 0, MULTIPLE_REAL_RCPTS 0, NO_URI_HTTPS 0, REFERENCES 0, SINGLE_URI_IN_BODY 0, URI_ENDS_IN_HTML 0, __ANY_URI 0, __CC_NAME 0, __CC_NAME_DIFF_FROM_ACC 0, __CC_REAL_NAMES 0, __CP_URI_IN_BODY 0, __HAS_CC_HDR 0, __HAS_FROM 0, __HAS_LIST_ID 0, __HAS_MSGID 0, __HAS_X_MAILER 0, __HAS_X_MAILING_LIST 0, __IN_REP_TO 0, __MIME_TEXT_ONLY 0, __MIME_TEXT_P 0, __MIME_TEXT_P1 0, __MULTIPLE_RCPTS_CC_X2 0, __NO_HTML_TAG_RAW 0, __REFERENCES 0, __SANE_MSGID 0, __SINGLE_URI_TEXT 0, __SUBJ_ALPHA_END 0, __TO_MALFORMED_2 0, __TO_NO_NAME 0, __URI_IN_BODY 0, __URI_NO_WWW 0, __URI_NS , __URI_WITH_PATH 0' When a command ends up in a STALL on the control pipe, use the Request Error Code control to provide a more precise error information to the user. Signed-off-by: Guennadi Liakhovetski --- drivers/media/usb/uvc/uvc_video.c | 59 +++++++++++++++++++++++++++++++++++---- 1 file changed, 53 insertions(+), 6 deletions(-) diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index 07a6c83..e530839 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -34,15 +34,59 @@ static int __uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit, __u8 intfnum, __u8 cs, void *data, __u16 size, int timeout) { - __u8 type = USB_TYPE_CLASS | USB_RECIP_INTERFACE; + __u8 type = USB_TYPE_CLASS | USB_RECIP_INTERFACE, tmp, error; unsigned int pipe; + int ret; pipe = (query & 0x80) ? usb_rcvctrlpipe(dev->udev, 0) : usb_sndctrlpipe(dev->udev, 0); type |= (query & 0x80) ? USB_DIR_IN : USB_DIR_OUT; - return usb_control_msg(dev->udev, pipe, query, type, cs << 8, + ret = usb_control_msg(dev->udev, pipe, query, type, cs << 8, unit << 8 | intfnum, data, size, timeout); + + if (ret != -EPIPE) + return ret; + + tmp = *(u8 *)data; + + pipe = usb_rcvctrlpipe(dev->udev, 0); + type = USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN; + ret = usb_control_msg(dev->udev, pipe, UVC_GET_CUR, type, + UVC_VC_REQUEST_ERROR_CODE_CONTROL << 8, + unit << 8 | intfnum, data, 1, timeout); + error = *(u8 *)data; + *(u8 *)data = tmp; + + if (ret < 0) + return ret; + + if (!ret) + return -EINVAL; + + uvc_trace(UVC_TRACE_CONTROL, "Control error %u\n", error); + + switch (error) { + case 0: + /* Cannot happen - we received a STALL */ + return -EPIPE; + case 1: /* Not ready */ + return -EAGAIN; + case 2: /* Wrong state */ + return -EILSEQ; + case 3: /* Power */ + return -EREMOTE; + case 4: /* Out of range */ + return -ERANGE; + case 5: /* Invalid unit */ + case 6: /* Invalid control */ + case 7: /* Invalid Request */ + case 8: /* Invalid value within range */ + default: /* reserved or unknown */ + break; + } + + return -EINVAL; } static const char *uvc_query_name(__u8 query) @@ -80,7 +124,7 @@ int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit, uvc_printk(KERN_ERR, "Failed to query (%s) UVC control %u on " "unit %u: %d (exp. %u).\n", uvc_query_name(query), cs, unit, ret, size); - return -EIO; + return ret < 0 ? ret : -EIO; } return 0; @@ -203,13 +247,15 @@ static int uvc_get_video_ctrl(struct uvc_streaming *stream, uvc_warn_once(stream->dev, UVC_WARN_PROBE_DEF, "UVC non " "compliance - GET_DEF(PROBE) not supported. " "Enabling workaround.\n"); - ret = -EIO; + if (ret >= 0) + ret = -EIO; goto out; } else if (ret != size) { uvc_printk(KERN_ERR, "Failed to query (%u) UVC %s control : " "%d (exp. %u).\n", query, probe ? "probe" : "commit", ret, size); - ret = -EIO; + if (ret >= 0) + ret = -EIO; goto out; } @@ -290,7 +336,8 @@ static int uvc_set_video_ctrl(struct uvc_streaming *stream, uvc_printk(KERN_ERR, "Failed to set UVC %s control : " "%d (exp. %u).\n", probe ? "probe" : "commit", ret, size); - ret = -EIO; + if (ret >= 0) + ret = -EIO; } kfree(data);