]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
[media] uvc gadget: switch to v4l2 core locking
authorHans Verkuil <hans.verkuil@cisco.com>
Tue, 17 Feb 2015 08:44:06 +0000 (05:44 -0300)
committerMauro Carvalho Chehab <mchehab@osg.samsung.com>
Mon, 2 Mar 2015 20:05:23 +0000 (17:05 -0300)
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 f035eb4e976ef5a059e30bc91cfd310ff030a7d3 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: Hans Verkuil <hans.verkuil@cisco.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
drivers/usb/gadget/function/f_uvc.c
drivers/usb/gadget/function/uvc.h
drivers/usb/gadget/function/uvc_queue.c
drivers/usb/gadget/function/uvc_queue.h
drivers/usb/gadget/function/uvc_v4l2.c
drivers/usb/gadget/function/uvc_video.c

index 76891adfba7a414b87e5fd03252928e32492f7eb..3242bc684e2db47199d13faefede5df145828ca3 100644 (file)
@@ -447,6 +447,7 @@ uvc_register_video(struct uvc_device *uvc)
        video->ioctl_ops = &uvc_v4l2_ioctl_ops;
        video->release = video_device_release;
        video->vfl_dir = VFL_DIR_TX;
+       video->lock = &uvc->video.mutex;
        strlcpy(video->name, cdev->gadget->name, sizeof(video->name));
 
        uvc->vdev = video;
@@ -918,6 +919,7 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi)
        if (uvc == NULL)
                return ERR_PTR(-ENOMEM);
 
+       mutex_init(&uvc->video.mutex);
        uvc->state = UVC_STATE_DISCONNECTED;
        opts = fi_to_f_uvc_opts(fi);
 
index f67695cb28f8a8429987beffd8aaf44a3bd0303c..3390ecd1a1f30b7d10bf2b03fbb46500ed2dfab8 100644 (file)
@@ -115,6 +115,7 @@ struct uvc_video
        unsigned int width;
        unsigned int height;
        unsigned int imagesize;
+       struct mutex mutex;     /* protects frame parameters */
 
        /* Requests */
        unsigned int req_size;
index 8ea8b3b227b497108815118a9f38f297f81b6df3..d617c39a00527414ea2561c3332a7c508f7b7815 100644 (file)
@@ -104,29 +104,16 @@ static void uvc_buffer_queue(struct vb2_buffer *vb)
        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 = {
        .queue_setup = uvc_queue_setup,
        .buf_prepare = uvc_buffer_prepare,
        .buf_queue = uvc_buffer_queue,
-       .wait_prepare = uvc_wait_prepare,
-       .wait_finish = uvc_wait_finish,
+       .wait_prepare = vb2_ops_wait_prepare,
+       .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;
 
@@ -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.buf_struct_size = sizeof(struct uvc_buffer);
        queue->queue.ops = &uvc_queue_qops;
+       queue->queue.lock = lock;
        queue->queue.mem_ops = &vb2_vmalloc_memops;
        queue->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC
                                     | V4L2_BUF_FLAG_TSTAMP_SRC_EOF;
@@ -142,7 +130,6 @@ int uvcg_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type)
        if (ret)
                return ret;
 
-       mutex_init(&queue->mutex);
        spin_lock_init(&queue->irqlock);
        INIT_LIST_HEAD(&queue->irqqueue);
        queue->flags = 0;
