summaryrefslogtreecommitdiffstats
path: root/drivers/media/video/uvc/uvc_v4l2.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/uvc/uvc_v4l2.c')
-rw-r--r--drivers/media/video/uvc/uvc_v4l2.c60
1 files changed, 24 insertions, 36 deletions
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c
index a2bdd80..23239a4 100644
--- a/drivers/media/video/uvc/uvc_v4l2.c
+++ b/drivers/media/video/uvc/uvc_v4l2.c
@@ -364,37 +364,30 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream,
* unprivileged state. Only a single instance can be in a privileged state at
* a given time. Trying to perform an operation that requires privileges will
* automatically acquire the required privileges if possible, or return -EBUSY
- * otherwise. Privileges are dismissed when closing the instance.
+ * otherwise. Privileges are dismissed when closing the instance or when
+ * freeing the video buffers using VIDIOC_REQBUFS.
*
* Operations that require privileges are:
*
* - VIDIOC_S_INPUT
* - VIDIOC_S_PARM
* - VIDIOC_S_FMT
- * - VIDIOC_TRY_FMT
* - VIDIOC_REQBUFS
*/
static int uvc_acquire_privileges(struct uvc_fh *handle)
{
- int ret = 0;
-
/* Always succeed if the handle is already privileged. */
if (handle->state == UVC_HANDLE_ACTIVE)
return 0;
/* Check if the device already has a privileged handle. */
- mutex_lock(&uvc_driver.open_mutex);
if (atomic_inc_return(&handle->stream->active) != 1) {
atomic_dec(&handle->stream->active);
- ret = -EBUSY;
- goto done;
+ return -EBUSY;
}
handle->state = UVC_HANDLE_ACTIVE;
-
-done:
- mutex_unlock(&uvc_driver.open_mutex);
- return ret;
+ return 0;
}
static void uvc_dismiss_privileges(struct uvc_fh *handle)
@@ -421,24 +414,20 @@ static int uvc_v4l2_open(struct file *file)
int ret = 0;
uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_open\n");
- mutex_lock(&uvc_driver.open_mutex);
stream = video_drvdata(file);
- if (stream->dev->state & UVC_DEV_DISCONNECTED) {
- ret = -ENODEV;
- goto done;
- }
+ if (stream->dev->state & UVC_DEV_DISCONNECTED)
+ return -ENODEV;
ret = usb_autopm_get_interface(stream->dev->intf);
if (ret < 0)
- goto done;
+ return ret;
/* Create the device handle. */
handle = kzalloc(sizeof *handle, GFP_KERNEL);
if (handle == NULL) {
usb_autopm_put_interface(stream->dev->intf);
- ret = -ENOMEM;
- goto done;
+ return -ENOMEM;
}
if (atomic_inc_return(&stream->dev->users) == 1) {
@@ -447,7 +436,7 @@ static int uvc_v4l2_open(struct file *file)
usb_autopm_put_interface(stream->dev->intf);
atomic_dec(&stream->dev->users);
kfree(handle);
- goto done;
+ return ret;
}
}
@@ -456,11 +445,7 @@ static int uvc_v4l2_open(struct file *file)
handle->state = UVC_HANDLE_PASSIVE;
file->private_data = handle;
- kref_get(&stream->dev->kref);
-
-done:
- mutex_unlock(&uvc_driver.open_mutex);
- return ret;
+ return 0;
}
static int uvc_v4l2_release(struct file *file)
@@ -490,7 +475,6 @@ static int uvc_v4l2_release(struct file *file)
uvc_status_stop(stream->dev);
usb_autopm_put_interface(stream->dev->intf);
- kref_put(&stream->dev->kref, uvc_delete);
return 0;
}
@@ -636,12 +620,16 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
(chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
if (index != 0)
return -EINVAL;
- iterm = list_first_entry(&chain->iterms,
- struct uvc_entity, chain);
+ list_for_each_entry(iterm, &chain->entities, chain) {
+ if (UVC_ENTITY_IS_ITERM(iterm))
+ break;
+ }
pin = iterm->id;
- } else if (pin < selector->selector.bNrInPins) {
- pin = selector->selector.baSourceID[index];
- list_for_each_entry(iterm, chain->iterms.next, chain) {
+ } else if (pin < selector->bNrInPins) {
+ pin = selector->baSourceID[index];
+ list_for_each_entry(iterm, &chain->entities, chain) {
+ if (!UVC_ENTITY_IS_ITERM(iterm))
+ continue;
if (iterm->id == pin)
break;
}
@@ -692,7 +680,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
break;
}
- if (input == 0 || input > chain->selector->selector.bNrInPins)
+ if (input == 0 || input > chain->selector->bNrInPins)
return -EINVAL;
return uvc_query_ctrl(chain->dev, UVC_SET_CUR,
@@ -731,9 +719,6 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct uvc_streaming_control probe;
- if ((ret = uvc_acquire_privileges(handle)) < 0)
- return ret;
-
return uvc_v4l2_try_format(stream, arg, &probe, NULL, NULL);
}
@@ -888,6 +873,9 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
if (ret < 0)
return ret;
+ if (ret == 0)
+ uvc_dismiss_privileges(handle);
+
rb->count = ret;
ret = 0;
break;
@@ -1051,7 +1039,7 @@ static ssize_t uvc_v4l2_read(struct file *file, char __user *data,
size_t count, loff_t *ppos)
{
uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_read: not implemented.\n");
- return -ENODEV;
+ return -EINVAL;
}
/*
OpenPOWER on IntegriCloud