summaryrefslogtreecommitdiff
path: root/drivers/media/video/vivi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/vivi.c')
-rw-r--r--drivers/media/video/vivi.c579
1 files changed, 331 insertions, 248 deletions
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index c49c39386bd0..2238a613d664 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -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,12 +26,12 @@
#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-ctrls.h>
+#include <media/v4l2-fh.h>
#include <media/v4l2-common.h>
#define VIVI_MODULE_NAME "vivi"
@@ -42,7 +45,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 +136,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;
};
@@ -162,13 +160,20 @@ static LIST_HEAD(vivi_devlist);
struct vivi_dev {
struct list_head vivi_devlist;
struct v4l2_device v4l2_dev;
+ struct v4l2_ctrl_handler ctrl_handler;
/* controls */
- int brightness;
- int contrast;
- int saturation;
- int hue;
- int volume;
+ struct v4l2_ctrl *brightness;
+ struct v4l2_ctrl *contrast;
+ struct v4l2_ctrl *saturation;
+ struct v4l2_ctrl *hue;
+ struct v4l2_ctrl *volume;
+ struct v4l2_ctrl *button;
+ struct v4l2_ctrl *boolean;
+ struct v4l2_ctrl *int32;
+ struct v4l2_ctrl *int64;
+ struct v4l2_ctrl *menu;
+ struct v4l2_ctrl *string;
spinlock_t slock;
struct mutex mutex;
@@ -181,6 +186,7 @@ struct vivi_dev {
/* Several counters */
unsigned ms;
unsigned long jiffies;
+ unsigned button_pressed;
int mv_count; /* Controls bars movement */
@@ -190,9 +196,10 @@ 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;
u8 bars[9][3];
u8 line[MAX_WIDTH * 4];
};
@@ -443,10 +450,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;
@@ -472,22 +479,38 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
dev->width, dev->height, dev->input);
gen_text(dev, vbuf, line++ * 16, 16, str);
+ mutex_lock(&dev->ctrl_handler.lock);
snprintf(str, sizeof(str), " brightness %3d, contrast %3d, saturation %3d, hue %d ",
- dev->brightness,
- dev->contrast,
- dev->saturation,
- dev->hue);
+ dev->brightness->cur.val,
+ dev->contrast->cur.val,
+ dev->saturation->cur.val,
+ dev->hue->cur.val);
gen_text(dev, vbuf, line++ * 16, 16, str);
- snprintf(str, sizeof(str), " volume %3d ", dev->volume);
+ snprintf(str, sizeof(str), " volume %3d ", dev->volume->cur.val);
gen_text(dev, vbuf, line++ * 16, 16, str);
+ snprintf(str, sizeof(str), " int32 %d, int64 %lld ",
+ dev->int32->cur.val,
+ dev->int64->cur.val64);
+ gen_text(dev, vbuf, line++ * 16, 16, str);
+ snprintf(str, sizeof(str), " boolean %d, menu %s, string \"%s\" ",
+ dev->boolean->cur.val,
+ dev->menu->qmenu[dev->menu->cur.val],
+ dev->string->cur.string);
+ mutex_unlock(&dev->ctrl_handler.lock);
+ gen_text(dev, vbuf, line++ * 16, 16, str);
+ if (dev->button_pressed) {
+ dev->button_pressed--;
+ snprintf(str, sizeof(str), " button pressed!");
+ gen_text(dev, vbuf, line++ * 16, 16, str);
+ }
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 +527,17 @@ static void vivi_thread_tick(struct vivi_dev *dev)
goto unlock;
}
- buf = list_entry(dma_q->active.next,
- struct vivi_buffer, vb.queue);
+ buf = list_entry(dma_q->active.next, struct vivi_buffer, list);
+ list_del(&buf->list);
- /* Nobody is waiting on this buffer, return */
- if (!waitqueue_active(&buf->vb.done))
- goto unlock;
-
- 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 +588,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 +605,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;
+
+ if (0 == *nbuffers)
+ *nbuffers = 32;
- *size = dev->width * dev->height * 2;
+ while (size * *nbuffers > vid_limit * 1024 * 1024)
+ (*nbuffers)--;
- if (0 == *count)
- *count = 32;
+ *nplanes = 1;
- while (*size * *count > vid_limit * 1024 * 1024)
- (*count)--;
+ sizes[0] = size;
- dprintk(dev, 1, "%s, count=%d, size=%d\n", __func__,
- *count, *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);
+
+ BUG_ON(NULL == dev->fmt);
- dprintk(dev, 1, "%s, state: %i\n", __func__, buf->vb.state);
+ /*
+ * 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.
+ */
- videobuf_vmalloc_free(&buf->vb);
- dprintk(dev, 1, "free_buffer: freed\n");
- buf->vb.state = VIDEOBUF_NEEDS_INIT;
+ 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;
+ }
- /* 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;
+ vb2_set_plane_payload(&buf->vb, 0, size);
+
+ 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;
+}
- free_buffer(vq, buf);
+static void vivi_lock(struct vb2_queue *vq)
+{
+ struct vivi_dev *dev = vb2_get_drv_priv(vq);
+ mutex_lock(&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 void vivi_unlock(struct vb2_queue *vq)
+{
+ struct vivi_dev *dev = vb2_get_drv_priv(vq);
+ mutex_unlock(&dev->mutex);
+}
+
+
+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 +840,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 +886,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)
@@ -938,80 +982,14 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
}
/* --- controls ---------------------------------------------- */
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
-{
- switch (qc->id) {
- case V4L2_CID_AUDIO_VOLUME:
- return v4l2_ctrl_query_fill(qc, 0, 255, 1, 200);
- case V4L2_CID_BRIGHTNESS:
- return v4l2_ctrl_query_fill(qc, 0, 255, 1, 127);
- case V4L2_CID_CONTRAST:
- return v4l2_ctrl_query_fill(qc, 0, 255, 1, 16);
- case V4L2_CID_SATURATION:
- return v4l2_ctrl_query_fill(qc, 0, 255, 1, 127);
- case V4L2_CID_HUE:
- return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
- }
- return -EINVAL;
-}
-static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
+static int vivi_s_ctrl(struct v4l2_ctrl *ctrl)
{
- struct vivi_dev *dev = video_drvdata(file);
+ struct vivi_dev *dev = container_of(ctrl->handler, struct vivi_dev, ctrl_handler);
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_VOLUME:
- ctrl->value = dev->volume;
- return 0;
- case V4L2_CID_BRIGHTNESS:
- ctrl->value = dev->brightness;
- return 0;
- case V4L2_CID_CONTRAST:
- ctrl->value = dev->contrast;
- return 0;
- case V4L2_CID_SATURATION:
- ctrl->value = dev->saturation;
- return 0;
- case V4L2_CID_HUE:
- ctrl->value = dev->hue;
- return 0;
- }
- return -EINVAL;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct vivi_dev *dev = video_drvdata(file);
- struct v4l2_queryctrl qc;
- int err;
-
- qc.id = ctrl->id;
- err = vidioc_queryctrl(file, priv, &qc);
- if (err < 0)
- return err;
- if (ctrl->value < qc.minimum || ctrl->value > qc.maximum)
- return -ERANGE;
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_VOLUME:
- dev->volume = ctrl->value;
- return 0;
- case V4L2_CID_BRIGHTNESS:
- dev->brightness = ctrl->value;
- return 0;
- case V4L2_CID_CONTRAST:
- dev->contrast = ctrl->value;
- return 0;
- case V4L2_CID_SATURATION:
- dev->saturation = ctrl->value;
- return 0;
- case V4L2_CID_HUE:
- dev->hue = ctrl->value;
- return 0;
- }
- return -EINVAL;
+ if (ctrl == dev->button)
+ dev->button_pressed = 30;
+ return 0;
}
/* ------------------------------------------------------------------
@@ -1023,21 +1001,19 @@ 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,11 +1021,12 @@ 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));
- return 0;
+ if (v4l2_fh_is_singular_file(file))
+ vb2_queue_release(&dev->vb_vidq);
+ return v4l2_fh_release(file);
}
static int vivi_mmap(struct file *file, struct vm_area_struct *vma)
@@ -1059,8 +1036,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,
@@ -1068,8 +1044,82 @@ static int vivi_mmap(struct file *file, struct vm_area_struct *vma)
return ret;
}
+static const struct v4l2_ctrl_ops vivi_ctrl_ops = {
+ .s_ctrl = vivi_s_ctrl,
+};
+
+#define VIVI_CID_CUSTOM_BASE (V4L2_CID_USER_BASE | 0xf000)
+
+static const struct v4l2_ctrl_config vivi_ctrl_button = {
+ .ops = &vivi_ctrl_ops,
+ .id = VIVI_CID_CUSTOM_BASE + 0,
+ .name = "Button",
+ .type = V4L2_CTRL_TYPE_BUTTON,
+};
+
+static const struct v4l2_ctrl_config vivi_ctrl_boolean = {
+ .ops = &vivi_ctrl_ops,
+ .id = VIVI_CID_CUSTOM_BASE + 1,
+ .name = "Boolean",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .min = 0,
+ .max = 1,
+ .step = 1,
+ .def = 1,
+};
+
+static const struct v4l2_ctrl_config vivi_ctrl_int32 = {
+ .ops = &vivi_ctrl_ops,
+ .id = VIVI_CID_CUSTOM_BASE + 2,
+ .name = "Integer 32 Bits",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0x80000000,
+ .max = 0x7fffffff,
+ .step = 1,
+};
+
+static const struct v4l2_ctrl_config vivi_ctrl_int64 = {
+ .ops = &vivi_ctrl_ops,
+ .id = VIVI_CID_CUSTOM_BASE + 3,
+ .name = "Integer 64 Bits",
+ .type = V4L2_CTRL_TYPE_INTEGER64,
+};
+
+static const char * const vivi_ctrl_menu_strings[] = {
+ "Menu Item 0 (Skipped)",
+ "Menu Item 1",
+ "Menu Item 2 (Skipped)",
+ "Menu Item 3",
+ "Menu Item 4",
+ "Menu Item 5 (Skipped)",
+ NULL,
+};
+
+static const struct v4l2_ctrl_config vivi_ctrl_menu = {
+ .ops = &vivi_ctrl_ops,
+ .id = VIVI_CID_CUSTOM_BASE + 4,
+ .name = "Menu",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .min = 1,
+ .max = 4,
+ .def = 3,
+ .menu_skip_mask = 0x04,
+ .qmenu = vivi_ctrl_menu_strings,
+};
+
+static const struct v4l2_ctrl_config vivi_ctrl_string = {
+ .ops = &vivi_ctrl_ops,
+ .id = VIVI_CID_CUSTOM_BASE + 5,
+ .name = "String",
+ .type = V4L2_CTRL_TYPE_STRING,
+ .min = 2,
+ .max = 4,
+ .step = 1,
+};
+
static const struct v4l2_file_operations vivi_fops = {
.owner = THIS_MODULE,
+ .open = v4l2_fh_open,
.release = vivi_close,
.read = vivi_read,
.poll = vivi_poll,
@@ -1093,9 +1143,6 @@ static const struct v4l2_ioctl_ops vivi_ioctl_ops = {
.vidioc_s_input = vidioc_s_input,
.vidioc_streamon = vidioc_streamon,
.vidioc_streamoff = vidioc_streamoff,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
};
static struct video_device vivi_template = {
@@ -1126,6 +1173,7 @@ static int vivi_release(void)
video_device_node_name(dev->vfd));
video_unregister_device(dev->vfd);
v4l2_device_unregister(&dev->v4l2_dev);
+ v4l2_ctrl_handler_free(&dev->ctrl_handler);
kfree(dev);
}
@@ -1136,6 +1184,8 @@ static int __init vivi_create_instance(int inst)
{
struct vivi_dev *dev;
struct video_device *vfd;
+ struct v4l2_ctrl_handler *hdl;
+ struct vb2_queue *q;
int ret;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
@@ -1151,20 +1201,46 @@ static int __init vivi_create_instance(int inst)
dev->fmt = &formats[0];
dev->width = 640;
dev->height = 480;
- dev->volume = 200;
- dev->brightness = 127;
- dev->contrast = 16;
- dev->saturation = 127;
- dev->hue = 0;
+ hdl = &dev->ctrl_handler;
+ v4l2_ctrl_handler_init(hdl, 11);
+ dev->volume = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
+ V4L2_CID_AUDIO_VOLUME, 0, 255, 1, 200);
+ dev->brightness = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, 0, 255, 1, 127);
+ dev->contrast = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
+ V4L2_CID_CONTRAST, 0, 255, 1, 16);
+ dev->saturation = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
+ V4L2_CID_SATURATION, 0, 255, 1, 127);
+ dev->hue = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
+ V4L2_CID_HUE, -128, 127, 1, 0);
+ dev->button = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_button, NULL);
+ dev->int32 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int32, NULL);
+ dev->int64 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int64, NULL);
+ dev->boolean = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_boolean, NULL);
+ dev->menu = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_menu, NULL);
+ dev->string = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_string, NULL);
+ if (hdl->error) {
+ ret = hdl->error;
+ goto unreg_dev;
+ }
+ dev->v4l2_dev.ctrl_handler = hdl;
/* 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 +1254,12 @@ static int __init vivi_create_instance(int inst)
*vfd = vivi_template;
vfd->debug = debug;
vfd->v4l2_dev = &dev->v4l2_dev;
+ set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
+
+ /*
+ * 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);
@@ -1200,6 +1282,7 @@ static int __init vivi_create_instance(int inst)
rel_vdev:
video_device_release(vfd);
unreg_dev:
+ v4l2_ctrl_handler_free(hdl);
v4l2_device_unregister(&dev->v4l2_dev);
free_dev:
kfree(dev);