[media] v4l: vivi: port to videobuf2
authorPawel Osciak <p.osciak@samsung.com>
Wed, 19 Jan 2011 15:02:29 +0000 (13:02 -0200)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Mon, 21 Mar 2011 23:31:48 +0000 (20:31 -0300)
Make vivi use videobuf2 in place of videobuf.

Signed-off-by: Pawel Osciak <p.osciak@samsung.com>
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
CC: Pawel Osciak <pawel@osciak.com>
Reviewed-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/video/Kconfig
drivers/media/video/vivi.c

index f86e407..d40a8fc 100644 (file)
@@ -549,7 +549,7 @@ config VIDEO_VIVI
        depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64
        depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE
        select FONT_8x16
-       select VIDEOBUF_VMALLOC
+       select VIDEOBUF2_VMALLOC
        default n
        ---help---
          Enables a virtual video driver. This device shows a color bar
index c49c393..9ed3831 100644 (file)
@@ -7,6 +7,9 @@
  *      John Sokol <sokol--a.t--videotechnology.com>
  *      http://v4l.videotechnology.com/
  *
+ *      Conversion to videobuf2 by Pawel Osciak & Marek Szyprowski
+ *      Copyright (c) 2010 Samsung Electronics
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the BSD Licence, GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the
 #include <linux/mutex.h>
 #include <linux/videodev2.h>
 #include <linux/kthread.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
 #include <linux/freezer.h>
-#endif
-#include <media/videobuf-vmalloc.h>
+#include <media/videobuf2-vmalloc.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-common.h>
@@ -42,7 +43,7 @@
 #define MAX_HEIGHT 1200
 
 #define VIVI_MAJOR_VERSION 0
-#define VIVI_MINOR_VERSION 7
+#define VIVI_MINOR_VERSION 8
 #define VIVI_RELEASE 0
 #define VIVI_VERSION \
        KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE)
@@ -133,16 +134,11 @@ static struct vivi_fmt *get_format(struct v4l2_format *f)
        return &formats[k];
 }
 
-struct sg_to_addr {
-       int pos;
-       struct scatterlist *sg;
-};
-
 /* buffer for one video frame */
 struct vivi_buffer {
        /* common v4l buffer stuff -- must be first */
-       struct videobuf_buffer vb;
-
+       struct vb2_buffer       vb;
+       struct list_head        list;
        struct vivi_fmt        *fmt;
 };
 
@@ -190,9 +186,11 @@ struct vivi_dev {
        /* video capture */
        struct vivi_fmt            *fmt;
        unsigned int               width, height;
-       struct videobuf_queue      vb_vidq;
+       struct vb2_queue           vb_vidq;
+       enum v4l2_field            field;
+       unsigned int               field_count;
 
-       unsigned long              generating;
+       unsigned int               open_count;
        u8                         bars[9][3];
        u8                         line[MAX_WIDTH * 4];
 };
@@ -443,10 +441,10 @@ static void gen_text(struct vivi_dev *dev, char *basep,
 
 static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
 {
-       int hmax = buf->vb.height;
-       int wmax = buf->vb.width;
+       int wmax = dev->width;
+       int hmax = dev->height;
        struct timeval ts;
-       void *vbuf = videobuf_to_vmalloc(&buf->vb);
+       void *vbuf = vb2_plane_vaddr(&buf->vb, 0);
        unsigned ms;
        char str[100];
        int h, line = 1;
@@ -483,11 +481,11 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
 
        dev->mv_count += 2;
 
-       /* Advice that buffer was filled */
-       buf->vb.field_count++;
+       buf->vb.v4l2_buf.field = dev->field;
+       dev->field_count++;
+       buf->vb.v4l2_buf.sequence = dev->field_count >> 1;
        do_gettimeofday(&ts);
-       buf->vb.ts = ts;
-       buf->vb.state = VIDEOBUF_DONE;
+       buf->vb.v4l2_buf.timestamp = ts;
 }
 
 static void vivi_thread_tick(struct vivi_dev *dev)
@@ -504,23 +502,17 @@ static void vivi_thread_tick(struct vivi_dev *dev)
                goto unlock;
        }
 
-       buf = list_entry(dma_q->active.next,
-                        struct vivi_buffer, vb.queue);
-
-       /* Nobody is waiting on this buffer, return */
-       if (!waitqueue_active(&buf->vb.done))
-               goto unlock;
+       buf = list_entry(dma_q->active.next, struct vivi_buffer, list);
+       list_del(&buf->list);
 
