Commit 8ded351a authored by Marin Mitov's avatar Marin Mitov Committed by Greg Kroah-Hartman

staging: use videobuf2 framework for drivers/staging/dt3155v4l driver

This patch transforms drivers/staging/dt3155v4l driver to use videobuf2 framework.
Tested and works with "xawtv -f".

Either streaming API or read method should be selected during kernel configuration.

If both are selected into the driver (not possible without another patching),
either due to my misunderstanding or problems in xawtv (or both), I get kernel panic
after some start/stop of xawtv (not strictly reproducible).
Signed-off-by: default avatarMarin Mitov <mitov@issp.bas.bg>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 7a176332
config VIDEO_DT3155 config VIDEO_DT3155
tristate "DT3155 frame grabber, Video4Linux interface" tristate "DT3155 frame grabber, Video4Linux interface"
depends on PCI && VIDEO_DEV && VIDEO_V4L2 depends on PCI && VIDEO_DEV && VIDEO_V4L2
select VIDEOBUF_DMA_CONTIG select VIDEOBUF2_DMA_CONTIG
default n default n
---help--- ---help---
Enables dt3155 device driver for the DataTranslation DT3155 frame grabber. Enables dt3155 device driver for the DataTranslation DT3155 frame grabber.
...@@ -18,3 +18,11 @@ config DT3155_CCIR ...@@ -18,3 +18,11 @@ config DT3155_CCIR
---help--- ---help---
Select it for CCIR/50Hz (European region), Select it for CCIR/50Hz (European region),
or leave it unselected for RS-170/60Hz (North America). or leave it unselected for RS-170/60Hz (North America).
config DT3155_STREAMING
bool "Selects streaming capture method"
depends on VIDEO_DT3155
default y
---help---
Select it if you want to use streaming of memory mapped buffers
or leave it unselected if you want to use read method (one copy more).
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
#include <linux/kthread.h> #include <linux/kthread.h>
#include <media/v4l2-dev.h> #include <media/v4l2-dev.h>
#include <media/v4l2-ioctl.h> #include <media/v4l2-ioctl.h>
#include <media/videobuf-dma-contig.h> #include <media/videobuf2-dma-contig.h>
#include "dt3155v4l.h" #include "dt3155v4l.h"
...@@ -38,6 +38,12 @@ ...@@ -38,6 +38,12 @@
#define DT3155_BUF_SIZE (768 * 576) #define DT3155_BUF_SIZE (768 * 576)
#ifdef CONFIG_DT3155_STREAMING
#define DT3155_CAPTURE_METHOD V4L2_CAP_STREAMING
#else
#define DT3155_CAPTURE_METHOD V4L2_CAP_READWRITE
#endif
/* global initializers (for all boards) */ /* global initializers (for all boards) */
#ifdef CONFIG_DT3155_CCIR #ifdef CONFIG_DT3155_CCIR
static const u8 csr2_init = VT_50HZ; static const u8 csr2_init = VT_50HZ;
...@@ -197,14 +203,14 @@ static int wait_i2c_reg(void __iomem *addr) ...@@ -197,14 +203,14 @@ static int wait_i2c_reg(void __iomem *addr)
static int static int
dt3155_start_acq(struct dt3155_priv *pd) dt3155_start_acq(struct dt3155_priv *pd)
{ {
struct videobuf_buffer *vb = pd->curr_buf; struct vb2_buffer *vb = pd->curr_buf;
dma_addr_t dma_addr; dma_addr_t dma_addr;
dma_addr = videobuf_to_dma_contig(vb); dma_addr = vb2_dma_contig_plane_paddr(vb, 0);
iowrite32(dma_addr, pd->regs + EVEN_DMA_START); iowrite32(dma_addr, pd->regs + EVEN_DMA_START);
iowrite32(dma_addr + vb->width, pd->regs + ODD_DMA_START); iowrite32(dma_addr + img_width, pd->regs + ODD_DMA_START);
iowrite32(vb->width, pd->regs + EVEN_DMA_STRIDE); iowrite32(img_width, pd->regs + EVEN_DMA_STRIDE);
iowrite32(vb->width, pd->regs + ODD_DMA_STRIDE); iowrite32(img_width, pd->regs + ODD_DMA_STRIDE);
/* enable interrupts, clear all irq flags */ /* enable interrupts, clear all irq flags */
iowrite32(FLD_START_EN | FLD_END_ODD_EN | FLD_START | iowrite32(FLD_START_EN | FLD_END_ODD_EN | FLD_START |
FLD_END_EVEN | FLD_END_ODD, pd->regs + INT_CSR); FLD_END_EVEN | FLD_END_ODD, pd->regs + INT_CSR);
...@@ -221,95 +227,110 @@ dt3155_start_acq(struct dt3155_priv *pd) ...@@ -221,95 +227,110 @@ dt3155_start_acq(struct dt3155_priv *pd)
return 0; /* success */ return 0; /* success */
} }
/*
* driver-specific callbacks (vb2_ops)
*/
static int static int
dt3155_stop_acq(struct dt3155_priv *pd) dt3155_queue_setup(struct vb2_queue *q, unsigned int *num_buffers,
unsigned int *num_planes, unsigned long sizes[],
void *alloc_ctxs[])
{ {
int tmp; struct dt3155_priv *pd = vb2_get_drv_priv(q);
void *ret;
if (*num_buffers == 0)
*num_buffers = 1;
*num_planes = 1;
sizes[0] = img_width * img_height;
if (pd->q->alloc_ctx[0])
return 0;
ret = vb2_dma_contig_init_ctx(&pd->pdev->dev);
if (IS_ERR(ret))
return PTR_ERR(ret);
pd->q->alloc_ctx[0] = ret;
return 0;
}
/* stop the board */ static void
wait_i2c_reg(pd->regs); dt3155_wait_prepare(struct vb2_queue *q)
write_i2c_reg(pd->regs, CSR2, pd->csr2); {
struct dt3155_priv *pd = vb2_get_drv_priv(q);
/* disable all irqs, clear all irq flags */ mutex_unlock(pd->vdev->lock);
iowrite32(FLD_START | FLD_END_EVEN | FLD_END_ODD, pd->regs + INT_CSR); }
write_i2c_reg(pd->regs, EVEN_CSR, CSR_ERROR | CSR_DONE);
write_i2c_reg(pd->regs, ODD_CSR, CSR_ERROR | CSR_DONE); static void
tmp = ioread32(pd->regs + CSR1) & (FLD_CRPT_EVEN | FLD_CRPT_ODD); dt3155_wait_finish(struct vb2_queue *q)
if (tmp) {
printk(KERN_ERR "dt3155: corrupted field %u\n", tmp); struct dt3155_priv *pd = vb2_get_drv_priv(q);
iowrite32(FIFO_EN | SRST | FLD_CRPT_ODD | FLD_CRPT_EVEN |
FLD_DN_ODD | FLD_DN_EVEN | CAP_CONT_EVEN | CAP_CONT_ODD, mutex_lock(pd->vdev->lock);
pd->regs + CSR1);
return 0;
} }
/* Locking: Caller holds q->vb_lock */
static int static int
dt3155_buf_setup(struct videobuf_queue *q, unsigned int *count, dt3155_buf_prepare(struct vb2_buffer *vb)
unsigned int *size)
{ {
*size = img_width * img_height; vb2_set_plane_payload(vb, 0, img_width * img_height);
return 0; return 0;
} }
/* Locking: Caller holds q->vb_lock */
static int static int
dt3155_buf_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, dt3155_start_streaming(struct vb2_queue *q)
enum v4l2_field field)
{ {
int ret = 0; return 0;
vb->width = img_width;
vb->height = img_height;
vb->size = img_width * img_height;
vb->field = field;
if (vb->state == VIDEOBUF_NEEDS_INIT)
ret = videobuf_iolock(q, vb, NULL);
if (ret) {
vb->state = VIDEOBUF_ERROR;
printk(KERN_ERR "ERROR: videobuf_iolock() failed\n");
videobuf_dma_contig_free(q, vb); /* FIXME: needed? */
} else
vb->state = VIDEOBUF_PREPARED;
return ret;
} }
/* Locking: Caller holds q->vb_lock & q->irqlock */ static int
static void dt3155_stop_streaming(struct vb2_queue *q)
dt3155_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
{ {
struct dt3155_priv *pd = q->priv_data; struct dt3155_priv *pd = vb2_get_drv_priv(q);
struct vb2_buffer *vb;
if (vb->state != VIDEOBUF_NEEDS_INIT) {
vb->state = VIDEOBUF_QUEUED; spin_lock_irq(&pd->lock);
list_add_tail(&vb->queue, &pd->dmaq); while (!list_empty(&pd->dmaq)) {
wake_up_interruptible_sync(&pd->do_dma); vb = list_first_entry(&pd->dmaq, typeof(*vb), done_entry);
} else list_del(&vb->done_entry);
vb->state = VIDEOBUF_ERROR; vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
}
spin_unlock_irq(&pd->lock);
msleep(45); /* irq hendler will stop the hardware */
return 0;
} }
/* Locking: Caller holds q->vb_lock */
static void static void
dt3155_buf_release(struct videobuf_queue *q, struct videobuf_buffer *vb) dt3155_buf_queue(struct vb2_buffer *vb)
{ {
if (vb->state == VIDEOBUF_ACTIVE) struct dt3155_priv *pd = vb2_get_drv_priv(vb->vb2_queue);
videobuf_waiton(q, vb, 0, 0); /* FIXME: cannot be interrupted */
videobuf_dma_contig_free(q, vb); /* pd->q->streaming = 1 when dt3155_buf_queue() is invoked */
vb->state = VIDEOBUF_NEEDS_INIT; spin_lock_irq(&pd->lock);
if (pd->curr_buf)
list_add_tail(&vb->done_entry, &pd->dmaq);
else {
pd->curr_buf = vb;
dt3155_start_acq(pd);
}
spin_unlock_irq(&pd->lock);
} }
/*
* end driver-specific callbacks
*/
static struct videobuf_queue_ops vbq_ops = { const struct vb2_ops q_ops = {
.buf_setup = dt3155_buf_setup, .queue_setup = dt3155_queue_setup,
.wait_prepare = dt3155_wait_prepare,
.wait_finish = dt3155_wait_finish,
.buf_prepare = dt3155_buf_prepare, .buf_prepare = dt3155_buf_prepare,
.start_streaming = dt3155_start_streaming,
.stop_streaming = dt3155_stop_streaming,
.buf_queue = dt3155_buf_queue, .buf_queue = dt3155_buf_queue,
.buf_release = dt3155_buf_release,
}; };
static irqreturn_t static irqreturn_t
dt3155_irq_handler_even(int irq, void *dev_id) dt3155_irq_handler_even(int irq, void *dev_id)
{ {
struct dt3155_priv *ipd = dev_id; struct dt3155_priv *ipd = dev_id;
struct videobuf_buffer *ivb; struct vb2_buffer *ivb;
dma_addr_t dma_addr; dma_addr_t dma_addr;
u32 tmp; u32 tmp;
...@@ -341,33 +362,22 @@ dt3155_irq_handler_even(int irq, void *dev_id) ...@@ -341,33 +362,22 @@ dt3155_irq_handler_even(int irq, void *dev_id)
} }
spin_lock(&ipd->lock); spin_lock(&ipd->lock);
if (ipd->curr_buf && ipd->curr_buf->state == VIDEOBUF_ACTIVE) { if (ipd->curr_buf) {
if (waitqueue_active(&ipd->curr_buf->done)) { do_gettimeofday(&ipd->curr_buf->v4l2_buf.timestamp);
do_gettimeofday(&ipd->curr_buf->ts); ipd->curr_buf->v4l2_buf.sequence = (ipd->field_count) >> 1;
ipd->curr_buf->field_count = ipd->field_count; vb2_buffer_done(ipd->curr_buf, VB2_BUF_STATE_DONE);
ipd->curr_buf->state = VIDEOBUF_DONE;
wake_up(&ipd->curr_buf->done);
} else {
ivb = ipd->curr_buf;
goto load_dma;
} }
} else
goto stop_dma; if (!ipd->q->streaming || list_empty(&ipd->dmaq))
if (list_empty(&ipd->dmaq))
goto stop_dma; goto stop_dma;
ivb = list_first_entry(&ipd->dmaq, typeof(*ivb), queue); ivb = list_first_entry(&ipd->dmaq, typeof(*ivb), done_entry);
list_del(&ivb->queue); list_del(&ivb->done_entry);
if (ivb->state == VIDEOBUF_QUEUED) {
ivb->state = VIDEOBUF_ACTIVE;
ipd->curr_buf = ivb; ipd->curr_buf = ivb;
} else dma_addr = vb2_dma_contig_plane_paddr(ivb, 0);
goto stop_dma;
load_dma:
dma_addr = videobuf_to_dma_contig(ivb);
iowrite32(dma_addr, ipd->regs + EVEN_DMA_START); iowrite32(dma_addr, ipd->regs + EVEN_DMA_START);
iowrite32(dma_addr + ivb->width, ipd->regs + ODD_DMA_START); iowrite32(dma_addr + img_width, ipd->regs + ODD_DMA_START);
iowrite32(ivb->width, ipd->regs + EVEN_DMA_STRIDE); iowrite32(img_width, ipd->regs + EVEN_DMA_STRIDE);
iowrite32(ivb->width, ipd->regs + ODD_DMA_STRIDE); iowrite32(img_width, ipd->regs + ODD_DMA_STRIDE);
mmiowb(); mmiowb();
/* enable interrupts, clear all irq flags */ /* enable interrupts, clear all irq flags */
iowrite32(FLD_START_EN | FLD_END_ODD_EN | FLD_START | iowrite32(FLD_START_EN | FLD_END_ODD_EN | FLD_START |
...@@ -379,68 +389,40 @@ dt3155_irq_handler_even(int irq, void *dev_id) ...@@ -379,68 +389,40 @@ dt3155_irq_handler_even(int irq, void *dev_id)
ipd->curr_buf = NULL; ipd->curr_buf = NULL;
/* stop the board */ /* stop the board */
write_i2c_reg_nowait(ipd->regs, CSR2, ipd->csr2); write_i2c_reg_nowait(ipd->regs, CSR2, ipd->csr2);
iowrite32(FIFO_EN | SRST | FLD_CRPT_ODD | FLD_CRPT_EVEN |
FLD_DN_ODD | FLD_DN_EVEN, ipd->regs + CSR1);
/* disable interrupts, clear all irq flags */ /* disable interrupts, clear all irq flags */
iowrite32(FLD_START | FLD_END_EVEN | FLD_END_ODD, ipd->regs + INT_CSR); iowrite32(FLD_START | FLD_END_EVEN | FLD_END_ODD, ipd->regs + INT_CSR);
spin_unlock(&ipd->lock); spin_unlock(&ipd->lock);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static int
dt3155_threadfn(void *arg)
{
struct dt3155_priv *pd = arg;
struct videobuf_buffer *vb;
unsigned long flags;
while (1) {
wait_event_interruptible(pd->do_dma,
kthread_should_stop() || !list_empty(&pd->dmaq));
if (kthread_should_stop())
break;
spin_lock_irqsave(&pd->lock, flags);
if (pd->curr_buf) /* dma is active */
goto done;
if (list_empty(&pd->dmaq)) /* no empty biffers */
goto done;
vb = list_first_entry(&pd->dmaq, typeof(*vb), queue);
list_del(&vb->queue);
if (vb->state == VIDEOBUF_QUEUED) {
vb->state = VIDEOBUF_ACTIVE;
pd->curr_buf = vb;
spin_unlock_irqrestore(&pd->lock, flags);
/* start dma */
dt3155_start_acq(pd);
continue;
} else
printk(KERN_DEBUG "%s(): This is a BUG\n", __func__);
done:
spin_unlock_irqrestore(&pd->lock, flags);
}
return 0;
}
static int static int
dt3155_open(struct file *filp) dt3155_open(struct file *filp)
{ {
int ret = 0; int ret = 0;
struct dt3155_priv *pd = video_drvdata(filp); struct dt3155_priv *pd = video_drvdata(filp);
printk(KERN_INFO "dt3155: open(): minor: %i\n", pd->vdev->minor); printk(KERN_INFO "dt3155: open(): minor: %i, users: %i\n",
pd->vdev->minor, pd->users);
if (mutex_lock_interruptible(&pd->mux) == -EINTR)
return -ERESTARTSYS;
if (!pd->users) { if (!pd->users) {
pd->vidq = kzalloc(sizeof(*pd->vidq), GFP_KERNEL); pd->q = kzalloc(sizeof(*pd->q), GFP_KERNEL);
if (!pd->vidq) { if (!pd->q) {
printk(KERN_ERR "dt3155: error: alloc queue\n"); printk(KERN_ERR "dt3155: error: alloc queue\n");
ret = -ENOMEM; ret = -ENOMEM;
goto err_alloc_queue; goto err_alloc_queue;
} }
videobuf_queue_dma_contig_init(pd->vidq, &vbq_ops, pd->q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
&pd->pdev->dev, &pd->lock, pd->q->io_modes = VB2_READ | VB2_MMAP;
V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE, pd->q->ops = &q_ops;
sizeof(struct videobuf_buffer), pd, NULL); pd->q->mem_ops = &vb2_dma_contig_memops;
pd->q->drv_priv = pd;
pd->curr_buf = NULL;
pd->field_count = 0;
vb2_queue_init(pd->q); /* cannot fail */
INIT_LIST_HEAD(&pd->dmaq);
spin_lock_init(&pd->lock);
/* disable all irqs, clear all irq flags */ /* disable all irqs, clear all irq flags */
iowrite32(FLD_START | FLD_END_EVEN | FLD_END_ODD, iowrite32(FLD_START | FLD_END_EVEN | FLD_END_ODD,
pd->regs + INT_CSR); pd->regs + INT_CSR);
...@@ -451,26 +433,13 @@ dt3155_open(struct file *filp) ...@@ -451,26 +433,13 @@ dt3155_open(struct file *filp)
printk(KERN_ERR "dt3155: error: request_irq\n"); printk(KERN_ERR "dt3155: error: request_irq\n");
goto err_request_irq; goto err_request_irq;
} }
pd->curr_buf = NULL;
pd->thread = kthread_run(dt3155_threadfn, pd,
"dt3155_thread_%i", pd->vdev->minor);
if (IS_ERR(pd->thread)) {
printk(KERN_ERR "dt3155: kthread_run() failed\n");
ret = PTR_ERR(pd->thread);
goto err_thread;
}
pd->field_count = 0;
} }
pd->users++; pd->users++;
goto done; return 0; /* success */
err_thread:
free_irq(pd->pdev->irq, pd);
err_request_irq: err_request_irq:
kfree(pd->vidq); kfree(pd->q);
pd->vidq = NULL; pd->q = NULL;
err_alloc_queue: err_alloc_queue:
done:
mutex_unlock(&pd->mux);
return ret; return ret;
} }
...@@ -478,61 +447,29 @@ static int ...@@ -478,61 +447,29 @@ static int
dt3155_release(struct file *filp) dt3155_release(struct file *filp)
{ {
struct dt3155_priv *pd = video_drvdata(filp); struct dt3155_priv *pd = video_drvdata(filp);
struct videobuf_buffer *tmp;
unsigned long flags;
int ret = 0;
printk(KERN_INFO "dt3155: release(): minor: %i\n", pd->vdev->minor); printk(KERN_INFO "dt3155: release(): minor: %i, users: %i\n",
pd->vdev->minor, pd->users - 1);
if (mutex_lock_interruptible(&pd->mux) == -EINTR)
return -ERESTARTSYS;
pd->users--; pd->users--;
BUG_ON(pd->users < 0); BUG_ON(pd->users < 0);
if (pd->acq_fp == filp) {
spin_lock_irqsave(&pd->lock, flags);
INIT_LIST_HEAD(&pd->dmaq); /* queue is emptied */
tmp = pd->curr_buf;
spin_unlock_irqrestore(&pd->lock, flags);
if (tmp)
videobuf_waiton(pd->vidq, tmp, 0, 1); /* block, interruptible */
dt3155_stop_acq(pd);
videobuf_stop(pd->vidq);
pd->acq_fp = NULL;
pd->streaming = 0;
}
if (!pd->users) { if (!pd->users) {
kthread_stop(pd->thread); vb2_queue_release(pd->q);
free_irq(pd->pdev->irq, pd); free_irq(pd->pdev->irq, pd);
kfree(pd->vidq); if (pd->q->alloc_ctx[0])
pd->vidq = NULL; vb2_dma_contig_cleanup_ctx(pd->q->alloc_ctx[0]);
kfree(pd->q);
pd->q = NULL;
} }
mutex_unlock(&pd->mux); return 0;
return ret;
} }
static ssize_t static ssize_t
dt3155_read(struct file *filp, char __user *user, size_t size, loff_t *loff) dt3155_read(struct file *filp, char __user *user, size_t size, loff_t *loff)
{ {
struct dt3155_priv *pd = video_drvdata(filp); struct dt3155_priv *pd = video_drvdata(filp);
int ret;
return vb2_read(pd->q, user, size, loff, filp->f_flags & O_NONBLOCK);
if (mutex_lock_interruptible(&pd->mux) == -EINTR)
return -ERESTARTSYS;
if (!pd->acq_fp) {
pd->acq_fp = filp;
pd->streaming = 0;
} else if (pd->acq_fp != filp) {
ret = -EBUSY;
goto done;
} else if (pd->streaming == 1) {
ret = -EINVAL;
goto done;
}
ret = videobuf_read_stream(pd->vidq, user, size, loff, 0,
filp->f_flags & O_NONBLOCK);
done:
mutex_unlock(&pd->mux);
return ret;
} }
static unsigned int static unsigned int
...@@ -540,7 +477,7 @@ dt3155_poll(struct file *filp, struct poll_table_struct *polltbl) ...@@ -540,7 +477,7 @@ dt3155_poll(struct file *filp, struct poll_table_struct *polltbl)
{ {
struct dt3155_priv *pd = video_drvdata(filp); struct dt3155_priv *pd = video_drvdata(filp);
return videobuf_poll_stream(filp, pd->vidq, polltbl); return vb2_poll(pd->q, filp, polltbl);
} }
static int static int
...@@ -548,7 +485,7 @@ dt3155_mmap(struct file *filp, struct vm_area_struct *vma) ...@@ -548,7 +485,7 @@ dt3155_mmap(struct file *filp, struct vm_area_struct *vma)
{ {
struct dt3155_priv *pd = video_drvdata(filp); struct dt3155_priv *pd = video_drvdata(filp);
return videobuf_mmap_mapper(pd->vidq, vma); return vb2_mmap(pd->q, vma);
} }
static const struct v4l2_file_operations dt3155_fops = { static const struct v4l2_file_operations dt3155_fops = {
...@@ -565,46 +502,16 @@ static int ...@@ -565,46 +502,16 @@ static int
dt3155_ioc_streamon(struct file *filp, void *p, enum v4l2_buf_type type) dt3155_ioc_streamon(struct file *filp, void *p, enum v4l2_buf_type type)
{ {
struct dt3155_priv *pd = video_drvdata(filp); struct dt3155_priv *pd = video_drvdata(filp);
int ret = -ERESTARTSYS;
if (mutex_lock_interruptible(&pd->mux) == -EINTR) return vb2_streamon(pd->q, type);
return ret;
if (!pd->acq_fp) {
ret = videobuf_streamon(pd->vidq);
if (ret)
goto unlock;
pd->acq_fp = filp;
pd->streaming = 1;
wake_up_interruptible_sync(&pd->do_dma);
} else if (pd->acq_fp == filp) {
pd->streaming = 1;
ret = videobuf_streamon(pd->vidq);
if (!ret)
wake_up_interruptible_sync(&pd->do_dma);
} else
ret = -EBUSY;
unlock:
mutex_unlock(&pd->mux);
return ret;
} }
static int static int
dt3155_ioc_streamoff(struct file *filp, void *p, enum v4l2_buf_type type) dt3155_ioc_streamoff(struct file *filp, void *p, enum v4l2_buf_type type)
{ {
struct dt3155_priv *pd = video_drvdata(filp); struct dt3155_priv *pd = video_drvdata(filp);
struct videobuf_buffer *tmp;
unsigned long flags;
int ret;
ret = videobuf_streamoff(pd->vidq); return vb2_streamoff(pd->q, type);
if (ret)
return ret;
spin_lock_irqsave(&pd->lock, flags);
tmp = pd->curr_buf;
spin_unlock_irqrestore(&pd->lock, flags);
if (tmp)
videobuf_waiton(pd->vidq, tmp, 0, 1); /* block, interruptible */
return ret;
} }
static int static int
...@@ -618,8 +525,7 @@ dt3155_ioc_querycap(struct file *filp, void *p, struct v4l2_capability *cap) ...@@ -618,8 +525,7 @@ dt3155_ioc_querycap(struct file *filp, void *p, struct v4l2_capability *cap)
cap->version = cap->version =
KERNEL_VERSION(DT3155_VER_MAJ, DT3155_VER_MIN, DT3155_VER_EXT); KERNEL_VERSION(DT3155_VER_MAJ, DT3155_VER_MIN, DT3155_VER_EXT);
cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_STREAMING | DT3155_CAPTURE_METHOD;
V4L2_CAP_READWRITE;
return 0; return 0;
} }
...@@ -667,93 +573,39 @@ dt3155_ioc_try_fmt_vid_cap(struct file *filp, void *p, struct v4l2_format *f) ...@@ -667,93 +573,39 @@ dt3155_ioc_try_fmt_vid_cap(struct file *filp, void *p, struct v4l2_format *f)
static int static int
dt3155_ioc_s_fmt_vid_cap(struct file *filp, void *p, struct v4l2_format *f) dt3155_ioc_s_fmt_vid_cap(struct file *filp, void *p, struct v4l2_format *f)
{ {
struct dt3155_priv *pd = video_drvdata(filp); return dt3155_ioc_g_fmt_vid_cap(filp, p, f);
int ret = -ERESTARTSYS;
if (mutex_lock_interruptible(&pd->mux) == -EINTR)
return ret;
if (!pd->acq_fp) {
pd->acq_fp = filp;
pd->streaming = 0;
} else if (pd->acq_fp != filp) {
ret = -EBUSY;
goto done;
}
/* FIXME: we don't change the format for now
if (pd->vidq->streaming || pd->vidq->reading || pd->curr_buff) {
ret = -EBUSY;
goto done;
}
*/
ret = dt3155_ioc_g_fmt_vid_cap(filp, p, f);
done:
mutex_unlock(&pd->mux);
return ret;
} }
static int static int
dt3155_ioc_reqbufs(struct file *filp, void *p, struct v4l2_requestbuffers *b) dt3155_ioc_reqbufs(struct file *filp, void *p, struct v4l2_requestbuffers *b)
{ {
struct dt3155_priv *pd = video_drvdata(filp); struct dt3155_priv *pd = video_drvdata(filp);
struct videobuf_queue *q = pd->vidq;
int ret = -ERESTARTSYS;
if (b->memory != V4L2_MEMORY_MMAP) return vb2_reqbufs(pd->q, b);
return -EINVAL;
if (mutex_lock_interruptible(&pd->mux) == -EINTR)
return ret;
if (!pd->acq_fp)
pd->acq_fp = filp;
else if (pd->acq_fp != filp) {
ret = -EBUSY;
goto done;
}
pd->streaming = 1;
ret = 0;
done:
mutex_unlock(&pd->mux);
if (ret)
return ret;
if (b->count)
ret = videobuf_reqbufs(q, b);
else { /* FIXME: is it necessary? */
printk(KERN_DEBUG "dt3155: request to free buffers\n");
/* ret = videobuf_mmap_free(q); */
ret = dt3155_ioc_streamoff(filp, p,
V4L2_BUF_TYPE_VIDEO_CAPTURE);
}
return ret;
} }
static int static int
dt3155_ioc_querybuf(struct file *filp, void *p, struct v4l2_buffer *b) dt3155_ioc_querybuf(struct file *filp, void *p, struct v4l2_buffer *b)
{ {
struct dt3155_priv *pd = video_drvdata(filp); struct dt3155_priv *pd = video_drvdata(filp);
struct videobuf_queue *q = pd->vidq;
return videobuf_querybuf(q, b); return vb2_querybuf(pd->q, b);
} }
static int static int
dt3155_ioc_qbuf(struct file *filp, void *p, struct v4l2_buffer *b) dt3155_ioc_qbuf(struct file *filp, void *p, struct v4l2_buffer *b)
{ {
struct dt3155_priv *pd = video_drvdata(filp); struct dt3155_priv *pd = video_drvdata(filp);
struct videobuf_queue *q = pd->vidq;
int ret;
ret = videobuf_qbuf(q, b); return vb2_qbuf(pd->q, b);
if (ret)
return ret;
return videobuf_querybuf(q, b);
} }
static int static int
dt3155_ioc_dqbuf(struct file *filp, void *p, struct v4l2_buffer *b) dt3155_ioc_dqbuf(struct file *filp, void *p, struct v4l2_buffer *b)
{ {
struct dt3155_priv *pd = video_drvdata(filp); struct dt3155_priv *pd = video_drvdata(filp);
struct videobuf_queue *q = pd->vidq;
return videobuf_dqbuf(q, b, filp->f_flags & O_NONBLOCK); return vb2_dqbuf(pd->q, b, filp->f_flags & O_NONBLOCK);
} }
static int static int
...@@ -880,21 +732,21 @@ static const struct v4l2_ioctl_ops dt3155_ioctl_ops = { ...@@ -880,21 +732,21 @@ static const struct v4l2_ioctl_ops dt3155_ioctl_ops = {
}; };
static int __devinit static int __devinit
dt3155_init_board(struct pci_dev *dev) dt3155_init_board(struct pci_dev *pdev)
{ {
struct dt3155_priv *pd = pci_get_drvdata(dev); struct dt3155_priv *pd = pci_get_drvdata(pdev);
void *buf_cpu; void *buf_cpu;
dma_addr_t buf_dma; dma_addr_t buf_dma;
int i; int i;
u8 tmp; u8 tmp;
pci_set_master(dev); /* dt3155 needs it */ pci_set_master(pdev); /* dt3155 needs it */
/* resetting the adapter */ /* resetting the adapter */
iowrite32(FLD_CRPT_ODD | FLD_CRPT_EVEN | FLD_DN_ODD | FLD_DN_EVEN, iowrite32(FLD_CRPT_ODD | FLD_CRPT_EVEN | FLD_DN_ODD | FLD_DN_EVEN,
pd->regs + CSR1); pd->regs + CSR1);
mmiowb(); mmiowb();
msleep(10); msleep(20);
/* initializing adaper registers */ /* initializing adaper registers */
iowrite32(FIFO_EN | SRST, pd->regs + CSR1); iowrite32(FIFO_EN | SRST, pd->regs + CSR1);
...@@ -949,7 +801,7 @@ dt3155_init_board(struct pci_dev *dev) ...@@ -949,7 +801,7 @@ dt3155_init_board(struct pci_dev *dev)
write_i2c_reg(pd->regs, AD_CMD, VIDEO_CNL_1 | SYNC_CNL_1 | SYNC_LVL_3); write_i2c_reg(pd->regs, AD_CMD, VIDEO_CNL_1 | SYNC_CNL_1 | SYNC_LVL_3);
/* allocate memory, and initialize the DMA machine */ /* allocate memory, and initialize the DMA machine */
buf_cpu = dma_alloc_coherent(&dev->dev, DT3155_BUF_SIZE, &buf_dma, buf_cpu = dma_alloc_coherent(&pdev->dev, DT3155_BUF_SIZE, &buf_dma,
GFP_KERNEL); GFP_KERNEL);
if (!buf_cpu) { if (!buf_cpu) {
printk(KERN_ERR "dt3155: dma_alloc_coherent " printk(KERN_ERR "dt3155: dma_alloc_coherent "
...@@ -975,7 +827,7 @@ dt3155_init_board(struct pci_dev *dev) ...@@ -975,7 +827,7 @@ dt3155_init_board(struct pci_dev *dev)
iowrite32(FIFO_EN | SRST | FLD_DN_EVEN | FLD_DN_ODD, pd->regs + CSR1); iowrite32(FIFO_EN | SRST | FLD_DN_EVEN | FLD_DN_ODD, pd->regs + CSR1);
/* deallocate memory */ /* deallocate memory */
dma_free_coherent(&dev->dev, DT3155_BUF_SIZE, buf_cpu, buf_dma); dma_free_coherent(&pdev->dev, DT3155_BUF_SIZE, buf_cpu, buf_dma);
if (tmp & BUSY_EVEN) { if (tmp & BUSY_EVEN) {
printk(KERN_ERR "dt3155: BUSY_EVEN not cleared\n"); printk(KERN_ERR "dt3155: BUSY_EVEN not cleared\n");
return -EIO; return -EIO;
...@@ -996,7 +848,7 @@ static struct video_device dt3155_vdev = { ...@@ -996,7 +848,7 @@ static struct video_device dt3155_vdev = {
/* same as in drivers/base/dma-coherent.c */ /* same as in drivers/base/dma-coherent.c */
struct dma_coherent_mem { struct dma_coherent_mem {
void *virt_base; void *virt_base;
u32 device_base; dma_addr_t device_base;
int size; int size;
int flags; int flags;
unsigned long *bitmap; unsigned long *bitmap;
...@@ -1058,18 +910,18 @@ dt3155_free_coherent(struct device *dev) ...@@ -1058,18 +910,18 @@ dt3155_free_coherent(struct device *dev)
} }
static int __devinit static int __devinit
dt3155_probe(struct pci_dev *dev, const struct pci_device_id *id) dt3155_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{ {
int err; int err;
struct dt3155_priv *pd; struct dt3155_priv *pd;
printk(KERN_INFO "dt3155: probe()\n"); printk(KERN_INFO "dt3155: probe()\n");
err = dma_set_mask(&dev->dev, DMA_BIT_MASK(32)); err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
if (err) { if (err) {
printk(KERN_ERR "dt3155: cannot set dma_mask\n"); printk(KERN_ERR "dt3155: cannot set dma_mask\n");
return -ENODEV; return -ENODEV;
} }
err = dma_set_coherent_mask(&dev->dev, DMA_BIT_MASK(32)); err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
if (err) { if (err) {
printk(KERN_ERR "dt3155: cannot set dma_coherent_mask\n"); printk(KERN_ERR "dt3155: cannot set dma_coherent_mask\n");
return -ENODEV; return -ENODEV;
...@@ -1085,31 +937,31 @@ dt3155_probe(struct pci_dev *dev, const struct pci_device_id *id) ...@@ -1085,31 +937,31 @@ dt3155_probe(struct pci_dev *dev, const struct pci_device_id *id)
goto err_video_device_alloc; goto err_video_device_alloc;
} }
*pd->vdev = dt3155_vdev; *pd->vdev = dt3155_vdev;
pci_set_drvdata(dev, pd); /* for use in dt3155_remove() */ pci_set_drvdata(pdev, pd); /* for use in dt3155_remove() */
video_set_drvdata(pd->vdev, pd); /* for use in video_fops */ video_set_drvdata(pd->vdev, pd); /* for use in video_fops */
pd->users = 0; pd->users = 0;
pd->acq_fp = NULL; pd->pdev = pdev;
pd->pdev = dev;
INIT_LIST_HEAD(&pd->dmaq); INIT_LIST_HEAD(&pd->dmaq);
init_waitqueue_head(&pd->do_dma);
mutex_init(&pd->mux); mutex_init(&pd->mux);
pd->vdev->lock = &pd->mux; /* for locking v4l2_file_operations */
spin_lock_init(&pd->lock);
pd->csr2 = csr2_init; pd->csr2 = csr2_init;
pd->config = config_init; pd->config = config_init;
err = pci_enable_device(pd->pdev); err = pci_enable_device(pdev);
if (err) { if (err) {
printk(KERN_ERR "dt3155: pci_dev not enabled\n"); printk(KERN_ERR "dt3155: pci_dev not enabled\n");
goto err_enable_dev; goto err_enable_dev;
} }
err = pci_request_region(pd->pdev, 0, pci_name(pd->pdev)); err = pci_request_region(pdev, 0, pci_name(pdev));
if (err) if (err)
goto err_req_region; goto err_req_region;
pd->regs = pci_iomap(pd->pdev, 0, pci_resource_len(pd->pdev, 0)); pd->regs = pci_iomap(pdev, 0, pci_resource_len(pd->pdev, 0));
if (!pd->regs) { if (!pd->regs) {
err = -ENOMEM; err = -ENOMEM;
printk(KERN_ERR "dt3155: pci_iomap failed\n"); printk(KERN_ERR "dt3155: pci_iomap failed\n");
goto err_pci_iomap; goto err_pci_iomap;
} }
err = dt3155_init_board(pd->pdev); err = dt3155_init_board(pdev);
if (err) { if (err) {
printk(KERN_ERR "dt3155: dt3155_init_board failed\n"); printk(KERN_ERR "dt3155: dt3155_init_board failed\n");
goto err_init_board; goto err_init_board;
...@@ -1119,7 +971,7 @@ dt3155_probe(struct pci_dev *dev, const struct pci_device_id *id) ...@@ -1119,7 +971,7 @@ dt3155_probe(struct pci_dev *dev, const struct pci_device_id *id)
printk(KERN_ERR "dt3155: Cannot register video device\n"); printk(KERN_ERR "dt3155: Cannot register video device\n");
goto err_init_board; goto err_init_board;
} }
err = dt3155_alloc_coherent(&dev->dev, DT3155_CHUNK_SIZE, err = dt3155_alloc_coherent(&pdev->dev, DT3155_CHUNK_SIZE,
DMA_MEMORY_MAP); DMA_MEMORY_MAP);
if (err) if (err)
printk(KERN_INFO "dt3155: preallocated 8 buffers\n"); printk(KERN_INFO "dt3155: preallocated 8 buffers\n");
...@@ -1127,11 +979,11 @@ dt3155_probe(struct pci_dev *dev, const struct pci_device_id *id) ...@@ -1127,11 +979,11 @@ dt3155_probe(struct pci_dev *dev, const struct pci_device_id *id)
return 0; /* success */ return 0; /* success */
err_init_board: err_init_board:
pci_iounmap(pd->pdev, pd->regs); pci_iounmap(pdev, pd->regs);
err_pci_iomap: err_pci_iomap:
pci_release_region(pd->pdev, 0); pci_release_region(pdev, 0);
err_req_region: err_req_region:
pci_disable_device(pd->pdev); pci_disable_device(pdev);
err_enable_dev: err_enable_dev:
video_device_release(pd->vdev); video_device_release(pd->vdev);
err_video_device_alloc: err_video_device_alloc:
...@@ -1140,16 +992,16 @@ dt3155_probe(struct pci_dev *dev, const struct pci_device_id *id) ...@@ -1140,16 +992,16 @@ dt3155_probe(struct pci_dev *dev, const struct pci_device_id *id)
} }
static void __devexit static void __devexit
dt3155_remove(struct pci_dev *dev) dt3155_remove(struct pci_dev *pdev)
{ {
struct dt3155_priv *pd = pci_get_drvdata(dev); struct dt3155_priv *pd = pci_get_drvdata(pdev);
printk(KERN_INFO "dt3155: remove()\n"); printk(KERN_INFO "dt3155: remove()\n");
dt3155_free_coherent(&dev->dev); dt3155_free_coherent(&pdev->dev);
video_unregister_device(pd->vdev); video_unregister_device(pd->vdev);
pci_iounmap(dev, pd->regs); pci_iounmap(pdev, pd->regs);
pci_release_region(pd->pdev, 0); pci_release_region(pdev, 0);
pci_disable_device(pd->pdev); pci_disable_device(pdev);
/* /*
* video_device_release() is invoked automatically * video_device_release() is invoked automatically
* see: struct video_device dt3155_vdev * see: struct video_device dt3155_vdev
......
...@@ -179,18 +179,13 @@ struct dt3155_stats { ...@@ -179,18 +179,13 @@ struct dt3155_stats {
* struct dt3155_priv - private data structure * struct dt3155_priv - private data structure
* *
* @vdev: pointer to video_device structure * @vdev: pointer to video_device structure
* @acq_fp pointer to filp that starts acquisition
* @streaming streaming is negotiated
* @pdev: pointer to pci_dev structure * @pdev: pointer to pci_dev structure
* @vidq pointer to videobuf_queue structure * @q pointer to vb2_queue structure
* @curr_buf: pointer to curren buffer * @curr_buf: pointer to curren buffer
* @thread pointer to worker thraed * @mux: mutex to protect the instance
* @irq_handler: irq handler for the driver * @irq_handler: irq handler for the driver
* @qt_ops local copy of dma-contig qtype_ops
* @dmaq queue for dma buffers * @dmaq queue for dma buffers
* @do_dma wait queue of the kernel thread * @lock spinlock for dma queue
* @mux: mutex to protect the instance
* @lock spinlock for videobuf queues
* @field_count fields counter * @field_count fields counter
* @stats: statistics structure * @stats: statistics structure
* @users open count * @users open count
...@@ -200,17 +195,12 @@ struct dt3155_stats { ...@@ -200,17 +195,12 @@ struct dt3155_stats {
*/ */
struct dt3155_priv { struct dt3155_priv {
struct video_device *vdev; struct video_device *vdev;
struct file *acq_fp;
int streaming;
struct pci_dev *pdev; struct pci_dev *pdev;
struct videobuf_queue *vidq; struct vb2_queue *q;
struct videobuf_buffer *curr_buf; struct vb2_buffer *curr_buf;
struct task_struct *thread; struct mutex mux;
irq_handler_t irq_handler; irq_handler_t irq_handler;
struct videobuf_qtype_ops qt_ops;
struct list_head dmaq; struct list_head dmaq;
wait_queue_head_t do_dma;
struct mutex mux;
spinlock_t lock; spinlock_t lock;
unsigned int field_count; unsigned int field_count;
struct dt3155_stats stats; struct dt3155_stats stats;
......
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