From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C22A0C433EF for ; Mon, 13 Dec 2021 09:55:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S238929AbhLMJzB (ORCPT ); Mon, 13 Dec 2021 04:55:01 -0500 Received: from sin.source.kernel.org ([145.40.73.55]:43242 "EHLO sin.source.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S238338AbhLMJwz (ORCPT ); Mon, 13 Dec 2021 04:52:55 -0500 Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by sin.source.kernel.org (Postfix) with ESMTPS id A0EB2CE0B20; Mon, 13 Dec 2021 09:52:53 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 5141CC00446; Mon, 13 Dec 2021 09:52:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1639389171; bh=OmBOJoUcK9yVbqTo2K0oRQzntw2nDurZuujaF4S9vhs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=RK+uBSrm+Z19/mRVmzq3Qmm7vvLZZZvXU5dy3ARzQ3R1qvWUPq8HIpxBaJ2ajhjy3 LA6wPQNE4RqsGTRgDBvcWgwdUlmLkO6Ulwvf1C5dB4ZRRf4IZM/bdf2bRjopHFGp99 8GJ/CEB2yPt3ruXnFmXkaAypA6xV63QOPLfVoCx0= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Michael Tretter , Laurent Pinchart , Thomas Haemmerle , Michael Grzeschik , Felipe Balbi , Dan Vacura Subject: [PATCH 5.15 001/171] usb: gadget: uvc: fix multiple opens Date: Mon, 13 Dec 2021 10:28:36 +0100 Message-Id: <20211213092945.142139233@linuxfoundation.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20211213092945.091487407@linuxfoundation.org> References: <20211213092945.091487407@linuxfoundation.org> User-Agent: quilt/0.66 X-stable: review X-Patchwork-Hint: ignore MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: stable@vger.kernel.org From: Thomas Haemmerle commit 72ee48ee8925446eaeda8e4ef3f2eb16b4a93d2a upstream. Currently, the UVC function is activated when open on the corresponding v4l2 device is called. On another open the activation of the function fails since the deactivation counter in `usb_function_activate` equals 0. However the error is not returned to userspace since the open of the v4l2 device is successful. On a close the function is deactivated (since deactivation counter still equals 0) and the video is disabled in `uvc_v4l2_release`, although the UVC application potentially is streaming. Move activation of UVC function to subscription on UVC_EVENT_SETUP because there we can guarantee for a userspace application utilizing UVC. Block subscription on UVC_EVENT_SETUP while another application already is subscribed to it, indicated by `bool func_connected` in `struct uvc_device`. Extend the `struct uvc_file_handle` with member `bool is_uvc_app_handle` to tag it as the handle used by the userspace UVC application. With this a process is able to check capabilities of the v4l2 device without deactivating the function for the actual UVC application. Reviewed-By: Michael Tretter Reviewed-by: Laurent Pinchart Signed-off-by: Thomas Haemmerle Signed-off-by: Michael Tretter Signed-off-by: Michael Grzeschik Acked-by: Felipe Balbi Link: https://lore.kernel.org/r/20211003201355.24081-1-m.grzeschik@pengutronix.de Cc: Dan Vacura Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/uvc.h | 2 + drivers/usb/gadget/function/uvc_v4l2.c | 49 ++++++++++++++++++++++++++++----- 2 files changed, 44 insertions(+), 7 deletions(-) --- a/drivers/usb/gadget/function/uvc.h +++ b/drivers/usb/gadget/function/uvc.h @@ -126,6 +126,7 @@ struct uvc_device { enum uvc_state state; struct usb_function func; struct uvc_video video; + bool func_connected; /* Descriptors */ struct { @@ -156,6 +157,7 @@ static inline struct uvc_device *to_uvc( struct uvc_file_handle { struct v4l2_fh vfh; struct uvc_video *device; + bool is_uvc_app_handle; }; #define to_uvc_file_handle(handle) \ --- a/drivers/usb/gadget/function/uvc_v4l2.c +++ b/drivers/usb/gadget/function/uvc_v4l2.c @@ -227,17 +227,55 @@ static int uvc_v4l2_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub) { + struct uvc_device *uvc = video_get_drvdata(fh->vdev); + struct uvc_file_handle *handle = to_uvc_file_handle(fh); + int ret; + if (sub->type < UVC_EVENT_FIRST || sub->type > UVC_EVENT_LAST) return -EINVAL; - return v4l2_event_subscribe(fh, sub, 2, NULL); + if (sub->type == UVC_EVENT_SETUP && uvc->func_connected) + return -EBUSY; + + ret = v4l2_event_subscribe(fh, sub, 2, NULL); + if (ret < 0) + return ret; + + if (sub->type == UVC_EVENT_SETUP) { + uvc->func_connected = true; + handle->is_uvc_app_handle = true; + uvc_function_connect(uvc); + } + + return 0; +} + +static void uvc_v4l2_disable(struct uvc_device *uvc) +{ + uvc->func_connected = false; + uvc_function_disconnect(uvc); + uvcg_video_enable(&uvc->video, 0); + uvcg_free_buffers(&uvc->video.queue); } static int uvc_v4l2_unsubscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub) { - return v4l2_event_unsubscribe(fh, sub); + struct uvc_device *uvc = video_get_drvdata(fh->vdev); + struct uvc_file_handle *handle = to_uvc_file_handle(fh); + int ret; + + ret = v4l2_event_unsubscribe(fh, sub); + if (ret < 0) + return ret; + + if (sub->type == UVC_EVENT_SETUP && handle->is_uvc_app_handle) { + uvc_v4l2_disable(uvc); + handle->is_uvc_app_handle = false; + } + + return 0; } static long @@ -292,7 +330,6 @@ uvc_v4l2_open(struct file *file) handle->device = &uvc->video; file->private_data = &handle->vfh; - uvc_function_connect(uvc); return 0; } @@ -304,11 +341,9 @@ uvc_v4l2_release(struct file *file) struct uvc_file_handle *handle = to_uvc_file_handle(file->private_data); struct uvc_video *video = handle->device; - uvc_function_disconnect(uvc); - mutex_lock(&video->mutex); - uvcg_video_enable(video, 0); - uvcg_free_buffers(&video->queue); + if (handle->is_uvc_app_handle) + uvc_v4l2_disable(uvc); mutex_unlock(&video->mutex); file->private_data = NULL;