|
@@ -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
|
|
@@ -23,10 +26,8 @@
|
|
|
#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);
|