Commit 0b6e30bd authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab
Browse files

media: saa7146: convert to vb2



Convert this driver from the old videobuf framework to the vb2
frame.

Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@kernel.org>
parent b3b2dd37
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -6,5 +6,5 @@ config VIDEO_SAA7146
config VIDEO_SAA7146_VV
	tristate
	depends on VIDEO_DEV
	select VIDEOBUF_DMA_SG
	select VIDEOBUF2_DMA_SG
	select VIDEO_SAA7146
+57 −261
Original line number Diff line number Diff line
@@ -42,22 +42,6 @@ void saa7146_res_free(struct saa7146_dev *dev, unsigned int bits)
}


/********************************************************************************/
/* common dma functions */

void saa7146_dma_free(struct saa7146_dev *dev,struct videobuf_queue *q,
						struct saa7146_buf *buf)
{
	struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
	DEB_EE("dev:%p, buf:%p\n", dev, buf);

	videobuf_waiton(q, &buf->vb, 0, 0);
	videobuf_dma_unmap(q->dev, dma);
	videobuf_dma_free(dma);
	buf->vb.state = VIDEOBUF_NEEDS_INIT;
}


/********************************************************************************/
/* common buffer functions */

@@ -76,8 +60,7 @@ int saa7146_buffer_queue(struct saa7146_dev *dev,
		DEB_D("immediately activating buffer %p\n", buf);
		buf->activate(dev,buf,NULL);
	} else {
		list_add_tail(&buf->vb.queue,&q->queue);
		buf->vb.state = VIDEOBUF_QUEUED;
		list_add_tail(&buf->list, &q->queue);
		DEB_D("adding buffer %p to queue. (active buffer present)\n",
		      buf);
	}