-       list_del(&buf->vb.queue);
-
-       do_gettimeofday(&buf->vb.ts);
+       do_gettimeofday(&buf->vb.v4l2_buf.timestamp);
 
        /* Fill buffer */
        vivi_fillbuff(dev, buf);
        dprintk(dev, 1, "filled buffer %p\n", buf);
 
-       wake_up(&buf->vb.done);
-       dprintk(dev, 2, "[%p/%d] wakeup\n", buf, buf->vb. i);
+       vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
+       dprintk(dev, 2, "[%p/%d] done\n", buf, buf->vb.v4l2_buf.index);
 unlock:
        spin_unlock_irqrestore(&dev->slock, flags);
 }
@@ -571,17 +563,12 @@ static int vivi_thread(void *data)
        return 0;
 }
 
-static void vivi_start_generating(struct file *file)
+static int vivi_start_generating(struct vivi_dev *dev)
 {
-       struct vivi_dev *dev = video_drvdata(file);
        struct vivi_dmaqueue *dma_q = &dev->vidq;
 
        dprintk(dev, 1, "%s\n", __func__);
 
-       if (test_and_set_bit(0, &dev->generating))
-               return;
-       file->private_data = dev;
-
        /* Resets frame counters */
        dev->ms = 0;
        dev->mv_count = 0;
@@ -593,146 +580,200 @@ static void vivi_start_generating(struct file *file)
 
        if (IS_ERR(dma_q->kthread)) {
                v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
-               clear_bit(0, &dev->generating);
-               return;
+               return PTR_ERR(dma_q->kthread);
        }
        /* Wakes thread */
        wake_up_interruptible(&dma_q->wq);
 
        dprintk(dev, 1, "returning from %s\n", __func__);
+       return 0;
 }
 
-static void vivi_stop_generating(struct file *file)
+static void vivi_stop_generating(struct vivi_dev *dev)
 {
-       struct vivi_dev *dev = video_drvdata(file);
        struct vivi_dmaqueue *dma_q = &dev->vidq;
 
        dprintk(dev, 1, "%s\n", __func__);
 
-       if (!file->private_data)
-               return;
-       if (!test_and_clear_bit(0, &dev->generating))
-               return;
-
        /* shutdown control thread */
        if (dma_q->kthread) {
                kthread_stop(dma_q->kthread);
                dma_q->kthread = NULL;
        }
-       videobuf_stop(&dev->vb_vidq);
-       videobuf_mmap_free(&dev->vb_vidq);
-}
 
-static int vivi_is_generating(struct vivi_dev *dev)
-{
-       return test_bit(0, &dev->generating);
+       /*
+        * Typical driver might need to wait here until dma engine stops.
+        * In this case we can abort imiedetly, so it's just a noop.
+        */
+
+       /* Release all active buffers */
+       while (!list_empty(&dma_q->active)) {
+               struct vivi_buffer *buf;
+               buf = list_entry(dma_q->active.next, struct vivi_buffer, list);
+               list_del(&buf->list);
+               vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+               dprintk(dev, 2, "[%p/%d] done\n", buf, buf->vb.v4l2_buf.index);
+       }
 }
-
 /* ------------------------------------------------------------------
        Videobuf operations
    ------------------------------------------------------------------*/
-static int
-buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
+static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
+                               unsigned int *nplanes, unsigned long sizes[],
+                               void *alloc_ctxs[])
 {
-       struct vivi_dev *dev = vq->priv_data;
+       struct vivi_dev *dev = vb2_get_drv_priv(vq);
+       unsigned long size;
+
+       size = dev->width * dev->height * 2;
 
-       *size = dev->width * dev->height * 2;
+       if (0 == *nbuffers)
+               *nbuffers = 32;
 
-       if (0 == *count)
-               *count = 32;
+       while (size * *nbuffers > vid_limit * 1024 * 1024)
+               (*nbuffers)--;
 
-       while (*size * *count > vid_limit * 1024 * 1024)
-               (*count)--;
+       *nplanes = 1;
 
-       dprintk(dev, 1, "%s, count=%d, size=%d\n", __func__,
-               *count, *size);
+       sizes[0] = size;
+
+       /*
+        * videobuf2-vmalloc allocator is context-less so no need to set
+        * alloc_ctxs array.
+        */
+
+       dprintk(dev, 1, "%s, count=%d, size=%ld\n", __func__,
+               *nbuffers, size);
 
        return 0;
 }
 
