[media] saa7134: convert to vb2

Convert the saa7134 driver to vb2.

Note that while this uses the vb2-dma-sg version, the VB2_USERPTR mode is
disabled. The DMA hardware only supports DMAing full pages, and in the
USERPTR memory model the first and last scatter-gather buffer is almost
never a full page.

In practice this means that we can't use the VB2_USERPTR mode.

This has been tested with raw video, compressed video, VBI, radio, DVB and
video overlays.

Unfortunately, a vb2 conversion is one of those things you cannot split
up in smaller patches, it's all or nothing. This patch switches the whole
driver over to vb2, using the vb2 ioctl and fop helper functions.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
This commit is contained in:
Hans Verkuil 2014-04-17 07:30:53 -03:00 committed by Mauro Carvalho Chehab
parent a00e68888d
commit 2ada815fc4
8 changed files with 557 additions and 744 deletions

View File

@ -1,7 +1,7 @@
config VIDEO_SAA7134
tristate "Philips SAA7134 support"
depends on VIDEO_DEV && PCI && I2C
select VIDEOBUF_DMA_SG
select VIDEOBUF2_DMA_SG
select VIDEO_TUNER
select VIDEO_TVEEPROM
select CRC32
@ -37,7 +37,7 @@ config VIDEO_SAA7134_RC
config VIDEO_SAA7134_DVB
tristate "DVB/ATSC Support for saa7134 based TV cards"
depends on VIDEO_SAA7134 && DVB_CORE
select VIDEOBUF_DVB
select VIDEOBUF2_DVB
select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT
select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT
select DVB_TDA1004X if MEDIA_SUBDRV_AUTOSELECT

View File

@ -203,16 +203,16 @@ int saa7134_buffer_count(unsigned int size, unsigned int count)
int saa7134_buffer_startpage(struct saa7134_buf *buf)
{
return saa7134_buffer_pages(buf->vb.bsize) * buf->vb.i;
return saa7134_buffer_pages(vb2_plane_size(&buf->vb2, 0)) * buf->vb2.v4l2_buf.index;
}
unsigned long saa7134_buffer_base(struct saa7134_buf *buf)
{
unsigned long base;
struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
struct sg_table *dma = vb2_dma_sg_plane_desc(&buf->vb2, 0);
base = saa7134_buffer_startpage(buf) * 4096;
base += dma->sglist[0].offset;
base += dma->sgl[0].offset;
return base;
}
@ -242,9 +242,11 @@ int saa7134_pgtable_build(struct pci_dev *pci, struct saa7134_pgtable *pt,
BUG_ON(NULL == pt || NULL == pt->cpu);
ptr = pt->cpu + startpage;
for (i = 0; i < length; i++, list++)
for (i = 0; i < length; i++, list = sg_next(list)) {
for (p = 0; p * 4096 < list->length; p++, ptr++)
*ptr = cpu_to_le32(sg_dma_address(list) - list->offset);
*ptr = cpu_to_le32(sg_dma_address(list) +
list->offset + p * 4096);
}
return 0;
}
@ -258,44 +260,31 @@ void saa7134_pgtable_free(struct pci_dev *pci, struct saa7134_pgtable *pt)
/* ------------------------------------------------------------------ */
void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf)
{
struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
BUG_ON(in_interrupt());
videobuf_waiton(q, &buf->vb, 0, 0);
videobuf_dma_unmap(q->dev, dma);
videobuf_dma_free(dma);
buf->vb.state = VIDEOBUF_NEEDS_INIT;
}
/* ------------------------------------------------------------------ */
int saa7134_buffer_queue(struct saa7134_dev *dev,
struct saa7134_dmaqueue *q,
struct saa7134_buf *buf)
{
struct saa7134_buf *next = NULL;
unsigned long flags;
assert_spin_locked(&dev->slock);
spin_lock_irqsave(&dev->slock, flags);
dprintk("buffer_queue %p\n", buf);
if (NULL == q->curr) {
if (!q->need_two) {
q->curr = buf;
buf->activate(dev, buf, NULL);
} else if (list_empty(&q->queue)) {
list_add_tail(&buf->vb.queue,&q->queue);
buf->vb.state = VIDEOBUF_QUEUED;
list_add_tail(&buf->entry, &q->queue);
} else {
next = list_entry(q->queue.next, struct saa7134_buf,
vb.queue);
entry);
q->curr = buf;
buf->activate(dev, buf, next);
}
} else {
list_add_tail(&buf->vb.queue, &q->queue);
buf->vb.state = VIDEOBUF_QUEUED;
list_add_tail(&buf->entry, &q->queue);
}
spin_unlock_irqrestore(&dev->slock, flags);
return 0;
}
@ -303,13 +292,12 @@ void saa7134_buffer_finish(struct saa7134_dev *dev,
struct saa7134_dmaqueue *q,
unsigned int state)
{
assert_spin_locked(&dev->slock);
dprintk("buffer_finish %p\n", q->curr);
/* finish current buffer */
q->curr->vb.state = state;
v4l2_get_timestamp(&q->curr->vb.ts);
wake_up(&q->curr->vb.done);
v4l2_get_timestamp(&q->curr->vb2.v4l2_buf.timestamp);
q->curr->vb2.v4l2_buf.sequence = q->seq_nr++;
vb2_buffer_done(&q->curr->vb2, state);
q->curr = NULL;
}
@ -323,13 +311,12 @@ void saa7134_buffer_next(struct saa7134_dev *dev,
if (!list_empty(&q->queue)) {
/* activate next one from queue */
buf = list_entry(q->queue.next, struct saa7134_buf, vb.queue);
buf = list_entry(q->queue.next, struct saa7134_buf, entry);
dprintk("buffer_next %p [prev=%p/next=%p]\n",
buf, q->queue.prev, q->queue.next);
list_del(&buf->vb.queue);
list_del(&buf->entry);
if (!list_empty(&q->queue))
next = list_entry(q->queue.next, struct saa7134_buf,
vb.queue);
next = list_entry(q->queue.next, struct saa7134_buf, entry);
q->curr = buf;
buf->activate(dev, buf, next);
dprintk("buffer_next #2 prev=%p/next=%p\n",
@ -339,10 +326,6 @@ void saa7134_buffer_next(struct saa7134_dev *dev,
dprintk("buffer_next %p\n", NULL);
saa7134_set_dmabits(dev);
del_timer(&q->timeout);
if (card_has_mpeg(dev))
if (dev->ts_started)
saa7134_ts_stop(dev);
}
}
@ -363,12 +346,32 @@ void saa7134_buffer_timeout(unsigned long data)
try to start over with the next one. */
if (q->curr) {
dprintk("timeout on %p\n", q->curr);
saa7134_buffer_finish(dev, q, VIDEOBUF_ERROR);
saa7134_buffer_finish(dev, q, VB2_BUF_STATE_ERROR);
}
saa7134_buffer_next(dev, q);
spin_unlock_irqrestore(&dev->slock, flags);
}
void saa7134_stop_streaming(struct saa7134_dev *dev, struct saa7134_dmaqueue *q)
{
unsigned long flags;
struct list_head *pos, *n;
struct saa7134_buf *tmp;
spin_lock_irqsave(&dev->slock, flags);
if (!list_empty(&q->queue)) {
list_for_each_safe(pos, n, &q->queue) {
tmp = list_entry(pos, struct saa7134_buf, entry);
vb2_buffer_done(&tmp->vb2, VB2_BUF_STATE_ERROR);
list_del(pos);
tmp = NULL;
}
}
spin_unlock_irqrestore(&dev->slock, flags);
saa7134_buffer_timeout((unsigned long)q); /* also calls del_timer(&q->timeout) */
}
EXPORT_SYMBOL_GPL(saa7134_stop_streaming);
/* ------------------------------------------------------------------ */
int saa7134_set_dmabits(struct saa7134_dev *dev)
@ -388,7 +391,7 @@ int saa7134_set_dmabits(struct saa7134_dev *dev)
ctrl |= SAA7134_MAIN_CTRL_TE0;
irq |= SAA7134_IRQ1_INTE_RA0_1 |
SAA7134_IRQ1_INTE_RA0_0;
cap = dev->video_q.curr->vb.field;
cap = dev->field;
}
/* video capture -- dma 1+2 (planar modes) */
@ -1046,6 +1049,8 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
dev->video_dev = vdev_init(dev,&saa7134_video_template,"video");
dev->video_dev->ctrl_handler = &dev->ctrl_handler;
dev->video_dev->lock = &dev->lock;
dev->video_dev->queue = &dev->video_vbq;
err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER,
video_nr[dev->nr]);
if (err < 0) {
@ -1058,6 +1063,8 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
dev->vbi_dev = vdev_init(dev, &saa7134_video_template, "vbi");
dev->vbi_dev->ctrl_handler = &dev->ctrl_handler;
dev->vbi_dev->lock = &dev->lock;
dev->vbi_dev->queue = &dev->vbi_vbq;
err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI,
vbi_nr[dev->nr]);
@ -1069,6 +1076,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
if (card_has_radio(dev)) {
dev->radio_dev = vdev_init(dev,&saa7134_radio_template,"radio");
dev->radio_dev->ctrl_handler = &dev->radio_ctrl_handler;
dev->radio_dev->lock = &dev->lock;
err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO,
radio_nr[dev->nr]);
if (err < 0)
@ -1188,7 +1196,7 @@ static int saa7134_buffer_requeue(struct saa7134_dev *dev,
if (!list_empty(&q->queue))
next = list_entry(q->queue.next, struct saa7134_buf,
vb.queue);
entry);
buf->activate(dev, buf, next);
return 0;

View File