@@ -88,21 +71,31 @@ void saa7146_buffer_finish(struct saa7146_dev *dev,
			   struct saa7146_dmaqueue *q,
			   int state)
{
	struct saa7146_vv *vv = dev->vv_data;
	struct saa7146_buf *buf = q->curr;

	assert_spin_locked(&dev->slock);
	DEB_EE("dev:%p, dmaq:%p, state:%d\n", dev, q, state);
	DEB_EE("q->curr:%p\n", q->curr);

	/* finish current buffer */
	if (NULL == q->curr) {
	if (!buf) {
		DEB_D("aiii. no current buffer\n");
		return;
	}

	q->curr->vb.state = state;
	q->curr->vb.ts = ktime_get_ns();
	wake_up(&q->curr->vb.done);

	q->curr = NULL;
	buf->vb.vb2_buf.timestamp = ktime_get_ns();
	if (vv->video_fmt.field == V4L2_FIELD_ALTERNATE)
		buf->vb.field = vv->last_field;
	else if (vv->video_fmt.field == V4L2_FIELD_ANY)
		buf->vb.field = (vv->video_fmt.height > vv->standard->v_max_out / 2)
			? V4L2_FIELD_INTERLACED
			: V4L2_FIELD_BOTTOM;
	else
		buf->vb.field = vv->video_fmt.field;
	buf->vb.sequence = vv->seqnr++;
	vb2_buffer_done(&buf->vb.vb2_buf, state);
}

void saa7146_buffer_next(struct saa7146_dev *dev,
@@ -118,10 +111,10 @@ void saa7146_buffer_next(struct saa7146_dev *dev,
	assert_spin_locked(&dev->slock);
	if (!list_empty(&q->queue)) {
		/* activate next one from queue */
		buf = list_entry(q->queue.next,struct saa7146_buf,vb.queue);
		list_del(&buf->vb.queue);
		buf = list_entry(q->queue.next, struct saa7146_buf, list);
		list_del(&buf->list);
		if (!list_empty(&q->queue))
			next = list_entry(q->queue.next,struct saa7146_buf, vb.queue);
			next = list_entry(q->queue.next, struct saa7146_buf, list);
		q->curr = buf;
		DEB_INT("next buffer: buf:%p, prev:%p, next:%p\n",
			buf, q->queue.prev, q->queue.next);
@@ -169,7 +162,7 @@ void saa7146_buffer_timeout(struct timer_list *t)
	spin_lock_irqsave(&dev->slock,flags);
	if (q->curr) {
		DEB_D("timeout on %p\n", q->curr);
		saa7146_buffer_finish(dev,q,VIDEOBUF_ERROR);
		saa7146_buffer_finish(dev, q, VB2_BUF_STATE_ERROR);
	}

	/* we don't restart the transfer here like other drivers do. when
@@ -178,257 +171,39 @@ void saa7146_buffer_timeout(struct timer_list *t)
	   we mess up our capture logic. if a timeout occurs on another buffer,
	   then something is seriously broken before, so no need to buffer the
	   next capture IMHO... */
/*
	saa7146_buffer_next(dev,q);
*/

	saa7146_buffer_next(dev, q, 0);

	spin_unlock_irqrestore(&dev->slock,flags);
}

/********************************************************************************/
/* file operations */

static int fops_open(struct file *file)
{
	struct video_device *vdev = video_devdata(file);
	struct saa7146_dev *dev = video_drvdata(file);
	struct saa7146_fh *fh = NULL;
	int result = 0;

	DEB_EE("file:%p, dev:%s\n", file, video_device_node_name(vdev));

	if (mutex_lock_interruptible(vdev->lock))
		return -ERESTARTSYS;

	DEB_D("using: %p\n", dev);

	/* check if an extension is registered */
	if( NULL == dev->ext ) {
		DEB_S("no extension registered for this device\n");
		result = -ENODEV;
		goto out;
	}

	/* allocate per open data */
	fh = kzalloc(sizeof(*fh),GFP_KERNEL);
	if (NULL == fh) {
		DEB_S("cannot allocate memory for per open data\n");
		result = -ENOMEM;
		goto out;
	}

	v4l2_fh_init(&fh->fh, vdev);

	file->private_data = &fh->fh;

	if (vdev->vfl_type == VFL_TYPE_VBI) {
		DEB_S("initializing vbi...\n");
		if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
			result = saa7146_vbi_uops.open(dev,file);
		if (dev->ext_vv_data->vbi_fops.open)
			dev->ext_vv_data->vbi_fops.open(file);
	} else {
		DEB_S("initializing video...\n");
		result = saa7146_video_uops.open(dev,file);
	}

	if (0 != result) {
		goto out;
	}

	if( 0 == try_module_get(dev->ext->module)) {
		result = -EINVAL;
		goto out;
	}

	result = 0;
	v4l2_fh_add(&fh->fh);
out:
	if (fh && result != 0) {
		kfree(fh);
		file->private_data = NULL;
	}
	mutex_unlock(vdev->lock);
	return result;
}

static int fops_release(struct file *file)
{
	struct video_device *vdev = video_devdata(file);
	struct saa7146_dev *dev = video_drvdata(file);
	struct saa7146_fh  *fh  = file->private_data;

	DEB_EE("file:%p\n", file);

	mutex_lock(vdev->lock);

	if (vdev->vfl_type == VFL_TYPE_VBI) {
		if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
			saa7146_vbi_uops.release(dev,file);
		if (dev->ext_vv_data->vbi_fops.release)
			dev->ext_vv_data->vbi_fops.release(file);
	} else {
		saa7146_video_uops.release(dev,file);
	}

	v4l2_fh_del(&fh->fh);
	v4l2_fh_exit(&fh->fh);
	module_put(dev->ext->module);
	file->private_data = NULL;
	kfree(fh);

	mutex_unlock(vdev->lock);

	return 0;
}

static int fops_mmap(struct file *file, struct vm_area_struct * vma)
{
	struct video_device *vdev = video_devdata(file);
	struct saa7146_dev *dev = video_drvdata(file);
	struct saa7146_fh *fh = file->private_data;
	struct videobuf_queue *q;
	int res;

	switch (vdev->vfl_type) {
	case VFL_TYPE_VIDEO: {
		DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, vma:%p\n",
		       file, vma);
		q = &fh->video_q;
		break;
		}
	case VFL_TYPE_VBI: {
		DEB_EE("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, vma:%p\n",
		       file, vma);
		if (dev->ext_vv_data->capabilities & V4L2_CAP_SLICED_VBI_OUTPUT)
			return -ENODEV;
		q = &fh->vbi_q;
		break;
		}
	default:
		BUG();
	}

	if (mutex_lock_interruptible(vdev->lock))
		return -ERESTARTSYS;
	res = videobuf_mmap_mapper(q, vma);
	mutex_unlock(vdev->lock);
	return res;
}

static __poll_t __fops_poll(struct file *file, struct poll_table_struct *wait)
{
	struct video_device *vdev = video_devdata(file);
	struct saa7146_dev *dev = video_drvdata(file);
	struct saa7146_fh *fh = file->private_data;
	struct videobuf_buffer *buf = NULL;
	struct videobuf_queue *q;
	__poll_t res = v4l2_ctrl_poll(file, wait);

	DEB_EE("file:%p, poll:%p\n", file, wait);

	if (vdev->vfl_type == VFL_TYPE_VBI) {
		if (dev->ext_vv_data->capabilities & V4L2_CAP_SLICED_VBI_OUTPUT)
			return res | EPOLLOUT | EPOLLWRNORM;
		if( 0 == fh->vbi_q.streaming )
			return res | videobuf_poll_stream(file, &fh->vbi_q, wait);
		q = &fh->vbi_q;
	} else {
		DEB_D("using video queue\n");
		q = &fh->video_q;
	}

	if (!list_empty(&q->stream))
		buf = list_entry(q->stream.next, struct videobuf_buffer, stream);

	if (!buf) {
		DEB_D("buf == NULL!\n");
		return res | EPOLLERR;
	}

	poll_wait(file, &buf->done, wait);
	if (buf->state == VIDEOBUF_DONE || buf->state == VIDEOBUF_ERROR) {
		DEB_D("poll succeeded!\n");
		return res | EPOLLIN | EPOLLRDNORM;
	}

	DEB_D("nothing to poll for, buf->state:%d\n", buf->state);
	return res;
}

static __poll_t fops_poll(struct file *file, struct poll_table_struct *wait)
{
	struct video_device *vdev = video_devdata(file);
	__poll_t res;

	mutex_lock(vdev->lock);
	res = __fops_poll(file, wait);
	mutex_unlock(vdev->lock);
	return res;
}

static ssize_t fops_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
{
	struct video_device *vdev = video_devdata(file);
	struct saa7146_dev *dev = video_drvdata(file);
	int ret;

	switch (vdev->vfl_type) {
	case VFL_TYPE_VIDEO:
/*
		DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, data:%p, count:%lun",
		       file, data, (unsigned long)count);
*/
		return saa7146_video_uops.read(file,data,count,ppos);
	case VFL_TYPE_VBI:
/*
		DEB_EE("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, data:%p, count:%lu\n",
		       file, data, (unsigned long)count);
*/
		if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE) {
			if (mutex_lock_interruptible(vdev->lock))
				return -ERESTARTSYS;
			ret = saa7146_vbi_uops.read(file, data, count, ppos);
			mutex_unlock(vdev->lock);
			return ret;
		}
		return -EINVAL;
	default:
		BUG();
	}
}

static ssize_t fops_write(struct file *file, const char __user *data, size_t count, loff_t *ppos)
{
	struct video_device *vdev = video_devdata(file);
	struct saa7146_dev *dev = video_drvdata(file);
	int ret;

	switch (vdev->vfl_type) {
	case VFL_TYPE_VIDEO:
	if (vdev->vfl_type != VFL_TYPE_VBI || !dev->ext_vv_data->vbi_fops.write)
		return -EINVAL;
	case VFL_TYPE_VBI:
		if (dev->ext_vv_data->vbi_fops.write) {
	if (mutex_lock_interruptible(vdev->lock))
		return -ERESTARTSYS;
	ret = dev->ext_vv_data->vbi_fops.write(file, data, count, ppos);
	mutex_unlock(vdev->lock);
	return ret;
}
		return -EINVAL;
	default:
		BUG();
	}
}

static const struct v4l2_file_operations video_fops =
{
	.owner		= THIS_MODULE,
	.open		= fops_open,
	.release	= fops_release,
	.read		= fops_read,
	.open		= v4l2_fh_open,
	.release	= vb2_fop_release,
	.read		= vb2_fop_read,
	.write		= fops_write,
	.poll		= fops_poll,
	.mmap		= fops_mmap,
	.poll		= vb2_fop_poll,
	.mmap		= vb2_fop_mmap,
	.unlocked_ioctl	= video_ioctl2,
};

@@ -568,16 +343,20 @@ EXPORT_SYMBOL_GPL(saa7146_vv_release);
int saa7146_register_device(struct video_device *vfd, struct saa7146_dev *dev,
			    char *name, int type)
{
	struct vb2_queue *q;
	int err;
	int i;

	DEB_EE("dev:%p, name:'%s', type:%d\n", dev, name, type);

	vfd->fops = &video_fops;
	if (type == VFL_TYPE_VIDEO)
	if (type == VFL_TYPE_VIDEO) {
		vfd->ioctl_ops = &dev->ext_vv_data->vid_ops;
	else
		q = &dev->vv_data->video_dmaq.q;
	} else {
		vfd->ioctl_ops = &dev->ext_vv_data->vbi_ops;
		q = &dev->vv_data->vbi_dmaq.q;
	}
	vfd->release = video_device_release_empty;
	vfd->lock = &dev->v4l2_lock;
	vfd->v4l2_dev = &dev->v4l2_dev;
@@ -598,6 +377,23 @@ int saa7146_register_device(struct video_device *vfd, struct saa7146_dev *dev,
	} else {
		vfd->device_caps &= ~V4L2_CAP_VIDEO_CAPTURE;
	}

	q->type = type == VFL_TYPE_VIDEO ? V4L2_BUF_TYPE_VIDEO_CAPTURE : V4L2_BUF_TYPE_VBI_CAPTURE;
	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
	q->io_modes = VB2_MMAP | VB2_READ | VB2_DMABUF;
	q->ops = type == VFL_TYPE_VIDEO ? &video_qops : &vbi_qops;
	q->mem_ops = &vb2_dma_sg_memops;
	q->drv_priv = dev;
	q->gfp_flags = __GFP_DMA32;
	q->buf_struct_size = sizeof(struct saa7146_buf);
	q->lock = &dev->v4l2_lock;
	q->min_buffers_needed = 2;
	q->dev = &dev->pci->dev;
	err = vb2_queue_init(q);
	if (err)
		return err;
	vfd->queue = q;

	video_set_drvdata(vfd, dev);

	err = video_register_device(vfd, type, -1);
+115 −163
Original line number Diff line number Diff line
@@ -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,111 +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_dev *dev = video_drvdata(file);
	struct saa7146_buf *buf = (struct saa7146_buf *)vb;

	int err = 0;
	int lines, llength, size;
/* ------------------------------------------------------------------ */

	lines   = 16 * 2 ; /* 2 fields */
	llength = vbi_pixel_to_capture;
	size = lines * llength;
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;

	DEB_VBI("vb:%p\n", vb);
	if (*num_planes)
		return sizes[0] < size ? -EINVAL : 0;
	*num_planes = 1;
	sizes[0] = size;

	if (0 != buf->vb.baddr  &&  buf->vb.bsize < size) {
		DEB_VBI("size mismatch\n");
		return -EINVAL;
	return 0;
}

	if (buf->vb.size != size)
		saa7146_dma_free(dev,q,buf);
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 (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
		struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
	spin_lock_irqsave(&dev->slock, flags);

		buf->vb.width  = llength;
		buf->vb.height = lines;
		buf->vb.size   = size;
		buf->vb.field  = field;	// FIXME: check this
	saa7146_buffer_queue(dev, &dev->vv_data->vbi_dmaq, buf);
	spin_unlock_irqrestore(&dev->slock, flags);
}

		saa7146_pgtable_free(dev->pci, &buf->pt[2]);
		saa7146_pgtable_alloc(dev->pci, &buf->pt[2]);
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;

		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_dev *dev = video_drvdata(file);
	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_dev *dev = video_drvdata(file);
	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 = video_drvdata(file);
	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);

@@ -333,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);

