aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Grzeschik <m.grzeschik@pengutronix.de>2023-09-11 16:05:28 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2023-10-02 13:58:35 +0200
commit3a63f86c6a6cb0601f0563a81574745da2979e3b (patch)
tree8f42b03440a4ea5d37450bb158cee76e5b6beaeb
parentusb: gadget: udc: Handle gadget_connect failure during bind operation (diff)
downloadlinux-rng-3a63f86c6a6cb0601f0563a81574745da2979e3b.tar.xz
linux-rng-3a63f86c6a6cb0601f0563a81574745da2979e3b.zip
usb: gadget: uvc: stop pump thread on video disable
Since the uvc-video gadget driver is using the v4l2 interface, the streamon and streamoff can be triggered at any times. To ensure that the pump worker will be closed as soon the userspace is calling streamoff we synchronize the state of the gadget ensuring the pump worker to bail out. Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de> Link: https://lore.kernel.org/r/20230911140530.2995138-2-m.grzeschik@pengutronix.de Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/usb/gadget/function/uvc_video.c8
1 files changed, 7 insertions, 1 deletions
diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c
index 91af3b1ef0d4..4b68a3a9815d 100644
--- a/drivers/usb/gadget/function/uvc_video.c
+++ b/drivers/usb/gadget/function/uvc_video.c
@@ -384,13 +384,14 @@ static void uvcg_video_pump(struct work_struct *work)
struct uvc_video_queue *queue = &video->queue;
/* video->max_payload_size is only set when using bulk transfer */
bool is_bulk = video->max_payload_size;
+ struct uvc_device *uvc = video->uvc;
struct usb_request *req = NULL;
struct uvc_buffer *buf;
unsigned long flags;
bool buf_done;
int ret;
- while (video->ep->enabled) {
+ while (video->ep->enabled && uvc->state == UVC_STATE_STREAMING) {
/*
* Retrieve the first available USB request, protected by the
* request lock.
@@ -488,6 +489,7 @@ static void uvcg_video_pump(struct work_struct *work)
*/
int uvcg_video_enable(struct uvc_video *video, int enable)
{
+ struct uvc_device *uvc = video->uvc;
unsigned int i;
int ret;
@@ -498,6 +500,8 @@ int uvcg_video_enable(struct uvc_video *video, int enable)
}
if (!enable) {
+ uvc->state = UVC_STATE_CONNECTED;
+
cancel_work_sync(&video->pump);
uvcg_queue_cancel(&video->queue, 0);
@@ -523,6 +527,8 @@ int uvcg_video_enable(struct uvc_video *video, int enable)
video->encode = video->queue.use_sg ?
uvc_video_encode_isoc_sg : uvc_video_encode_isoc;
+ uvc->state = UVC_STATE_STREAMING;
+
video->req_int_count = 0;
queue_work(video->async_wq, &video->pump);