@ -602,10 +602,10 @@ static int configure_tda827x_fe(struct saa7134_dev *dev,
struct tda1004x_config *cdec_conf,
struct tda827x_config *tuner_conf)
{
struct videobuf_dvb_frontend *fe0;
struct vb2_dvb_frontend *fe0;
/* Get the first frontend */
fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
fe0 = vb2_dvb_get_frontend(&dev->frontends, 1);
if (!fe0)
return -EINVAL;
@ -1215,29 +1215,38 @@ static int dvb_init(struct saa7134_dev *dev)
{
int ret;
int attach_xc3028 = 0;
struct videobuf_dvb_frontend *fe0;
struct vb2_dvb_frontend *fe0;
struct vb2_queue *q;
/* FIXME: add support for multi-frontend */
mutex_init(&dev->frontends.lock);
INIT_LIST_HEAD(&dev->frontends.felist);
printk(KERN_INFO "%s() allocating 1 frontend\n", __func__);
fe0 = videobuf_dvb_alloc_frontend(&dev->frontends, 1);
fe0 = vb2_dvb_alloc_frontend(&dev->frontends, 1);
if (!fe0) {
printk(KERN_ERR "%s() failed to alloc\n", __func__);
return -ENOMEM;
}
/* init struct videobuf_dvb */
/* init struct vb2_dvb */
dev->ts.nr_bufs = 32;
dev->ts.nr_packets = 32*4;
fe0->dvb.name = dev->name;
videobuf_queue_sg_init(&fe0->dvb.dvbq, &saa7134_ts_qops,
&dev->pci->dev, &dev->slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_ALTERNATE,
sizeof(struct saa7134_buf),
&dev->ts_q, NULL);
q = &fe0->dvb.dvbq;
q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
q->io_modes = VB2_MMAP | VB2_READ;
q->drv_priv = &dev->ts_q;
q->ops = &saa7134_ts_qops;
q->mem_ops = &vb2_dma_sg_memops;
q->buf_struct_size = sizeof(struct saa7134_buf);
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
q->lock = &dev->lock;
ret = vb2_queue_init(q);
if (ret) {
vb2_dvb_dealloc_frontends(&dev->frontends);
return ret;
}
switch (dev->board) {
case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL:
@ -1876,7 +1885,7 @@ static int dvb_init(struct saa7134_dev *dev)
fe0->dvb.frontend->callback = saa7134_tuner_callback;
/* register everything else */
ret = videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev,
ret = vb2_dvb_register_bus(&dev->frontends, THIS_MODULE, dev,
&dev->pci->dev, adapter_nr, 0);
/* this sequence is necessary to make the tda1004x load its firmware
@ -1893,16 +1902,17 @@ static int dvb_init(struct saa7134_dev *dev)
return ret;
detach_frontend:
videobuf_dvb_dealloc_frontends(&dev->frontends);
vb2_dvb_dealloc_frontends(&dev->frontends);
vb2_queue_release(&fe0->dvb.dvbq);
return -EINVAL;
}
static int dvb_fini(struct saa7134_dev *dev)
{
struct videobuf_dvb_frontend *fe0;
struct vb2_dvb_frontend *fe0;
/* Get the first frontend */
fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
fe0 = vb2_dvb_get_frontend(&dev->frontends, 1);
if (!fe0)
return -EINVAL;
@ -1933,7 +1943,8 @@ static int dvb_fini(struct saa7134_dev *dev)
}
}
}
videobuf_dvb_unregister_bus(&dev->frontends);
vb2_dvb_unregister_bus(&dev->frontends);
vb2_queue_release(&fe0->dvb.dvbq);
return 0;
}

View File

