[media] cx23885: convert to vb2
As usual, this patch is very large due to the fact that half a vb2 conversion isn't possible. And since this affects 417, alsa, core, dvb, vbi and video the changes are all over. What made this more difficult was the peculiar way the risc program was setup. The driver allowed for running out of buffers in which case the DMA would stop and restart when the next buffer was queued. There was also a complicated timeout system for when buffers weren't filled. This was replaced by a much simpler scheme where there is always one buffer around and the DMA will just cycle that buffer until a new buffer is queued. In that case the previous buffer will be chained to the new buffer. An interrupt is generated at the start of the new buffer telling the driver that the previous buffer can be passed on to userspace. Much simpler and more robust. The old code seems to be copied from the cx88 driver. But it didn't fit the vb2 ops very well and replacing it with the new scheme made the code easier to understand. Not to mention that this patch removes 600 lines of code. Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
This commit is contained in:
parent
73d8102298
commit
453afdd9ce
|
@ -7,8 +7,8 @@ config VIDEO_CX23885
|
|||
select VIDEO_TUNER
|
||||
select VIDEO_TVEEPROM
|
||||
depends on RC_CORE
|
||||
select VIDEOBUF_DVB
|
||||
select VIDEOBUF_DMA_SG
|
||||
select VIDEOBUF2_DVB
|
||||
select VIDEOBUF2_DMA_SG
|
||||
select VIDEO_CX25840
|
||||
select VIDEO_CX2341X
|
||||
select DVB_DIB7000P if MEDIA_SUBDRV_AUTOSELECT
|
||||
|
|
|
@ -48,8 +48,8 @@
|
|||
* | DATA7| DATA6| DATA5| DATA4| DATA3| DATA2| DATA1| DATA0|
|
||||
* +-------+-------+-------+-------+-------+-------+-------+-------+
|
||||
*/
|
||||
#include <media/videobuf-dma-sg.h>
|
||||
#include <media/videobuf-dvb.h>
|
||||
#include <dvb_demux.h>
|
||||
#include <dvb_frontend.h>
|
||||
#include "altera-ci.h"
|
||||
#include "dvb_ca_en50221.h"
|
||||
|
||||
|
|
|
@ -1138,47 +1138,100 @@ static int cx23885_initialize_codec(struct cx23885_dev *dev, int startencoder)
|
|||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
static int bb_buf_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 *num_buffers, unsigned int *num_planes,
|
||||
unsigned int sizes[], void *alloc_ctxs[])
|
||||
{
|
||||
struct cx23885_fh *fh = q->priv_data;
|
||||
|
||||
fh->q_dev->ts1.ts_packet_size = mpeglinesize;
|
||||
fh->q_dev->ts1.ts_packet_count = mpeglines;
|
||||
|
||||
*size = fh->q_dev->ts1.ts_packet_size * fh->q_dev->ts1.ts_packet_count;
|
||||
*count = mpegbufs;
|
||||
struct cx23885_dev *dev = q->drv_priv;
|
||||
|
||||
dev->ts1.ts_packet_size = mpeglinesize;
|
||||
dev->ts1.ts_packet_count = mpeglines;
|
||||
*num_planes = 1;
|
||||
sizes[0] = mpeglinesize * mpeglines;
|
||||
*num_buffers = mpegbufs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bb_buf_prepare(struct videobuf_queue *q,
|
||||
struct videobuf_buffer *vb, enum v4l2_field field)
|
||||
static int buffer_prepare(struct vb2_buffer *vb)
|
||||
{
|
||||
struct cx23885_fh *fh = q->priv_data;
|
||||
return cx23885_buf_prepare(q, &fh->q_dev->ts1,
|
||||
(struct cx23885_buffer *)vb,
|
||||
field);
|
||||
struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
|
||||
struct cx23885_buffer *buf =
|
||||
container_of(vb, struct cx23885_buffer, vb);
|
||||
|
||||
return cx23885_buf_prepare(buf, &dev->ts1);
|
||||
}
|
||||
|
||||
static void bb_buf_queue(struct videobuf_queue *q,
|
||||
struct videobuf_buffer *vb)
|
||||
static void buffer_finish(struct vb2_buffer *vb)
|
||||
{
|
||||
struct cx23885_fh *fh = q->priv_data;
|
||||
cx23885_buf_queue(&fh->q_dev->ts1, (struct cx23885_buffer *)vb);
|
||||
struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
|
||||
struct cx23885_buffer *buf = container_of(vb,
|
||||
struct cx23885_buffer, vb);
|
||||
struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
|
||||
|
||||
cx23885_free_buffer(dev, buf);
|
||||
|
||||
dma_unmap_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
|
||||
}
|
||||
|
||||
static void bb_buf_release(struct videobuf_queue *q,
|
||||
struct videobuf_buffer *vb)
|
||||
static void buffer_queue(struct vb2_buffer *vb)
|
||||
{
|
||||
cx23885_free_buffer(q, (struct cx23885_buffer *)vb);
|
||||
struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
|
||||
struct cx23885_buffer *buf = container_of(vb,
|
||||
struct cx23885_buffer, vb);
|
||||
|
||||
cx23885_buf_queue(&dev->ts1, buf);
|
||||
}
|
||||
|
||||
static struct videobuf_queue_ops cx23885_qops = {
|
||||
.buf_setup = bb_buf_setup,
|
||||
.buf_prepare = bb_buf_prepare,
|
||||
.buf_queue = bb_buf_queue,
|
||||
.buf_release = bb_buf_release,
|
||||
static int cx23885_start_streaming(struct vb2_queue *q, unsigned int count)
|
||||
{
|
||||
struct cx23885_dev *dev = q->drv_priv;
|
||||
struct cx23885_dmaqueue *dmaq = &dev->ts1.mpegq;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
ret = cx23885_initialize_codec(dev, 1);
|
||||
if (ret == 0) {
|
||||
struct cx23885_buffer *buf = list_entry(dmaq->active.next,
|
||||
struct cx23885_buffer, queue);
|
||||
|
||||
cx23885_start_dma(&dev->ts1, dmaq, buf);
|
||||
return 0;
|
||||
}
|
||||
spin_lock_irqsave(&dev->slock, flags);
|
||||
while (!list_empty(&dmaq->active)) {
|
||||
struct cx23885_buffer *buf = list_entry(dmaq->active.next,
|
||||
struct cx23885_buffer, queue);
|
||||
|
||||
list_del(&buf->queue);
|
||||
vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED);
|
||||
}
|
||||
spin_unlock_irqrestore(&dev->slock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void cx23885_stop_streaming(struct vb2_queue *q)
|
||||
{
|
||||
struct cx23885_dev *dev = q->drv_priv;
|
||||
|
||||
/* stop mpeg capture */
|
||||
cx23885_api_cmd(dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
|
||||
CX23885_END_NOW, CX23885_MPEG_CAPTURE,
|
||||
CX23885_RAW_BITS_NONE);
|
||||
|
||||
msleep(500);
|
||||
cx23885_417_check_encoder(dev);
|
||||
cx23885_cancel_buffers(&dev->ts1);
|
||||
}
|
||||
|
||||
static struct vb2_ops cx23885_qops = {
|
||||
.queue_setup = queue_setup,
|
||||
.buf_prepare = buffer_prepare,
|
||||
.buf_finish = buffer_finish,
|
||||
.buf_queue = buffer_queue,
|
||||
.wait_prepare = vb2_ops_wait_prepare,
|
||||
.wait_finish = vb2_ops_wait_finish,
|
||||
.start_streaming = cx23885_start_streaming,
|
||||
.stop_streaming = cx23885_stop_streaming,
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
@ -1316,7 +1369,6 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
|
|||
struct v4l2_format *f)
|
||||
{
|
||||
struct cx23885_dev *dev = video_drvdata(file);
|
||||
struct cx23885_fh *fh = file->private_data;
|
||||
|
||||
f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
|
||||
f->fmt.pix.bytesperline = 0;
|
||||
|
@ -1325,9 +1377,9 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
|
|||
f->fmt.pix.colorspace = 0;
|
||||
f->fmt.pix.width = dev->ts1.width;
|
||||
f->fmt.pix.height = dev->ts1.height;
|
||||
f->fmt.pix.field = fh->mpegq.field;
|
||||
dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d, f: %d\n",
|
||||
dev->ts1.width, dev->ts1.height, fh->mpegq.field);
|
||||
f->fmt.pix.field = V4L2_FIELD_INTERLACED;
|
||||
dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d\n",
|
||||
dev->ts1.width, dev->ts1.height);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1335,15 +1387,15 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
|
|||
struct v4l2_format *f)
|
||||
{
|
||||
struct cx23885_dev *dev = video_drvdata(file);
|
||||
struct cx23885_fh *fh = file->private_data;
|
||||
|
||||
f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
|
||||
f->fmt.pix.bytesperline = 0;
|
||||
f->fmt.pix.sizeimage =
|
||||
dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
|
||||
f->fmt.pix.colorspace = 0;
|
||||
dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n",
|
||||
dev->ts1.width, dev->ts1.height, fh->mpegq.field);
|
||||
f->fmt.pix.field = V4L2_FIELD_INTERLACED;
|
||||
dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d\n",
|
||||
dev->ts1.width, dev->ts1.height);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1357,58 +1409,12 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
|
|||
f->fmt.pix.sizeimage =
|
||||
dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
|
||||
f->fmt.pix.colorspace = 0;
|
||||
f->fmt.pix.field = V4L2_FIELD_INTERLACED;
|
||||
dprintk(1, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n",
|
||||
f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_reqbufs(struct file *file, void *priv,
|
||||
struct v4l2_requestbuffers *p)
|
||||
{
|
||||
struct cx23885_fh *fh = file->private_data;
|
||||
|
||||
return videobuf_reqbufs(&fh->mpegq, p);
|
||||
}
|
||||
|
||||
static int vidioc_querybuf(struct file *file, void *priv,
|
||||
struct v4l2_buffer *p)
|
||||
{
|
||||
struct cx23885_fh *fh = file->private_data;
|
||||
|
||||
return videobuf_querybuf(&fh->mpegq, p);
|
||||
}
|
||||
|
||||
static int vidioc_qbuf(struct file *file, void *priv,
|
||||
struct v4l2_buffer *p)
|
||||
{
|
||||
struct cx23885_fh *fh = file->private_data;
|
||||
|
||||
return videobuf_qbuf(&fh->mpegq, p);
|
||||
}
|
||||
|
||||
static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
|
||||
{
|
||||
struct cx23885_fh *fh = priv;
|
||||
|
||||
return videobuf_dqbuf(&fh->mpegq, b, file->f_flags & O_NONBLOCK);
|
||||
}
|
||||
|
||||
|
||||
static int vidioc_streamon(struct file *file, void *priv,
|
||||
enum v4l2_buf_type i)
|
||||
{
|
||||
struct cx23885_fh *fh = file->private_data;
|
||||
|
||||
return videobuf_streamon(&fh->mpegq);
|
||||
}
|
||||
|
||||
static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
|
||||
{
|
||||
struct cx23885_fh *fh = file->private_data;
|
||||
|
||||
return videobuf_streamoff(&fh->mpegq);
|
||||
}
|
||||
|
||||
static int vidioc_log_status(struct file *file, void *priv)
|
||||
{
|
||||
struct cx23885_dev *dev = video_drvdata(file);
|
||||
|
@ -1420,120 +1426,14 @@ static int vidioc_log_status(struct file *file, void *priv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int mpeg_open(struct file *file)
|
||||
{
|
||||
struct cx23885_dev *dev = video_drvdata(file);
|
||||
struct video_device *vdev = video_devdata(file);
|
||||
struct cx23885_fh *fh;
|
||||
|
||||
dprintk(2, "%s()\n", __func__);
|
||||
|
||||
/* allocate + initialize per filehandle data */
|
||||
fh = kzalloc(sizeof(*fh), GFP_KERNEL);
|
||||
if (!fh)
|
||||
return -ENOMEM;
|
||||
|
||||
v4l2_fh_init(&fh->fh, vdev);
|
||||
file->private_data = fh;
|
||||
fh->q_dev = dev;
|
||||
|
||||
videobuf_queue_sg_init(&fh->mpegq, &cx23885_qops,
|
||||
&dev->pci->dev, &dev->ts1.slock,
|
||||
V4L2_BUF_TYPE_VIDEO_CAPTURE,
|
||||
V4L2_FIELD_INTERLACED,
|
||||
sizeof(struct cx23885_buffer),
|
||||
fh, NULL);
|
||||
v4l2_fh_add(&fh->fh);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mpeg_release(struct file *file)
|
||||
{
|
||||
struct cx23885_dev *dev = video_drvdata(file);
|
||||
struct cx23885_fh *fh = file->private_data;
|
||||
|
||||
dprintk(2, "%s()\n", __func__);
|
||||
|
||||
/* FIXME: Review this crap */
|
||||
/* Shut device down on last close */
|
||||
if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) {
|
||||
if (atomic_dec_return(&dev->v4l_reader_count) == 0) {
|
||||
/* stop mpeg capture */
|
||||
cx23885_api_cmd(dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
|
||||
CX23885_END_NOW, CX23885_MPEG_CAPTURE,
|
||||
CX23885_RAW_BITS_NONE);
|
||||
|
||||
msleep(500);
|
||||
cx23885_417_check_encoder(dev);
|
||||
|
||||
cx23885_cancel_buffers(&dev->ts1);
|
||||
}
|
||||
}
|
||||
|
||||
if (fh->mpegq.streaming)
|
||||
videobuf_streamoff(&fh->mpegq);
|
||||
if (fh->mpegq.reading)
|
||||
videobuf_read_stop(&fh->mpegq);
|
||||
|
||||
videobuf_mmap_free(&fh->mpegq);
|
||||
v4l2_fh_del(&fh->fh);
|
||||
v4l2_fh_exit(&fh->fh);
|
||||
file->private_data = NULL;
|
||||
kfree(fh);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t mpeg_read(struct file *file, char __user *data,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct cx23885_dev *dev = video_drvdata(file);
|
||||
struct cx23885_fh *fh = file->private_data;
|
||||
|
||||
dprintk(2, "%s()\n", __func__);
|
||||
|
||||
/* Deal w/ A/V decoder * and mpeg encoder sync issues. */
|
||||
/* Start mpeg encoder on first read. */
|
||||
if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) {
|
||||
if (atomic_inc_return(&dev->v4l_reader_count) == 1) {
|
||||
if (cx23885_initialize_codec(dev, 1) < 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return videobuf_read_stream(&fh->mpegq, data, count, ppos, 0,
|
||||
file->f_flags & O_NONBLOCK);
|
||||
}
|
||||
|
||||
static unsigned int mpeg_poll(struct file *file,
|
||||
struct poll_table_struct *wait)
|
||||
{
|
||||
struct cx23885_dev *dev = video_drvdata(file);
|
||||
struct cx23885_fh *fh = file->private_data;
|
||||
|
||||
dprintk(2, "%s\n", __func__);
|
||||
|
||||
return videobuf_poll_stream(file, &fh->mpegq, wait);
|
||||
}
|
||||
|
||||
static int mpeg_mmap(struct file *file, struct vm_area_struct *vma)
|
||||
{
|
||||
struct cx23885_dev *dev = video_drvdata(file);
|
||||
struct cx23885_fh *fh = file->private_data;
|
||||
|
||||
dprintk(2, "%s()\n", __func__);
|
||||
|
||||
return videobuf_mmap_mapper(&fh->mpegq, vma);
|
||||
}
|
||||
|
||||
static struct v4l2_file_operations mpeg_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = mpeg_open,
|
||||
.release = mpeg_release,
|
||||
.read = mpeg_read,
|
||||
.poll = mpeg_poll,
|
||||
.mmap = mpeg_mmap,
|
||||
.open = v4l2_fh_open,
|
||||
.release = vb2_fop_release,
|
||||
.read = vb2_fop_read,
|
||||
.poll = vb2_fop_poll,
|
||||
.unlocked_ioctl = video_ioctl2,
|
||||
.mmap = vb2_fop_mmap,
|
||||
};
|
||||
|
||||
static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
|
||||
|
@ -1551,12 +1451,13 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
|
|||
.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
|
||||
.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
|
||||
.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
|
||||
.vidioc_reqbufs = vidioc_reqbufs,
|
||||
.vidioc_querybuf = vidioc_querybuf,
|
||||
.vidioc_qbuf = vidioc_qbuf,
|
||||
.vidioc_dqbuf = vidioc_dqbuf,
|
||||
.vidioc_streamon = vidioc_streamon,
|
||||
.vidioc_streamoff = vidioc_streamoff,
|
||||
.vidioc_reqbufs = vb2_ioctl_reqbufs,
|
||||
.vidioc_prepare_buf = vb2_ioctl_prepare_buf,
|
||||
.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_log_status = vidioc_log_status,
|
||||
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
||||
.vidioc_g_chip_info = cx23885_g_chip_info,
|
||||
|
@ -1613,6 +1514,7 @@ int cx23885_417_register(struct cx23885_dev *dev)
|
|||
/* FIXME: Port1 hardcoded here */
|
||||
int err = -ENODEV;
|
||||
struct cx23885_tsport *tsport = &dev->ts1;
|
||||
struct vb2_queue *q;
|
||||
|
||||
dprintk(1, "%s()\n", __func__);
|
||||
|
||||
|
@ -1640,8 +1542,24 @@ int cx23885_417_register(struct cx23885_dev *dev)
|
|||
/* Allocate and initialize V4L video device */
|
||||
dev->v4l_device = cx23885_video_dev_alloc(tsport,
|
||||
dev->pci, &cx23885_mpeg_template, "mpeg");
|
||||
q = &dev->vb2_mpegq;
|
||||
q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
|
||||
q->gfp_flags = GFP_DMA32;
|
||||
q->min_buffers_needed = 2;
|
||||
q->drv_priv = dev;
|
||||
q->buf_struct_size = sizeof(struct cx23885_buffer);
|
||||
q->ops = &cx23885_qops;
|
||||
q->mem_ops = &vb2_dma_sg_memops;
|
||||
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
|
||||
q->lock = &dev->lock;
|
||||
|
||||
err = vb2_queue_init(q);
|
||||
if (err < 0)
|
||||
return err;
|
||||
video_set_drvdata(dev->v4l_device, dev);
|
||||
dev->v4l_device->lock = &dev->lock;
|
||||
dev->v4l_device->queue = q;
|
||||
err = video_register_device(dev->v4l_device,
|
||||
VFL_TYPE_GRABBER, -1);
|
||||
if (err < 0) {
|
||||
|
|
|
@ -389,6 +389,7 @@ static int snd_cx23885_hw_params(struct snd_pcm_substream *substream,
|
|||
return -ENOMEM;
|
||||
|
||||
buf->bpl = chip->period_size;
|
||||
chip->buf = buf;
|
||||
|
||||
ret = cx23885_alsa_dma_init(chip,
|
||||
(PAGE_ALIGN(chip->dma_size) >> PAGE_SHIFT));
|
||||
|
@ -409,8 +410,6 @@ static int snd_cx23885_hw_params(struct snd_pcm_substream *substream,
|
|||
buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
|
||||
buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
|
||||
|
||||
chip->buf = buf;
|
||||
|
||||
substream->runtime->dma_area = chip->buf->vaddr;
|
||||
substream->runtime->dma_bytes = chip->dma_size;
|
||||
substream->runtime->dma_addr = 0;
|
||||
|
@ -419,6 +418,7 @@ static int snd_cx23885_hw_params(struct snd_pcm_substream *substream,
|
|||
|
||||
error:
|
||||
kfree(buf);
|
||||
chip->buf = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -416,39 +416,23 @@ static int cx23885_risc_decode(u32 risc)
|
|||
return incr[risc >> 28] ? incr[risc >> 28] : 1;
|
||||
}
|
||||
|
||||
void cx23885_wakeup(struct cx23885_tsport *port,
|
||||
static void cx23885_wakeup(struct cx23885_tsport *port,
|
||||
struct cx23885_dmaqueue *q, u32 count)
|
||||
{
|
||||
struct cx23885_dev *dev = port->dev;
|
||||
struct cx23885_buffer *buf;
|
||||
int bc;
|
||||
|
||||
for (bc = 0;; bc++) {
|
||||
if (list_empty(&q->active))
|
||||
break;
|
||||
buf = list_entry(q->active.next,
|
||||
struct cx23885_buffer, vb.queue);
|
||||
|
||||
/* count comes from the hw and is is 16bit wide --
|
||||
* this trick handles wrap-arounds correctly for
|
||||
* up to 32767 buffers in flight... */
|
||||
if ((s16) (count - buf->count) < 0)
|
||||
break;
|
||||
|
||||
v4l2_get_timestamp(&buf->vb.ts);
|
||||
dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i,
|
||||
count, buf->count);
|
||||
buf->vb.state = VIDEOBUF_DONE;
|
||||
list_del(&buf->vb.queue);
|
||||
wake_up(&buf->vb.done);
|
||||
}
|
||||
if (list_empty(&q->active))
|
||||
del_timer(&q->timeout);
|
||||
else
|
||||
mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
|
||||
if (bc != 1)
|
||||
printk(KERN_WARNING "%s: %d buffers handled (should be 1)\n",
|
||||
__func__, bc);
|
||||
return;
|
||||
buf = list_entry(q->active.next,
|
||||
struct cx23885_buffer, queue);
|
||||
|
||||
v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
|
||||
buf->vb.v4l2_buf.sequence = q->count++;
|
||||
dprintk(1, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.v4l2_buf.index,
|
||||
count, q->count);
|
||||
list_del(&buf->queue);
|
||||
vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
|
||||
}
|
||||
|
||||
int cx23885_sram_channel_setup(struct cx23885_dev *dev,
|
||||
|
@ -478,8 +462,8 @@ int cx23885_sram_channel_setup(struct cx23885_dev *dev,
|
|||
lines = 6;
|
||||
BUG_ON(lines < 2);
|
||||
|
||||
cx_write(8 + 0, RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
|
||||
cx_write(8 + 4, 8);
|
||||
cx_write(8 + 0, RISC_JUMP | RISC_CNT_RESET);
|
||||
cx_write(8 + 4, 12);
|
||||
cx_write(8 + 8, 0);
|
||||
|
||||
/* write CDT */
|
||||
|
@ -695,10 +679,6 @@ static int get_resources(struct cx23885_dev *dev)
|
|||
return -EBUSY;
|
||||
}
|
||||
|
||||
static void cx23885_timeout(unsigned long data);
|
||||
int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
|
||||
u32 reg, u32 mask, u32 value);
|
||||
|
||||
static int cx23885_init_tsport(struct cx23885_dev *dev,
|
||||
struct cx23885_tsport *port, int portno)
|
||||
{
|
||||
|
@ -715,11 +695,6 @@ static int cx23885_init_tsport(struct cx23885_dev *dev,
|
|||
port->nr = portno;
|
||||
|
||||
INIT_LIST_HEAD(&port->mpegq.active);
|
||||
INIT_LIST_HEAD(&port->mpegq.queued);
|
||||
port->mpegq.timeout.function = cx23885_timeout;
|
||||
port->mpegq.timeout.data = (unsigned long)port;
|
||||
init_timer(&port->mpegq.timeout);
|
||||
|
||||
mutex_init(&port->frontends.lock);
|
||||
INIT_LIST_HEAD(&port->frontends.felist);
|
||||
port->frontends.active_fe_id = 0;
|
||||
|
@ -772,9 +747,6 @@ static int cx23885_init_tsport(struct cx23885_dev *dev,
|
|||
BUG();
|
||||
}
|
||||
|
||||
cx23885_risc_stopper(dev->pci, &port->mpegq.stopper,
|
||||
port->reg_dma_ctl, port->dma_ctl_val, 0x00);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1085,11 +1057,18 @@ static void cx23885_dev_unregister(struct cx23885_dev *dev)
|
|||
static __le32 *cx23885_risc_field(__le32 *rp, struct scatterlist *sglist,
|
||||
unsigned int offset, u32 sync_line,
|
||||
unsigned int bpl, unsigned int padding,
|
||||
unsigned int lines, unsigned int lpi)
|
||||
unsigned int lines, unsigned int lpi, bool jump)
|
||||
{
|
||||
struct scatterlist *sg;
|
||||
unsigned int line, todo, sol;
|
||||
|
||||
|
||||
if (jump) {
|
||||
*(rp++) = cpu_to_le32(RISC_JUMP);
|
||||
*(rp++) = cpu_to_le32(0);
|
||||
*(rp++) = cpu_to_le32(0); /* bits 63-32 */
|
||||
}
|
||||
|
||||
/* sync instruction */
|
||||
if (sync_line != NO_SYNC_LINE)
|
||||
*(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
|
||||
|
@ -1164,7 +1143,7 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
|
|||
/* write and jump need and extra dword */
|
||||
instructions = fields * (1 + ((bpl + padding) * lines)
|
||||
/ PAGE_SIZE + lines);
|
||||
instructions += 2;
|
||||
instructions += 5;
|
||||
rc = btcx_riscmem_alloc(pci, risc, instructions*12);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
@ -1173,10 +1152,10 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
|
|||
rp = risc->cpu;
|
||||
if (UNSET != top_offset)
|
||||
rp = cx23885_risc_field(rp, sglist, top_offset, 0,
|
||||
bpl, padding, lines, 0);
|
||||
bpl, padding, lines, 0, true);
|
||||
if (UNSET != bottom_offset)
|
||||
rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x200,
|
||||
bpl, padding, lines, 0);
|
||||
bpl, padding, lines, 0, UNSET == top_offset);
|
||||
|
||||
/* save pointer to jmp instruction address */
|
||||
risc->jmp = rp;
|
||||
|
@ -1200,7 +1179,7 @@ int cx23885_risc_databuffer(struct pci_dev *pci,
|
|||
than PAGE_SIZE */
|
||||
/* Jump and write need an extra dword */
|
||||
instructions = 1 + (bpl * lines) / PAGE_SIZE + lines;
|
||||
instructions += 1;
|
||||
instructions += 4;
|
||||
|
||||
rc = btcx_riscmem_alloc(pci, risc, instructions*12);
|
||||
if (rc < 0)
|
||||
|
@ -1209,7 +1188,7 @@ int cx23885_risc_databuffer(struct pci_dev *pci,
|
|||
/* write risc instructions */
|
||||
rp = risc->cpu;
|
||||
rp = cx23885_risc_field(rp, sglist, 0, NO_SYNC_LINE,
|
||||
bpl, 0, lines, lpi);
|
||||
bpl, 0, lines, lpi, lpi == 0);
|
||||
|
||||
/* save pointer to jmp instruction address */
|
||||
risc->jmp = rp;
|
||||
|
@ -1239,7 +1218,7 @@ int cx23885_risc_vbibuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
|
|||
/* write and jump need and extra dword */
|
||||
instructions = fields * (1 + ((bpl + padding) * lines)
|
||||
/ PAGE_SIZE + lines);
|
||||
instructions += 2;
|
||||
instructions += 5;
|
||||
rc = btcx_riscmem_alloc(pci, risc, instructions*12);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
@ -1250,11 +1229,11 @@ int cx23885_risc_vbibuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
|
|||
* in the userland vbi payload */
|
||||
if (UNSET != top_offset)
|
||||
rp = cx23885_risc_field(rp, sglist, top_offset, 6,
|
||||
bpl, padding, lines, 0);
|
||||
bpl, padding, lines, 0, true);
|
||||
|
||||
if (UNSET != bottom_offset)
|
||||
rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x207,
|
||||
bpl, padding, lines, 0);
|
||||
bpl, padding, lines, 0, UNSET == top_offset);
|
||||
|
||||
|
||||
|
||||
|
@ -1265,38 +1244,10 @@ int cx23885_risc_vbibuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
|
|||
}
|
||||
|
||||
|
||||
int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
|
||||
u32 reg, u32 mask, u32 value)
|
||||
void cx23885_free_buffer(struct cx23885_dev *dev, struct cx23885_buffer *buf)
|
||||
{
|
||||
__le32 *rp;
|
||||
int rc;
|
||||
|
||||
rc = btcx_riscmem_alloc(pci, risc, 4*16);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* write risc instructions */
|
||||
rp = risc->cpu;
|
||||
*(rp++) = cpu_to_le32(RISC_WRITECR | RISC_IRQ2);
|
||||
*(rp++) = cpu_to_le32(reg);
|
||||
*(rp++) = cpu_to_le32(value);
|
||||
*(rp++) = cpu_to_le32(mask);
|
||||
*(rp++) = cpu_to_le32(RISC_JUMP);
|
||||
*(rp++) = cpu_to_le32(risc->dma);
|
||||
*(rp++) = cpu_to_le32(0); /* bits 63-32 */
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *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);
|
||||
btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc);
|
||||
buf->vb.state = VIDEOBUF_NEEDS_INIT;
|
||||
btcx_riscmem_free(dev->pci, &buf->risc);
|
||||
}
|
||||
|
||||
static void cx23885_tsport_reg_dump(struct cx23885_tsport *port)
|
||||
|
@ -1351,7 +1302,7 @@ static void cx23885_tsport_reg_dump(struct cx23885_tsport *port)
|
|||
port->reg_ts_int_msk, cx_read(port->reg_ts_int_msk));
|
||||
}
|
||||
|
||||
static int cx23885_start_dma(struct cx23885_tsport *port,
|
||||
int cx23885_start_dma(struct cx23885_tsport *port,
|
||||
struct cx23885_dmaqueue *q,
|
||||
struct cx23885_buffer *buf)
|
||||
{
|
||||
|
@ -1359,7 +1310,7 @@ static int cx23885_start_dma(struct cx23885_tsport *port,
|
|||
u32 reg;
|
||||
|
||||
dprintk(1, "%s() w: %d, h: %d, f: %d\n", __func__,
|
||||
buf->vb.width, buf->vb.height, buf->vb.field);
|
||||
dev->width, dev->height, dev->field);
|
||||
|
||||
/* Stop the fifo and risc engine for this port */
|
||||
cx_clear(port->reg_dma_ctl, port->dma_ctl_val);
|
||||
|
@ -1375,7 +1326,7 @@ static int cx23885_start_dma(struct cx23885_tsport *port,
|
|||
}
|
||||
|
||||
/* write TS length to chip */
|
||||
cx_write(port->reg_lngth, buf->vb.width);
|
||||
cx_write(port->reg_lngth, port->ts_packet_size);
|
||||
|
||||
if ((!(cx23885_boards[dev->board].portb & CX23885_MPEG_DVB)) &&
|
||||
(!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB))) {
|
||||
|
@ -1404,7 +1355,7 @@ static int cx23885_start_dma(struct cx23885_tsport *port,
|
|||
/* NOTE: this is 2 (reserved) for portb, does it matter? */
|
||||
/* reset counter to zero */
|
||||
cx_write(port->reg_gpcnt_ctl, 3);
|
||||
q->count = 1;
|
||||
q->count = 0;
|
||||
|
||||
/* Set VIDB pins to input */
|
||||
if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) {
|
||||
|
@ -1493,134 +1444,83 @@ static int cx23885_stop_dma(struct cx23885_tsport *port)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int cx23885_restart_queue(struct cx23885_tsport *port,
|
||||
struct cx23885_dmaqueue *q)
|
||||
{
|
||||
struct cx23885_dev *dev = port->dev;
|
||||
struct cx23885_buffer *buf;
|
||||
|
||||
dprintk(5, "%s()\n", __func__);
|
||||
if (list_empty(&q->active)) {
|
||||
struct cx23885_buffer *prev;
|
||||
prev = NULL;
|
||||
|
||||
dprintk(5, "%s() queue is empty\n", __func__);
|
||||
|
||||
for (;;) {
|
||||
if (list_empty(&q->queued))
|
||||
return 0;
|
||||
buf = list_entry(q->queued.next, struct cx23885_buffer,
|
||||
vb.queue);
|
||||
if (NULL == prev) {
|
||||
list_move_tail(&buf->vb.queue, &q->active);
|
||||
cx23885_start_dma(port, q, buf);
|
||||
buf->vb.state = VIDEOBUF_ACTIVE;
|
||||
buf->count = q->count++;
|
||||
mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
|
||||
dprintk(5, "[%p/%d] restart_queue - f/active\n",
|
||||
buf, buf->vb.i);
|
||||
|
||||
} else if (prev->vb.width == buf->vb.width &&
|
||||
prev->vb.height == buf->vb.height &&
|
||||
prev->fmt == buf->fmt) {
|
||||
list_move_tail(&buf->vb.queue, &q->active);
|
||||
buf->vb.state = VIDEOBUF_ACTIVE;
|
||||
buf->count = q->count++;
|
||||
prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
|
||||
/* 64 bit bits 63-32 */
|
||||
prev->risc.jmp[2] = cpu_to_le32(0);
|
||||
dprintk(5, "[%p/%d] restart_queue - m/active\n",
|
||||
buf, buf->vb.i);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
prev = buf;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue);
|
||||
dprintk(2, "restart_queue [%p/%d]: restart dma\n",
|
||||
buf, buf->vb.i);
|
||||
cx23885_start_dma(port, q, buf);
|
||||
list_for_each_entry(buf, &q->active, vb.queue)
|
||||
buf->count = q->count++;
|
||||
mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port,
|
||||
struct cx23885_buffer *buf, enum v4l2_field field)
|
||||
int cx23885_buf_prepare(struct cx23885_buffer *buf, struct cx23885_tsport *port)
|
||||
{
|
||||
struct cx23885_dev *dev = port->dev;
|
||||
int size = port->ts_packet_size * port->ts_packet_count;
|
||||
struct sg_table *sgt = vb2_dma_sg_plane_desc(&buf->vb, 0);
|
||||
int rc;
|
||||
|
||||
dprintk(1, "%s: %p\n", __func__, buf);
|
||||
if (0 != buf->vb.baddr && buf->vb.bsize < size)
|
||||
if (vb2_plane_size(&buf->vb, 0) < size)
|
||||
return -EINVAL;
|
||||
vb2_set_plane_payload(&buf->vb, 0, size);
|
||||
|
||||
if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
|
||||
buf->vb.width = port->ts_packet_size;
|
||||
buf->vb.height = port->ts_packet_count;
|
||||
buf->vb.size = size;
|
||||
buf->vb.field = field /*V4L2_FIELD_TOP*/;
|
||||
rc = dma_map_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
|
||||
if (!rc)
|
||||
return -EIO;
|
||||
|
||||
rc = videobuf_iolock(q, &buf->vb, NULL);
|
||||
if (0 != rc)
|
||||
goto fail;
|
||||
cx23885_risc_databuffer(dev->pci, &buf->risc,
|
||||
videobuf_to_dma(&buf->vb)->sglist,
|
||||
buf->vb.width, buf->vb.height, 0);
|
||||
}
|
||||
buf->vb.state = VIDEOBUF_PREPARED;
|
||||
cx23885_risc_databuffer(dev->pci, &buf->risc,
|
||||
sgt->sgl,
|
||||
port->ts_packet_size, port->ts_packet_count, 0);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
cx23885_free_buffer(q, buf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* The risc program for each buffer works as follows: it starts with a simple
|
||||
* 'JUMP to addr + 12', which is effectively a NOP. Then the code to DMA the
|
||||
* buffer follows and at the end we have a JUMP back to the start + 12 (skipping
|
||||
* the initial JUMP).
|
||||
*
|
||||
* This is the risc program of the first buffer to be queued if the active list
|
||||
* is empty and it just keeps DMAing this buffer without generating any
|
||||
* interrupts.
|
||||
*
|
||||
* If a new buffer is added then the initial JUMP in the code for that buffer
|
||||
* will generate an interrupt which signals that the previous buffer has been
|
||||
* DMAed successfully and that it can be returned to userspace.
|
||||
*
|
||||
* It also sets the final jump of the previous buffer to the start of the new
|
||||
* buffer, thus chaining the new buffer into the DMA chain. This is a single
|
||||
* atomic u32 write, so there is no race condition.
|
||||
*
|
||||
* The end-result of all this that you only get an interrupt when a buffer
|
||||
* is ready, so the control flow is very easy.
|
||||
*/
|
||||
void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf)
|
||||
{
|
||||
struct cx23885_buffer *prev;
|
||||
struct cx23885_dev *dev = port->dev;
|
||||
struct cx23885_dmaqueue *cx88q = &port->mpegq;
|
||||
unsigned long flags;
|
||||
|
||||
/* add jump to stopper */
|
||||
buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
|
||||
buf->risc.jmp[1] = cpu_to_le32(cx88q->stopper.dma);
|
||||
buf->risc.cpu[1] = cpu_to_le32(buf->risc.dma + 12);
|
||||
buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_CNT_INC);
|
||||
buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma + 12);
|
||||
buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
|
||||
|
||||
spin_lock_irqsave(&dev->slock, flags);
|
||||
if (list_empty(&cx88q->active)) {
|
||||
dprintk(1, "queue is empty - first active\n");
|
||||
list_add_tail(&buf->vb.queue, &cx88q->active);
|
||||
cx23885_start_dma(port, cx88q, buf);
|
||||
buf->vb.state = VIDEOBUF_ACTIVE;
|
||||
buf->count = cx88q->count++;
|
||||
mod_timer(&cx88q->timeout, jiffies + BUFFER_TIMEOUT);
|
||||
list_add_tail(&buf->queue, &cx88q->active);
|
||||
dprintk(1, "[%p/%d] %s - first active\n",
|
||||
buf, buf->vb.i, __func__);
|
||||
buf, buf->vb.v4l2_buf.index, __func__);
|
||||
} else {
|
||||
dprintk(1, "queue is not empty - append to active\n");
|
||||
buf->risc.cpu[0] |= cpu_to_le32(RISC_IRQ1);
|
||||
prev = list_entry(cx88q->active.prev, struct cx23885_buffer,
|
||||
vb.queue);
|
||||
list_add_tail(&buf->vb.queue, &cx88q->active);
|
||||
buf->vb.state = VIDEOBUF_ACTIVE;
|
||||
buf->count = cx88q->count++;
|
||||
queue);
|
||||
list_add_tail(&buf->queue, &cx88q->active);
|
||||
prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
|
||||
prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */
|
||||
dprintk(1, "[%p/%d] %s - append to active\n",
|
||||
buf, buf->vb.i, __func__);
|
||||
buf, buf->vb.v4l2_buf.index, __func__);
|
||||
}
|
||||
spin_unlock_irqrestore(&dev->slock, flags);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
|
||||
static void do_cancel_buffers(struct cx23885_tsport *port, char *reason,
|
||||
int restart)
|
||||
static void do_cancel_buffers(struct cx23885_tsport *port, char *reason)
|
||||
{
|
||||
struct cx23885_dev *dev = port->dev;
|
||||
struct cx23885_dmaqueue *q = &port->mpegq;
|
||||
|
@ -1630,16 +1530,11 @@ static void do_cancel_buffers(struct cx23885_tsport *port, char *reason,
|
|||
spin_lock_irqsave(&port->slock, flags);
|
||||
while (!list_empty(&q->active)) {
|
||||
buf = list_entry(q->active.next, struct cx23885_buffer,
|
||||
vb.queue);
|
||||
list_del(&buf->vb.queue);
|
||||
buf->vb.state = VIDEOBUF_ERROR;
|
||||
wake_up(&buf->vb.done);
|
||||
queue);
|
||||
list_del(&buf->queue);
|
||||
vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
|
||||
dprintk(1, "[%p/%d] %s - dma=0x%08lx\n",
|
||||
buf, buf->vb.i, reason, (unsigned long)buf->risc.dma);
|
||||
}
|
||||
if (restart) {
|
||||
dprintk(1, "restarting queue\n");
|
||||
cx23885_restart_queue(port, q);
|
||||
buf, buf->vb.v4l2_buf.index, reason, (unsigned long)buf->risc.dma);
|
||||
}
|
||||
spin_unlock_irqrestore(&port->slock, flags);
|
||||
}
|
||||
|
@ -1647,27 +1542,10 @@ static void do_cancel_buffers(struct cx23885_tsport *port, char *reason,
|
|||
void cx23885_cancel_buffers(struct cx23885_tsport *port)
|
||||
{
|
||||
struct cx23885_dev *dev = port->dev;
|
||||
struct cx23885_dmaqueue *q = &port->mpegq;
|
||||
|
||||
dprintk(1, "%s()\n", __func__);
|
||||
del_timer_sync(&q->timeout);
|
||||
cx23885_stop_dma(port);
|
||||
do_cancel_buffers(port, "cancel", 0);
|
||||
}
|
||||
|
||||
static void cx23885_timeout(unsigned long data)
|
||||
{
|
||||
struct cx23885_tsport *port = (struct cx23885_tsport *)data;
|
||||
struct cx23885_dev *dev = port->dev;
|
||||
|
||||
dprintk(1, "%s()\n", __func__);
|
||||
|
||||
if (debug > 5)
|
||||
cx23885_sram_channel_dump(dev,
|
||||
&dev->sram_channels[port->sram_chno]);
|
||||
|
||||
cx23885_stop_dma(port);
|
||||
do_cancel_buffers(port, "timeout", 1);
|
||||
do_cancel_buffers(port, "cancel");
|
||||
}
|
||||
|
||||
int cx23885_irq_417(struct cx23885_dev *dev, u32 status)
|
||||
|
@ -1717,11 +1595,6 @@ int cx23885_irq_417(struct cx23885_dev *dev, u32 status)
|
|||
spin_lock(&port->slock);
|
||||
cx23885_wakeup(port, &port->mpegq, count);
|
||||
spin_unlock(&port->slock);
|
||||
} else if (status & VID_B_MSK_RISCI2) {
|
||||
dprintk(7, " VID_B_MSK_RISCI2\n");
|
||||
spin_lock(&port->slock);
|
||||
cx23885_restart_queue(port, &port->mpegq);
|
||||
spin_unlock(&port->slock);
|
||||
}
|
||||
if (status) {
|
||||
cx_write(port->reg_ts_int_stat, status);
|
||||
|
@ -1773,14 +1646,6 @@ static int cx23885_irq_ts(struct cx23885_tsport *port, u32 status)
|
|||
cx23885_wakeup(port, &port->mpegq, count);
|
||||
spin_unlock(&port->slock);
|
||||
|
||||
} else if (status & VID_BC_MSK_RISCI2) {
|
||||
|
||||
dprintk(7, " (RISCI2 0x%08x)\n", VID_BC_MSK_RISCI2);
|
||||
|
||||
spin_lock(&port->slock);
|
||||
cx23885_restart_queue(port, &port->mpegq);
|
||||
spin_unlock(&port->slock);
|
||||
|
||||
}
|
||||
if (status) {
|
||||
cx_write(port->reg_ts_int_stat, status);
|
||||
|
|
|
@ -87,59 +87,95 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
|||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
static int dvb_buf_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 *num_buffers, unsigned int *num_planes,
|
||||
unsigned int sizes[], void *alloc_ctxs[])
|
||||
{
|
||||
struct cx23885_tsport *port = q->priv_data;
|
||||
struct cx23885_tsport *port = q->drv_priv;
|
||||
|
||||
port->ts_packet_size = 188 * 4;
|
||||
port->ts_packet_count = 32;
|
||||
|
||||
*size = port->ts_packet_size * port->ts_packet_count;
|
||||
*count = 32;
|
||||
*num_planes = 1;
|
||||
sizes[0] = port->ts_packet_size * port->ts_packet_count;
|
||||
*num_buffers = 32;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dvb_buf_prepare(struct videobuf_queue *q,
|
||||
struct videobuf_buffer *vb, enum v4l2_field field)
|
||||
|
||||
static int buffer_prepare(struct vb2_buffer *vb)
|
||||
{
|
||||
struct cx23885_tsport *port = q->priv_data;
|
||||
return cx23885_buf_prepare(q, port, (struct cx23885_buffer *)vb, field);
|
||||
struct cx23885_tsport *port = vb->vb2_queue->drv_priv;
|
||||
struct cx23885_buffer *buf =
|
||||
container_of(vb, struct cx23885_buffer, vb);
|
||||
|
||||
return cx23885_buf_prepare(buf, port);
|
||||
}
|
||||
|
||||
static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
|
||||
static void buffer_finish(struct vb2_buffer *vb)
|
||||
{
|
||||
struct cx23885_tsport *port = q->priv_data;
|
||||
cx23885_buf_queue(port, (struct cx23885_buffer *)vb);
|
||||
struct cx23885_tsport *port = vb->vb2_queue->drv_priv;
|
||||
struct cx23885_dev *dev = port->dev;
|
||||
struct cx23885_buffer *buf = container_of(vb,
|
||||
struct cx23885_buffer, vb);
|
||||
struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
|
||||
|
||||
cx23885_free_buffer(dev, buf);
|
||||
|
||||
dma_unmap_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
|
||||
}
|
||||
|
||||
static void dvb_buf_release(struct videobuf_queue *q,
|
||||
struct videobuf_buffer *vb)
|
||||
static void buffer_queue(struct vb2_buffer *vb)
|
||||
{
|
||||
cx23885_free_buffer(q, (struct cx23885_buffer *)vb);
|
||||
struct cx23885_tsport *port = vb->vb2_queue->drv_priv;
|
||||
struct cx23885_buffer *buf = container_of(vb,
|
||||
struct cx23885_buffer, vb);
|
||||
|
||||
cx23885_buf_queue(port, buf);
|
||||
}
|
||||
|
||||
static void cx23885_dvb_gate_ctrl(struct cx23885_tsport *port, int open)
|
||||
{
|
||||
struct videobuf_dvb_frontends *f;
|
||||
struct videobuf_dvb_frontend *fe;
|
||||
struct vb2_dvb_frontends *f;
|
||||
struct vb2_dvb_frontend *fe;
|
||||
|
||||
f = &port->frontends;
|
||||
|
||||
if (f->gate <= 1) /* undefined or fe0 */
|
||||
fe = videobuf_dvb_get_frontend(f, 1);
|
||||
fe = vb2_dvb_get_frontend(f, 1);
|
||||
else
|
||||
fe = videobuf_dvb_get_frontend(f, f->gate);
|
||||
fe = vb2_dvb_get_frontend(f, f->gate);
|
||||
|
||||
if (fe && fe->dvb.frontend && fe->dvb.frontend->ops.i2c_gate_ctrl)
|
||||
fe->dvb.frontend->ops.i2c_gate_ctrl(fe->dvb.frontend, open);
|
||||
}
|
||||
|
||||
static struct videobuf_queue_ops dvb_qops = {
|
||||
.buf_setup = dvb_buf_setup,
|
||||
.buf_prepare = dvb_buf_prepare,
|
||||
.buf_queue = dvb_buf_queue,
|
||||
.buf_release = dvb_buf_release,
|
||||
static int cx23885_start_streaming(struct vb2_queue *q, unsigned int count)
|
||||
{
|
||||
struct cx23885_tsport *port = q->drv_priv;
|
||||
struct cx23885_dmaqueue *dmaq = &port->mpegq;
|
||||
struct cx23885_buffer *buf = list_entry(dmaq->active.next,
|
||||
struct cx23885_buffer, queue);
|
||||
|
||||
cx23885_start_dma(port, dmaq, buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cx23885_stop_streaming(struct vb2_queue *q)
|
||||
{
|
||||
struct cx23885_tsport *port = q->drv_priv;
|
||||
|
||||
cx23885_cancel_buffers(port);
|
||||
}
|
||||
|
||||
static struct vb2_ops dvb_qops = {
|
||||
.queue_setup = queue_setup,
|
||||
.buf_prepare = buffer_prepare,
|
||||
.buf_finish = buffer_finish,
|
||||
.buf_queue = buffer_queue,
|
||||
.wait_prepare = vb2_ops_wait_prepare,
|
||||
.wait_finish = vb2_ops_wait_finish,
|
||||
.start_streaming = cx23885_start_streaming,
|
||||
.stop_streaming = cx23885_stop_streaming,
|
||||
};
|
||||
|
||||
static struct s5h1409_config hauppauge_generic_config = {
|
||||
|
@ -859,16 +895,16 @@ static int dvb_register(struct cx23885_tsport *port)
|
|||
struct dib7000p_ops dib7000p_ops;
|
||||
struct cx23885_dev *dev = port->dev;
|
||||
struct cx23885_i2c *i2c_bus = NULL, *i2c_bus2 = NULL;
|
||||
struct videobuf_dvb_frontend *fe0, *fe1 = NULL;
|
||||
struct vb2_dvb_frontend *fe0, *fe1 = NULL;
|
||||
int mfe_shared = 0; /* bus not shared by default */
|
||||
int ret;
|
||||
|
||||
/* Get the first frontend */
|
||||
fe0 = videobuf_dvb_get_frontend(&port->frontends, 1);
|
||||
fe0 = vb2_dvb_get_frontend(&port->frontends, 1);
|
||||
if (!fe0)
|
||||
return -EINVAL;
|
||||
|
||||
/* init struct videobuf_dvb */
|
||||
/* init struct vb2_dvb */
|
||||
fe0->dvb.name = dev->name;
|
||||
|
||||
/* multi-frontend gate control is undefined or defaults to fe0 */
|
||||
|
@ -1388,7 +1424,7 @@ static int dvb_register(struct cx23885_tsport *port)
|
|||
fe0->dvb.frontend->ops.tuner_ops.init(fe0->dvb.frontend);
|
||||
}
|
||||
/* MFE frontend 2 */
|
||||
fe1 = videobuf_dvb_get_frontend(&port->frontends, 2);
|
||||
fe1 = vb2_dvb_get_frontend(&port->frontends, 2);
|
||||
if (fe1 == NULL)
|
||||
goto frontend_detach;
|
||||
/* DVB-C init */
|
||||
|
@ -1528,7 +1564,7 @@ static int dvb_register(struct cx23885_tsport *port)
|
|||
fe0->dvb.frontend->ops.analog_ops.standby(fe0->dvb.frontend);
|
||||
|
||||
/* register everything */
|
||||
ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port,
|
||||
ret = vb2_dvb_register_bus(&port->frontends, THIS_MODULE, port,
|
||||
&dev->pci->dev, adapter_nr, mfe_shared);
|
||||
if (ret)
|
||||
goto frontend_detach;
|
||||
|
@ -1577,14 +1613,14 @@ static int dvb_register(struct cx23885_tsport *port)
|
|||
|
||||
frontend_detach:
|
||||
port->gate_ctrl = NULL;
|
||||
videobuf_dvb_dealloc_frontends(&port->frontends);
|
||||
vb2_dvb_dealloc_frontends(&port->frontends);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int cx23885_dvb_register(struct cx23885_tsport *port)
|
||||
{
|
||||
|
||||
struct videobuf_dvb_frontend *fe0;
|
||||
struct vb2_dvb_frontend *fe0;
|
||||
struct cx23885_dev *dev = port->dev;
|
||||
int err, i;
|
||||
|
||||
|
@ -1601,13 +1637,15 @@ int cx23885_dvb_register(struct cx23885_tsport *port)
|
|||
port->num_frontends);
|
||||
|
||||
for (i = 1; i <= port->num_frontends; i++) {
|
||||
if (videobuf_dvb_alloc_frontend(
|
||||
struct vb2_queue *q;
|
||||
|
||||
if (vb2_dvb_alloc_frontend(
|
||||
&port->frontends, i) == NULL) {
|
||||
printk(KERN_ERR "%s() failed to alloc\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
fe0 = videobuf_dvb_get_frontend(&port->frontends, i);
|
||||
fe0 = vb2_dvb_get_frontend(&port->frontends, i);
|
||||
if (!fe0)
|
||||
err = -EINVAL;
|
||||
|
||||
|
@ -1623,10 +1661,21 @@ int cx23885_dvb_register(struct cx23885_tsport *port)
|
|||
/* dvb stuff */
|
||||
/* We have to init the queue for each frontend on a port. */
|
||||
printk(KERN_INFO "%s: cx23885 based dvb card\n", dev->name);
|
||||
videobuf_queue_sg_init(&fe0->dvb.dvbq, &dvb_qops,
|
||||
&dev->pci->dev, &port->slock,
|
||||
V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_TOP,
|
||||
sizeof(struct cx23885_buffer), port, NULL);
|
||||
q = &fe0->dvb.dvbq;
|
||||
q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
|
||||
q->gfp_flags = GFP_DMA32;
|
||||
q->min_buffers_needed = 2;
|
||||
q->drv_priv = port;
|
||||
q->buf_struct_size = sizeof(struct cx23885_buffer);
|
||||
q->ops = &dvb_qops;
|
||||
q->mem_ops = &vb2_dma_sg_memops;
|
||||
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
|
||||
q->lock = &dev->lock;
|
||||
|
||||
err = vb2_queue_init(q);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
err = dvb_register(port);
|
||||
if (err != 0)
|
||||
|
@ -1638,7 +1687,7 @@ int cx23885_dvb_register(struct cx23885_tsport *port)
|
|||
|
||||
int cx23885_dvb_unregister(struct cx23885_tsport *port)
|
||||
{
|
||||
struct videobuf_dvb_frontend *fe0;
|
||||
struct vb2_dvb_frontend *fe0;
|
||||
|
||||
/* FIXME: in an error condition where the we have
|
||||
* an expected number of frontends (attach problem)
|
||||
|
@ -1647,9 +1696,9 @@ int cx23885_dvb_unregister(struct cx23885_tsport *port)
|
|||
* This comment only applies to future boards IF they
|
||||
* implement MFE support.
|
||||
*/
|
||||
fe0 = videobuf_dvb_get_frontend(&port->frontends, 1);
|
||||
fe0 = vb2_dvb_get_frontend(&port->frontends, 1);
|
||||
if (fe0 && fe0->dvb.frontend)
|
||||
videobuf_dvb_unregister_bus(&port->frontends);
|
||||
vb2_dvb_unregister_bus(&port->frontends);
|
||||
|
||||
switch (port->dev->board) {
|
||||
case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
|
||||
|
|
|
@ -38,9 +38,8 @@ MODULE_PARM_DESC(vbi_debug, "enable debug messages [vbi]");
|
|||
/* ------------------------------------------------------------------ */
|
||||
|
||||
#define VBI_LINE_LENGTH 1440
|
||||
#define NTSC_VBI_START_LINE 10 /* line 10 - 21 */
|
||||
#define NTSC_VBI_END_LINE 21
|
||||
#define NTSC_VBI_LINES (NTSC_VBI_END_LINE - NTSC_VBI_START_LINE + 1)
|
||||
#define VBI_NTSC_LINE_COUNT 12
|
||||
#define VBI_PAL_LINE_COUNT 18
|
||||
|
||||
|
||||
int cx23885_vbi_fmt(struct file *file, void *priv,
|
||||
|
@ -48,22 +47,23 @@ int cx23885_vbi_fmt(struct file *file, void *priv,
|
|||
{
|
||||
struct cx23885_dev *dev = video_drvdata(file);
|
||||
|
||||
f->fmt.vbi.sampling_rate = 27000000;
|
||||
f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH;
|
||||
f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
|
||||
f->fmt.vbi.offset = 0;
|
||||
f->fmt.vbi.flags = 0;
|
||||
if (dev->tvnorm & V4L2_STD_525_60) {
|
||||
/* ntsc */
|
||||
f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH;
|
||||
f->fmt.vbi.sampling_rate = 27000000;
|
||||
f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
|
||||
f->fmt.vbi.offset = 0;
|
||||
f->fmt.vbi.flags = 0;
|
||||
f->fmt.vbi.start[0] = 10;
|
||||
f->fmt.vbi.count[0] = 17;
|
||||
f->fmt.vbi.start[1] = 263 + 10 + 1;
|
||||
f->fmt.vbi.count[1] = 17;
|
||||
f->fmt.vbi.start[1] = 272;
|
||||
f->fmt.vbi.count[0] = VBI_NTSC_LINE_COUNT;
|
||||
f->fmt.vbi.count[1] = VBI_NTSC_LINE_COUNT;
|
||||
} else if (dev->tvnorm & V4L2_STD_625_50) {
|
||||
/* pal */
|
||||
f->fmt.vbi.sampling_rate = 35468950;
|
||||
f->fmt.vbi.start[0] = 7 - 1;
|
||||
f->fmt.vbi.start[1] = 319 - 1;
|
||||
f->fmt.vbi.start[0] = 6;
|
||||
f->fmt.vbi.start[1] = 318;
|
||||
f->fmt.vbi.count[0] = VBI_PAL_LINE_COUNT;
|
||||
f->fmt.vbi.count[1] = VBI_PAL_LINE_COUNT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -89,15 +89,6 @@ int cx23885_vbi_irq(struct cx23885_dev *dev, u32 status)
|
|||
handled++;
|
||||
}
|
||||
|
||||
if (status & VID_BC_MSK_VBI_RISCI2) {
|
||||
dprintk(1, "%s() VID_BC_MSK_VBI_RISCI2\n", __func__);
|
||||
dprintk(2, "stopper vbi\n");
|
||||
spin_lock(&dev->slock);
|
||||
cx23885_restart_vbi_queue(dev, &dev->vbiq);
|
||||
spin_unlock(&dev->slock);
|
||||
handled++;
|
||||
}
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
|
@ -109,13 +100,13 @@ static int cx23885_start_vbi_dma(struct cx23885_dev *dev,
|
|||
|
||||
/* setup fifo + format */
|
||||
cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH02],
|
||||
buf->vb.width, buf->risc.dma);
|
||||
VBI_LINE_LENGTH, buf->risc.dma);
|
||||
|
||||
/* reset counter */
|
||||
cx_write(VID_A_GPCNT_CTL, 3);
|
||||
cx_write(VID_A_VBI_CTRL, 3);
|
||||
cx_write(VBI_A_GPCNT_CTL, 3);
|
||||
q->count = 1;
|
||||
q->count = 0;
|
||||
|
||||
/* enable irq */
|
||||
cx23885_irq_add_enable(dev, 0x01);
|
||||
|
@ -128,163 +119,153 @@ static int cx23885_start_vbi_dma(struct cx23885_dev *dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int cx23885_restart_vbi_queue(struct cx23885_dev *dev,
|
||||
struct cx23885_dmaqueue *q)
|
||||
{
|
||||
struct cx23885_buffer *buf;
|
||||
struct list_head *item;
|
||||
|
||||
if (list_empty(&q->active))
|
||||
return 0;
|
||||
|
||||
buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue);
|
||||
dprintk(2, "restart_queue [%p/%d]: restart dma\n",
|
||||
buf, buf->vb.i);
|
||||
cx23885_start_vbi_dma(dev, q, buf);
|
||||
list_for_each(item, &q->active) {
|
||||
buf = list_entry(item, struct cx23885_buffer, vb.queue);
|
||||
buf->count = q->count++;
|
||||
}
|
||||
mod_timer(&q->timeout, jiffies + (BUFFER_TIMEOUT / 30));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cx23885_vbi_timeout(unsigned long data)
|
||||
{
|
||||
struct cx23885_dev *dev = (struct cx23885_dev *)data;
|
||||
struct cx23885_dmaqueue *q = &dev->vbiq;
|
||||
struct cx23885_buffer *buf;
|
||||
unsigned long flags;
|
||||
|
||||
/* Stop the VBI engine */
|
||||
cx_clear(VID_A_DMA_CTL, 0x22);
|
||||
|
||||
spin_lock_irqsave(&dev->slock, flags);
|
||||
while (!list_empty(&q->active)) {
|
||||
buf = list_entry(q->active.next, struct cx23885_buffer,
|
||||
vb.queue);
|
||||
list_del(&buf->vb.queue);
|
||||
buf->vb.state = VIDEOBUF_ERROR;
|
||||
wake_up(&buf->vb.done);
|
||||
printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", dev->name,
|
||||
buf, buf->vb.i, (unsigned long)buf->risc.dma);
|
||||
}
|
||||
cx23885_restart_vbi_queue(dev, q);
|
||||
spin_unlock_irqrestore(&dev->slock, flags);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
#define VBI_LINE_LENGTH 1440
|
||||
#define VBI_LINE_COUNT 17
|
||||
|
||||
static int
|
||||
vbi_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 *num_buffers, unsigned int *num_planes,
|
||||
unsigned int sizes[], void *alloc_ctxs[])
|
||||
{
|
||||
*size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2;
|
||||
if (0 == *count)
|
||||
*count = vbibufs;
|
||||
if (*count < 2)
|
||||
*count = 2;
|
||||
if (*count > 32)
|
||||
*count = 32;
|
||||
struct cx23885_dev *dev = q->drv_priv;
|
||||
unsigned lines = VBI_PAL_LINE_COUNT;
|
||||
|
||||
if (dev->tvnorm & V4L2_STD_525_60)
|
||||
lines = VBI_NTSC_LINE_COUNT;
|
||||
*num_planes = 1;
|
||||
sizes[0] = lines * VBI_LINE_LENGTH * 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
|
||||
enum v4l2_field field)
|
||||
static int buffer_prepare(struct vb2_buffer *vb)
|
||||
{
|
||||
struct cx23885_fh *fh = q->priv_data;
|
||||
struct cx23885_dev *dev = fh->q_dev;
|
||||
struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
|
||||
struct cx23885_buffer *buf = container_of(vb,
|
||||
struct cx23885_buffer, vb);
|
||||
struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
|
||||
unsigned int size;
|
||||
int rc;
|
||||
struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
|
||||
unsigned lines = VBI_PAL_LINE_COUNT;
|
||||
int ret;
|
||||
|
||||
size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2;
|
||||
if (0 != buf->vb.baddr && buf->vb.bsize < size)
|
||||
if (dev->tvnorm & V4L2_STD_525_60)
|
||||
lines = VBI_NTSC_LINE_COUNT;
|
||||
|
||||
if (vb2_plane_size(vb, 0) < lines * VBI_LINE_LENGTH * 2)
|
||||
return -EINVAL;
|
||||
vb2_set_plane_payload(vb, 0, lines * VBI_LINE_LENGTH * 2);
|
||||
|
||||
if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
|
||||
buf->vb.width = VBI_LINE_LENGTH;
|
||||
buf->vb.height = VBI_LINE_COUNT;
|
||||
buf->vb.size = size;
|
||||
buf->vb.field = V4L2_FIELD_SEQ_TB;
|
||||
ret = dma_map_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
|
||||
if (!ret)
|
||||
return -EIO;
|
||||
|
||||
rc = videobuf_iolock(q, &buf->vb, NULL);
|
||||
if (0 != rc)
|
||||
goto fail;
|
||||
cx23885_risc_vbibuffer(dev->pci, &buf->risc,
|
||||
dma->sglist,
|
||||
0, buf->vb.width * buf->vb.height,
|
||||
buf->vb.width, 0,
|
||||
buf->vb.height);
|
||||
}
|
||||
buf->vb.state = VIDEOBUF_PREPARED;
|
||||
cx23885_risc_vbibuffer(dev->pci, &buf->risc,
|
||||
sgt->sgl,
|
||||
0, VBI_LINE_LENGTH * lines,
|
||||
VBI_LINE_LENGTH, 0,
|
||||
lines);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
cx23885_free_buffer(q, buf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void
|
||||
vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
|
||||
static void buffer_finish(struct vb2_buffer *vb)
|
||||
{
|
||||
struct cx23885_buffer *buf =
|
||||
container_of(vb, struct cx23885_buffer, vb);
|
||||
struct cx23885_buffer *prev;
|
||||
struct cx23885_fh *fh = vq->priv_data;
|
||||
struct cx23885_dev *dev = fh->q_dev;
|
||||
struct cx23885_dmaqueue *q = &dev->vbiq;
|
||||
struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
|
||||
struct cx23885_buffer *buf = container_of(vb,
|
||||
struct cx23885_buffer, vb);
|
||||
struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
|
||||
|
||||
/* add jump to stopper */
|
||||
buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
|
||||
buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
|
||||
cx23885_free_buffer(vb->vb2_queue->drv_priv, buf);
|
||||
|
||||
dma_unmap_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
|
||||
}
|
||||
|
||||
/*
|
||||
* The risc program for each buffer works as follows: it starts with a simple
|
||||
* 'JUMP to addr + 12', which is effectively a NOP. Then the code to DMA the
|
||||
* buffer follows and at the end we have a JUMP back to the start + 12 (skipping
|
||||
* the initial JUMP).
|
||||
*
|
||||
* This is the risc program of the first buffer to be queued if the active list
|
||||
* is empty and it just keeps DMAing this buffer without generating any
|
||||
* interrupts.
|
||||
*
|
||||
* If a new buffer is added then the initial JUMP in the code for that buffer
|
||||
* will generate an interrupt which signals that the previous buffer has been
|
||||
* DMAed successfully and that it can be returned to userspace.
|
||||
*
|
||||
* It also sets the final jump of the previous buffer to the start of the new
|
||||
* buffer, thus chaining the new buffer into the DMA chain. This is a single
|
||||
* atomic u32 write, so there is no race condition.
|
||||
*
|
||||
* The end-result of all this that you only get an interrupt when a buffer
|
||||
* is ready, so the control flow is very easy.
|
||||
*/
|
||||
static void buffer_queue(struct vb2_buffer *vb)
|
||||
{
|
||||
struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
|
||||
struct cx23885_buffer *buf = container_of(vb, struct cx23885_buffer, vb);
|
||||
struct cx23885_buffer *prev;
|
||||
struct cx23885_dmaqueue *q = &dev->vbiq;
|
||||
unsigned long flags;
|
||||
|
||||
buf->risc.cpu[1] = cpu_to_le32(buf->risc.dma + 12);
|
||||
buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_CNT_INC);
|
||||
buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma + 12);
|
||||
buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
|
||||
|
||||
if (list_empty(&q->active)) {
|
||||
list_add_tail(&buf->vb.queue, &q->active);
|
||||
cx23885_start_vbi_dma(dev, q, buf);
|
||||
buf->vb.state = VIDEOBUF_ACTIVE;
|
||||
buf->count = q->count++;
|
||||
mod_timer(&q->timeout, jiffies + (BUFFER_TIMEOUT / 30));
|
||||
spin_lock_irqsave(&dev->slock, flags);
|
||||
list_add_tail(&buf->queue, &q->active);
|
||||
spin_unlock_irqrestore(&dev->slock, flags);
|
||||
dprintk(2, "[%p/%d] vbi_queue - first active\n",
|
||||
buf, buf->vb.i);
|
||||
buf, buf->vb.v4l2_buf.index);
|
||||
|
||||
} else {
|
||||
buf->risc.cpu[0] |= cpu_to_le32(RISC_IRQ1);
|
||||
prev = list_entry(q->active.prev, struct cx23885_buffer,
|
||||
vb.queue);
|
||||
list_add_tail(&buf->vb.queue, &q->active);
|
||||
buf->vb.state = VIDEOBUF_ACTIVE;
|
||||
buf->count = q->count++;
|
||||
queue);
|
||||
spin_lock_irqsave(&dev->slock, flags);
|
||||
list_add_tail(&buf->queue, &q->active);
|
||||
spin_unlock_irqrestore(&dev->slock, flags);
|
||||
prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
|
||||
prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63-32 */
|
||||
dprintk(2, "[%p/%d] buffer_queue - append to active\n",
|
||||
buf, buf->vb.i);
|
||||
buf, buf->vb.v4l2_buf.index);
|
||||
}
|
||||
}
|
||||
|
||||
static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
|
||||
static int cx23885_start_streaming(struct vb2_queue *q, unsigned int count)
|
||||
{
|
||||
struct cx23885_buffer *buf =
|
||||
container_of(vb, struct cx23885_buffer, vb);
|
||||
struct cx23885_dev *dev = q->drv_priv;
|
||||
struct cx23885_dmaqueue *dmaq = &dev->vbiq;
|
||||
struct cx23885_buffer *buf = list_entry(dmaq->active.next,
|
||||
struct cx23885_buffer, queue);
|
||||
|
||||
cx23885_free_buffer(q, buf);
|
||||
cx23885_start_vbi_dma(dev, dmaq, buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct videobuf_queue_ops cx23885_vbi_qops = {
|
||||
.buf_setup = vbi_setup,
|
||||
.buf_prepare = vbi_prepare,
|
||||
.buf_queue = vbi_queue,
|
||||
.buf_release = vbi_release,
|
||||
};
|
||||
static void cx23885_stop_streaming(struct vb2_queue *q)
|
||||
{
|
||||
struct cx23885_dev *dev = q->drv_priv;
|
||||
struct cx23885_dmaqueue *dmaq = &dev->vbiq;
|
||||
unsigned long flags;
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* End:
|
||||
*/
|
||||
cx_clear(VID_A_DMA_CTL, 0x22); /* FIFO and RISC enable */
|
||||
spin_lock_irqsave(&dev->slock, flags);
|
||||
while (!list_empty(&dmaq->active)) {
|
||||
struct cx23885_buffer *buf = list_entry(dmaq->active.next,
|
||||
struct cx23885_buffer, queue);
|
||||
|
||||
list_del(&buf->queue);
|
||||
vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
|
||||
}
|
||||
spin_unlock_irqrestore(&dev->slock, flags);
|
||||
}
|
||||
|
||||
|
||||
struct vb2_ops cx23885_vbi_qops = {
|
||||
.queue_setup = queue_setup,
|
||||
.buf_prepare = buffer_prepare,
|
||||
.buf_finish = buffer_finish,
|
||||
.buf_queue = buffer_queue,
|
||||
.wait_prepare = vb2_ops_wait_prepare,
|
||||
.wait_finish = vb2_ops_wait_finish,
|
||||
.start_streaming = cx23885_start_streaming,
|
||||
.stop_streaming = cx23885_stop_streaming,
|
||||
};
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -25,8 +25,8 @@
|
|||
#include <media/v4l2-ctrls.h>
|
||||
#include <media/tuner.h>
|
||||
#include <media/tveeprom.h>
|
||||
#include <media/videobuf-dma-sg.h>
|
||||
#include <media/videobuf-dvb.h>
|
||||
#include <media/videobuf2-dma-sg.h>
|
||||
#include <media/videobuf2-dvb.h>
|
||||
#include <media/rc-core.h>
|
||||
|
||||
#include "btcx-risc.h"
|
||||
|
@ -35,7 +35,7 @@
|
|||
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#define CX23885_VERSION "0.0.3"
|
||||
#define CX23885_VERSION "0.0.4"
|
||||
|
||||
#define UNSET (-1U)
|
||||
|
||||
|
@ -44,9 +44,6 @@
|
|||
/* Max number of inputs by card */
|
||||
#define MAX_CX23885_INPUT 8
|
||||
#define INPUT(nr) (&cx23885_boards[dev->board].input[nr])
|
||||
#define RESOURCE_OVERLAY 1
|
||||
#define RESOURCE_VIDEO 2
|
||||
#define RESOURCE_VBI 4
|
||||
|
||||
#define BUFFER_TIMEOUT (HZ) /* 0.5 seconds */
|
||||
|
||||
|
@ -136,20 +133,6 @@ struct cx23885_tvnorm {
|
|||
u32 cxoformat;
|
||||
};
|
||||
|
||||
struct cx23885_fh {
|
||||
struct v4l2_fh fh;
|
||||
u32 resources;
|
||||
struct cx23885_dev *q_dev;
|
||||
|
||||
/* vbi capture */
|
||||
struct videobuf_queue vidq;
|
||||
struct videobuf_queue vbiq;
|
||||
|
||||
/* MPEG Encoder specifics ONLY */
|
||||
struct videobuf_queue mpegq;
|
||||
atomic_t v4l_reading;
|
||||
};
|
||||
|
||||
enum cx23885_itype {
|
||||
CX23885_VMUX_COMPOSITE1 = 1,
|
||||
CX23885_VMUX_COMPOSITE2,
|
||||
|
@ -172,7 +155,8 @@ enum cx23885_src_sel_type {
|
|||
/* buffer for one video frame */
|
||||
struct cx23885_buffer {
|
||||
/* common v4l buffer stuff -- must be first */
|
||||
struct videobuf_buffer vb;
|
||||
struct vb2_buffer vb;
|
||||
struct list_head queue;
|
||||
|
||||
/* cx23885 specific */
|
||||
unsigned int bpl;
|
||||
|
@ -248,9 +232,6 @@ struct cx23885_i2c {
|
|||
|
||||
struct cx23885_dmaqueue {
|
||||
struct list_head active;
|
||||
struct list_head queued;
|
||||
struct timer_list timeout;
|
||||
struct btcx_riscmem stopper;
|
||||
u32 count;
|
||||
};
|
||||
|
||||
|
@ -260,7 +241,7 @@ struct cx23885_tsport {
|
|||
int nr;
|
||||
int sram_chno;
|
||||
|
||||
struct videobuf_dvb_frontends frontends;
|
||||
struct vb2_dvb_frontends frontends;
|
||||
|
||||
/* dma queues */
|
||||
struct cx23885_dmaqueue mpegq;
|
||||
|
@ -389,7 +370,6 @@ struct cx23885_dev {
|
|||
} bridge;
|
||||
|
||||
/* Analog video */
|
||||
u32 resources;
|
||||
unsigned int input;
|
||||
unsigned int audinput; /* Selectable audio input */
|
||||
u32 tvaudio;
|
||||
|
@ -420,16 +400,20 @@ struct cx23885_dev {
|
|||
/* video capture */
|
||||
struct cx23885_fmt *fmt;
|
||||
unsigned int width, height;
|
||||
unsigned field;
|
||||
|
||||
struct cx23885_dmaqueue vidq;
|
||||
struct vb2_queue vb2_vidq;
|
||||
struct cx23885_dmaqueue vbiq;
|
||||
struct vb2_queue vb2_vbiq;
|
||||
|
||||
spinlock_t slock;
|
||||
|
||||
/* MPEG Encoder ONLY settings */
|
||||
u32 cx23417_mailbox;
|
||||
struct cx2341x_handler cxhdl;
|
||||
struct video_device *v4l_device;
|
||||
atomic_t v4l_reader_count;
|
||||
struct vb2_queue vb2_mpegq;
|
||||
struct cx23885_tvnorm encodernorm;
|
||||
|
||||
/* Analog raw audio */
|
||||
|
@ -505,9 +489,6 @@ extern int cx23885_sram_channel_setup(struct cx23885_dev *dev,
|
|||
extern void cx23885_sram_channel_dump(struct cx23885_dev *dev,
|
||||
struct sram_channel *ch);
|
||||
|
||||
extern int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
|
||||
u32 reg, u32 mask, u32 value);
|
||||
|
||||
extern int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
|
||||
struct scatterlist *sglist,
|
||||
unsigned int top_offset, unsigned int bottom_offset,
|
||||
|
@ -518,13 +499,11 @@ extern int cx23885_risc_vbibuffer(struct pci_dev *pci,
|
|||
unsigned int top_offset, unsigned int bottom_offset,
|
||||
unsigned int bpl, unsigned int padding, unsigned int lines);
|
||||
|
||||
int cx23885_start_dma(struct cx23885_tsport *port,
|
||||
struct cx23885_dmaqueue *q,
|
||||
struct cx23885_buffer *buf);
|
||||
void cx23885_cancel_buffers(struct cx23885_tsport *port);
|
||||
|
||||
extern int cx23885_restart_queue(struct cx23885_tsport *port,
|
||||
struct cx23885_dmaqueue *q);
|
||||
|
||||
extern void cx23885_wakeup(struct cx23885_tsport *port,
|
||||
struct cx23885_dmaqueue *q, u32 count);
|
||||
|
||||
extern void cx23885_gpio_set(struct cx23885_dev *dev, u32 mask);
|
||||
extern void cx23885_gpio_clear(struct cx23885_dev *dev, u32 mask);
|
||||
|
@ -558,13 +537,11 @@ extern void cx23885_card_setup_pre_i2c(struct cx23885_dev *dev);
|
|||
extern int cx23885_dvb_register(struct cx23885_tsport *port);
|
||||
extern int cx23885_dvb_unregister(struct cx23885_tsport *port);
|
||||
|
||||
extern int cx23885_buf_prepare(struct videobuf_queue *q,
|
||||
struct cx23885_tsport *port,
|
||||
struct cx23885_buffer *buf,
|
||||
enum v4l2_field field);
|
||||
extern int cx23885_buf_prepare(struct cx23885_buffer *buf,
|
||||
struct cx23885_tsport *port);
|
||||
extern void cx23885_buf_queue(struct cx23885_tsport *port,
|
||||
struct cx23885_buffer *buf);
|
||||
extern void cx23885_free_buffer(struct videobuf_queue *q,
|
||||
extern void cx23885_free_buffer(struct cx23885_dev *dev,
|
||||
struct cx23885_buffer *buf);
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
|
@ -586,9 +563,7 @@ int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm);
|
|||
extern int cx23885_vbi_fmt(struct file *file, void *priv,
|
||||
struct v4l2_format *f);
|
||||
extern void cx23885_vbi_timeout(unsigned long data);
|
||||
extern struct videobuf_queue_ops cx23885_vbi_qops;
|
||||
extern int cx23885_restart_vbi_queue(struct cx23885_dev *dev,
|
||||
struct cx23885_dmaqueue *q);
|
||||
extern struct vb2_ops cx23885_vbi_qops;
|
||||
extern int cx23885_vbi_irq(struct cx23885_dev *dev, u32 status);
|
||||
|
||||
/* cx23885-i2c.c */
|
||||
|
|
Loading…
Reference in New Issue