-static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf)
+static int buffer_init(struct vb2_buffer *vb)
 {
-       struct vivi_dev *dev = vq->priv_data;
+       struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
 
-       dprintk(dev, 1, "%s, state: %i\n", __func__, buf->vb.state);
+       BUG_ON(NULL == dev->fmt);
 
-       videobuf_vmalloc_free(&buf->vb);
-       dprintk(dev, 1, "free_buffer: freed\n");
-       buf->vb.state = VIDEOBUF_NEEDS_INIT;
+       /*
+        * This callback is called once per buffer, after its allocation.
+        *
+        * Vivi does not allow changing format during streaming, but it is
+        * possible to do so when streaming is paused (i.e. in streamoff state).
+        * Buffers however are not freed when going into streamoff and so
+        * buffer size verification has to be done in buffer_prepare, on each
+        * qbuf.
+        * It would be best to move verification code here to buf_init and
+        * s_fmt though.
+        */
+
+       return 0;
 }
 
-static int
-buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
-                                               enum v4l2_field field)
+static int buffer_prepare(struct vb2_buffer *vb)
 {
-       struct vivi_dev *dev = vq->priv_data;
+       struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
        struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
-       int rc;
+       unsigned long size;
 
-       dprintk(dev, 1, "%s, field=%d\n", __func__, field);
+       dprintk(dev, 1, "%s, field=%d\n", __func__, vb->v4l2_buf.field);
 
        BUG_ON(NULL == dev->fmt);
 
+       /*
+        * Theses properties only change when queue is idle, see s_fmt.
+        * The below checks should not be performed here, on each
+        * buffer_prepare (i.e. on each qbuf). Most of the code in this function
+        * should thus be moved to buffer_init and s_fmt.
+        */
        if (dev->width  < 48 || dev->width  > MAX_WIDTH ||
            dev->height < 32 || dev->height > MAX_HEIGHT)
                return -EINVAL;
 
-       buf->vb.size = dev->width * dev->height * 2;
-       if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
+       size = dev->width * dev->height * 2;
+       if (vb2_plane_size(vb, 0) < size) {
+               dprintk(dev, 1, "%s data will not fit into plane (%lu < %lu)\n",
+                               __func__, vb2_plane_size(vb, 0), size);
                return -EINVAL;
+       }
+
+       vb2_set_plane_payload(&buf->vb, 0, size);
 
-       /* These properties only change when queue is idle, see s_fmt */
-       buf->fmt       = dev->fmt;
-       buf->vb.width  = dev->width;
-       buf->vb.height = dev->height;
-       buf->vb.field  = field;
+       buf->fmt = dev->fmt;
 
        precalculate_bars(dev);
        precalculate_line(dev);
 
-       if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
-               rc = videobuf_iolock(vq, &buf->vb, NULL);
-               if (rc < 0)
-                       goto fail;
-       }
+       return 0;
+}
 
-       buf->vb.state = VIDEOBUF_PREPARED;
+static int buffer_finish(struct vb2_buffer *vb)
+{
+       struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+       dprintk(dev, 1, "%s\n", __func__);
        return 0;
+}
+
+static void buffer_cleanup(struct vb2_buffer *vb)
+{
+       struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+       dprintk(dev, 1, "%s\n", __func__);
 
-fail:
-       free_buffer(vq, buf);
-       return rc;
 }
 
-static void
-buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+static void buffer_queue(struct vb2_buffer *vb)
 {
-       struct vivi_dev *dev = vq->priv_data;
+       struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
        struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
        struct vivi_dmaqueue *vidq = &dev->vidq;
+       unsigned long flags = 0;
 
        dprintk(dev, 1, "%s\n", __func__);
 
-       buf->vb.state = VIDEOBUF_QUEUED;
-       list_add_tail(&buf->vb.queue, &vidq->active);
+       spin_lock_irqsave(&dev->slock, flags);
+       list_add_tail(&buf->list, &vidq->active);
+       spin_unlock_irqrestore(&dev->slock, flags);
 }
 
-static void buffer_release(struct videobuf_queue *vq,
-                          struct videobuf_buffer *vb)
+static int start_streaming(struct vb2_queue *vq)
 {
-       struct vivi_dev *dev = vq->priv_data;
-       struct vivi_buffer *buf  = container_of(vb, struct vivi_buffer, vb);
+       struct vivi_dev *dev = vb2_get_drv_priv(vq);
+       dprintk(dev, 1, "%s\n", __func__);
+       return vivi_start_generating(dev);
+}
 