@ -48,11 +48,16 @@ MODULE_PARM_DESC(debug,"enable debug messages");
/* ------------------------------------------------------------------ */
static void ts_reset_encoder(struct saa7134_dev* dev);
static int ts_init_encoder(struct saa7134_dev* dev)
static int start_streaming(struct vb2_queue *vq, unsigned int count)
{
struct saa7134_dmaqueue *dmaq = vq->drv_priv;
struct saa7134_dev *dev = dmaq->dev;
u32 leading_null_bytes = 0;
int err;
err = saa7134_ts_start_streaming(vq, count);
if (err)
return err;
/* If more cards start to need this, then this
should probably be added to the card definitions. */
@ -63,110 +68,44 @@ static int ts_init_encoder(struct saa7134_dev* dev)
leading_null_bytes = 1;
break;
}
ts_reset_encoder(dev);
saa_call_all(dev, core, init, leading_null_bytes);
/* Unmute audio */
saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
saa_readb(SAA7134_AUDIO_MUTE_CTRL) & ~(1 << 6));
dev->empress_started = 1;
return 0;
}
static void ts_reset_encoder(struct saa7134_dev* dev)
static void stop_streaming(struct vb2_queue *vq)
{
if (!dev->empress_started)
return;
struct saa7134_dmaqueue *dmaq = vq->drv_priv;
struct saa7134_dev *dev = dmaq->dev;
saa7134_ts_stop_streaming(vq);
saa_writeb(SAA7134_SPECIAL_MODE, 0x00);
msleep(10);
msleep(20);
saa_writeb(SAA7134_SPECIAL_MODE, 0x01);
msleep(100);
/* Mute audio */
saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
saa_readb(SAA7134_AUDIO_MUTE_CTRL) | (1 << 6));
dev->empress_started = 0;
}
static struct vb2_ops saa7134_empress_qops = {
.queue_setup = saa7134_ts_queue_setup,
.buf_init = saa7134_ts_buffer_init,
.buf_prepare = saa7134_ts_buffer_prepare,
.buf_finish = saa7134_ts_buffer_finish,
.buf_queue = saa7134_vb2_buffer_queue,
.wait_prepare = vb2_ops_wait_prepare,
.wait_finish = vb2_ops_wait_finish,
.start_streaming = start_streaming,
.stop_streaming = stop_streaming,
};
/* ------------------------------------------------------------------ */
static int ts_open(struct file *file)
{
struct video_device *vdev = video_devdata(file);
struct saa7134_dev *dev = video_drvdata(file);
struct saa7134_fh *fh;
/* allocate + initialize per filehandle data */
fh = kzalloc(sizeof(*fh), GFP_KERNEL);
if (NULL == fh)
return -ENOMEM;
v4l2_fh_init(&fh->fh, vdev);
file->private_data = fh;
fh->is_empress = true;
v4l2_fh_add(&fh->fh);
/* Unmute audio */
saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
saa_readb(SAA7134_AUDIO_MUTE_CTRL) & ~(1 << 6));
return 0;
}
static int ts_release(struct file *file)
{
struct saa7134_dev *dev = video_drvdata(file);
struct saa7134_fh *fh = file->private_data;
if (res_check(fh, RESOURCE_EMPRESS)) {
videobuf_stop(&dev->empress_vbq);
videobuf_mmap_free(&dev->empress_vbq);
/* stop the encoder */
ts_reset_encoder(dev);
/* Mute audio */
saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
saa_readb(SAA7134_AUDIO_MUTE_CTRL) | (1 << 6));
}
v4l2_fh_del(&fh->fh);
v4l2_fh_exit(&fh->fh);
return 0;
}
static ssize_t
ts_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
{
struct saa7134_dev *dev = video_drvdata(file);
if (res_locked(dev, RESOURCE_EMPRESS))
return -EBUSY;
if (!dev->empress_started)
ts_init_encoder(dev);
return videobuf_read_stream(&dev->empress_vbq,
data, count, ppos, 0,
file->f_flags & O_NONBLOCK);
}
static unsigned int
ts_poll(struct file *file, struct poll_table_struct *wait)
{
unsigned long req_events = poll_requested_events(wait);
struct saa7134_dev *dev = video_drvdata(file);
struct saa7134_fh *fh = file->private_data;
unsigned int rc = 0;
if (v4l2_event_pending(&fh->fh))
rc = POLLPRI;
else if (req_events & POLLPRI)
poll_wait(file, &fh->fh.wait, wait);
return rc | videobuf_poll_stream(file, &dev->empress_vbq, wait);
}
static int
ts_mmap(struct file *file, struct vm_area_struct * vma)
{
struct saa7134_dev *dev = video_drvdata(file);
return videobuf_mmap_mapper(&dev->empress_vbq, vma);
}
static int empress_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
@ -235,11 +174,11 @@ static int empress_try_fmt_vid_cap(struct file *file, void *priv,
static const struct v4l2_file_operations ts_fops =
{
.owner = THIS_MODULE,
.open = ts_open,
.release = ts_release,
.read = ts_read,
.poll = ts_poll,
.mmap = ts_mmap,
.open = v4l2_fh_open,
.release = vb2_fop_release,
.read = vb2_fop_read,
.poll = vb2_fop_poll,
.mmap = vb2_fop_mmap,
.ioctl = video_ioctl2,
};
@ -249,12 +188,12 @@ static const struct v4l2_ioctl_ops ts_ioctl_ops = {
.vidioc_try_fmt_vid_cap = empress_try_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = empress_s_fmt_vid_cap,
.vidioc_g_fmt_vid_cap = empress_g_fmt_vid_cap,
.vidioc_reqbufs = saa7134_reqbufs,
.vidioc_querybuf = saa7134_querybuf,
.vidioc_qbuf = saa7134_qbuf,
.vidioc_dqbuf = saa7134_dqbuf,
.vidioc_streamon = saa7134_streamon,
.vidioc_streamoff = saa7134_streamoff,
.vidioc_reqbufs = vb2_ioctl_reqbufs,
.vidioc_querybuf = vb2_ioctl_querybuf,
.vidioc_qbuf = vb2_ioctl_qbuf,
.vidioc_dqbuf = vb2_ioctl_dqbuf,
.vidioc_streamon = vb2_ioctl_streamon,
.vidioc_streamoff = vb2_ioctl_streamoff,
.vidioc_g_frequency = saa7134_g_frequency,
.vidioc_s_frequency = saa7134_s_frequency,
.vidioc_g_tuner = saa7134_g_tuner,
@ -317,6 +256,7 @@ static bool empress_ctrl_filter(const struct v4l2_ctrl *ctrl)
static int empress_init(struct saa7134_dev *dev)
{
struct v4l2_ctrl_handler *hdl = &dev->empress_ctrl_handler;
struct vb2_queue *q;
int err;
dprintk("%s: %s\n",dev->name,__func__);
@ -326,6 +266,7 @@ static int empress_init(struct saa7134_dev *dev)
*(dev->empress_dev) = saa7134_empress_template;
dev->empress_dev->v4l2_dev = &dev->v4l2_dev;
dev->empress_dev->release = video_device_release;
dev->empress_dev->lock = &dev->lock;
snprintf(dev->empress_dev->name, sizeof(dev->empress_dev->name),
"%s empress (%s)", dev->name,
saa7134_boards[dev->board].name);
@ -342,6 +283,26 @@ static int empress_init(struct saa7134_dev *dev)
INIT_WORK(&dev->empress_workqueue, empress_signal_update);
q = &dev->empress_vbq;
q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
/*
* Do not add VB2_USERPTR: the saa7134 DMA engine cannot handle
* transfers that do not start at the beginning of a page. A USERPTR
* can start anywhere in a page, so USERPTR support is a no-go.
*/
q->io_modes = VB2_MMAP | VB2_READ;
q->drv_priv = &dev->ts_q;
q->ops = &saa7134_empress_qops;
q->gfp_flags = GFP_DMA32;
q->mem_ops = &vb2_dma_sg_memops;
q->buf_struct_size = sizeof(struct saa7134_buf);
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
q->lock = &dev->lock;
err = vb2_queue_init(q);
if (err)
return err;
dev->empress_dev->queue = q;
video_set_drvdata(dev->empress_dev, dev);
err = video_register_device(dev->empress_dev,VFL_TYPE_GRABBER,
empress_nr[dev->nr]);
@ -355,13 +316,6 @@ static int empress_init(struct saa7134_dev *dev)
printk(KERN_INFO "%s: registered device %s [mpeg]\n",
dev->name, video_device_node_name(dev->empress_dev));
videobuf_queue_sg_init(&dev->empress_vbq, &saa7134_ts_qops,
&dev->pci->dev, &dev->slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_ALTERNATE,
sizeof(struct saa7134_buf),
&dev->ts_q, NULL);
empress_signal_update(&dev->empress_workqueue);
return 0;
}
@ -374,6 +328,7 @@ static int empress_fini(struct saa7134_dev *dev)
return 0;
flush_work(&dev->empress_workqueue);
video_unregister_device(dev->empress_dev);
vb2_queue_release(&dev->empress_vbq);
v4l2_ctrl_handler_free(&dev->empress_ctrl_handler);
dev->empress_dev = NULL;
return 0;

View File

@ -39,26 +39,29 @@ MODULE_PARM_DESC(ts_debug,"enable debug messages [ts]");
printk(KERN_DEBUG "%s/ts: " fmt, dev->name , ## arg)
/* ------------------------------------------------------------------ */
static int buffer_activate(struct saa7134_dev *dev,
struct saa7134_buf *buf,
struct saa7134_buf *next)
{
dprintk("buffer_activate [%p]",buf);
buf->vb.state = VIDEOBUF_ACTIVE;
buf->top_seen = 0;
if (!dev->ts_started)
dev->ts_field = V4L2_FIELD_TOP;
if (NULL == next)
next = buf;
if (V4L2_FIELD_TOP == buf->vb.field) {
if (V4L2_FIELD_TOP == dev->ts_field) {
dprintk("- [top] buf=%p next=%p\n",buf,next);
saa_writel(SAA7134_RS_BA1(5),saa7134_buffer_base(buf));
saa_writel(SAA7134_RS_BA2(5),saa7134_buffer_base(next));
dev->ts_field = V4L2_FIELD_BOTTOM;
} else {
dprintk("- [bottom] buf=%p next=%p\n",buf,next);
saa_writel(SAA7134_RS_BA1(5),saa7134_buffer_base(next));
saa_writel(SAA7134_RS_BA2(5),saa7134_buffer_base(buf));
dev->ts_field = V4L2_FIELD_TOP;
}
/* start DMA */
@ -72,99 +75,123 @@ static int buffer_activate(struct saa7134_dev *dev,
return 0;
}
static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
enum v4l2_field field)
int saa7134_ts_buffer_init(struct vb2_buffer *vb2)
{
struct saa7134_dmaqueue *dmaq = q->priv_data;
struct saa7134_dev *dev = dmaq->dev;
struct saa7134_buf *buf = container_of(vb, struct saa7134_buf, vb);
unsigned int lines, llength, size;
int err;
struct saa7134_dmaqueue *dmaq = vb2->vb2_queue->drv_priv;
struct saa7134_buf *buf = container_of(vb2, struct saa7134_buf, vb2);
dprintk("buffer_prepare [%p,%s]\n", buf, v4l2_field_names[field]);
dmaq->curr = NULL;
buf->activate = buffer_activate;
return 0;
}
EXPORT_SYMBOL_GPL(saa7134_ts_buffer_init);
int saa7134_ts_buffer_prepare(struct vb2_buffer *vb2)
{
struct saa7134_dmaqueue *dmaq = vb2->vb2_queue->drv_priv;
struct saa7134_dev *dev = dmaq->dev;
struct saa7134_buf *buf = container_of(vb2, struct saa7134_buf, vb2);
struct sg_table *dma = vb2_dma_sg_plane_desc(vb2, 0);
unsigned int lines, llength, size;
int ret;
dprintk("buffer_prepare [%p]\n", buf);
llength = TS_PACKET_SIZE;
lines = dev->ts.nr_packets;
size = lines * llength;
if (0 != buf->vb.baddr && buf->vb.bsize < size)
if (vb2_plane_size(vb2, 0) < size)
return -EINVAL;
if (buf->vb.size != size) {
saa7134_dma_free(q,buf);
}
vb2_set_plane_payload(vb2, 0, size);
vb2->v4l2_buf.field = dev->field;
if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
dprintk("buffer_prepare: needs_init\n");
buf->vb.width = llength;
buf->vb.height = lines;
buf->vb.size = size;
err = videobuf_iolock(q,&buf->vb,NULL);
if (err)
goto oops;
err = saa7134_pgtable_build(dev->pci, &dmaq->pt,
dma->sglist,
dma->sglen,
saa7134_buffer_startpage(buf));
if (err)
goto oops;
}
buf->vb.state = VIDEOBUF_PREPARED;
buf->activate = buffer_activate;
buf->vb.field = field;
return 0;
oops:
saa7134_dma_free(q,buf);
return err;
ret = dma_map_sg(&dev->pci->dev, dma->sgl, dma->nents, DMA_FROM_DEVICE);
if (!ret)
return -EIO;
return saa7134_pgtable_build(dev->pci, &dmaq->pt, dma->sgl, dma->nents,
saa7134_buffer_startpage(buf));
}
EXPORT_SYMBOL_GPL(saa7134_ts_buffer_prepare);
static int
buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
void saa7134_ts_buffer_finish(struct vb2_buffer *vb2)
{
struct saa7134_dmaqueue *dmaq = q->priv_data;
struct saa7134_dmaqueue *dmaq = vb2->vb2_queue->drv_priv;
struct saa7134_dev *dev = dmaq->dev;
struct saa7134_buf *buf = container_of(vb2, struct saa7134_buf, vb2);
struct sg_table *dma = vb2_dma_sg_plane_desc(&buf->vb2, 0);
*size = TS_PACKET_SIZE * dev->ts.nr_packets;
if (0 == *count)
*count = dev->ts.nr_bufs;
*count = saa7134_buffer_count(*size,*count);
dma_unmap_sg(&dev->pci->dev, dma->sgl, dma->nents, DMA_FROM_DEVICE);
}
EXPORT_SYMBOL_GPL(saa7134_ts_buffer_finish);
int saa7134_ts_queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
{
struct saa7134_dmaqueue *dmaq = q->drv_priv;
struct saa7134_dev *dev = dmaq->dev;
int size = TS_PACKET_SIZE * dev->ts.nr_packets;
if (0 == *nbuffers)
*nbuffers = dev->ts.nr_bufs;
*nbuffers = saa7134_buffer_count(size, *nbuffers);
if (*nbuffers < 3)
*nbuffers = 3;
*nplanes = 1;
sizes[0] = size;
return 0;
}
EXPORT_SYMBOL_GPL(saa7134_ts_queue_setup);
static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
int saa7134_ts_start_streaming(struct vb2_queue *vq, unsigned int count)
{
struct saa7134_dmaqueue *dmaq = q->priv_data;
struct saa7134_dev *dev = dmaq->dev;
struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
saa7134_buffer_queue(dev,&dev->ts_q,buf);
}
static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
{
struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
struct saa7134_dmaqueue *dmaq = q->priv_data;
struct saa7134_dmaqueue *dmaq = vq->drv_priv;
struct saa7134_dev *dev = dmaq->dev;
if (dev->ts_started)
saa7134_ts_stop(dev);
/*
* Planar video capture and TS share the same DMA channel,
* so only one can be active at a time.
*/
if (vb2_is_busy(&dev->video_vbq) && dev->fmt->planar) {
struct saa7134_buf *buf, *tmp;
saa7134_dma_free(q,buf);
list_for_each_entry_safe(buf, tmp, &dmaq->queue, entry) {
list_del(&buf->entry);
vb2_buffer_done(&buf->vb2, VB2_BUF_STATE_QUEUED);
}
if (dmaq->curr) {
vb2_buffer_done(&dmaq->curr->vb2, VB2_BUF_STATE_QUEUED);
dmaq->curr = NULL;
}
return -EBUSY;
}
dmaq->seq_nr = 0;
return 0;
}
EXPORT_SYMBOL_GPL(saa7134_ts_start_streaming);
struct videobuf_queue_ops saa7134_ts_qops = {
.buf_setup = buffer_setup,
.buf_prepare = buffer_prepare,
.buf_queue = buffer_queue,
.buf_release = buffer_release,
void saa7134_ts_stop_streaming(struct vb2_queue *vq)
{
struct saa7134_dmaqueue *dmaq = vq->drv_priv;
struct saa7134_dev *dev = dmaq->dev;
saa7134_ts_stop(dev);
saa7134_stop_streaming(dev, dmaq);
}
EXPORT_SYMBOL_GPL(saa7134_ts_stop_streaming);
struct vb2_ops saa7134_ts_qops = {
.queue_setup = saa7134_ts_queue_setup,
.buf_init = saa7134_ts_buffer_init,
.buf_prepare = saa7134_ts_buffer_prepare,
.buf_finish = saa7134_ts_buffer_finish,
.buf_queue = saa7134_vb2_buffer_queue,
.wait_prepare = vb2_ops_wait_prepare,
.wait_finish = vb2_ops_wait_finish,
.stop_streaming = saa7134_ts_stop_streaming,
};
EXPORT_SYMBOL_GPL(saa7134_ts_qops);
@ -229,7 +256,8 @@ int saa7134_ts_stop(struct saa7134_dev *dev)
{
dprintk("TS stop\n");
BUG_ON(!dev->ts_started);
if (!dev->ts_started)
return 0;
/* Stop TS stream */
switch (saa7134_boards[dev->board].ts_type) {
@ -250,7 +278,8 @@ int saa7134_ts_start(struct saa7134_dev *dev)
{
dprintk("TS start\n");
BUG_ON(dev->ts_started);
if (WARN_ON(dev->ts_started))
return 0;
/* dma: setup channel 5 (= TS) */
saa_writeb(SAA7134_TS_DMA0, (dev->ts.nr_packets - 1) & 0xff);
@ -306,15 +335,15 @@ void saa7134_irq_ts_done(struct saa7134_dev *dev, unsigned long status)
spin_lock(&dev->slock);
if (dev->ts_q.curr) {
field = dev->ts_q.curr->vb.field;
if (field == V4L2_FIELD_TOP) {
field = dev->ts_field;
if (field != V4L2_FIELD_TOP) {
if ((status & 0x100000) != 0x000000)
goto done;
} else {
if ((status & 0x100000) != 0x100000)
goto done;
}
saa7134_buffer_finish(dev, &dev->ts_q, VIDEOBUF_DONE);
saa7134_buffer_finish(dev, &dev->ts_q, VB2_BUF_STATE_DONE);
}
saa7134_buffer_next(dev,&dev->ts_q);

View File

@ -81,10 +81,10 @@ static int buffer_activate(struct saa7134_dev *dev,
struct saa7134_buf *buf,
struct saa7134_buf *next)
{
struct saa7134_dmaqueue *dmaq = buf->vb2.vb2_queue->drv_priv;
unsigned long control, base;
dprintk("buffer_activate [%p]\n", buf);
buf->vb.state = VIDEOBUF_ACTIVE;
buf->top_seen = 0;
task_init(dev, buf, TASK_A);
@ -96,7 +96,7 @@ static int buffer_activate(struct saa7134_dev *dev,
base = saa7134_buffer_base(buf);
control = SAA7134_RS_CONTROL_BURST_16 |
SAA7134_RS_CONTROL_ME |
(dev->vbi_q.pt.dma >> 12);
(dmaq->pt.dma >> 12);
saa_writel(SAA7134_RS_BA1(2), base);
saa_writel(SAA7134_RS_BA2(2), base + dev->vbi_hlen * dev->vbi_vlen);
saa_writel(SAA7134_RS_PITCH(2), dev->vbi_hlen);
@ -108,93 +108,83 @@ static int buffer_activate(struct saa7134_dev *dev,
/* start DMA */
saa7134_set_dmabits(dev);
mod_timer(&dev->vbi_q.timeout, jiffies + BUFFER_TIMEOUT);
mod_timer(&dmaq->timeout, jiffies + BUFFER_TIMEOUT);
return 0;
}
static int buffer_prepare(struct videobuf_queue *q,
struct videobuf_buffer *vb,
enum v4l2_field field)
static int buffer_prepare(struct vb2_buffer *vb2)
{
struct saa7134_dmaqueue *dmaq = q->priv_data;
struct saa7134_dmaqueue *dmaq = vb2->vb2_queue->drv_priv;
struct saa7134_dev *dev = dmaq->dev;
struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
struct saa7134_buf *buf = container_of(vb2, struct saa7134_buf, vb2);
struct sg_table *dma = vb2_dma_sg_plane_desc(&buf->vb2, 0);
unsigned int size;
int err;
int ret;
size = dev->vbi_hlen * dev->vbi_vlen * 2;
if (0 != buf->vb.baddr && buf->vb.bsize < size)
if (vb2_plane_size(vb2, 0) < size)
return -EINVAL;
if (buf->vb.size != size)
saa7134_dma_free(q,buf);
vb2_set_plane_payload(vb2, 0, size);
if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
buf->vb.width = dev->vbi_hlen;
buf->vb.height = dev->vbi_vlen;
buf->vb.size = size;
err = videobuf_iolock(q,&buf->vb,NULL);
if (err)
goto oops;
err = saa7134_pgtable_build(dev->pci, &dmaq->pt,
dma->sglist,
dma->sglen,
saa7134_buffer_startpage(buf));
if (err)
goto oops;
}
buf->vb.state = VIDEOBUF_PREPARED;
buf->activate = buffer_activate;
buf->vb.field = field;
return 0;
oops:
saa7134_dma_free(q,buf);
return err;
ret = dma_map_sg(&dev->pci->dev, dma->sgl, dma->nents, DMA_FROM_DEVICE);
if (!ret)
return -EIO;
return saa7134_pgtable_build(dev->pci, &dmaq->pt, dma->sgl, dma->nents,
saa7134_buffer_startpage(buf));
}
static int
buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
static int queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
{
struct saa7134_dmaqueue *dmaq = q->priv_data;
struct saa7134_dmaqueue *dmaq = q->drv_priv;
struct saa7134_dev *dev = dmaq->dev;
unsigned int size;
dev->vbi_vlen = dev->tvnorm->vbi_v_stop_0 - dev->tvnorm->vbi_v_start_0 + 1;
if (dev->vbi_vlen > VBI_LINE_COUNT)
dev->vbi_vlen = VBI_LINE_COUNT;
dev->vbi_hlen = VBI_LINE_LENGTH;
*size = dev->vbi_hlen * dev->vbi_vlen * 2;
if (0 == *count)
*count = vbibufs;
*count = saa7134_buffer_count(*size,*count);
size = dev->vbi_hlen * dev->vbi_vlen * 2;
*nbuffers = saa7134_buffer_count(size, *nbuffers);
*nplanes = 1;
sizes[0] = size;
return 0;
}
static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
static int buffer_init(struct vb2_buffer *vb2)
{
struct saa7134_dmaqueue *dmaq = q->priv_data;
struct saa7134_dmaqueue *dmaq = vb2->vb2_queue->drv_priv;
struct saa7134_buf *buf = container_of(vb2, struct saa7134_buf, vb2);
dmaq->curr = NULL;
buf->activate = buffer_activate;
return 0;
}
static void buffer_finish(struct vb2_buffer *vb2)
{
struct saa7134_dmaqueue *dmaq = vb2->vb2_queue->drv_priv;
struct saa7134_dev *dev = dmaq->dev;
struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
struct saa7134_buf *buf = container_of(vb2, struct saa7134_buf, vb2);
struct sg_table *dma = vb2_dma_sg_plane_desc(&buf->vb2, 0);
saa7134_buffer_queue(dev,&dev->vbi_q,buf);
dma_unmap_sg(&dev->pci->dev, dma->sgl, dma->nents, DMA_FROM_DEVICE);
}
static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
{
struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
saa7134_dma_free(q,buf);
}
struct videobuf_queue_ops saa7134_vbi_qops = {
.buf_setup = buffer_setup,
.buf_prepare = buffer_prepare,
.buf_queue = buffer_queue,
.buf_release = buffer_release,
struct vb2_ops saa7134_vbi_qops = {
.queue_setup = queue_setup,
.buf_init = buffer_init,
.buf_prepare = buffer_prepare,
.buf_finish = buffer_finish,
.buf_queue = saa7134_vb2_buffer_queue,
.wait_prepare = vb2_ops_wait_prepare,
.wait_finish = vb2_ops_wait_finish,
.start_streaming = saa7134_vb2_start_streaming,
.stop_streaming = saa7134_vb2_stop_streaming,
};
/* ------------------------------------------------------------------ */
@ -224,7 +214,6 @@ void saa7134_irq_vbi_done(struct saa7134_dev *dev, unsigned long status)
{
spin_lock(&dev->slock);
if (dev->vbi_q.curr) {
dev->vbi_fieldcount++;
/* make sure we have seen both fields */
if ((status & 0x10) == 0x00) {
dev->vbi_q.curr->top_seen = 1;
@ -233,8 +222,7 @@ void saa7134_irq_vbi_done(struct saa7134_dev *dev, unsigned long status)
if (!dev->vbi_q.curr->top_seen)
goto done;
dev->vbi_q.curr->vb.field_count = dev->vbi_fieldcount;
saa7134_buffer_finish(dev, &dev->vbi_q, VIDEOBUF_DONE);
saa7134_buffer_finish(dev, &dev->vbi_q, VB2_BUF_STATE_DONE);
}
saa7134_buffer_next(dev, &dev->vbi_q);

View File

@ -381,42 +381,6 @@ static struct saa7134_format* format_by_fourcc(unsigned int fourcc)
return NULL;
}
/* ----------------------------------------------------------------------- */
/* resource management */
static int res_get(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bit)
{
if (fh->resources & bit)
/* have it already allocated */
return 1;
/* is it free? */
mutex_lock(&dev->lock);
if (dev->resources & bit) {
/* no, someone else uses it */
mutex_unlock(&dev->lock);
return 0;
}
/* it's free, grab it */
fh->resources |= bit;
dev->resources |= bit;
dprintk("res: get %d\n",bit);
mutex_unlock(&dev->lock);
return 1;
}
static
void res_free(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bits)
{
BUG_ON((fh->resources & bits) != bits);
mutex_lock(&dev->lock);
fh->resources &= ~bits;
dev->resources &= ~bits;
dprintk("res: put %d\n",bits);
mutex_unlock(&dev->lock);
}
/* ------------------------------------------------------------------ */
static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
@ -824,15 +788,15 @@ static int buffer_activate(struct saa7134_dev *dev,
struct saa7134_buf *buf,
struct saa7134_buf *next)
{
struct saa7134_dmaqueue *dmaq = buf->vb2.vb2_queue->drv_priv;
unsigned long base,control,bpl;
unsigned long bpl_uv,lines_uv,base2,base3,tmp; /* planar */
dprintk("buffer_activate buf=%p\n",buf);
buf->vb.state = VIDEOBUF_ACTIVE;
buf->top_seen = 0;
set_size(dev, TASK_A, buf->vb.width, buf->vb.height,
V4L2_FIELD_HAS_BOTH(buf->vb.field));
set_size(dev, TASK_A, dev->width, dev->height,
V4L2_FIELD_HAS_BOTH(dev->field));
if (dev->fmt->yuv)
saa_andorb(SAA7134_DATA_PATH(TASK_A), 0x3f, 0x03);
else
@ -842,17 +806,17 @@ static int buffer_activate(struct saa7134_dev *dev,
/* DMA: setup channel 0 (= Video Task A0) */
base = saa7134_buffer_base(buf);
if (dev->fmt->planar)
bpl = buf->vb.width;
bpl = dev->width;
else
bpl = (buf->vb.width * dev->fmt->depth) / 8;
bpl = (dev->width * dev->fmt->depth) / 8;
control = SAA7134_RS_CONTROL_BURST_16 |
SAA7134_RS_CONTROL_ME |
(dev->video_q.pt.dma >> 12);
(dmaq->pt.dma >> 12);
if (dev->fmt->bswap)
control |= SAA7134_RS_CONTROL_BSWAP;
if (dev->fmt->wswap)
control |= SAA7134_RS_CONTROL_WSWAP;
if (V4L2_FIELD_HAS_BOTH(buf->vb.field)) {
if (V4L2_FIELD_HAS_BOTH(dev->field)) {
/* interlaced */
saa_writel(SAA7134_RS_BA1(0),base);
saa_writel(SAA7134_RS_BA2(0),base+bpl);
@ -868,14 +832,14 @@ static int buffer_activate(struct saa7134_dev *dev,
if (dev->fmt->planar) {
/* DMA: setup channel 4+5 (= planar task A) */
bpl_uv = bpl >> dev->fmt->hshift;
lines_uv = buf->vb.height >> dev->fmt->vshift;
base2 = base + bpl * buf->vb.height;
lines_uv = dev->height >> dev->fmt->vshift;
base2 = base + bpl * dev->height;
base3 = base2 + bpl_uv * lines_uv;
if (dev->fmt->uvswap)
tmp = base2, base2 = base3, base3 = tmp;
dprintk("uv: bpl=%ld lines=%ld base2/3=%ld/%ld\n",
bpl_uv,lines_uv,base2,base3);
if (V4L2_FIELD_HAS_BOTH(buf->vb.field)) {
if (V4L2_FIELD_HAS_BOTH(dev->field)) {
/* interlaced */
saa_writel(SAA7134_RS_BA1(4),base2);
saa_writel(SAA7134_RS_BA2(4),base2+bpl_uv);
@ -898,23 +862,61 @@ static int buffer_activate(struct saa7134_dev *dev,
/* start DMA */
saa7134_set_dmabits(dev);
mod_timer(&dev->video_q.timeout, jiffies + BUFFER_TIMEOUT);
mod_timer(&dmaq->timeout, jiffies + BUFFER_TIMEOUT);
return 0;
}
static int buffer_prepare(struct videobuf_queue *q,
struct videobuf_buffer *vb,
enum v4l2_field field)
static int buffer_init(struct vb2_buffer *vb2)
{
struct saa7134_dmaqueue *dmaq = q->priv_data;
struct saa7134_dev *dev = dmaq->dev;
struct saa7134_buf *buf = container_of(vb, struct saa7134_buf, vb);
unsigned int size;
int err;
struct saa7134_dmaqueue *dmaq = vb2->vb2_queue->drv_priv;
struct saa7134_buf *buf = container_of(vb2, struct saa7134_buf, vb2);
/* sanity checks */
if (NULL == dev->fmt)
dmaq->curr = NULL;
buf->activate = buffer_activate;
return 0;
}
static int buffer_prepare(struct vb2_buffer *vb2)
{
struct saa7134_dmaqueue *dmaq = vb2->vb2_queue->drv_priv;
struct saa7134_dev *dev = dmaq->dev;
struct saa7134_buf *buf = container_of(vb2, struct saa7134_buf, vb2);
struct sg_table *dma = vb2_dma_sg_plane_desc(&buf->vb2, 0);
unsigned int size;
int ret;
size = (dev->width * dev->height * dev->fmt->depth) >> 3;
if (vb2_plane_size(vb2, 0) < size)
return -EINVAL;
vb2_set_plane_payload(vb2, 0, size);
vb2->v4l2_buf.field = dev->field;
ret = dma_map_sg(&dev->pci->dev, dma->sgl, dma->nents, DMA_FROM_DEVICE);
if (!ret)
return -EIO;
return saa7134_pgtable_build(dev->pci, &dmaq->pt, dma->sgl, dma->nents,
saa7134_buffer_startpage(buf));
}
static void buffer_finish(struct vb2_buffer *vb2)
{
struct saa7134_dmaqueue *dmaq = vb2->vb2_queue->drv_priv;
struct saa7134_dev *dev = dmaq->dev;
struct saa7134_buf *buf = container_of(vb2, struct saa7134_buf, vb2);
struct sg_table *dma = vb2_dma_sg_plane_desc(&buf->vb2, 0);
dma_unmap_sg(&dev->pci->dev, dma->sgl, dma->nents, DMA_FROM_DEVICE);
}
static int queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
{
struct saa7134_dmaqueue *dmaq = q->drv_priv;
struct saa7134_dev *dev = dmaq->dev;
int size = dev->fmt->depth * dev->width * dev->height >> 3;
if (dev->width < 48 ||
dev->height < 32 ||
dev->width/4 > dev->crop_current.width ||
@ -922,82 +924,88 @@ static int buffer_prepare(struct videobuf_queue *q,
dev->width > dev->crop_bounds.width ||
dev->height > dev->crop_bounds.height)
return -EINVAL;
size = (dev->width * dev->height * dev->fmt->depth) >> 3;
if (0 != buf->vb.baddr && buf->vb.bsize < size)
return -EINVAL;
dprintk("buffer_prepare [%d,size=%dx%d,bytes=%d,fields=%s,%s]\n",
vb->i, dev->width, dev->height, size, v4l2_field_names[field],
dev->fmt->name);
if (buf->vb.width != dev->width ||
buf->vb.height != dev->height ||
buf->vb.size != size ||
buf->vb.field != field) {
saa7134_dma_free(q,buf);
}
if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
buf->vb.width = dev->width;
buf->vb.height = dev->height;
buf->vb.size = size;
buf->vb.field = field;
dev->video_q.curr = NULL;
err = videobuf_iolock(q,&buf->vb,&dev->ovbuf);
if (err)
goto oops;
err = saa7134_pgtable_build(dev->pci, &dmaq->pt,
dma->sglist,
dma->sglen,
saa7134_buffer_startpage(buf));
if (err)
goto oops;
}
buf->vb.state = VIDEOBUF_PREPARED;
buf->activate = buffer_activate;
return 0;
oops:
saa7134_dma_free(q,buf);
return err;
}
static int
buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
{
struct saa7134_dmaqueue *dmaq = q->priv_data;
struct saa7134_dev *dev = dmaq->dev;
*size = dev->fmt->depth * dev->width * dev->height >> 3;
if (0 == *count)
*count = gbuffers;
*count = saa7134_buffer_count(*size,*count);
*nbuffers = saa7134_buffer_count(size, *nbuffers);
*nplanes = 1;
sizes[0] = size;
return 0;
}
static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
/*
* move buffer to hardware queue
*/
void saa7134_vb2_buffer_queue(struct vb2_buffer *vb)
{
struct saa7134_dmaqueue *dmaq = q->priv_data;
struct saa7134_dmaqueue *dmaq = vb->vb2_queue->drv_priv;
struct saa7134_dev *dev = dmaq->dev;
struct saa7134_buf *buf = container_of(vb, struct saa7134_buf, vb);
struct saa7134_buf *buf = container_of(vb, struct saa7134_buf, vb2);
saa7134_buffer_queue(dev, &dev->video_q, buf);
saa7134_buffer_queue(dev, dmaq, buf);
}
EXPORT_SYMBOL_GPL(saa7134_vb2_buffer_queue);
static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
int saa7134_vb2_start_streaming(struct vb2_queue *vq, unsigned int count)
{
struct saa7134_buf *buf = container_of(vb, struct saa7134_buf, vb);
struct saa7134_dmaqueue *dmaq = vq->drv_priv;
struct saa7134_dev *dev = dmaq->dev;
saa7134_dma_free(q,buf);
/*
* Planar video capture and TS share the same DMA channel,
* so only one can be active at a time.
*/
if (card_is_empress(dev) && vb2_is_busy(&dev->empress_vbq) &&
dmaq == &dev->video_q && dev->fmt->planar) {
struct saa7134_buf *buf, *tmp;
list_for_each_entry_safe(buf, tmp, &dmaq->queue, entry) {
list_del(&buf->entry);
vb2_buffer_done(&buf->vb2, VB2_BUF_STATE_QUEUED);
}
if (dmaq->curr) {
vb2_buffer_done(&dmaq->curr->vb2, VB2_BUF_STATE_QUEUED);
dmaq->curr = NULL;
}
return -EBUSY;
}
/* The SAA7134 has a 1K FIFO; the datasheet suggests that when
* configured conservatively, there's 22 usec of buffering for video.
* We therefore request a DMA latency of 20 usec, giving us 2 usec of
* margin in case the FIFO is configured differently to the datasheet.
* Unfortunately, I lack register-level documentation to check the
* Linux FIFO setup and confirm the perfect value.
*/
if ((dmaq == &dev->video_q && !vb2_is_streaming(&dev->vbi_vbq)) ||
(dmaq == &dev->vbi_q && !vb2_is_streaming(&dev->video_vbq)))
pm_qos_add_request(&dev->qos_request,
PM_QOS_CPU_DMA_LATENCY, 20);
dmaq->seq_nr = 0;
return 0;
}
static struct videobuf_queue_ops video_qops = {
.buf_setup = buffer_setup,
.buf_prepare = buffer_prepare,
.buf_queue = buffer_queue,
.buf_release = buffer_release,
void saa7134_vb2_stop_streaming(struct vb2_queue *vq)
{
struct saa7134_dmaqueue *dmaq = vq->drv_priv;
struct saa7134_dev *dev = dmaq->dev;
saa7134_stop_streaming(dev, dmaq);
if ((dmaq == &dev->video_q && !vb2_is_streaming(&dev->vbi_vbq)) ||
(dmaq == &dev->vbi_q && !vb2_is_streaming(&dev->video_vbq)))
pm_qos_remove_request(&dev->qos_request);
}
static struct vb2_ops vb2_qops = {
.queue_setup = queue_setup,
.buf_init = buffer_init,
.buf_prepare = buffer_prepare,
.buf_finish = buffer_finish,
.buf_queue = saa7134_vb2_buffer_queue,
.wait_prepare = vb2_ops_wait_prepare,
.wait_finish = vb2_ops_wait_finish,
.start_streaming = saa7134_vb2_start_streaming,
.stop_streaming = saa7134_vb2_stop_streaming,
};
/* ------------------------------------------------------------------ */
@ -1075,7 +1083,7 @@ static int saa7134_s_ctrl(struct v4l2_ctrl *ctrl)
default:
return -EINVAL;
}
if (restart_overlay && res_locked(dev, RESOURCE_OVERLAY)) {
if (restart_overlay && dev->overlay_owner) {
spin_lock_irqsave(&dev->slock, flags);
stop_preview(dev);
start_preview(dev);
@ -1086,55 +1094,21 @@ static int saa7134_s_ctrl(struct v4l2_ctrl *ctrl)
/* ------------------------------------------------------------------ */
static struct videobuf_queue *saa7134_queue(struct file *file)
static inline struct vb2_queue *saa7134_queue(struct file *file)
{
struct video_device *vdev = video_devdata(file);
struct saa7134_dev *dev = video_drvdata(file);
struct saa7134_fh *fh = file->private_data;
struct videobuf_queue *q = NULL;
switch (vdev->vfl_type) {
case VFL_TYPE_GRABBER:
q = fh->is_empress ? &dev->empress_vbq : &dev->video_vbq;
break;
case VFL_TYPE_VBI:
q = &dev->vbi_vbq;
break;
default:
BUG();
}
return q;
}
static int saa7134_resource(struct file *file)
{
struct video_device *vdev = video_devdata(file);
struct saa7134_fh *fh = file->private_data;
if (vdev->vfl_type == VFL_TYPE_GRABBER)
return fh->is_empress ? RESOURCE_EMPRESS : RESOURCE_VIDEO;
if (vdev->vfl_type == VFL_TYPE_VBI)
return RESOURCE_VBI;
BUG();
return 0;
return video_devdata(file)->queue;
}
static int video_open(struct file *file)
{
struct video_device *vdev = video_devdata(file);
struct saa7134_dev *dev = video_drvdata(file);
struct saa7134_fh *fh;
int ret = v4l2_fh_open(file);
/* allocate + initialize per filehandle data */
fh = kzalloc(sizeof(*fh),GFP_KERNEL);
if (NULL == fh)
return -ENOMEM;
v4l2_fh_init(&fh->fh, vdev);
file->private_data = fh;
if (ret < 0)
return ret;
mutex_lock(&dev->lock);
if (vdev->vfl_type == VFL_TYPE_RADIO) {
/* switch to radio mode */
saa7134_tvaudio_setinput(dev, &card(dev).radio);
@ -1143,127 +1117,34 @@ static int video_open(struct file *file)
/* switch to video/vbi mode */
video_mux(dev, dev->ctl_input);
}
v4l2_fh_add(&fh->fh);
mutex_unlock(&dev->lock);
return 0;
}
static ssize_t
video_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
{
struct video_device *vdev = video_devdata(file);
struct saa7134_dev *dev = video_drvdata(file);
struct saa7134_fh *fh = file->private_data;
switch (vdev->vfl_type) {
case VFL_TYPE_GRABBER:
if (res_locked(dev, RESOURCE_VIDEO))
return -EBUSY;
return videobuf_read_one(saa7134_queue(file),
data, count, ppos,
file->f_flags & O_NONBLOCK);
case VFL_TYPE_VBI:
if (!res_get(dev, fh, RESOURCE_VBI))
return -EBUSY;
return videobuf_read_stream(saa7134_queue(file),
data, count, ppos, 1,
file->f_flags & O_NONBLOCK);
break;
default:
BUG();
return 0;
}
}
static unsigned int
video_poll(struct file *file, struct poll_table_struct *wait)
{
unsigned long req_events = poll_requested_events(wait);
struct video_device *vdev = video_devdata(file);
struct saa7134_dev *dev = video_drvdata(file);
struct saa7134_fh *fh = file->private_data;
struct videobuf_buffer *buf = NULL;
struct videobuf_queue *q = &dev->video_vbq;
unsigned int rc = 0;
if (v4l2_event_pending(&fh->fh))
rc = POLLPRI;
else if (req_events & POLLPRI)
poll_wait(file, &fh->fh.wait, wait);
if (vdev->vfl_type == VFL_TYPE_VBI)
return rc | videobuf_poll_stream(file, &dev->vbi_vbq, wait);
if (res_check(fh, RESOURCE_VIDEO)) {
mutex_lock(&q->vb_lock);
if (!list_empty(&q->stream))
buf = list_entry(q->stream.next, struct videobuf_buffer, stream);
} else {
mutex_lock(&q->vb_lock);
if (UNSET == q->read_off) {
/* need to capture a new frame */
if (res_locked(dev, RESOURCE_VIDEO))
goto err;
if (0 != q->ops->buf_prepare(q, q->read_buf, q->field))
goto err;
q->ops->buf_queue(q, q->read_buf);
q->read_off = 0;
}
buf = q->read_buf;
}
if (!buf)
goto err;
poll_wait(file, &buf->done, wait);
if (buf->state == VIDEOBUF_DONE || buf->state == VIDEOBUF_ERROR)
rc |= POLLIN | POLLRDNORM;
mutex_unlock(&q->vb_lock);
return rc;
err:
mutex_unlock(&q->vb_lock);
return rc | POLLERR;
}
static int video_release(struct file *file)
{
struct video_device *vdev = video_devdata(file);
struct saa7134_dev *dev = video_drvdata(file);
struct saa7134_fh *fh = file->private_data;
struct v4l2_fh *fh = file->private_data;
struct saa6588_command cmd;
unsigned long flags;
mutex_lock(&dev->lock);
saa7134_tvaudio_close(dev);
/* turn off overlay */
if (res_check(fh, RESOURCE_OVERLAY)) {
if (fh == dev->overlay_owner) {
spin_lock_irqsave(&dev->slock,flags);
stop_preview(dev);
spin_unlock_irqrestore(&dev->slock,flags);
res_free(dev, fh, RESOURCE_OVERLAY);
dev->overlay_owner = NULL;
}
/* stop video capture */
if (res_check(fh, RESOURCE_VIDEO)) {
pm_qos_remove_request(&dev->qos_request);
videobuf_streamoff(&dev->video_vbq);
res_free(dev, fh, RESOURCE_VIDEO);
videobuf_mmap_free(&dev->video_vbq);
INIT_LIST_HEAD(&dev->video_vbq.stream);
}
if (dev->video_vbq.read_buf) {
buffer_release(&dev->video_vbq, dev->video_vbq.read_buf);
kfree(dev->video_vbq.read_buf);
}
/* stop vbi capture */
if (res_check(fh, RESOURCE_VBI)) {
videobuf_stop(&dev->vbi_vbq);
res_free(dev, fh, RESOURCE_VBI);
videobuf_mmap_free(&dev->vbi_vbq);
INIT_LIST_HEAD(&dev->vbi_vbq.stream);
}
if (vdev->vfl_type == VFL_TYPE_RADIO)
v4l2_fh_release(file);
else
_vb2_fop_release(file, NULL);
/* ts-capture will not work in planar mode, so turn it off Hac: 04.05*/
saa_andorb(SAA7134_OFMT_VIDEO_A, 0x1f, 0);
@ -1274,19 +1155,11 @@ static int video_release(struct file *file)
saa_call_all(dev, core, s_power, 0);
if (vdev->vfl_type == VFL_TYPE_RADIO)
saa_call_all(dev, core, ioctl, SAA6588_CMD_CLOSE, &cmd);
mutex_unlock(&dev->lock);
v4l2_fh_del(&fh->fh);
v4l2_fh_exit(&fh->fh);
file->private_data = NULL;
kfree(fh);
return 0;
}
static int video_mmap(struct file *file, struct vm_area_struct * vma)
{
return videobuf_mmap_mapper(saa7134_queue(file), vma);
}
static ssize_t radio_read(struct file *file, char __user *data,
size_t count, loff_t *ppos)
{
@ -1299,7 +1172,9 @@ static ssize_t radio_read(struct file *file, char __user *data,
cmd.instance = file;
cmd.result = -ENODEV;
mutex_lock(&dev->lock);
saa_call_all(dev, core, ioctl, SAA6588_CMD_READ, &cmd);
mutex_unlock(&dev->lock);
return cmd.result;
}
@ -1313,7 +1188,9 @@ static unsigned int radio_poll(struct file *file, poll_table *wait)
cmd.instance = file;
cmd.event_list = wait;
cmd.result = 0;
mutex_lock(&dev->lock);
saa_call_all(dev, core, ioctl, SAA6588_CMD_POLL, &cmd);
mutex_unlock(&dev->lock);
return rc | cmd.result;
}
@ -1347,7 +1224,7 @@ static int saa7134_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->video_vbq.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;
@ -1371,7 +1248,6 @@ static int saa7134_g_fmt_vid_overlay(struct file *file, void *priv,
printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
return -EINVAL;
}
mutex_lock(&dev->lock);
f->fmt.win = dev->win;
f->fmt.win.clips = clips;
if (clips == NULL)
@ -1385,7 +1261,6 @@ static int saa7134_g_fmt_vid_overlay(struct file *file, void *priv,
sizeof(struct v4l2_rect)))
err = -EFAULT;
}
mutex_unlock(&dev->lock);
return err;
}
@ -1469,7 +1344,7 @@ static int saa7134_s_fmt_vid_cap(struct file *file, void *priv,
dev->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
dev->width = f->fmt.pix.width;
dev->height = f->fmt.pix.height;
dev->video_vbq.field = f->fmt.pix.field;
dev->field = f->fmt.pix.field;
return 0;
}
@ -1490,25 +1365,20 @@ static int saa7134_s_fmt_vid_overlay(struct file *file, void *priv,
if (0 != err)
return err;
mutex_lock(&dev->lock);
dev->win = f->fmt.win;
dev->nclips = f->fmt.win.clipcount;
if (copy_from_user(dev->clips, f->fmt.win.clips,
sizeof(struct v4l2_clip) * dev->nclips)) {
mutex_unlock(&dev->lock);
sizeof(struct v4l2_clip) * dev->nclips))
return -EFAULT;
}
if (res_check(priv, RESOURCE_OVERLAY)) {
if (priv == dev->overlay_owner) {
spin_lock_irqsave(&dev->slock, flags);
stop_preview(dev);
start_preview(dev);
spin_unlock_irqrestore(&dev->slock, flags);
}
mutex_unlock(&dev->lock);
return 0;
}
@ -1560,9 +1430,7 @@ int saa7134_s_input(struct file *file, void *priv, unsigned int i)
return -EINVAL;
if (NULL == card_in(dev, i).name)
return -EINVAL;
mutex_lock(&dev->lock);
video_mux(dev, i);
mutex_unlock(&dev->lock);
return 0;
}
EXPORT_SYMBOL_GPL(saa7134_s_input);
@ -1572,7 +1440,6 @@ int saa7134_querycap(struct file *file, void *priv,
{
struct saa7134_dev *dev = video_drvdata(file);
struct video_device *vdev = video_devdata(file);
struct saa7134_fh *fh = priv;
u32 radio_caps, video_caps, vbi_caps;
unsigned int tuner_type = dev->tuner_type;
@ -1591,7 +1458,7 @@ int saa7134_querycap(struct file *file, void *priv,
radio_caps |= V4L2_CAP_RDS_CAPTURE;
video_caps = V4L2_CAP_VIDEO_CAPTURE;
if (saa7134_no_overlay <= 0 && !fh->is_empress)
if (saa7134_no_overlay <= 0 && !is_empress(file))
video_caps |= V4L2_CAP_VIDEO_OVERLAY;
vbi_caps = V4L2_CAP_VBI_CAPTURE;
@ -1622,12 +1489,12 @@ EXPORT_SYMBOL_GPL(saa7134_querycap);
int saa7134_s_std(struct file *file, void *priv, v4l2_std_id id)
{
struct saa7134_dev *dev = video_drvdata(file);
struct saa7134_fh *fh = priv;
struct v4l2_fh *fh = priv;
unsigned long flags;
unsigned int i;
v4l2_std_id fixup;
if (fh->is_empress && res_locked(dev, RESOURCE_OVERLAY)) {
if (is_empress(file) && dev->overlay_owner) {
/* Don't change the std from the mpeg device
if overlay is active. */
return -EBUSY;
@ -1666,8 +1533,7 @@ int saa7134_s_std(struct file *file, void *priv, v4l2_std_id id)
id = tvnorms[i].id;
mutex_lock(&dev->lock);
if (!fh->is_empress && res_check(fh, RESOURCE_OVERLAY)) {
if (!is_empress(file) && fh == dev->overlay_owner) {
spin_lock_irqsave(&dev->slock, flags);
stop_preview(dev);
spin_unlock_irqrestore(&dev->slock, flags);
@ -1681,7 +1547,6 @@ int saa7134_s_std(struct file *file, void *priv, v4l2_std_id id)
set_tvnorm(dev, &tvnorms[i]);
saa7134_tvaudio_do_scan(dev);
mutex_unlock(&dev->lock);
return 0;
}
EXPORT_SYMBOL_GPL(saa7134_s_std);
@ -1768,9 +1633,9 @@ static int saa7134_s_crop(struct file *file, void *f, const struct v4l2_crop *cr
crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
return -EINVAL;
if (res_locked(dev, RESOURCE_OVERLAY))
if (dev->overlay_owner)
return -EBUSY;
if (res_locked(dev, RESOURCE_VIDEO))
if (vb2_is_streaming(&dev->video_vbq))
return -EBUSY;
*c = crop->c;
@ -1864,12 +1729,10 @@ int saa7134_s_frequency(struct file *file, void *priv,
if (0 != f->tuner)
return -EINVAL;
mutex_lock(&dev->lock);
saa_call_all(dev, tuner, s_frequency, f);
saa7134_tvaudio_do_scan(dev);
mutex_unlock(&dev->lock);
return 0;
}
EXPORT_SYMBOL_GPL(saa7134_s_frequency);
@ -1953,87 +1816,24 @@ static int saa7134_overlay(struct file *file, void *priv, unsigned int on)
return -EINVAL;
}
if (!res_get(dev, priv, RESOURCE_OVERLAY))
if (dev->overlay_owner && priv != dev->overlay_owner)
return -EBUSY;
dev->overlay_owner = priv;
spin_lock_irqsave(&dev->slock, flags);
start_preview(dev);
spin_unlock_irqrestore(&dev->slock, flags);
}
if (!on) {
if (!res_check(priv, RESOURCE_OVERLAY))
if (priv != dev->overlay_owner)
return -EINVAL;
spin_lock_irqsave(&dev->slock, flags);
stop_preview(dev);
spin_unlock_irqrestore(&dev->slock, flags);
res_free(dev, priv, RESOURCE_OVERLAY);
dev->overlay_owner = NULL;
}
return 0;
}
int saa7134_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *p)
{
return videobuf_reqbufs(saa7134_queue(file), p);
}
EXPORT_SYMBOL_GPL(saa7134_reqbufs);
int saa7134_querybuf(struct file *file, void *priv,
struct v4l2_buffer *b)
{
return videobuf_querybuf(saa7134_queue(file), b);
}
EXPORT_SYMBOL_GPL(saa7134_querybuf);
int saa7134_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
{
return videobuf_qbuf(saa7134_queue(file), b);
}
EXPORT_SYMBOL_GPL(saa7134_qbuf);
int saa7134_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
{
return videobuf_dqbuf(saa7134_queue(file), b,
file->f_flags & O_NONBLOCK);
}
EXPORT_SYMBOL_GPL(saa7134_dqbuf);
int saa7134_streamon(struct file *file, void *priv,
enum v4l2_buf_type type)
{
struct saa7134_dev *dev = video_drvdata(file);
int res = saa7134_resource(file);
if (!res_get(dev, priv, res))
return -EBUSY;
/* The SAA7134 has a 1K FIFO; the datasheet suggests that when
* configured conservatively, there's 22 usec of buffering for video.
* We therefore request a DMA latency of 20 usec, giving us 2 usec of
* margin in case the FIFO is configured differently to the datasheet.
* Unfortunately, I lack register-level documentation to check the
* Linux FIFO setup and confirm the perfect value.
*/
if (res != RESOURCE_EMPRESS)
pm_qos_add_request(&dev->qos_request,
PM_QOS_CPU_DMA_LATENCY, 20);
return videobuf_streamon(saa7134_queue(file));
}
EXPORT_SYMBOL_GPL(saa7134_streamon);
int saa7134_streamoff(struct file *file, void *priv,
enum v4l2_buf_type type)
{
struct saa7134_dev *dev = video_drvdata(file);
int res = saa7134_resource(file);
if (res != RESOURCE_EMPRESS)
pm_qos_remove_request(&dev->qos_request);
return videobuf_streamoff(saa7134_queue(file));
}
EXPORT_SYMBOL_GPL(saa7134_streamoff);
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int vidioc_g_register (struct file *file, void *priv,
struct v4l2_dbg_register *reg)
@ -2091,10 +1891,10 @@ static const struct v4l2_file_operations video_fops =
.owner = THIS_MODULE,
.open = video_open,
.release = video_release,
.read = video_read,
.poll = video_poll,
.mmap = video_mmap,
.ioctl = video_ioctl2,
.read = vb2_fop_read,
.poll = vb2_fop_poll,
.mmap = vb2_fop_mmap,
.unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops video_ioctl_ops = {
@ -2111,18 +1911,18 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_try_fmt_vbi_cap = saa7134_try_get_set_fmt_vbi_cap,
.vidioc_s_fmt_vbi_cap = saa7134_try_get_set_fmt_vbi_cap,
.vidioc_cropcap = saa7134_cropcap,
.vidioc_reqbufs = saa7134_reqbufs,
.vidioc_querybuf = saa7134_querybuf,
.vidioc_qbuf = saa7134_qbuf,
.vidioc_dqbuf = saa7134_dqbuf,
.vidioc_reqbufs = vb2_ioctl_reqbufs,
.vidioc_querybuf = vb2_ioctl_querybuf,
.vidioc_qbuf = vb2_ioctl_qbuf,
.vidioc_dqbuf = vb2_ioctl_dqbuf,
.vidioc_s_std = saa7134_s_std,
.vidioc_g_std = saa7134_g_std,
.vidioc_querystd = saa7134_querystd,
.vidioc_enum_input = saa7134_enum_input,
.vidioc_g_input = saa7134_g_input,
.vidioc_s_input = saa7134_s_input,
.vidioc_streamon = saa7134_streamon,
.vidioc_streamoff = saa7134_streamoff,
.vidioc_streamon = vb2_ioctl_streamon,
.vidioc_streamoff = vb2_ioctl_streamoff,
.vidioc_g_tuner = saa7134_g_tuner,
.vidioc_s_tuner = saa7134_s_tuner,
.vidioc_g_crop = saa7134_g_crop,
@ -2146,7 +1946,7 @@ static const struct v4l2_file_operations radio_fops = {
.open = video_open,
.read = radio_read,
.release = video_release,
.ioctl = video_ioctl2,
.unlocked_ioctl = video_ioctl2,
.poll = radio_poll,
};
@ -2224,6 +2024,8 @@ static const struct v4l2_ctrl_config saa7134_ctrl_automute = {
int saa7134_video_init1(struct saa7134_dev *dev)
{
struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
struct vb2_queue *q;
int ret;
/* sanitycheck insmod options */
if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME)
@ -2275,6 +2077,7 @@ int saa7134_video_init1(struct saa7134_dev *dev)
dev->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24);
dev->width = 720;
dev->height = 576;
dev->field = V4L2_FIELD_INTERLACED;
dev->win.w.width = dev->width;
dev->win.w.height = dev->height;
dev->win.field = V4L2_FIELD_INTERLACED;
@ -2286,19 +2089,40 @@ int saa7134_video_init1(struct saa7134_dev *dev)
if (saa7134_boards[dev->board].video_out)
saa7134_videoport_init(dev);
videobuf_queue_sg_init(&dev->video_vbq, &video_qops,
&dev->pci->dev, &dev->slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_INTERLACED,
sizeof(struct saa7134_buf),
&dev->video_q, NULL);
videobuf_queue_sg_init(&dev->vbi_vbq, &saa7134_vbi_qops,
&dev->pci->dev, &dev->slock,
V4L2_BUF_TYPE_VBI_CAPTURE,
V4L2_FIELD_SEQ_TB,
sizeof(struct saa7134_buf),
&dev->vbi_q, NULL);
q = &dev->video_vbq;
q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
/*
* Do not add VB2_USERPTR: the saa7134 DMA engine cannot handle
* transfers that do not start at the beginning of a page. A USERPTR
* can start anywhere in a page, so USERPTR support is a no-go.
*/
q->io_modes = VB2_MMAP | VB2_READ;
q->drv_priv = &dev->video_q;
q->ops = &vb2_qops;
q->gfp_flags = GFP_DMA32;
q->mem_ops = &vb2_dma_sg_memops;
q->buf_struct_size = sizeof(struct saa7134_buf);
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
q->lock = &dev->lock;
ret = vb2_queue_init(q);
if (ret)
return ret;
saa7134_pgtable_alloc(dev->pci, &dev->video_q.pt);
q = &dev->vbi_vbq;
q->type = V4L2_BUF_TYPE_VBI_CAPTURE;
/* Don't add VB2_USERPTR, see comment above */
q->io_modes = VB2_MMAP | VB2_READ;
q->drv_priv = &dev->vbi_q;
q->ops = &saa7134_vbi_qops;
q->gfp_flags = GFP_DMA32;
q->mem_ops = &vb2_dma_sg_memops;
q->buf_struct_size = sizeof(struct saa7134_buf);
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
q->lock = &dev->lock;
ret = vb2_queue_init(q);
if (ret)
return ret;
saa7134_pgtable_alloc(dev->pci, &dev->vbi_q.pt);
return 0;
@ -2307,7 +2131,9 @@ int saa7134_video_init1(struct saa7134_dev *dev)
void saa7134_video_fini(struct saa7134_dev *dev)
{
/* free stuff */
vb2_queue_release(&dev->video_vbq);
saa7134_pgtable_free(dev->pci, &dev->video_q.pt);
vb2_queue_release(&dev->vbi_vbq);
saa7134_pgtable_free(dev->pci, &dev->vbi_q.pt);
v4l2_ctrl_handler_free(&dev->ctrl_handler);
if (card_has_radio(dev))
@ -2401,8 +2227,7 @@ void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status)
spin_lock(&dev->slock);
if (dev->video_q.curr) {
dev->video_fieldcount++;
field = dev->video_q.curr->vb.field;
field = dev->field;
if (V4L2_FIELD_HAS_BOTH(field)) {
/* make sure we have seen both fields */
if ((status & 0x10) == 0x00) {
@ -2418,8 +2243,7 @@ void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status)
if ((status & 0x10) != 0x00)
goto done;
}
dev->video_q.curr->vb.field_count = dev->video_fieldcount;
saa7134_buffer_finish(dev, &dev->video_q, VIDEOBUF_DONE);
saa7134_buffer_finish(dev, &dev->video_q, VB2_BUF_STATE_DONE);
}
saa7134_buffer_next(dev, &dev->video_q);

View File

@ -41,11 +41,11 @@
#include <media/tuner.h>
#include <media/rc-core.h>
#include <media/ir-kbd-i2c.h>
#include <media/videobuf-dma-sg.h>
#include <media/videobuf2-dma-sg.h>
#include <sound/core.h>
#include <sound/pcm.h>
#if IS_ENABLED(CONFIG_VIDEO_SAA7134_DVB)
#include <media/videobuf-dvb.h>
#include <media/videobuf2-dvb.h>
#endif
#include "tda8290.h"
@ -453,13 +453,15 @@ struct saa7134_thread {
/* buffer for one video/vbi/ts frame */
struct saa7134_buf {
/* common v4l buffer stuff -- must be first */
struct videobuf_buffer vb;
struct vb2_buffer vb2;
/* saa7134 specific */
unsigned int top_seen;
int (*activate)(struct saa7134_dev *dev,
struct saa7134_buf *buf,
struct saa7134_buf *next);
struct list_head entry;
};
struct saa7134_dmaqueue {
@ -468,16 +470,10 @@ struct saa7134_dmaqueue {
struct list_head queue;
struct timer_list timeout;
unsigned int need_two;
unsigned int seq_nr;
struct saa7134_pgtable pt;
};
/* video filehandle status */
struct saa7134_fh {
struct v4l2_fh fh;
bool is_empress;
unsigned int resources;
};
/* dmasound dsp status */
struct saa7134_dmasound {
struct mutex lock;
@ -583,20 +579,35 @@ struct saa7134_dev {
struct v4l2_window win;
struct v4l2_clip clips[8];
unsigned int nclips;
struct v4l2_fh *overlay_owner;
/* video+ts+vbi capture */
struct saa7134_dmaqueue video_q;
struct videobuf_queue video_vbq;
struct vb2_queue video_vbq;
struct saa7134_dmaqueue vbi_q;
struct videobuf_queue vbi_vbq;
unsigned int video_fieldcount;
unsigned int vbi_fieldcount;
struct vb2_queue vbi_vbq;
enum v4l2_field field;
struct saa7134_format *fmt;
unsigned int width, height;
unsigned int vbi_hlen, vbi_vlen;
struct pm_qos_request qos_request;
/* SAA7134_MPEG_* */
struct saa7134_ts ts;
struct saa7134_dmaqueue ts_q;
enum v4l2_field ts_field;
int ts_started;
struct saa7134_mpeg_ops *mops;
/* SAA7134_MPEG_EMPRESS only */
struct video_device *empress_dev;
struct v4l2_subdev *empress_sd;
struct vb2_queue empress_vbq;
struct work_struct empress_workqueue;
int empress_started;
struct v4l2_ctrl_handler empress_ctrl_handler;
/* various v4l controls */
struct saa7134_tvnorm *tvnorm; /* video */
struct saa7134_tvaudio *tvaudio;
@ -633,23 +644,9 @@ struct saa7134_dev {
/* I2C keyboard data */
struct IR_i2c_init_data init_data;
/* SAA7134_MPEG_* */
struct saa7134_ts ts;
struct saa7134_dmaqueue ts_q;
int ts_started;
struct saa7134_mpeg_ops *mops;
/* SAA7134_MPEG_EMPRESS only */
struct video_device *empress_dev;
struct v4l2_subdev *empress_sd;
struct videobuf_queue empress_vbq;
struct work_struct empress_workqueue;
int empress_started;
struct v4l2_ctrl_handler empress_ctrl_handler;
#if IS_ENABLED(CONFIG_VIDEO_SAA7134_DVB)
/* SAA7134_MPEG_DVB only */
struct videobuf_dvb_frontends frontends;
struct vb2_dvb_frontends frontends;
int (*original_demod_sleep)(struct dvb_frontend *fe);
int (*original_set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage);
int (*original_set_high_voltage)(struct dvb_frontend *fe, long arg);
@ -703,14 +700,12 @@ struct saa7134_dev {
_rc; \
})
static inline int res_check(struct saa7134_fh *fh, unsigned int bit)
static inline bool is_empress(struct file *file)
{
return fh->resources & bit;
}
struct video_device *vdev = video_devdata(file);
struct saa7134_dev *dev = video_get_drvdata(vdev);
static inline int res_locked(struct saa7134_dev *dev, unsigned int bit)
{
return dev->resources & bit;
return vdev->queue == &dev->empress_vbq;
}
/* ----------------------------------------------------------- */
@ -741,7 +736,7 @@ void saa7134_buffer_finish(struct saa7134_dev *dev, struct saa7134_dmaqueue *q,
unsigned int state);
void saa7134_buffer_next(struct saa7134_dev *dev, struct saa7134_dmaqueue *q);
void saa7134_buffer_timeout(unsigned long data);
void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf);
void saa7134_stop_streaming(struct saa7134_dev *dev, struct saa7134_dmaqueue *q);
int saa7134_set_dmabits(struct saa7134_dev *dev);
@ -775,6 +770,10 @@ extern unsigned int video_debug;
extern struct video_device saa7134_video_template;
extern struct video_device saa7134_radio_template;
void saa7134_vb2_buffer_queue(struct vb2_buffer *vb);
int saa7134_vb2_start_streaming(struct vb2_queue *vq, unsigned int count);
void saa7134_vb2_stop_streaming(struct vb2_queue *vq);
int saa7134_s_std(struct file *file, void *priv, v4l2_std_id id);
int saa7134_g_std(struct file *file, void *priv, v4l2_std_id *id);
int saa7134_querystd(struct file *file, void *priv, v4l2_std_id *std);
@ -791,16 +790,6 @@ int saa7134_g_frequency(struct file *file, void *priv,
struct v4l2_frequency *f);
int saa7134_s_frequency(struct file *file, void *priv,
const struct v4l2_frequency *f);
int saa7134_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *p);
int saa7134_querybuf(struct file *file, void *priv,
struct v4l2_buffer *b);
int saa7134_qbuf(struct file *file, void *priv, struct v4l2_buffer *b);
int saa7134_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b);
int saa7134_streamon(struct file *file, void *priv,
enum v4l2_buf_type type);
int saa7134_streamoff(struct file *file, void *priv,
enum v4l2_buf_type type);
int saa7134_videoport_init(struct saa7134_dev *dev);
void saa7134_set_tvnorm_hw(struct saa7134_dev *dev);
@ -817,7 +806,16 @@ void saa7134_video_fini(struct saa7134_dev *dev);
#define TS_PACKET_SIZE 188 /* TS packets 188 bytes */
extern struct videobuf_queue_ops saa7134_ts_qops;
int saa7134_ts_buffer_init(struct vb2_buffer *vb2);
int saa7134_ts_buffer_prepare(struct vb2_buffer *vb2);
void saa7134_ts_buffer_finish(struct vb2_buffer *vb2);
int saa7134_ts_queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[]);
int saa7134_ts_start_streaming(struct vb2_queue *vq, unsigned int count);
void saa7134_ts_stop_streaming(struct vb2_queue *vq);
extern struct vb2_ops saa7134_ts_qops;
int saa7134_ts_init1(struct saa7134_dev *dev);
int saa7134_ts_fini(struct saa7134_dev *dev);
@ -834,7 +832,7 @@ int saa7134_ts_stop(struct saa7134_dev *dev);
/* ----------------------------------------------------------- */
/* saa7134-vbi.c */
extern struct videobuf_queue_ops saa7134_vbi_qops;
extern struct vb2_ops saa7134_vbi_qops;
extern struct video_device saa7134_vbi_template;
int saa7134_vbi_init1(struct saa7134_dev *dev);