Commit e007a325 authored by Pawel Osciak's avatar Pawel Osciak Committed by Mauro Carvalho Chehab

[media] v4l: vivi: port to videobuf2

Make vivi use videobuf2 in place of videobuf.
Signed-off-by: default avatarPawel Osciak <p.osciak@samsung.com>
Signed-off-by: default avatarMarek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: default avatarKyungmin Park <kyungmin.park@samsung.com>
CC: Pawel Osciak <pawel@osciak.com>
Reviewed-by: default avatarHans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent dbf05b27
...@@ -549,7 +549,7 @@ config VIDEO_VIVI ...@@ -549,7 +549,7 @@ config VIDEO_VIVI
depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64 depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64
depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE
select FONT_8x16 select FONT_8x16
select VIDEOBUF_VMALLOC select VIDEOBUF2_VMALLOC
default n default n
---help--- ---help---
Enables a virtual video driver. This device shows a color bar Enables a virtual video driver. This device shows a color bar
......
...@@ -7,6 +7,9 @@ ...@@ -7,6 +7,9 @@
* John Sokol <sokol--a.t--videotechnology.com> * John Sokol <sokol--a.t--videotechnology.com>
* http://v4l.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 * This program is free software; you can redistribute it and/or modify
* it under the terms of the BSD Licence, GNU General Public License * it under the terms of the BSD Licence, GNU General Public License
* as published by the Free Software Foundation; either version 2 of the * as published by the Free Software Foundation; either version 2 of the
...@@ -23,10 +26,8 @@ ...@@ -23,10 +26,8 @@
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/videodev2.h> #include <linux/videodev2.h>
#include <linux/kthread.h> #include <linux/kthread.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
#include <linux/freezer.h> #include <linux/freezer.h>
#endif #include <media/videobuf2-vmalloc.h>
#include <media/videobuf-vmalloc.h>
#include <media/v4l2-device.h> #include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h> #include <media/v4l2-ioctl.h>
#include <media/v4l2-common.h> #include <media/v4l2-common.h>
...@@ -42,7 +43,7 @@ ...@@ -42,7 +43,7 @@
#define MAX_HEIGHT 1200 #define MAX_HEIGHT 1200
#define VIVI_MAJOR_VERSION 0 #define VIVI_MAJOR_VERSION 0
#define VIVI_MINOR_VERSION 7 #define VIVI_MINOR_VERSION 8
#define VIVI_RELEASE 0 #define VIVI_RELEASE 0
#define VIVI_VERSION \ #define VIVI_VERSION \
KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE) KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE)
...@@ -133,16 +134,11 @@ static struct vivi_fmt *get_format(struct v4l2_format *f) ...@@ -133,16 +134,11 @@ static struct vivi_fmt *get_format(struct v4l2_format *f)
return &formats[k]; return &formats[k];
} }
struct sg_to_addr {
int pos;
struct scatterlist *sg;
};
/* buffer for one video frame */ /* buffer for one video frame */
struct vivi_buffer { struct vivi_buffer {
/* common v4l buffer stuff -- must be first */ /* common v4l buffer stuff -- must be first */
struct videobuf_buffer vb; struct vb2_buffer vb;
struct list_head list;
struct vivi_fmt *fmt; struct vivi_fmt *fmt;
}; };
...@@ -190,9 +186,11 @@ struct vivi_dev { ...@@ -190,9 +186,11 @@ struct vivi_dev {
/* video capture */ /* video capture */
struct vivi_fmt *fmt; struct vivi_fmt *fmt;
unsigned int width, height; 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 bars[9][3];
u8 line[MAX_WIDTH * 4]; u8 line[MAX_WIDTH * 4];
}; };
...@@ -443,10 +441,10 @@ static void gen_text(struct vivi_dev *dev, char *basep, ...@@ -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) static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
{ {
int hmax = buf->vb.height; int wmax = dev->width;
int wmax = buf->vb.width; int hmax = dev->height;
struct timeval ts; struct timeval ts;
void *vbuf = videobuf_to_vmalloc(&buf->vb); void *vbuf = vb2_plane_vaddr(&buf->vb, 0);
unsigned ms; unsigned ms;
char str[100]; char str[100];
int h, line = 1; int h, line = 1;
...@@ -483,11 +481,11 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf) ...@@ -483,11 +481,11 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
dev->mv_count += 2; dev->mv_count += 2;
/* Advice that buffer was filled */ buf->vb.v4l2_buf.field = dev->field;
buf->vb.field_count++; dev->field_count++;
buf->vb.v4l2_buf.sequence = dev->field_count >> 1;
do_gettimeofday(&ts); do_gettimeofday(&ts);
buf->vb.ts = ts; buf->vb.v4l2_buf.timestamp = ts;
buf->vb.state = VIDEOBUF_DONE;
} }
static void vivi_thread_tick(struct vivi_dev *dev) static void vivi_thread_tick(struct vivi_dev *dev)
...@@ -504,23 +502,17 @@ static void vivi_thread_tick(struct vivi_dev *dev) ...@@ -504,23 +502,17 @@ static void vivi_thread_tick(struct vivi_dev *dev)
goto unlock; goto unlock;
} }
buf = list_entry(dma_q->active.next, buf = list_entry(dma_q->active.next, struct vivi_buffer, list);
struct vivi_buffer, vb.queue); 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.v4l2_buf.timestamp);
do_gettimeofday(&buf->vb.ts);
/* Fill buffer */ /* Fill buffer */
vivi_fillbuff(dev, buf); vivi_fillbuff(dev, buf);
dprintk(dev, 1, "filled buffer %p\n", buf); dprintk(dev, 1, "filled buffer %p\n", buf);
wake_up(&buf->vb.done); vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
dprintk(dev, 2, "[%p/%d] wakeup\n", buf, buf->vb. i); dprintk(dev, 2, "[%p/%d] done\n", buf, buf->vb.v4l2_buf.index);
unlock: unlock:
spin_unlock_irqrestore(&dev->slock, flags); spin_unlock_irqrestore(&dev->slock, flags);
} }
...@@ -571,17 +563,12 @@ static int vivi_thread(void *data) ...@@ -571,17 +563,12 @@ static int vivi_thread(void *data)
return 0; 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; struct vivi_dmaqueue *dma_q = &dev->vidq;
dprintk(dev, 1, "%s\n", __func__); dprintk(dev, 1, "%s\n", __func__);
if (test_and_set_bit(0, &dev->generating))
return;
file->private_data = dev;
/* Resets frame counters */ /* Resets frame counters */
dev->ms = 0; dev->ms = 0;
dev->mv_count = 0; dev->mv_count = 0;
...@@ -593,146 +580,200 @@ static void vivi_start_generating(struct file *file) ...@@ -593,146 +580,200 @@ static void vivi_start_generating(struct file *file)
if (IS_ERR(dma_q->kthread)) { if (IS_ERR(dma_q->kthread)) {
v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n"); v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
clear_bit(0, &dev->generating); return PTR_ERR(dma_q->kthread);
return;
} }
/* Wakes thread */ /* Wakes thread */
wake_up_interruptible(&dma_q->wq); wake_up_interruptible(&dma_q->wq);
dprintk(dev, 1, "returning from %s\n", __func__); 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; struct vivi_dmaqueue *dma_q = &dev->vidq;
dprintk(dev, 1, "%s\n", __func__); dprintk(dev, 1, "%s\n", __func__);
if (!file->private_data)
return;
if (!test_and_clear_bit(0, &dev->generating))
return;
/* shutdown control thread */ /* shutdown control thread */
if (dma_q->kthread) { if (dma_q->kthread) {
kthread_stop(dma_q->kthread); kthread_stop(dma_q->kthread);
dma_q->kthread = NULL; dma_q->kthread = NULL;
} }
videobuf_stop(&dev->vb_vidq);
videobuf_mmap_free(&dev->vb_vidq);
}
static int vivi_is_generating(struct vivi_dev *dev) /*
{ * Typical driver might need to wait here until dma engine stops.
return test_bit(0, &dev->generating); * 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 Videobuf operations
------------------------------------------------------------------*/ ------------------------------------------------------------------*/
static int static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) 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) while (size * *nbuffers > vid_limit * 1024 * 1024)
*count = 32; (*nbuffers)--;
while (*size * *count > vid_limit * 1024 * 1024) *nplanes = 1;
(*count)--;
dprintk(dev, 1, "%s, count=%d, size=%d\n", __func__, sizes[0] = size;
*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; 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"); * This callback is called once per buffer, after its allocation.
buf->vb.state = VIDEOBUF_NEEDS_INIT; *
* 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 static int buffer_prepare(struct vb2_buffer *vb)
buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
enum v4l2_field field)
{ {
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_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); 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 || if (dev->width < 48 || dev->width > MAX_WIDTH ||
dev->height < 32 || dev->height > MAX_HEIGHT) dev->height < 32 || dev->height > MAX_HEIGHT)
return -EINVAL; return -EINVAL;
buf->vb.size = dev->width * dev->height * 2; size = dev->width * dev->height * 2;
if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) 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; 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->fmt = dev->fmt;
buf->vb.width = dev->width;
buf->vb.height = dev->height;
buf->vb.field = field;
precalculate_bars(dev); precalculate_bars(dev);
precalculate_line(dev); precalculate_line(dev);
if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { return 0;
rc = videobuf_iolock(vq, &buf->vb, NULL); }
if (rc < 0)
goto fail;
}
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; 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 static void buffer_queue(struct vb2_buffer *vb)
buffer_queue(struct videobuf_queue *vq, struct videobuf_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_buffer *buf = container_of(vb, struct vivi_buffer, vb);
struct vivi_dmaqueue *vidq = &dev->vidq; struct vivi_dmaqueue *vidq = &dev->vidq;
unsigned long flags = 0;
dprintk(dev, 1, "%s\n", __func__); dprintk(dev, 1, "%s\n", __func__);
buf->vb.state = VIDEOBUF_QUEUED; spin_lock_irqsave(&dev->slock, flags);
list_add_tail(&buf->vb.queue, &vidq->active); list_add_tail(&buf->list, &vidq->active);
spin_unlock_irqrestore(&dev->slock, flags);
} }
static void buffer_release(struct videobuf_queue *vq, static int start_streaming(struct vb2_queue *vq)
struct videobuf_buffer *vb)
{ {
struct vivi_dev *dev = vq->priv_data; struct vivi_dev *dev = vb2_get_drv_priv(vq);
struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); 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__); 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, static struct vb2_ops vivi_video_qops = {
.buf_prepare = buffer_prepare, .queue_setup = queue_setup,
.buf_queue = buffer_queue, .buf_init = buffer_init,
.buf_release = buffer_release, .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, ...@@ -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.width = dev->width;
f->fmt.pix.height = dev->height; 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.pixelformat = dev->fmt->fourcc;
f->fmt.pix.bytesperline = f->fmt.pix.bytesperline =
(f->fmt.pix.width * dev->fmt->depth) >> 3; (f->fmt.pix.width * dev->fmt->depth) >> 3;
...@@ -820,82 +861,60 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, ...@@ -820,82 +861,60 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f) struct v4l2_format *f)
{ {
struct vivi_dev *dev = video_drvdata(file); struct vivi_dev *dev = video_drvdata(file);
struct vb2_queue *q = &dev->vb_vidq;
int ret = vidioc_try_fmt_vid_cap(file, priv, f); int ret = vidioc_try_fmt_vid_cap(file, priv, f);
if (ret < 0) if (ret < 0)
return ret; return ret;
if (vivi_is_generating(dev)) { if (vb2_is_streaming(q)) {
dprintk(dev, 1, "%s device busy\n", __func__); dprintk(dev, 1, "%s device busy\n", __func__);
ret = -EBUSY; return -EBUSY;
goto out;
} }
dev->fmt = get_format(f); dev->fmt = get_format(f);
dev->width = f->fmt.pix.width; dev->width = f->fmt.pix.width;
dev->height = f->fmt.pix.height; dev->height = f->fmt.pix.height;
dev->vb_vidq.field = f->fmt.pix.field; dev->field = f->fmt.pix.field;
ret = 0;
out: return 0;
return ret;
} }
static int vidioc_reqbufs(struct file *file, void *priv, static int vidioc_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *p) struct v4l2_requestbuffers *p)
{ {
struct vivi_dev *dev = video_drvdata(file); struct vivi_dev *dev = video_drvdata(file);
return vb2_reqbufs(&dev->vb_vidq, p);
return videobuf_reqbufs(&dev->vb_vidq, p);
} }
static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p) static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
{ {
struct vivi_dev *dev = video_drvdata(file); struct vivi_dev *dev = video_drvdata(file);
return vb2_querybuf(&dev->vb_vidq, p);
return videobuf_querybuf(&dev->vb_vidq, p);
} }
static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
{ {
struct vivi_dev *dev = video_drvdata(file); struct vivi_dev *dev = video_drvdata(file);
return vb2_qbuf(&dev->vb_vidq, p);
return videobuf_qbuf(&dev->vb_vidq, p);
} }
static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
{ {
struct vivi_dev *dev = video_drvdata(file); struct vivi_dev *dev = video_drvdata(file);
return vb2_dqbuf(&dev->vb_vidq, p, file->f_flags & O_NONBLOCK);
return videobuf_dqbuf(&dev->vb_vidq, p,
file->f_flags & O_NONBLOCK);
} }
static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
{ {
struct vivi_dev *dev = video_drvdata(file); struct vivi_dev *dev = video_drvdata(file);
int ret; return vb2_streamon(&dev->vb_vidq, i);
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;
} }
static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
{ {
struct vivi_dev *dev = video_drvdata(file); struct vivi_dev *dev = video_drvdata(file);
int ret; return vb2_streamoff(&dev->vb_vidq, i);
if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
ret = videobuf_streamoff(&dev->vb_vidq);
if (!ret)
vivi_stop_generating(file);
return ret;
} }
static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *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, ...@@ -1018,26 +1037,33 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
File operations for the device 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 static ssize_t
vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos) vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
{ {
struct vivi_dev *dev = video_drvdata(file); struct vivi_dev *dev = video_drvdata(file);
vivi_start_generating(file); dprintk(dev, 1, "read called\n");
return videobuf_read_stream(&dev->vb_vidq, data, count, ppos, 0, return vb2_read(&dev->vb_vidq, data, count, ppos,
file->f_flags & O_NONBLOCK); file->f_flags & O_NONBLOCK);
} }
static unsigned int static unsigned int
vivi_poll(struct file *file, struct poll_table_struct *wait) vivi_poll(struct file *file, struct poll_table_struct *wait)
{ {
struct vivi_dev *dev = video_drvdata(file); 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__); dprintk(dev, 1, "%s\n", __func__);
return vb2_poll(q, file, wait);
vivi_start_generating(file);
return videobuf_poll_stream(file, q, wait);
} }
static int vivi_close(struct file *file) static int vivi_close(struct file *file)
...@@ -1045,10 +1071,11 @@ 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 video_device *vdev = video_devdata(file);
struct vivi_dev *dev = video_drvdata(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", if (--dev->open_count == 0)
video_device_node_name(vdev)); vb2_queue_release(&dev->vb_vidq);
return 0; return 0;
} }
...@@ -1059,8 +1086,7 @@ static int vivi_mmap(struct file *file, struct vm_area_struct *vma) ...@@ -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); 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", dprintk(dev, 1, "vma start=0x%08lx, size=%ld, ret=%d\n",
(unsigned long)vma->vm_start, (unsigned long)vma->vm_start,
(unsigned long)vma->vm_end - (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) ...@@ -1070,6 +1096,7 @@ static int vivi_mmap(struct file *file, struct vm_area_struct *vma)
static const struct v4l2_file_operations vivi_fops = { static const struct v4l2_file_operations vivi_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = vivi_open,
.release = vivi_close, .release = vivi_close,
.read = vivi_read, .read = vivi_read,
.poll = vivi_poll, .poll = vivi_poll,
...@@ -1136,6 +1163,7 @@ static int __init vivi_create_instance(int inst) ...@@ -1136,6 +1163,7 @@ static int __init vivi_create_instance(int inst)
{ {
struct vivi_dev *dev; struct vivi_dev *dev;
struct video_device *vfd; struct video_device *vfd;
struct vb2_queue *q;
int ret; int ret;
dev = kzalloc(sizeof(*dev), GFP_KERNEL); dev = kzalloc(sizeof(*dev), GFP_KERNEL);
...@@ -1159,12 +1187,20 @@ static int __init vivi_create_instance(int inst) ...@@ -1159,12 +1187,20 @@ static int __init vivi_create_instance(int inst)
/* initialize locks */ /* initialize locks */
spin_lock_init(&dev->slock); spin_lock_init(&dev->slock);
mutex_init(&dev->mutex);
videobuf_queue_vmalloc_init(&dev->vb_vidq, &vivi_video_qops, /* initialize queue */
NULL, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, q = &dev->vb_vidq;
V4L2_FIELD_INTERLACED, memset(q, 0, sizeof(dev->vb_vidq));
sizeof(struct vivi_buffer), dev, &dev->mutex); 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 video dma queues */
INIT_LIST_HEAD(&dev->vidq.active); INIT_LIST_HEAD(&dev->vidq.active);
...@@ -1178,6 +1214,11 @@ static int __init vivi_create_instance(int inst) ...@@ -1178,6 +1214,11 @@ static int __init vivi_create_instance(int inst)
*vfd = vivi_template; *vfd = vivi_template;
vfd->debug = debug; vfd->debug = debug;
vfd->v4l2_dev = &dev->v4l2_dev; 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; vfd->lock = &dev->mutex;
ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr); ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
......
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