+/* abort streaming and wait for last buffer */
+static int stop_streaming(struct vb2_queue *vq)
+{
+       struct vivi_dev *dev = vb2_get_drv_priv(vq);
        dprintk(dev, 1, "%s\n", __func__);
+       vivi_stop_generating(dev);
+       return 0;
+}
+
+static void vivi_lock(struct vb2_queue *vq)
+{
+       struct vivi_dev *dev = vb2_get_drv_priv(vq);
+       mutex_lock(&dev->mutex);
+}
 
-       free_buffer(vq, buf);
+static void vivi_unlock(struct vb2_queue *vq)
+{
+       struct vivi_dev *dev = vb2_get_drv_priv(vq);
+       mutex_unlock(&dev->mutex);
 }
 
-static struct videobuf_queue_ops vivi_video_qops = {
-       .buf_setup      = buffer_setup,
-       .buf_prepare    = buffer_prepare,
-       .buf_queue      = buffer_queue,
-       .buf_release    = buffer_release,
+
+static struct vb2_ops vivi_video_qops = {
+       .queue_setup            = queue_setup,
+       .buf_init               = buffer_init,
+       .buf_prepare            = buffer_prepare,
+       .buf_finish             = buffer_finish,
+       .buf_cleanup            = buffer_cleanup,
+       .buf_queue              = buffer_queue,
+       .start_streaming        = start_streaming,
+       .stop_streaming         = stop_streaming,
+       .wait_prepare           = vivi_unlock,
+       .wait_finish            = vivi_lock,
 };
 
 /* ------------------------------------------------------------------
@@ -774,7 +815,7 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
 
        f->fmt.pix.width        = dev->width;
        f->fmt.pix.height       = dev->height;
-       f->fmt.pix.field        = dev->vb_vidq.field;
+       f->fmt.pix.field        = dev->field;
        f->fmt.pix.pixelformat  = dev->fmt->fourcc;
        f->fmt.pix.bytesperline =
                (f->fmt.pix.width * dev->fmt->depth) >> 3;
@@ -820,82 +861,60 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
                                        struct v4l2_format *f)
 {
        struct vivi_dev *dev = video_drvdata(file);
+       struct vb2_queue *q = &dev->vb_vidq;
 
        int ret = vidioc_try_fmt_vid_cap(file, priv, f);
        if (ret < 0)
                return ret;
 
-       if (vivi_is_generating(dev)) {
+       if (vb2_is_streaming(q)) {
                dprintk(dev, 1, "%s device busy\n", __func__);
-               ret = -EBUSY;
-               goto out;
+               return -EBUSY;
        }
 
        dev->fmt = get_format(f);
        dev->width = f->fmt.pix.width;
        dev->height = f->fmt.pix.height;
-       dev->vb_vidq.field = f->fmt.pix.field;
-       ret = 0;
-out:
-       return ret;
+       dev->field = f->fmt.pix.field;
+
+       return 0;
 }
 
 static int vidioc_reqbufs(struct file *file, void *priv,
                          struct v4l2_requestbuffers *p)
 {
        struct vivi_dev *dev = video_drvdata(file);
-
-       return videobuf_reqbufs(&dev->vb_vidq, p);
+       return vb2_reqbufs(&dev->vb_vidq, p);
 }
 
 static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
 {
        struct vivi_dev *dev = video_drvdata(file);
-
-       return videobuf_querybuf(&dev->vb_vidq, p);
+       return vb2_querybuf(&dev->vb_vidq, p);
 }
 
 static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
 {
        struct vivi_dev *dev = video_drvdata(file);
-
-       return videobuf_qbuf(&dev->vb_vidq, p);
+       return vb2_qbuf(&dev->vb_vidq, p);
 }
 
 static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
 {
        struct vivi_dev *dev = video_drvdata(file);
-
-       return videobuf_dqbuf(&dev->vb_vidq, p,
-                               file->f_flags & O_NONBLOCK);
+       return vb2_dqbuf(&dev->vb_vidq, p, file->f_flags & O_NONBLOCK);
 }
 
 static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
 {
        struct vivi_dev *dev = video_drvdata(file);
-       int ret;
-
-       if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-       ret = videobuf_streamon(&dev->vb_vidq);
-       if (ret)
-               return ret;
-
-       vivi_start_generating(file);
-       return 0;
+       return vb2_streamon(&dev->vb_vidq, i);
 }
 
 static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
 {
        struct vivi_dev *dev = video_drvdata(file);
-       int ret;
-
-       if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-       ret = videobuf_streamoff(&dev->vb_vidq);
-       if (!ret)
-               vivi_stop_generating(file);
-       return ret;
+       return vb2_streamoff(&dev->vb_vidq, i);
 }
 
 static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i)
@@ -1018,26 +1037,33 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
        File operations for the device
    ------------------------------------------------------------------*/
 
+static int vivi_open(struct file *file)
+{
+       struct vivi_dev *dev = video_drvdata(file);
+
+       dprintk(dev, 1, "%s, %p\n", __func__, file);
+       dev->open_count++;
+       return 0;
+}
+
 static ssize_t
 vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
 {
        struct vivi_dev *dev = video_drvdata(file);
 
-       vivi_start_generating(file);
-       return videobuf_read_stream(&dev->vb_vidq, data, count, ppos, 0,
-                                       file->f_flags & O_NONBLOCK);
+       dprintk(dev, 1, "read called\n");
+       return vb2_read(&dev->vb_vidq, data, count, ppos,
+                      file->f_flags & O_NONBLOCK);
 }
 
 static unsigned int
 vivi_poll(struct file *file, struct poll_table_struct *wait)
 {
        struct vivi_dev *dev = video_drvdata(file);
-       struct videobuf_queue *q = &dev->vb_vidq;
+       struct vb2_queue *q = &dev->vb_vidq;
 
        dprintk(dev, 1, "%s\n", __func__);
-
-       vivi_start_generating(file);
-       return videobuf_poll_stream(file, q, wait);
+       return vb2_poll(q, file, wait);
 }
 
 static int vivi_close(struct file *file)
@@ -1045,10 +1071,11 @@ static int vivi_close(struct file *file)
        struct video_device  *vdev = video_devdata(file);
        struct vivi_dev *dev = video_drvdata(file);
 
-       vivi_stop_generating(file);
+       dprintk(dev, 1, "close called (dev=%s), file %p\n",
+               video_device_node_name(vdev), file);
 
-       dprintk(dev, 1, "close called (dev=%s)\n",
-               video_device_node_name(vdev));
+       if (--dev->open_count == 0)
+               vb2_queue_release(&dev->vb_vidq);
        return 0;
 }
 
