summaryrefslogtreecommitdiff
path: root/drivers/usb/gadget/function/uvc_v4l2.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2021-11-04 07:50:43 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2021-11-04 07:50:43 -0700
commit048ff8629e117d8411a787559417c781bcd78d7e (patch)
tree2cff07ed5c13a096d1c880139873870146cca74a /drivers/usb/gadget/function/uvc_v4l2.c
parent7ddb58cb0ecae8e8b6181d736a87667cc9ab8389 (diff)
parenta0548b26901f082684ad1fb3ba397d2de3a1406a (diff)
Merge tag 'usb-5.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB / Thunderbolt updates from Greg KH: "Here is the big set of USB and Thunderbolt driver updates for 5.16-rc1. Nothing major in here, just lots of little cleanups and additions for new hardware, all of which have been in linux-next for a while with no reported problems. Included in here are: - tiny Thunderbolt driver updates - USB typec driver updates - USB serial driver updates - USB gadget driver updates - dwc2 and dwc3 controller driver updates - tiny USB host driver updates - minor USB driver fixes and updates - USB dts updates for various platforms" * tag 'usb-5.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (123 commits) usb: gadget: Mark USB_FSL_QE broken on 64-bit usb: gadget: f_mass_storage: Disable eps during disconnect usb: gadget: udc: core: Revise comments for USB ep enable/disable USB: serial: keyspan: fix memleak on probe errors USB: serial: cp210x: use usb_control_msg_recv() and usb_control_msg_send() USB: serial: ch314: use usb_control_msg_recv() USB: iowarrior: fix control-message timeouts Documentation: USB: fix example bulk-message timeout usb: dwc2: stm32mp15: set otg_rev usb: dwc2: add otg_rev and otg_caps information for gadget driver dt-bindings: usb: dwc2: adopt otg properties defined in usb-drd.yaml dt-bindings: usb: dwc2: Add reference to usb-drd.yaml usb: gadget: uvc: implement dwPresentationTime and scrSourceClock usb: gadget: uvc: use on returned header len in video_encode_isoc_sg usb:gadget: f_uac1: fixed sync playback Docs: usb: remove :c:func: for usb_register and usb_deregister Docs: usb: update struct usb_driver usb: gadget: configfs: change config attributes file operation usb: gadget: configfs: add cfg_to_gadget_info() helper usb: dwc3: Align DWC3_EP_* flag macros ...
Diffstat (limited to 'drivers/usb/gadget/function/uvc_v4l2.c')
-rw-r--r--drivers/usb/gadget/function/uvc_v4l2.c52
1 files changed, 44 insertions, 8 deletions
diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c
index 4ca89eab6159..a2c78690c5c2 100644
--- a/drivers/usb/gadget/function/uvc_v4l2.c
+++ b/drivers/usb/gadget/function/uvc_v4l2.c
@@ -169,7 +169,8 @@ uvc_v4l2_qbuf(struct file *file, void *fh, struct v4l2_buffer *b)
if (ret < 0)
return ret;
- schedule_work(&video->pump);
+ if (uvc->state == UVC_STATE_STREAMING)
+ schedule_work(&video->pump);
return ret;
}
@@ -227,17 +228,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 +331,6 @@ uvc_v4l2_open(struct file *file)
handle->device = &uvc->video;
file->private_data = &handle->vfh;
- uvc_function_connect(uvc);
return 0;
}
@@ -304,11 +342,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;