diff options
author | Hans Verkuil <hans.verkuil@cisco.com> | 2014-08-14 06:43:01 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <m.chehab@samsung.com> | 2014-09-08 10:00:59 -0300 |
commit | 453afdd9ce33293f640e84dc17e5f366701516e8 (patch) | |
tree | 48c74ee1bb35d812a84162006c154a2cb4dfe4c7 /drivers/media/pci/cx23885/cx23885-video.c | |
parent | 73d8102298719863d54264f62521362487f84256 (diff) | |
download | op-kernel-dev-453afdd9ce33293f640e84dc17e5f366701516e8.zip op-kernel-dev-453afdd9ce33293f640e84dc17e5f366701516e8.tar.gz |
[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>
Diffstat (limited to 'drivers/media/pci/cx23885/cx23885-video.c')
-rw-r--r-- | drivers/media/pci/cx23885/cx23885-video.c | 810 |
1 files changed, 213 insertions, 597 deletions
diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index 9cd8cf4..c6921d4 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -98,34 +98,18 @@ void cx23885_video_wakeup(struct cx23885_dev *dev, struct cx23885_dmaqueue *q, u32 count) { 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_ERR "%s: %d buffers handled (should be 1)\n", - __func__, bc); + return; + buf = list_entry(q->active.next, + struct cx23885_buffer, queue); + + buf->vb.v4l2_buf.sequence = q->count++; + v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp); + dprintk(2, "[%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_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm) @@ -163,50 +147,6 @@ static struct video_device *cx23885_vdev_init(struct cx23885_dev *dev, return vfd; } -/* ------------------------------------------------------------------- */ -/* resource management */ - -static int res_get(struct cx23885_dev *dev, struct cx23885_fh *fh, - unsigned int bit) -{ - dprintk(1, "%s()\n", __func__); - if (fh->resources & bit) - /* have it already allocated */ - return 1; - - /* is it free? */ - if (dev->resources & bit) { - /* no, someone else uses it */ - return 0; - } - /* it's free, grab it */ - fh->resources |= bit; - dev->resources |= bit; - dprintk(1, "res: get %d\n", bit); - return 1; -} - -static int res_check(struct cx23885_fh *fh, unsigned int bit) -{ - return fh->resources & bit; -} - -static int res_locked(struct cx23885_dev *dev, unsigned int bit) -{ - return dev->resources & bit; -} - -static void res_free(struct cx23885_dev *dev, struct cx23885_fh *fh, - unsigned int bits) -{ - BUG_ON((fh->resources & bits) != bits); - dprintk(1, "%s()\n", __func__); - - fh->resources &= ~bits; - dev->resources &= ~bits; - dprintk(1, "res: put %d\n", bits); -} - int cx23885_flatiron_write(struct cx23885_dev *dev, u8 reg, u8 data) { /* 8 bit registers, 8 bit values */ @@ -356,7 +296,7 @@ static int cx23885_start_video_dma(struct cx23885_dev *dev, /* reset counter */ cx_write(VID_A_GPCNT_CTL, 3); - q->count = 1; + q->count = 0; /* enable irq */ cx23885_irq_add_enable(dev, 0x01); @@ -369,444 +309,206 @@ static int cx23885_start_video_dma(struct cx23885_dev *dev, return 0; } - -static int cx23885_restart_video_queue(struct cx23885_dev *dev, - struct cx23885_dmaqueue *q) +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_buffer *buf, *prev; - struct list_head *item; - dprintk(1, "%s()\n", __func__); - - if (!list_empty(&q->active)) { - 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_video_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); - return 0; - } + struct cx23885_dev *dev = q->drv_priv; - prev = NULL; - 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_video_dma(dev, q, buf); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); - dprintk(2, "[%p/%d] restart_queue - first 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); - prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63 - 32 */ - dprintk(2, "[%p/%d] restart_queue - move to active\n", - buf, buf->vb.i); - } else { - return 0; - } - prev = buf; - } -} - -static int buffer_setup(struct videobuf_queue *q, unsigned int *count, - unsigned int *size) -{ - struct cx23885_fh *fh = q->priv_data; - struct cx23885_dev *dev = fh->q_dev; - - *size = (dev->fmt->depth * dev->width * dev->height) >> 3; - if (0 == *count) - *count = 32; - if (*size * *count > vid_limit * 1024 * 1024) - *count = (vid_limit * 1024 * 1024) / *size; + *num_planes = 1; + sizes[0] = (dev->fmt->depth * dev->width * dev->height) >> 3; 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 *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); - int rc, init_buffer = 0; u32 line0_offset, line1_offset; - struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); + struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0); int field_tff; + int ret; - if (WARN_ON(NULL == dev->fmt)) - return -EINVAL; + buf->bpl = (dev->width * dev->fmt->depth) >> 3; - if (dev->width < 48 || dev->width > norm_maxw(dev->tvnorm) || - dev->height < 32 || dev->height > norm_maxh(dev->tvnorm)) - return -EINVAL; - buf->vb.size = (dev->width * dev->height * dev->fmt->depth) >> 3; - if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) + if (vb2_plane_size(vb, 0) < dev->height * buf->bpl) return -EINVAL; + vb2_set_plane_payload(vb, 0, dev->height * buf->bpl); - if (buf->fmt != dev->fmt || - buf->vb.width != dev->width || - buf->vb.height != dev->height || - buf->vb.field != field) { - buf->fmt = dev->fmt; - buf->vb.width = dev->width; - buf->vb.height = dev->height; - buf->vb.field = field; - init_buffer = 1; - } + ret = dma_map_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE); + if (!ret) + return -EIO; - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - init_buffer = 1; - rc = videobuf_iolock(q, &buf->vb, NULL); - if (0 != rc) - goto fail; - } + switch (dev->field) { + case V4L2_FIELD_TOP: + cx23885_risc_buffer(dev->pci, &buf->risc, + sgt->sgl, 0, UNSET, + buf->bpl, 0, dev->height); + break; + case V4L2_FIELD_BOTTOM: + cx23885_risc_buffer(dev->pci, &buf->risc, + sgt->sgl, UNSET, 0, + buf->bpl, 0, dev->height); + break; + case V4L2_FIELD_INTERLACED: + if (dev->tvnorm & V4L2_STD_NTSC) + /* NTSC or */ + field_tff = 1; + else + field_tff = 0; + + if (cx23885_boards[dev->board].force_bff) + /* PAL / SECAM OR 888 in NTSC MODE */ + field_tff = 0; - if (init_buffer) { - buf->bpl = buf->vb.width * buf->fmt->depth >> 3; - switch (buf->vb.field) { - case V4L2_FIELD_TOP: - cx23885_risc_buffer(dev->pci, &buf->risc, - dma->sglist, 0, UNSET, - buf->bpl, 0, buf->vb.height); - break; - case V4L2_FIELD_BOTTOM: - cx23885_risc_buffer(dev->pci, &buf->risc, - dma->sglist, UNSET, 0, - buf->bpl, 0, buf->vb.height); - break; - case V4L2_FIELD_INTERLACED: - if (dev->tvnorm & V4L2_STD_NTSC) - /* NTSC or */ - field_tff = 1; - else - field_tff = 0; - - if (cx23885_boards[dev->board].force_bff) - /* PAL / SECAM OR 888 in NTSC MODE */ - field_tff = 0; - - if (field_tff) { - /* cx25840 transmits NTSC bottom field first */ - dprintk(1, "%s() Creating TFF/NTSC risc\n", + if (field_tff) { + /* cx25840 transmits NTSC bottom field first */ + dprintk(1, "%s() Creating TFF/NTSC risc\n", __func__); - line0_offset = buf->bpl; - line1_offset = 0; - } else { - /* All other formats are top field first */ - dprintk(1, "%s() Creating BFF/PAL/SECAM risc\n", + line0_offset = buf->bpl; + line1_offset = 0; + } else { + /* All other formats are top field first */ + dprintk(1, "%s() Creating BFF/PAL/SECAM risc\n", __func__); - line0_offset = 0; - line1_offset = buf->bpl; - } - cx23885_risc_buffer(dev->pci, &buf->risc, - dma->sglist, line0_offset, - line1_offset, - buf->bpl, buf->bpl, - buf->vb.height >> 1); - break; - case V4L2_FIELD_SEQ_TB: - cx23885_risc_buffer(dev->pci, &buf->risc, - dma->sglist, - 0, buf->bpl * (buf->vb.height >> 1), - buf->bpl, 0, - buf->vb.height >> 1); - break; - case V4L2_FIELD_SEQ_BT: - cx23885_risc_buffer(dev->pci, &buf->risc, - dma->sglist, - buf->bpl * (buf->vb.height >> 1), 0, - buf->bpl, 0, - buf->vb.height >> 1); - break; - default: - BUG(); + line0_offset = 0; + line1_offset = buf->bpl; } + cx23885_risc_buffer(dev->pci, &buf->risc, + sgt->sgl, line0_offset, + line1_offset, + buf->bpl, buf->bpl, + dev->height >> 1); + break; + case V4L2_FIELD_SEQ_TB: + cx23885_risc_buffer(dev->pci, &buf->risc, + sgt->sgl, + 0, buf->bpl * (dev->height >> 1), + buf->bpl, 0, + dev->height >> 1); + break; + case V4L2_FIELD_SEQ_BT: + cx23885_risc_buffer(dev->pci, &buf->risc, + sgt->sgl, + buf->bpl * (dev->height >> 1), 0, + buf->bpl, 0, + dev->height >> 1); + break; + default: + BUG(); } - dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", - buf, buf->vb.i, + dprintk(2, "[%p/%d] buffer_init - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", + buf, buf->vb.v4l2_buf.index, dev->width, dev->height, dev->fmt->depth, dev->fmt->name, (unsigned long)buf->risc.dma); - - buf->vb.state = VIDEOBUF_PREPARED; return 0; +} - fail: - cx23885_free_buffer(q, buf); - return rc; +static void buffer_finish(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 sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0); + + cx23885_free_buffer(vb->vb2_queue->drv_priv, buf); + + dma_unmap_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE); } -static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) +/* + * 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_fh *fh = vq->priv_data; - struct cx23885_dev *dev = fh->q_dev; struct cx23885_dmaqueue *q = &dev->vidq; + 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(q->stopper.dma); + /* add jump to start */ + 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->queued)) { - list_add_tail(&buf->vb.queue, &q->queued); - buf->vb.state = VIDEOBUF_QUEUED; - dprintk(2, "[%p/%d] buffer_queue - append to queued\n", - buf, buf->vb.i); - - } else if (list_empty(&q->active)) { - list_add_tail(&buf->vb.queue, &q->active); - cx23885_start_video_dma(dev, q, buf); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + spin_lock_irqsave(&dev->slock, flags); + if (list_empty(&q->active)) { + list_add_tail(&buf->queue, &q->active); dprintk(2, "[%p/%d] buffer_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); - if (prev->vb.width == buf->vb.width && - prev->vb.height == buf->vb.height && - prev->fmt == buf->fmt) { - list_add_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(2, "[%p/%d] buffer_queue - append to active\n", - buf, buf->vb.i); - - } else { - list_add_tail(&buf->vb.queue, &q->queued); - buf->vb.state = VIDEOBUF_QUEUED; - dprintk(2, "[%p/%d] buffer_queue - first queued\n", - buf, buf->vb.i); - } - } -} - -static void buffer_release(struct videobuf_queue *q, - struct videobuf_buffer *vb) -{ - struct cx23885_buffer *buf = container_of(vb, - struct cx23885_buffer, vb); - - cx23885_free_buffer(q, buf); -} - -static struct videobuf_queue_ops cx23885_video_qops = { - .buf_setup = buffer_setup, - .buf_prepare = buffer_prepare, - .buf_queue = buffer_queue, - .buf_release = buffer_release, -}; - -static struct videobuf_queue *get_queue(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct cx23885_fh *fh = file->private_data; - - switch (vdev->vfl_type) { - case VFL_TYPE_GRABBER: - return &fh->vidq; - case VFL_TYPE_VBI: - return &fh->vbiq; - default: - WARN_ON(1); - return NULL; - } -} - -static int get_resource(u32 type) -{ - switch (type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - return RESOURCE_VIDEO; - case V4L2_BUF_TYPE_VBI_CAPTURE: - return RESOURCE_VBI; - default: - WARN_ON(1); - return 0; + queue); + list_add_tail(&buf->queue, &q->active); + prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); + dprintk(2, "[%p/%d] buffer_queue - append to active\n", + buf, buf->vb.v4l2_buf.index); } + spin_unlock_irqrestore(&dev->slock, flags); } -static int video_open(struct file *file) +static int cx23885_start_streaming(struct vb2_queue *q, unsigned int count) { - struct video_device *vdev = video_devdata(file); - struct cx23885_dev *dev = video_drvdata(file); - struct cx23885_fh *fh; - - dprintk(1, "open dev=%s\n", - video_device_node_name(vdev)); - - /* 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; - fh->q_dev = dev; - - videobuf_queue_sg_init(&fh->vidq, &cx23885_video_qops, - &dev->pci->dev, &dev->slock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_INTERLACED, - sizeof(struct cx23885_buffer), - fh, NULL); - - videobuf_queue_sg_init(&fh->vbiq, &cx23885_vbi_qops, - &dev->pci->dev, &dev->slock, - V4L2_BUF_TYPE_VBI_CAPTURE, - V4L2_FIELD_SEQ_TB, - sizeof(struct cx23885_buffer), - fh, NULL); - - v4l2_fh_add(&fh->fh); - - dprintk(1, "post videobuf_queue_init()\n"); + struct cx23885_dev *dev = q->drv_priv; + struct cx23885_dmaqueue *dmaq = &dev->vidq; + struct cx23885_buffer *buf = list_entry(dmaq->active.next, + struct cx23885_buffer, queue); + cx23885_start_video_dma(dev, dmaq, buf); return 0; } -static ssize_t video_read(struct file *file, char __user *data, - size_t count, loff_t *ppos) +static void cx23885_stop_streaming(struct vb2_queue *q) { - struct video_device *vdev = video_devdata(file); - struct cx23885_dev *dev = video_drvdata(file); - struct cx23885_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(&fh->vidq, 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(&fh->vbiq, data, count, ppos, 1, - file->f_flags & O_NONBLOCK); - default: - return -EINVAL; - } -} - -static unsigned int video_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct video_device *vdev = video_devdata(file); - struct cx23885_dev *dev = video_drvdata(file); - struct cx23885_fh *fh = file->private_data; - struct cx23885_buffer *buf; - unsigned long req_events = poll_requested_events(wait); - unsigned int rc = 0; - - if (v4l2_event_pending(&fh->fh)) - rc = POLLPRI; - else - poll_wait(file, &fh->fh.wait, wait); - if (!(req_events & (POLLIN | POLLRDNORM))) - return rc; - - if (vdev->vfl_type == VFL_TYPE_VBI) { - if (!res_get(dev, fh, RESOURCE_VBI)) - return rc | POLLERR; - return rc | videobuf_poll_stream(file, &fh->vbiq, wait); - } - - mutex_lock(&fh->vidq.vb_lock); - if (res_check(fh, RESOURCE_VIDEO)) { - /* streaming capture */ - if (list_empty(&fh->vidq.stream)) - goto done; - buf = list_entry(fh->vidq.stream.next, - struct cx23885_buffer, vb.stream); - } else { - /* read() capture */ - buf = (struct cx23885_buffer *)fh->vidq.read_buf; - if (NULL == buf) - goto done; - } - poll_wait(file, &buf->vb.done, wait); - if (buf->vb.state == VIDEOBUF_DONE || - buf->vb.state == VIDEOBUF_ERROR) - rc |= POLLIN | POLLRDNORM; -done: - mutex_unlock(&fh->vidq.vb_lock); - return rc; -} - -static int video_release(struct file *file) -{ - struct cx23885_dev *dev = video_drvdata(file); - struct cx23885_fh *fh = file->private_data; - - /* turn off overlay */ - if (res_check(fh, RESOURCE_OVERLAY)) { - /* FIXME */ - res_free(dev, fh, RESOURCE_OVERLAY); - } + struct cx23885_dev *dev = q->drv_priv; + struct cx23885_dmaqueue *dmaq = &dev->vidq; + unsigned long flags; - /* stop video capture */ - if (res_check(fh, RESOURCE_VIDEO)) { - videobuf_queue_cancel(&fh->vidq); - res_free(dev, fh, RESOURCE_VIDEO); - } - if (fh->vidq.read_buf) { - buffer_release(&fh->vidq, fh->vidq.read_buf); - kfree(fh->vidq.read_buf); - } + cx_clear(VID_A_DMA_CTL, 0x11); + spin_lock_irqsave(&dev->slock, flags); + while (!list_empty(&dmaq->active)) { + struct cx23885_buffer *buf = list_entry(dmaq->active.next, + struct cx23885_buffer, queue); - /* stop vbi capture */ - if (res_check(fh, RESOURCE_VBI)) { - if (fh->vbiq.streaming) - videobuf_streamoff(&fh->vbiq); - if (fh->vbiq.reading) - videobuf_read_stop(&fh->vbiq); - res_free(dev, fh, RESOURCE_VBI); + list_del(&buf->queue); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); } - - videobuf_mmap_free(&fh->vidq); - videobuf_mmap_free(&fh->vbiq); - - v4l2_fh_del(&fh->fh); - v4l2_fh_exit(&fh->fh); - file->private_data = NULL; - kfree(fh); - - /* We are not putting the tuner to sleep here on exit, because - * we want to use the mpeg encoder in another session to capture - * tuner video. Closing this will result in no video to the encoder. - */ - - return 0; + spin_unlock_irqrestore(&dev->slock, flags); } -static int video_mmap(struct file *file, struct vm_area_struct *vma) -{ - return videobuf_mmap_mapper(get_queue(file), vma); -} +static struct vb2_ops cx23885_video_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, +}; /* ------------------------------------------------------------------ */ /* VIDEO IOCTLS */ @@ -815,11 +517,10 @@ 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 = priv; f->fmt.pix.width = dev->width; f->fmt.pix.height = dev->height; - f->fmt.pix.field = fh->vidq.field; + f->fmt.pix.field = dev->field; f->fmt.pix.pixelformat = dev->fmt->fourcc; f->fmt.pix.bytesperline = (f->fmt.pix.width * dev->fmt->depth) >> 3; @@ -880,7 +581,6 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct cx23885_dev *dev = video_drvdata(file); - struct cx23885_fh *fh = priv; struct v4l2_mbus_framefmt mbus_fmt; int err; @@ -892,9 +592,9 @@ static int vidioc_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; - fh->vidq.field = f->fmt.pix.field; + dev->field = f->fmt.pix.field; dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, - dev->width, dev->height, fh->vidq.field); + dev->width, dev->height, dev->field); v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED); call_all(dev, video, s_mbus_fmt, &mbus_fmt); v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt); @@ -936,82 +636,6 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, return 0; } -static int vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *p) -{ - return videobuf_reqbufs(get_queue(file), p); -} - -static int vidioc_querybuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - return videobuf_querybuf(get_queue(file), p); -} - -static int vidioc_qbuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - return videobuf_qbuf(get_queue(file), p); -} - -static int vidioc_dqbuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - return videobuf_dqbuf(get_queue(file), p, - file->f_flags & O_NONBLOCK); -} - -static int vidioc_streamon(struct file *file, void *priv, - enum v4l2_buf_type i) -{ - struct cx23885_dev *dev = video_drvdata(file); - struct video_device *vdev = video_devdata(file); - struct cx23885_fh *fh = priv; - dprintk(1, "%s()\n", __func__); - - if (vdev->vfl_type == VFL_TYPE_VBI && - i != V4L2_BUF_TYPE_VBI_CAPTURE) - return -EINVAL; - if (vdev->vfl_type == VFL_TYPE_GRABBER && - i != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if (unlikely(!res_get(dev, fh, get_resource(i)))) - return -EBUSY; - - /* Don't start VBI streaming unless vida streaming - * has already started. - */ - if ((i == V4L2_BUF_TYPE_VBI_CAPTURE) && - ((cx_read(VID_A_DMA_CTL) & 0x11) == 0)) - return -EINVAL; - - return videobuf_streamon(get_queue(file)); -} - -static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) -{ - struct cx23885_dev *dev = video_drvdata(file); - struct video_device *vdev = video_devdata(file); - struct cx23885_fh *fh = priv; - int err, res; - dprintk(1, "%s()\n", __func__); - - if (vdev->vfl_type == VFL_TYPE_VBI && - i != V4L2_BUF_TYPE_VBI_CAPTURE) - return -EINVAL; - if (vdev->vfl_type == VFL_TYPE_GRABBER && - i != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - res = get_resource(i); - err = videobuf_streamoff(get_queue(file)); - if (err < 0) - return err; - res_free(dev, fh, res); - return 0; -} - static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) { struct cx23885_dev *dev = video_drvdata(file); @@ -1288,7 +912,7 @@ static int cx23885_set_freq_via_ops(struct cx23885_dev *dev, { struct v4l2_ctrl *mute; int old_mute_val = 1; - struct videobuf_dvb_frontend *vfe; + struct vb2_dvb_frontend *vfe; struct dvb_frontend *fe; struct analog_parameters params = { @@ -1312,7 +936,7 @@ static int cx23885_set_freq_via_ops(struct cx23885_dev *dev, dprintk(1, "%s() frequency=%d tuner=%d std=0x%llx\n", __func__, params.frequency, f->tuner, params.std); - vfe = videobuf_dvb_get_frontend(&dev->ts2.frontends, 1); + vfe = vb2_dvb_get_frontend(&dev->ts2.frontends, 1); if (!vfe) { return -EINVAL; } @@ -1368,28 +992,6 @@ static int vidioc_s_frequency(struct file *file, void *priv, /* ----------------------------------------------------------- */ -static void cx23885_vid_timeout(unsigned long data) -{ - struct cx23885_dev *dev = (struct cx23885_dev *)data; - struct cx23885_dmaqueue *q = &dev->vidq; - struct cx23885_buffer *buf; - unsigned long flags; - - 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(KERN_ERR "%s: [%p/%d] timeout - dma=0x%08lx\n", - dev->name, buf, buf->vb.i, - (unsigned long)buf->risc.dma); - } - cx23885_restart_video_queue(dev, q); - spin_unlock_irqrestore(&dev->slock, flags); -} - int cx23885_video_irq(struct cx23885_dev *dev, u32 status) { u32 mask, count; @@ -1434,13 +1036,6 @@ int cx23885_video_irq(struct cx23885_dev *dev, u32 status) spin_unlock(&dev->slock); handled++; } - if (status & VID_BC_MSK_RISCI2) { - dprintk(2, "stopper video\n"); - spin_lock(&dev->slock); - cx23885_restart_video_queue(dev, &dev->vidq); - spin_unlock(&dev->slock); - handled++; - } /* Allow the VBI framework to process it's payload */ handled += cx23885_vbi_irq(dev, status); @@ -1453,12 +1048,12 @@ int cx23885_video_irq(struct cx23885_dev *dev, u32 status) 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, + .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 video_ioctl_ops = { @@ -1470,18 +1065,19 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_g_fmt_vbi_cap = cx23885_vbi_fmt, .vidioc_try_fmt_vbi_cap = cx23885_vbi_fmt, .vidioc_s_fmt_vbi_cap = cx23885_vbi_fmt, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, + .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_s_std = vidioc_s_std, .vidioc_g_std = vidioc_g_std, .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, .vidioc_s_input = vidioc_s_input, .vidioc_log_status = vidioc_log_status, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, .vidioc_g_frequency = vidioc_g_frequency, @@ -1517,7 +1113,6 @@ void cx23885_video_unregister(struct cx23885_dev *dev) else video_device_release(dev->vbi_dev); dev->vbi_dev = NULL; - btcx_riscmem_free(dev->pci, &dev->vbiq.stopper); } if (dev->video_dev) { if (video_is_registered(dev->video_dev)) @@ -1525,8 +1120,6 @@ void cx23885_video_unregister(struct cx23885_dev *dev) else video_device_release(dev->video_dev); dev->video_dev = NULL; - - btcx_riscmem_free(dev->pci, &dev->vidq.stopper); } if (dev->audio_dev) @@ -1535,6 +1128,7 @@ void cx23885_video_unregister(struct cx23885_dev *dev) int cx23885_video_register(struct cx23885_dev *dev) { + struct vb2_queue *q; int err; dprintk(1, "%s()\n", __func__); @@ -1551,21 +1145,9 @@ int cx23885_video_register(struct cx23885_dev *dev) /* init video dma queues */ INIT_LIST_HEAD(&dev->vidq.active); - INIT_LIST_HEAD(&dev->vidq.queued); - dev->vidq.timeout.function = cx23885_vid_timeout; - dev->vidq.timeout.data = (unsigned long)dev; - init_timer(&dev->vidq.timeout); - cx23885_risc_stopper(dev->pci, &dev->vidq.stopper, - VID_A_DMA_CTL, 0x11, 0x00); /* init vbi dma queues */ INIT_LIST_HEAD(&dev->vbiq.active); - INIT_LIST_HEAD(&dev->vbiq.queued); - dev->vbiq.timeout.function = cx23885_vbi_timeout; - dev->vbiq.timeout.data = (unsigned long)dev; - init_timer(&dev->vbiq.timeout); - cx23885_risc_stopper(dev->pci, &dev->vbiq.stopper, - VID_A_DMA_CTL, 0x22, 0x00); cx23885_irq_add_enable(dev, 0x01); @@ -1626,9 +1208,42 @@ int cx23885_video_register(struct cx23885_dev *dev) cx23885_audio_mux(dev, 0); mutex_unlock(&dev->lock); + q = &dev->vb2_vidq; + 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_video_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) + goto fail_unreg; + + q = &dev->vb2_vbiq; + q->type = V4L2_BUF_TYPE_VBI_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_vbi_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) + goto fail_unreg; + /* register Video device */ dev->video_dev = cx23885_vdev_init(dev, dev->pci, &cx23885_video_template, "video"); + dev->video_dev->queue = &dev->vb2_vidq; err = video_register_device(dev->video_dev, VFL_TYPE_GRABBER, video_nr[dev->nr]); if (err < 0) { @@ -1642,6 +1257,7 @@ int cx23885_video_register(struct cx23885_dev *dev) /* register VBI device */ dev->vbi_dev = cx23885_vdev_init(dev, dev->pci, &cx23885_vbi_template, "vbi"); + dev->vbi_dev->queue = &dev->vb2_vbiq; err = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, vbi_nr[dev->nr]); if (err < 0) { |