@@ -349,36 +331,20 @@ 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_dev *dev = video_drvdata(file);
	struct saa7146_fh *fh = file->private_data;

	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 = 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(dev, RESOURCE_DMA3_BRS);
	if (0 == ret) {
@@ -392,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)) {
@@ -419,18 +377,54 @@ 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);

	if( fh == vv->vbi_streaming ) {
		vbi_stop(fh, file);
	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;
}

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)
{
	struct saa7146_vv *vv = dev->vv_data;
@@ -438,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);
	}
@@ -450,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 = video_drvdata(file);
	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,
};
+133 −357

File changed.

Preview size limit exceeded, changes collapsed.

+0 −10
Original line number Diff line number Diff line
@@ -587,7 +587,6 @@ static int vidioc_s_frequency(struct file *file, void *fh, const struct v4l2_fre
{
	struct saa7146_dev *dev = video_drvdata(file);
	struct mxb *mxb = (struct mxb *)dev->ext_priv;
	struct saa7146_vv *vv = dev->vv_data;

	if (f->tuner)
		return -EINVAL;
@@ -604,15 +603,6 @@ static int vidioc_s_frequency(struct file *file, void *fh, const struct v4l2_fre
	tuner_call(mxb, tuner, g_frequency, &mxb->cur_freq);
	if (mxb->cur_audinput == 0)
		mxb_update_audmode(mxb);

	if (mxb->cur_input)
		return 0;

	/* hack: changing the frequency should invalidate the vbi-counter (=> alevt) */
	spin_lock(&dev->slock);
	vv->vbi_fieldcount = 0;
	spin_unlock(&dev->slock);

	return 0;
}

Loading