@@ -1059,8 +1086,7 @@ static int vivi_mmap(struct file *file, struct vm_area_struct *vma)
 
        dprintk(dev, 1, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
 
-       ret = videobuf_mmap_mapper(&dev->vb_vidq, vma);
-
+       ret = vb2_mmap(&dev->vb_vidq, vma);
        dprintk(dev, 1, "vma start=0x%08lx, size=%ld, ret=%d\n",
                (unsigned long)vma->vm_start,
                (unsigned long)vma->vm_end - (unsigned long)vma->vm_start,
@@ -1070,6 +1096,7 @@ static int vivi_mmap(struct file *file, struct vm_area_struct *vma)
 
 static const struct v4l2_file_operations vivi_fops = {
        .owner          = THIS_MODULE,
+       .open           = vivi_open,
        .release        = vivi_close,
        .read           = vivi_read,
        .poll           = vivi_poll,
@@ -1136,6 +1163,7 @@ static int __init vivi_create_instance(int inst)
 {
        struct vivi_dev *dev;
        struct video_device *vfd;
+       struct vb2_queue *q;
        int ret;
 
        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
@@ -1159,12 +1187,20 @@ static int __init vivi_create_instance(int inst)
 
        /* initialize locks */
        spin_lock_init(&dev->slock);
-       mutex_init(&dev->mutex);
 
-       videobuf_queue_vmalloc_init(&dev->vb_vidq, &vivi_video_qops,
-                       NULL, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
-                       V4L2_FIELD_INTERLACED,
-                       sizeof(struct vivi_buffer), dev, &dev->mutex);
+       /* initialize queue */
+       q = &dev->vb_vidq;
+       memset(q, 0, sizeof(dev->vb_vidq));
+       q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
+       q->drv_priv = dev;
+       q->buf_struct_size = sizeof(struct vivi_buffer);
+       q->ops = &vivi_video_qops;
+       q->mem_ops = &vb2_vmalloc_memops;
+
+       vb2_queue_init(q);
+
+       mutex_init(&dev->mutex);
 
        /* init video dma queues */
        INIT_LIST_HEAD(&dev->vidq.active);
@@ -1178,6 +1214,11 @@ static int __init vivi_create_instance(int inst)
        *vfd = vivi_template;
        vfd->debug = debug;
        vfd->v4l2_dev = &dev->v4l2_dev;
+
+       /*
+        * Provide a mutex to v4l2 core. It will be used to protect
+        * all fops and v4l2 ioctls.
+        */
        vfd->lock = &dev->mutex;
 
        ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);