diff options
Diffstat (limited to 'drivers/media/common/saa7146/saa7146_vbi.c')
-rw-r--r-- | drivers/media/common/saa7146/saa7146_vbi.c | 287 |
1 files changed, 118 insertions, 169 deletions
diff --git a/drivers/media/common/saa7146/saa7146_vbi.c b/drivers/media/common/saa7146/saa7146_vbi.c index bd442b984423..bb7d81f7eba6 100644 --- a/drivers/media/common/saa7146/saa7146_vbi.c +++ b/drivers/media/common/saa7146/saa7146_vbi.c @@ -207,7 +207,6 @@ static int buffer_activate(struct saa7146_dev *dev, struct saa7146_buf *next) { struct saa7146_vv *vv = dev->vv_data; - buf->vb.state = VIDEOBUF_ACTIVE; DEB_VBI("dev:%p, buf:%p, next:%p\n", dev, buf, next); saa7146_set_vbi_capture(dev,buf,next); @@ -216,114 +215,101 @@ static int buffer_activate(struct saa7146_dev *dev, return 0; } -static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,enum v4l2_field field) -{ - struct file *file = q->priv_data; - struct saa7146_fh *fh = file->private_data; - struct saa7146_dev *dev = fh->dev; - struct saa7146_buf *buf = (struct saa7146_buf *)vb; +/* ------------------------------------------------------------------ */ - int err = 0; - int lines, llength, size; +static int queue_setup(struct vb2_queue *q, + unsigned int *num_buffers, unsigned int *num_planes, + unsigned int sizes[], struct device *alloc_devs[]) +{ + unsigned int size = 16 * 2 * vbi_pixel_to_capture; - lines = 16 * 2 ; /* 2 fields */ - llength = vbi_pixel_to_capture; - size = lines * llength; + if (*num_planes) + return sizes[0] < size ? -EINVAL : 0; + *num_planes = 1; + sizes[0] = size; - DEB_VBI("vb:%p\n", vb); + return 0; +} - if (0 != buf->vb.baddr && buf->vb.bsize < size) { - DEB_VBI("size mismatch\n"); - return -EINVAL; - } +static void buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct vb2_queue *vq = vb->vb2_queue; + struct saa7146_dev *dev = vb2_get_drv_priv(vq); + struct saa7146_buf *buf = container_of(vbuf, struct saa7146_buf, vb); + unsigned long flags; - if (buf->vb.size != size) - saa7146_dma_free(dev,q,buf); + spin_lock_irqsave(&dev->slock, flags); - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + saa7146_buffer_queue(dev, &dev->vv_data->vbi_dmaq, buf); + spin_unlock_irqrestore(&dev->slock, flags); +} - buf->vb.width = llength; - buf->vb.height = lines; - buf->vb.size = size; - buf->vb.field = field; // FIXME: check this +static int buf_init(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct saa7146_buf *buf = container_of(vbuf, struct saa7146_buf, vb); + struct sg_table *sgt = vb2_dma_sg_plane_desc(&buf->vb.vb2_buf, 0); + struct scatterlist *list = sgt->sgl; + int length = sgt->nents; + struct vb2_queue *vq = vb->vb2_queue; + struct saa7146_dev *dev = vb2_get_drv_priv(vq); + int ret; - saa7146_pgtable_free(dev->pci, &buf->pt[2]); - saa7146_pgtable_alloc(dev->pci, &buf->pt[2]); - - err = videobuf_iolock(q,&buf->vb, NULL); - if (err) - goto oops; - err = saa7146_pgtable_build_single(dev->pci, &buf->pt[2], - dma->sglist, dma->sglen); - if (0 != err) - return err; - } - buf->vb.state = VIDEOBUF_PREPARED; buf->activate = buffer_activate; - return 0; - - oops: - DEB_VBI("error out\n"); - saa7146_dma_free(dev,q,buf); + saa7146_pgtable_alloc(dev->pci, &buf->pt[2]); - return err; + ret = saa7146_pgtable_build_single(dev->pci, &buf->pt[2], + list, length); + if (ret) + saa7146_pgtable_free(dev->pci, &buf->pt[2]); + return ret; } -static int buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) +static int buf_prepare(struct vb2_buffer *vb) { - int llength,lines; - - lines = 16 * 2 ; /* 2 fields */ - llength = vbi_pixel_to_capture; - - *size = lines * llength; - *count = 2; - - DEB_VBI("count:%d, size:%d\n", *count, *size); + unsigned int size = 16 * 2 * vbi_pixel_to_capture; + if (vb2_plane_size(vb, 0) < size) + return -EINVAL; + vb2_set_plane_payload(vb, 0, size); return 0; } -static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) +static void buf_cleanup(struct vb2_buffer *vb) { - struct file *file = q->priv_data; - struct saa7146_fh *fh = file->private_data; - struct saa7146_dev *dev = fh->dev; - struct saa7146_vv *vv = dev->vv_data; - struct saa7146_buf *buf = (struct saa7146_buf *)vb; + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct saa7146_buf *buf = container_of(vbuf, struct saa7146_buf, vb); + struct vb2_queue *vq = vb->vb2_queue; + struct saa7146_dev *dev = vb2_get_drv_priv(vq); - DEB_VBI("vb:%p\n", vb); - saa7146_buffer_queue(dev, &vv->vbi_dmaq, buf); + saa7146_pgtable_free(dev->pci, &buf->pt[2]); } -static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) +static void return_buffers(struct vb2_queue *q, int state) { - struct file *file = q->priv_data; - struct saa7146_fh *fh = file->private_data; - struct saa7146_dev *dev = fh->dev; - struct saa7146_buf *buf = (struct saa7146_buf *)vb; - - DEB_VBI("vb:%p\n", vb); - saa7146_dma_free(dev,q,buf); + struct saa7146_dev *dev = vb2_get_drv_priv(q); + struct saa7146_dmaqueue *dq = &dev->vv_data->vbi_dmaq; + struct saa7146_buf *buf; + + if (dq->curr) { + buf = dq->curr; + dq->curr = NULL; + vb2_buffer_done(&buf->vb.vb2_buf, state); + } + while (!list_empty(&dq->queue)) { + buf = list_entry(dq->queue.next, struct saa7146_buf, list); + list_del(&buf->list); + vb2_buffer_done(&buf->vb.vb2_buf, state); + } } -static const struct videobuf_queue_ops vbi_qops = { - .buf_setup = buffer_setup, - .buf_prepare = buffer_prepare, - .buf_queue = buffer_queue, - .buf_release = buffer_release, -}; - -/* ------------------------------------------------------------------ */ - -static void vbi_stop(struct saa7146_fh *fh, struct file *file) +static void vbi_stop(struct saa7146_dev *dev) { - struct saa7146_dev *dev = fh->dev; struct saa7146_vv *vv = dev->vv_data; unsigned long flags; - DEB_VBI("dev:%p, fh:%p\n", dev, fh); + DEB_VBI("dev:%p\n", dev); spin_lock_irqsave(&dev->slock,flags); @@ -336,13 +322,6 @@ static void vbi_stop(struct saa7146_fh *fh, struct file *file) /* shut down dma 3 transfers */ saa7146_write(dev, MC1, MASK_20); - if (vv->vbi_dmaq.curr) - saa7146_buffer_finish(dev, &vv->vbi_dmaq, VIDEOBUF_DONE); - - videobuf_queue_cancel(&fh->vbi_q); - - vv->vbi_streaming = NULL; - del_timer(&vv->vbi_dmaq.timeout); del_timer(&vv->vbi_read_timeout); @@ -352,38 +331,22 @@ static void vbi_stop(struct saa7146_fh *fh, struct file *file) static void vbi_read_timeout(struct timer_list *t) { struct saa7146_vv *vv = from_timer(vv, t, vbi_read_timeout); - struct file *file = vv->vbi_read_timeout_file; - struct saa7146_fh *fh = file->private_data; - struct saa7146_dev *dev = fh->dev; - - DEB_VBI("dev:%p, fh:%p\n", dev, fh); + struct saa7146_dev *dev = vv->vbi_dmaq.dev; - vbi_stop(fh, file); -} - -static void vbi_init(struct saa7146_dev *dev, struct saa7146_vv *vv) -{ DEB_VBI("dev:%p\n", dev); - INIT_LIST_HEAD(&vv->vbi_dmaq.queue); - - timer_setup(&vv->vbi_dmaq.timeout, saa7146_buffer_timeout, 0); - vv->vbi_dmaq.dev = dev; - - init_waitqueue_head(&vv->vbi_wq); + vbi_stop(dev); } -static int vbi_open(struct saa7146_dev *dev, struct file *file) +static int vbi_begin(struct saa7146_dev *dev) { - struct saa7146_fh *fh = file->private_data; - struct saa7146_vv *vv = fh->dev->vv_data; - + struct saa7146_vv *vv = dev->vv_data; u32 arbtr_ctrl = saa7146_read(dev, PCI_BT_V1); int ret = 0; - DEB_VBI("dev:%p, fh:%p\n", dev, fh); + DEB_VBI("dev:%p\n", dev); - ret = saa7146_res_get(fh, RESOURCE_DMA3_BRS); + ret = saa7146_res_get(dev, RESOURCE_DMA3_BRS); if (0 == ret) { DEB_S("cannot get vbi RESOURCE_DMA3_BRS resource\n"); return -EBUSY; @@ -395,15 +358,7 @@ static int vbi_open(struct saa7146_dev *dev, struct file *file) saa7146_write(dev, PCI_BT_V1, arbtr_ctrl); saa7146_write(dev, MC2, (MASK_04|MASK_20)); - videobuf_queue_sg_init(&fh->vbi_q, &vbi_qops, - &dev->pci->dev, &dev->slock, - V4L2_BUF_TYPE_VBI_CAPTURE, - V4L2_FIELD_SEQ_TB, // FIXME: does this really work? - sizeof(struct saa7146_buf), - file, &dev->v4l2_lock); - vv->vbi_read_timeout.function = vbi_read_timeout; - vv->vbi_read_timeout_file = file; /* initialize the brs */ if ( 0 != (SAA7146_USE_PORT_B_FOR_VBI & dev->ext_vv_data->flags)) { @@ -422,16 +377,52 @@ static int vbi_open(struct saa7146_dev *dev, struct file *file) return 0; } -static void vbi_close(struct saa7146_dev *dev, struct file *file) +static int start_streaming(struct vb2_queue *q, unsigned int count) { - struct saa7146_fh *fh = file->private_data; - struct saa7146_vv *vv = dev->vv_data; - DEB_VBI("dev:%p, fh:%p\n", dev, fh); + struct saa7146_dev *dev = vb2_get_drv_priv(q); + int ret; + + if (!vb2_is_streaming(&dev->vv_data->vbi_dmaq.q)) + dev->vv_data->seqnr = 0; + ret = vbi_begin(dev); + if (ret) + return_buffers(q, VB2_BUF_STATE_QUEUED); + return ret; +} - if( fh == vv->vbi_streaming ) { - vbi_stop(fh, file); - } - saa7146_res_free(fh, RESOURCE_DMA3_BRS); +static void stop_streaming(struct vb2_queue *q) +{ + struct saa7146_dev *dev = vb2_get_drv_priv(q); + + vbi_stop(dev); + return_buffers(q, VB2_BUF_STATE_ERROR); + saa7146_res_free(dev, RESOURCE_DMA3_BRS); +} + +const struct vb2_ops vbi_qops = { + .queue_setup = queue_setup, + .buf_queue = buf_queue, + .buf_init = buf_init, + .buf_prepare = buf_prepare, + .buf_cleanup = buf_cleanup, + .start_streaming = start_streaming, + .stop_streaming = stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +/* ------------------------------------------------------------------ */ + +static void vbi_init(struct saa7146_dev *dev, struct saa7146_vv *vv) +{ + DEB_VBI("dev:%p\n", dev); + + INIT_LIST_HEAD(&vv->vbi_dmaq.queue); + + timer_setup(&vv->vbi_dmaq.timeout, saa7146_buffer_timeout, 0); + vv->vbi_dmaq.dev = dev; + + init_waitqueue_head(&vv->vbi_wq); } static void vbi_irq_done(struct saa7146_dev *dev, unsigned long status) @@ -441,10 +432,7 @@ static void vbi_irq_done(struct saa7146_dev *dev, unsigned long status) if (vv->vbi_dmaq.curr) { DEB_VBI("dev:%p, curr:%p\n", dev, vv->vbi_dmaq.curr); - /* this must be += 2, one count for each field */ - vv->vbi_fieldcount+=2; - vv->vbi_dmaq.curr->vb.field_count = vv->vbi_fieldcount; - saa7146_buffer_finish(dev, &vv->vbi_dmaq, VIDEOBUF_DONE); + saa7146_buffer_finish(dev, &vv->vbi_dmaq, VB2_BUF_STATE_DONE); } else { DEB_VBI("dev:%p\n", dev); } @@ -453,46 +441,7 @@ static void vbi_irq_done(struct saa7146_dev *dev, unsigned long status) spin_unlock(&dev->slock); } -static ssize_t vbi_read(struct file *file, char __user *data, size_t count, loff_t *ppos) -{ - struct saa7146_fh *fh = file->private_data; - struct saa7146_dev *dev = fh->dev; - struct saa7146_vv *vv = dev->vv_data; - ssize_t ret = 0; - - DEB_VBI("dev:%p, fh:%p\n", dev, fh); - - if( NULL == vv->vbi_streaming ) { - // fixme: check if dma3 is available - // fixme: activate vbi engine here if necessary. (really?) - vv->vbi_streaming = fh; - } - - if( fh != vv->vbi_streaming ) { - DEB_VBI("open %p is already using vbi capture\n", - vv->vbi_streaming); - return -EBUSY; - } - - mod_timer(&vv->vbi_read_timeout, jiffies+BUFFER_TIMEOUT); - ret = videobuf_read_stream(&fh->vbi_q, data, count, ppos, 1, - file->f_flags & O_NONBLOCK); -/* - printk("BASE_ODD3: 0x%08x\n", saa7146_read(dev, BASE_ODD3)); - printk("BASE_EVEN3: 0x%08x\n", saa7146_read(dev, BASE_EVEN3)); - printk("PROT_ADDR3: 0x%08x\n", saa7146_read(dev, PROT_ADDR3)); - printk("PITCH3: 0x%08x\n", saa7146_read(dev, PITCH3)); - printk("BASE_PAGE3: 0x%08x\n", saa7146_read(dev, BASE_PAGE3)); - printk("NUM_LINE_BYTE3: 0x%08x\n", saa7146_read(dev, NUM_LINE_BYTE3)); - printk("BRS_CTRL: 0x%08x\n", saa7146_read(dev, BRS_CTRL)); -*/ - return ret; -} - const struct saa7146_use_ops saa7146_vbi_uops = { .init = vbi_init, - .open = vbi_open, - .release = vbi_close, .irq_done = vbi_irq_done, - .read = vbi_read, }; |