From patchwork Wed Feb 26 13:38:10 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3724121 Return-Path: X-Original-To: patchwork-linux-media@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 084F59F2F7 for ; Wed, 26 Feb 2014 13:37:02 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 25C362017B for ; Wed, 26 Feb 2014 13:37:01 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 351532016C for ; Wed, 26 Feb 2014 13:37:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752040AbaBZNg5 (ORCPT ); Wed, 26 Feb 2014 08:36:57 -0500 Received: from perceval.ideasonboard.com ([95.142.166.194]:43625 "EHLO perceval.ideasonboard.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751072AbaBZNg5 (ORCPT ); Wed, 26 Feb 2014 08:36:57 -0500 Received: from avalon.ideasonboard.com (unknown [91.178.216.159]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id AA61E35A46; Wed, 26 Feb 2014 14:35:52 +0100 (CET) From: Laurent Pinchart To: linux-media@vger.kernel.org Cc: Oleksij Rempel , stable@vger.kernel.org Subject: [PATCH v2] uvcvideo: Do not use usb_set_interface on bulk EP Date: Wed, 26 Feb 2014 14:38:10 +0100 Message-Id: <1393421890-4816-1-git-send-email-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 1.8.3.2 Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Oleksij Rempel The UVC specification uses alternate setting selection to notify devices of stream start/stop. This breaks when using bulk-based devices, as the video streaming interface has a single alternate setting in that case, making video stream start and video stream stop events to appear identical to the device. Bulk-based devices are thus not well supported by UVC. The webcam built in the Asus Zenbook UX302LA ignores the set interface request and will keep the video stream enabled when the driver tries to stop it. If USB autosuspend is enabled the device will then be suspended and will crash, requiring a cold reboot. USB trace capture showed that Windows sends a CLEAR_FEATURE(HALT) request to the bulk endpoint when stopping the stream instead of selecting alternate setting 0. The camera then behaves correctly, and thus seems to require that behaviour. Replace selection of alternate setting 0 with clearing of the endpoint halt feature at video stream stop for bulk-based devices. Let's refrain from blaming Microsoft this time, as it's not clear whether this Windows-specific but USB-compliant behaviour was specifically developed to handle bulkd-based UVC devices, or if the camera just took advantage of it. CC: stable@vger.kernel.org Signed-off-by: Oleksij Rempel Signed-off-by: Laurent Pinchart --- drivers/media/usb/uvc/uvc_video.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index 103cd4e..8d52baf 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -1850,7 +1850,25 @@ int uvc_video_enable(struct uvc_streaming *stream, int enable) if (!enable) { uvc_uninit_video(stream, 1); - usb_set_interface(stream->dev->udev, stream->intfnum, 0); + if (stream->intf->num_altsetting > 1) { + usb_set_interface(stream->dev->udev, + stream->intfnum, 0); + } else { + /* UVC doesn't specify how to inform a bulk-based device + * when the video stream is stopped. Windows sends a + * CLEAR_FEATURE(HALT) request to the video streaming + * bulk endpoint, mimic the same behaviour. + */ + unsigned int epnum = stream->header.bEndpointAddress + & USB_ENDPOINT_NUMBER_MASK; + unsigned int dir = stream->header.bEndpointAddress + & USB_ENDPOINT_DIR_MASK; + unsigned int pipe; + + pipe = usb_sndbulkpipe(stream->dev->udev, epnum) | dir; + usb_clear_halt(stream->dev->udev, pipe); + } + uvc_queue_enable(&stream->queue, 0); uvc_video_clock_cleanup(stream); return 0;