@@ -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)
 {
-       mutex_lock(&queue->mutex);
        vb2_queue_release(&queue->queue);
-       mutex_unlock(&queue->mutex);
 }
 
 /*
@@ -168,22 +153,14 @@ int uvcg_alloc_buffers(struct uvc_video_queue *queue,
 {
        int ret;
 
-       mutex_lock(&queue->mutex);
        ret = vb2_reqbufs(&queue->queue, rb);
-       mutex_unlock(&queue->mutex);
 
        return ret ? ret : rb->count;
 }
 
 int uvcg_query_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf)
 {
-       int ret;
-
-       mutex_lock(&queue->mutex);
-       ret = vb2_querybuf(&queue->queue, buf);
-       mutex_unlock(&queue->mutex);
-
-       return ret;
+       return vb2_querybuf(&queue->queue, 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)
        unsigned long flags;
        int ret;
 
-       mutex_lock(&queue->mutex);
        ret = vb2_qbuf(&queue->queue, buf);
        if (ret < 0)
-               goto done;
+               return ret;
 
        spin_lock_irqsave(&queue->irqlock, flags);
        ret = (queue->flags & UVC_QUEUE_PAUSED) != 0;
        queue->flags &= ~UVC_QUEUE_PAUSED;
        spin_unlock_irqrestore(&queue->irqlock, flags);
-
-done:
-       mutex_unlock(&queue->mutex);
        return ret;
 }
 
@@ -213,13 +186,7 @@ done:
 int uvcg_dequeue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf,
                        int nonblocking)
 {
-       int ret;
-
-       mutex_lock(&queue->mutex);
-       ret = vb2_dqbuf(&queue->queue, buf, nonblocking);
-       mutex_unlock(&queue->mutex);
-
-       return ret;
+       return vb2_dqbuf(&queue->queue, buf, nonblocking);
 }
 
 /*
@@ -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,
                             poll_table *wait)
 {
-       unsigned int ret;
-
-       mutex_lock(&queue->mutex);
-       ret = vb2_poll(&queue->queue, file, wait);
-       mutex_unlock(&queue->mutex);
-
-       return ret;
+       return vb2_poll(&queue->queue, file, wait);
 }
 
 int uvcg_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma)
 {
-       int ret;
-
-       mutex_lock(&queue->mutex);
-       ret = vb2_mmap(&queue->queue, vma);
-       mutex_unlock(&queue->mutex);
-
-       return ret;
+       return vb2_mmap(&queue->queue, vma);
 }
 
 #ifndef CONFIG_MMU
@@ -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 pgoff)
 {
-       unsigned long ret;
-
-       mutex_lock(&queue->mutex);
-       ret = vb2_get_unmapped_area(&queue->queue, 0, 0, pgoff, 0);
-       mutex_unlock(&queue->mutex);
-       return ret;
+       return vb2_get_unmapped_area(&queue->queue, 0, 0, pgoff, 0);
 }
 #endif
 
@@ -327,18 +277,17 @@ int uvcg_queue_enable(struct uvc_video_queue *queue, int enable)
        unsigned long flags;
        int ret = 0;
 
-       mutex_lock(&queue->mutex);
        if (enable) {
                ret = vb2_streamon(&queue->queue, queue->queue.type);
                if (ret < 0)
-                       goto done;
+                       return ret;
 
                queue->sequence = 0;
                queue->buf_used = 0;
        } else {
                ret = vb2_streamoff(&queue->queue, queue->queue.type);
                if (ret < 0)
-                       goto done;
+                       return ret;
 
                spin_lock_irqsave(&queue->irqlock, flags);
                INIT_LIST_HEAD(&queue->irqqueue);
@@ -353,8 +302,6 @@ int uvcg_queue_enable(struct uvc_video_queue *queue, int enable)
                spin_unlock_irqrestore(&queue->irqlock, flags);
        }
 
-done:
-       mutex_unlock(&queue->mutex);
        return ret;
 }
 
index 03919c7249615adec90485ab42dd81f1fe5abd38..01ca9eab3481d4550f3d2a1fc99eafd547327a5c 100644 (file)
@@ -41,7 +41,6 @@ struct uvc_buffer {
 
 struct uvc_video_queue {
        struct vb2_queue queue;
-       struct mutex mutex;     /* Protects queue */
 
        unsigned int flags;
        __u32 sequence;
@@ -57,7 +56,8 @@ static inline int uvc_queue_streaming(struct uvc_video_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);
 
index 5aad7fededa589bdb7b143a9f6dfbfb65c81cedd..0bd696510cf872cc86d9eafd791658653ced66d3 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/device.h>
 #include <linux/errno.h>
 #include <linux/list.h>
-#include <linux/mutex.h>
 #include <linux/videodev2.h>
 #include <linux/vmalloc.h>
 #include <linux/wait.h>
@@ -311,8 +310,10 @@ uvc_v4l2_release(struct file *file)
 
        uvc_function_disconnect(uvc);
 
+       mutex_lock(&video->mutex);
        uvcg_video_enable(video, 0);
        uvcg_free_buffers(&video->queue);
+       mutex_unlock(&video->mutex);
 
        file->private_data = NULL;
        v4l2_fh_del(&handle->vfh);
index 9cb86bc1a9a5444b4ed7895489c2b0c5860bac37..8927358caf24b49e294d6f60a09a244d86da7250 100644 (file)
@@ -390,7 +390,8 @@ int uvcg_video_init(struct uvc_video *video)
        video->imagesize = 320 * 240 * 2;
 
        /* 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;
 }