Commit d8e96c4b authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab

[media] uvc gadget: switch to v4l2 core locking

Switch this driver over to the V4L2 core locking mechanism in preparation
for switching to unlocked_ioctl. Suggested by Laurent Pinchart.

This patch introduces a new mutex at the struct uvc_video level and
drops the old mutex at the queue level. The new lock is now used for all
ioctl locking and in the release file operation (the driver always has
to take care of locking in file operations, the core only serializes
ioctls).

Note that the mmap and get_unmapped_area file operations no longer take
a lock. Commit f035eb4e fixed a AB-BA
deadlock by moving all the locking down into vb2, so the mmap and
get_unmapped_area file operations should no longer do any locking before
calling into vb2.
Signed-off-by: default avatarHans Verkuil <hans.verkuil@cisco.com>
Acked-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@osg.samsung.com>
parent 2e1328dd
...@@ -447,6 +447,7 @@ uvc_register_video(struct uvc_device *uvc) ...@@ -447,6 +447,7 @@ uvc_register_video(struct uvc_device *uvc)
video->ioctl_ops = &uvc_v4l2_ioctl_ops; video->ioctl_ops = &uvc_v4l2_ioctl_ops;
video->release = video_device_release; video->release = video_device_release;
video->vfl_dir = VFL_DIR_TX; video->vfl_dir = VFL_DIR_TX;
video->lock = &uvc->video.mutex;
strlcpy(video->name, cdev->gadget->name, sizeof(video->name)); strlcpy(video->name, cdev->gadget->name, sizeof(video->name));
uvc->vdev = video; uvc->vdev = video;
...@@ -918,6 +919,7 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi) ...@@ -918,6 +919,7 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi)
if (uvc == NULL) if (uvc == NULL)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
mutex_init(&uvc->video.mutex);
uvc->state = UVC_STATE_DISCONNECTED; uvc->state = UVC_STATE_DISCONNECTED;
opts = fi_to_f_uvc_opts(fi); opts = fi_to_f_uvc_opts(fi);
......
...@@ -115,6 +115,7 @@ struct uvc_video ...@@ -115,6 +115,7 @@ struct uvc_video
unsigned int width; unsigned int width;
unsigned int height; unsigned int height;
unsigned int imagesize; unsigned int imagesize;
struct mutex mutex; /* protects frame parameters */
/* Requests */ /* Requests */
unsigned int req_size; unsigned int req_size;
......
...@@ -104,29 +104,16 @@ static void uvc_buffer_queue(struct vb2_buffer *vb) ...@@ -104,29 +104,16 @@ static void uvc_buffer_queue(struct vb2_buffer *vb)
spin_unlock_irqrestore(&queue->irqlock, flags); spin_unlock_irqrestore(&queue->irqlock, flags);
} }
static void uvc_wait_prepare(struct vb2_queue *vq)
{
struct uvc_video_queue *queue = vb2_get_drv_priv(vq);
mutex_unlock(&queue->mutex);
}
static void uvc_wait_finish(struct vb2_queue *vq)
{
struct uvc_video_queue *queue = vb2_get_drv_priv(vq);
mutex_lock(&queue->mutex);
}
static struct vb2_ops uvc_queue_qops = { static struct vb2_ops uvc_queue_qops = {
.queue_setup = uvc_queue_setup, .queue_setup = uvc_queue_setup,
.buf_prepare = uvc_buffer_prepare, .buf_prepare = uvc_buffer_prepare,
.buf_queue = uvc_buffer_queue, .buf_queue = uvc_buffer_queue,
.wait_prepare = uvc_wait_prepare, .wait_prepare = vb2_ops_wait_prepare,
.wait_finish = uvc_wait_finish, .wait_finish = vb2_ops_wait_finish,
}; };
int uvcg_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type) int uvcg_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type,
struct mutex *lock)
{ {
int ret; int ret;
...@@ -135,6 +122,7 @@ int uvcg_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type) ...@@ -135,6 +122,7 @@ int uvcg_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type)
queue->queue.drv_priv = queue; queue->queue.drv_priv = queue;
queue->queue.buf_struct_size = sizeof(struct uvc_buffer); queue->queue.buf_struct_size = sizeof(struct uvc_buffer);
queue->queue.ops = &uvc_queue_qops; queue->queue.ops = &uvc_queue_qops;
queue->queue.lock = lock;
queue->queue.mem_ops = &vb2_vmalloc_memops; queue->queue.mem_ops = &vb2_vmalloc_memops;
queue->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC queue->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC
| V4L2_BUF_FLAG_TSTAMP_SRC_EOF; | V4L2_BUF_FLAG_TSTAMP_SRC_EOF;
...@@ -142,7 +130,6 @@ int uvcg_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type) ...@@ -142,7 +130,6 @@ int uvcg_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type)
if (ret) if (ret)
return ret; return ret;
mutex_init(&queue->mutex);
spin_lock_init(&queue->irqlock); spin_lock_init(&queue->irqlock);
INIT_LIST_HEAD(&queue->irqqueue); INIT_LIST_HEAD(&queue->irqqueue);
queue->flags = 0; queue->flags = 0;
...@@ -155,9 +142,7 @@ int uvcg_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type) ...@@ -155,9 +142,7 @@ int uvcg_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type)
*/ */
void uvcg_free_buffers(struct uvc_video_queue *queue) void uvcg_free_buffers(struct uvc_video_queue *queue)
{ {
mutex_lock(&queue->mutex);
vb2_queue_release(&queue->queue); vb2_queue_release(&queue->queue);
mutex_unlock(&queue->mutex);
} }
/* /*
...@@ -168,22 +153,14 @@ int uvcg_alloc_buffers(struct uvc_video_queue *queue, ...@@ -168,22 +153,14 @@ int uvcg_alloc_buffers(struct uvc_video_queue *queue,
{ {
int ret; int ret;
mutex_lock(&queue->mutex);
ret = vb2_reqbufs(&queue->queue, rb); ret = vb2_reqbufs(&queue->queue, rb);
mutex_unlock(&queue->mutex);
return ret ? ret : rb->count; return ret ? ret : rb->count;
} }
int uvcg_query_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf) int uvcg_query_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf)
{ {
int ret; return vb2_querybuf(&queue->queue, buf);
mutex_lock(&queue->mutex);
ret = vb2_querybuf(&queue->queue, buf);
mutex_unlock(&queue->mutex);
return ret;
} }
int uvcg_queue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf) int uvcg_queue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf)
...@@ -191,18 +168,14 @@ int uvcg_queue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf) ...@@ -191,18 +168,14 @@ int uvcg_queue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf)
unsigned long flags; unsigned long flags;
int ret; int ret;
mutex_lock(&queue->mutex);
ret = vb2_qbuf(&queue->queue, buf); ret = vb2_qbuf(&queue->queue, buf);
if (ret < 0) if (ret < 0)
goto done; return ret;
spin_lock_irqsave(&queue->irqlock, flags); spin_lock_irqsave(&queue->irqlock, flags);
ret = (queue->flags & UVC_QUEUE_PAUSED) != 0; ret = (queue->flags & UVC_QUEUE_PAUSED) != 0;
queue->flags &= ~UVC_QUEUE_PAUSED; queue->flags &= ~UVC_QUEUE_PAUSED;
spin_unlock_irqrestore(&queue->irqlock, flags); spin_unlock_irqrestore(&queue->irqlock, flags);
done:
mutex_unlock(&queue->mutex);
return ret; return ret;
} }
...@@ -213,13 +186,7 @@ int uvcg_queue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf) ...@@ -213,13 +186,7 @@ int uvcg_queue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf)
int uvcg_dequeue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf, int uvcg_dequeue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf,
int nonblocking) int nonblocking)
{ {
int ret; return vb2_dqbuf(&queue->queue, buf, nonblocking);
mutex_lock(&queue->mutex);
ret = vb2_dqbuf(&queue->queue, buf, nonblocking);
mutex_unlock(&queue->mutex);
return ret;
} }
/* /*
...@@ -231,24 +198,12 @@ int uvcg_dequeue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf, ...@@ -231,24 +198,12 @@ int uvcg_dequeue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf,
unsigned int uvcg_queue_poll(struct uvc_video_queue *queue, struct file *file, unsigned int uvcg_queue_poll(struct uvc_video_queue *queue, struct file *file,
poll_table *wait) poll_table *wait)
{ {
unsigned int ret; return vb2_poll(&queue->queue, file, wait);
mutex_lock(&queue->mutex);
ret = vb2_poll(&queue->queue, file, wait);
mutex_unlock(&queue->mutex);
return ret;
} }
int uvcg_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma) int uvcg_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma)
{ {
int ret; return vb2_mmap(&queue->queue, vma);
mutex_lock(&queue->mutex);
ret = vb2_mmap(&queue->queue, vma);
mutex_unlock(&queue->mutex);
return ret;
} }
#ifndef CONFIG_MMU #ifndef CONFIG_MMU
...@@ -260,12 +215,7 @@ int uvcg_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma) ...@@ -260,12 +215,7 @@ int uvcg_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma)
unsigned long uvcg_queue_get_unmapped_area(struct uvc_video_queue *queue, unsigned long uvcg_queue_get_unmapped_area(struct uvc_video_queue *queue,
unsigned long pgoff) unsigned long pgoff)
{ {
unsigned long ret; return vb2_get_unmapped_area(&queue->queue, 0, 0, pgoff, 0);
mutex_lock(&queue->mutex);
ret = vb2_get_unmapped_area(&queue->queue, 0, 0, pgoff, 0);
mutex_unlock(&queue->mutex);
return ret;
} }
#endif #endif
...@@ -327,18 +277,17 @@ int uvcg_queue_enable(struct uvc_video_queue *queue, int enable) ...@@ -327,18 +277,17 @@ int uvcg_queue_enable(struct uvc_video_queue *queue, int enable)
unsigned long flags; unsigned long flags;
int ret = 0; int ret = 0;
mutex_lock(&queue->mutex);
if (enable) { if (enable) {
ret = vb2_streamon(&queue->queue, queue->queue.type); ret = vb2_streamon(&queue->queue, queue->queue.type);
if (ret < 0) if (ret < 0)
goto done; return ret;
queue->sequence = 0; queue->sequence = 0;
queue->buf_used = 0; queue->buf_used = 0;
} else { } else {
ret = vb2_streamoff(&queue->queue, queue->queue.type); ret = vb2_streamoff(&queue->queue, queue->queue.type);
if (ret < 0) if (ret < 0)
goto done; return ret;
spin_lock_irqsave(&queue->irqlock, flags); spin_lock_irqsave(&queue->irqlock, flags);
INIT_LIST_HEAD(&queue->irqqueue); INIT_LIST_HEAD(&queue->irqqueue);
...@@ -353,8 +302,6 @@ int uvcg_queue_enable(struct uvc_video_queue *queue, int enable) ...@@ -353,8 +302,6 @@ int uvcg_queue_enable(struct uvc_video_queue *queue, int enable)
spin_unlock_irqrestore(&queue->irqlock, flags); spin_unlock_irqrestore(&queue->irqlock, flags);
} }
done:
mutex_unlock(&queue->mutex);
return ret; return ret;
} }
......
...@@ -41,7 +41,6 @@ struct uvc_buffer { ...@@ -41,7 +41,6 @@ struct uvc_buffer {
struct uvc_video_queue { struct uvc_video_queue {
struct vb2_queue queue; struct vb2_queue queue;
struct mutex mutex; /* Protects queue */
unsigned int flags; unsigned int flags;
__u32 sequence; __u32 sequence;
...@@ -57,7 +56,8 @@ static inline int uvc_queue_streaming(struct uvc_video_queue *queue) ...@@ -57,7 +56,8 @@ static inline int uvc_queue_streaming(struct uvc_video_queue *queue)
return vb2_is_streaming(&queue->queue); return vb2_is_streaming(&queue->queue);
} }
int uvcg_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type); int uvcg_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type,
struct mutex *lock);
void uvcg_free_buffers(struct uvc_video_queue *queue); void uvcg_free_buffers(struct uvc_video_queue *queue);
......
...@@ -14,7 +14,6 @@ ...@@ -14,7 +14,6 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/mutex.h>
#include <linux/videodev2.h> #include <linux/videodev2.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/wait.h> #include <linux/wait.h>
...@@ -311,8 +310,10 @@ uvc_v4l2_release(struct file *file) ...@@ -311,8 +310,10 @@ uvc_v4l2_release(struct file *file)
uvc_function_disconnect(uvc); uvc_function_disconnect(uvc);
mutex_lock(&video->mutex);
uvcg_video_enable(video, 0); uvcg_video_enable(video, 0);
uvcg_free_buffers(&video->queue); uvcg_free_buffers(&video->queue);
mutex_unlock(&video->mutex);
file->private_data = NULL; file->private_data = NULL;
v4l2_fh_del(&handle->vfh); v4l2_fh_del(&handle->vfh);
......
...@@ -390,7 +390,8 @@ int uvcg_video_init(struct uvc_video *video) ...@@ -390,7 +390,8 @@ int uvcg_video_init(struct uvc_video *video)
video->imagesize = 320 * 240 * 2; video->imagesize = 320 * 240 * 2;
/* Initialize the video buffers queue. */ /* Initialize the video buffers queue. */
uvcg_queue_init(&video->queue, V4L2_BUF_TYPE_VIDEO_OUTPUT); uvcg_queue_init(&video->queue, V4L2_BUF_TYPE_VIDEO_OUTPUT,
&video->mutex);
return 0; return 0;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment