Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2ada815f authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab
Browse files

[media] saa7134: convert to vb2



Convert the saa7134 driver to vb2.

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

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

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

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

Signed-off-by: default avatarHans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: default avatarMauro Carvalho Chehab <m.chehab@samsung.com>
parent a00e6888
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
config VIDEO_SAA7134
	tristate "Philips SAA7134 support"
	depends on VIDEO_DEV && PCI && I2C
	select VIDEOBUF_DMA_SG
	select VIDEOBUF2_DMA_SG
	select VIDEO_TUNER
	select VIDEO_TVEEPROM
	select CRC32
@@ -37,7 +37,7 @@ config VIDEO_SAA7134_RC
config VIDEO_SAA7134_DVB
	tristate "DVB/ATSC Support for saa7134 based TV cards"
	depends on VIDEO_SAA7134 && DVB_CORE
	select VIDEOBUF_DVB
	select VIDEOBUF2_DVB
	select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT
	select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT
	select DVB_TDA1004X if MEDIA_SUBDRV_AUTOSELECT
+47 −39
Original line number Diff line number Diff line
@@ -203,16 +203,16 @@ int saa7134_buffer_count(unsigned int size, unsigned int count)

int saa7134_buffer_startpage(struct saa7134_buf *buf)
{
	return saa7134_buffer_pages(buf->vb.bsize) * buf->vb.i;
	return saa7134_buffer_pages(vb2_plane_size(&buf->vb2, 0)) * buf->vb2.v4l2_buf.index;
}

unsigned long saa7134_buffer_base(struct saa7134_buf *buf)
{
	unsigned long base;
	struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
	struct sg_table *dma = vb2_dma_sg_plane_desc(&buf->vb2, 0);

	base  = saa7134_buffer_startpage(buf) * 4096;
	base += dma->sglist[0].offset;
	base += dma->sgl[0].offset;
	return base;
}

@@ -242,9 +242,11 @@ int saa7134_pgtable_build(struct pci_dev *pci, struct saa7134_pgtable *pt,
	BUG_ON(NULL == pt || NULL == pt->cpu);

	ptr = pt->cpu + startpage;
	for (i = 0; i < length; i++, list++)
	for (i = 0; i < length; i++, list = sg_next(list)) {
		for (p = 0; p * 4096 < list->length; p++, ptr++)
			*ptr = cpu_to_le32(sg_dma_address(list) - list->offset);
			*ptr = cpu_to_le32(sg_dma_address(list) +
						list->offset + p * 4096);
	}
	return 0;
}

@@ -258,44 +260,31 @@ void saa7134_pgtable_free(struct pci_dev *pci, struct saa7134_pgtable *pt)

/* ------------------------------------------------------------------ */

void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf)
{
	struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
	BUG_ON(in_interrupt());

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

/* ------------------------------------------------------------------ */

int saa7134_buffer_queue(struct saa7134_dev *dev,
			 struct saa7134_dmaqueue *q,
			 struct saa7134_buf *buf)
{
	struct saa7134_buf *next = NULL;
	unsigned long flags;

	assert_spin_locked(&dev->slock);
	spin_lock_irqsave(&dev->slock, flags);
	dprintk("buffer_queue %p\n", buf);
	if (NULL == q->curr) {
		if (!q->need_two) {
			q->curr = buf;
			buf->activate(dev, buf, NULL);
		} else if (list_empty(&q->queue)) {
			list_add_tail(&buf->vb.queue,&q->queue);
			buf->vb.state = VIDEOBUF_QUEUED;
			list_add_tail(&buf->entry, &q->queue);
		} else {
			next = list_entry(q->queue.next, struct saa7134_buf,
					  vb.queue);
					  entry);
			q->curr = buf;
			buf->activate(dev, buf, next);
		}
	} else {
		list_add_tail(&buf->vb.queue, &q->queue);
		buf->vb.state = VIDEOBUF_QUEUED;
		list_add_tail(&buf->entry, &q->queue);
	}
	spin_unlock_irqrestore(&dev->slock, flags);
	return 0;
}

@@ -303,13 +292,12 @@ void saa7134_buffer_finish(struct saa7134_dev *dev,
			   struct saa7134_dmaqueue *q,
			   unsigned int state)
{
	assert_spin_locked(&dev->slock);
	dprintk("buffer_finish %p\n", q->curr);

	/* finish current buffer */
	q->curr->vb.state = state;
	v4l2_get_timestamp(&q->curr->vb.ts);
	wake_up(&q->curr->vb.done);
	v4l2_get_timestamp(&q->curr->vb2.v4l2_buf.timestamp);
	q->curr->vb2.v4l2_buf.sequence = q->seq_nr++;
	vb2_buffer_done(&q->curr->vb2, state);
	q->curr = NULL;
}

@@ -323,13 +311,12 @@ void saa7134_buffer_next(struct saa7134_dev *dev,

	if (!list_empty(&q->queue)) {
		/* activate next one from queue */
		buf = list_entry(q->queue.next, struct saa7134_buf, vb.queue);
		buf = list_entry(q->queue.next, struct saa7134_buf, entry);
		dprintk("buffer_next %p [prev=%p/next=%p]\n",
			buf, q->queue.prev, q->queue.next);
		list_del(&buf->vb.queue);
		list_del(&buf->entry);
		if (!list_empty(&q->queue))
			next = list_entry(q->queue.next, struct saa7134_buf,
					  vb.queue);
			next = list_entry(q->queue.next, struct saa7134_buf, entry);
		q->curr = buf;
		buf->activate(dev, buf, next);
		dprintk("buffer_next #2 prev=%p/next=%p\n",
@@ -339,10 +326,6 @@ void saa7134_buffer_next(struct saa7134_dev *dev,
		dprintk("buffer_next %p\n", NULL);
		saa7134_set_dmabits(dev);
		del_timer(&q->timeout);

		if (card_has_mpeg(dev))
			if (dev->ts_started)
				saa7134_ts_stop(dev);
	}
}

@@ -363,12 +346,32 @@ void saa7134_buffer_timeout(unsigned long data)
	   try to start over with the next one. */
	if (q->curr) {
		dprintk("timeout on %p\n", q->curr);
		saa7134_buffer_finish(dev, q, VIDEOBUF_ERROR);
		saa7134_buffer_finish(dev, q, VB2_BUF_STATE_ERROR);
	}
	saa7134_buffer_next(dev, q);
	spin_unlock_irqrestore(&dev->slock, flags);
}

void saa7134_stop_streaming(struct saa7134_dev *dev, struct saa7134_dmaqueue *q)
{
	unsigned long flags;
	struct list_head *pos, *n;
	struct saa7134_buf *tmp;

	spin_lock_irqsave(&dev->slock, flags);
	if (!list_empty(&q->queue)) {
		list_for_each_safe(pos, n, &q->queue) {
			 tmp = list_entry(pos, struct saa7134_buf, entry);
			 vb2_buffer_done(&tmp->vb2, VB2_BUF_STATE_ERROR);
			 list_del(pos);
			 tmp = NULL;
		}
	}
	spin_unlock_irqrestore(&dev->slock, flags);
	saa7134_buffer_timeout((unsigned long)q); /* also calls del_timer(&q->timeout) */
}
EXPORT_SYMBOL_GPL(saa7134_stop_streaming);

/* ------------------------------------------------------------------ */

int saa7134_set_dmabits(struct saa7134_dev *dev)
@@ -388,7 +391,7 @@ int saa7134_set_dmabits(struct saa7134_dev *dev)
		ctrl |= SAA7134_MAIN_CTRL_TE0;
		irq  |= SAA7134_IRQ1_INTE_RA0_1 |
			SAA7134_IRQ1_INTE_RA0_0;
		cap = dev->video_q.curr->vb.field;
		cap = dev->field;
	}

	/* video capture -- dma 1+2 (planar modes) */
@@ -1046,6 +1049,8 @@ static int saa7134_initdev(struct pci_dev *pci_dev,

	dev->video_dev = vdev_init(dev,&saa7134_video_template,"video");
	dev->video_dev->ctrl_handler = &dev->ctrl_handler;
	dev->video_dev->lock = &dev->lock;
	dev->video_dev->queue = &dev->video_vbq;
	err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER,
				    video_nr[dev->nr]);
	if (err < 0) {
@@ -1058,6 +1063,8 @@ static int saa7134_initdev(struct pci_dev *pci_dev,

	dev->vbi_dev = vdev_init(dev, &saa7134_video_template, "vbi");
	dev->vbi_dev->ctrl_handler = &dev->ctrl_handler;
	dev->vbi_dev->lock = &dev->lock;
	dev->vbi_dev->queue = &dev->vbi_vbq;

	err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI,
				    vbi_nr[dev->nr]);
@@ -1069,6 +1076,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
	if (card_has_radio(dev)) {
		dev->radio_dev = vdev_init(dev,&saa7134_radio_template,"radio");
		dev->radio_dev->ctrl_handler = &dev->radio_ctrl_handler;
		dev->radio_dev->lock = &dev->lock;
		err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO,
					    radio_nr[dev->nr]);
		if (err < 0)
@@ -1188,7 +1196,7 @@ static int saa7134_buffer_requeue(struct saa7134_dev *dev,

	if (!list_empty(&q->queue))
		next = list_entry(q->queue.next, struct saa7134_buf,
					  vb.queue);
					  entry);
	buf->activate(dev, buf, next);

	return 0;
+27 −16
Original line number Diff line number Diff line
@@ -602,10 +602,10 @@ static int configure_tda827x_fe(struct saa7134_dev *dev,
				struct tda1004x_config *cdec_conf,
				struct tda827x_config *tuner_conf)
{
	struct videobuf_dvb_frontend *fe0;
	struct vb2_dvb_frontend *fe0;

	/* Get the first frontend */
	fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
	fe0 = vb2_dvb_get_frontend(&dev->frontends, 1);

	if (!fe0)
		return -EINVAL;
@@ -1215,29 +1215,38 @@ static int dvb_init(struct saa7134_dev *dev)
{
	int ret;
	int attach_xc3028 = 0;
	struct videobuf_dvb_frontend *fe0;
	struct vb2_dvb_frontend *fe0;
	struct vb2_queue *q;

	/* FIXME: add support for multi-frontend */
	mutex_init(&dev->frontends.lock);
	INIT_LIST_HEAD(&dev->frontends.felist);

	printk(KERN_INFO "%s() allocating 1 frontend\n", __func__);
	fe0 = videobuf_dvb_alloc_frontend(&dev->frontends, 1);
	fe0 = vb2_dvb_alloc_frontend(&dev->frontends, 1);
	if (!fe0) {
		printk(KERN_ERR "%s() failed to alloc\n", __func__);
		return -ENOMEM;
	}

	/* init struct videobuf_dvb */
	/* init struct vb2_dvb */
	dev->ts.nr_bufs    = 32;
	dev->ts.nr_packets = 32*4;
	fe0->dvb.name = dev->name;
	videobuf_queue_sg_init(&fe0->dvb.dvbq, &saa7134_ts_qops,
			    &dev->pci->dev, &dev->slock,
			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
			    V4L2_FIELD_ALTERNATE,
			    sizeof(struct saa7134_buf),
			    &dev->ts_q, NULL);
	q = &fe0->dvb.dvbq;
	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	q->io_modes = VB2_MMAP | VB2_READ;
	q->drv_priv = &dev->ts_q;
	q->ops = &saa7134_ts_qops;
	q->mem_ops = &vb2_dma_sg_memops;
	q->buf_struct_size = sizeof(struct saa7134_buf);
	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
	q->lock = &dev->lock;
	ret = vb2_queue_init(q);
	if (ret) {
		vb2_dvb_dealloc_frontends(&dev->frontends);
		return ret;
	}

	switch (dev->board) {
	case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL:
@@ -1876,7 +1885,7 @@ static int dvb_init(struct saa7134_dev *dev)
	fe0->dvb.frontend->callback = saa7134_tuner_callback;

	/* register everything else */
	ret = videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev,
	ret = vb2_dvb_register_bus(&dev->frontends, THIS_MODULE, dev,
					&dev->pci->dev, adapter_nr, 0);

	/* this sequence is necessary to make the tda1004x load its firmware
@@ -1893,16 +1902,17 @@ static int dvb_init(struct saa7134_dev *dev)
	return ret;

detach_frontend:
	videobuf_dvb_dealloc_frontends(&dev->frontends);
	vb2_dvb_dealloc_frontends(&dev->frontends);
	vb2_queue_release(&fe0->dvb.dvbq);
	return -EINVAL;
}

static int dvb_fini(struct saa7134_dev *dev)
{
	struct videobuf_dvb_frontend *fe0;
	struct vb2_dvb_frontend *fe0;

	/* Get the first frontend */
	fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
	fe0 = vb2_dvb_get_frontend(&dev->frontends, 1);
	if (!fe0)
		return -EINVAL;

@@ -1933,7 +1943,8 @@ static int dvb_fini(struct saa7134_dev *dev)
			}
		}
	}
	videobuf_dvb_unregister_bus(&dev->frontends);
	vb2_dvb_unregister_bus(&dev->frontends);
	vb2_queue_release(&fe0->dvb.dvbq);
	return 0;
}

+65 −110
Original line number Diff line number Diff line
@@ -48,11 +48,16 @@ MODULE_PARM_DESC(debug,"enable debug messages");

/* ------------------------------------------------------------------ */

static void ts_reset_encoder(struct saa7134_dev* dev);

static int ts_init_encoder(struct saa7134_dev* dev)
static int start_streaming(struct vb2_queue *vq, unsigned int count)
{
	struct saa7134_dmaqueue *dmaq = vq->drv_priv;
	struct saa7134_dev *dev = dmaq->dev;
	u32 leading_null_bytes = 0;
	int err;

	err = saa7134_ts_start_streaming(vq, count);
	if (err)
		return err;

	/* If more cards start to need this, then this
	   should probably be added to the card definitions. */
@@ -63,109 +68,43 @@ static int ts_init_encoder(struct saa7134_dev* dev)
		leading_null_bytes = 1;
		break;
	}
	ts_reset_encoder(dev);
	saa_call_all(dev, core, init, leading_null_bytes);
	/* Unmute audio */
	saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
			saa_readb(SAA7134_AUDIO_MUTE_CTRL) & ~(1 << 6));
	dev->empress_started = 1;
	return 0;
}

static void ts_reset_encoder(struct saa7134_dev* dev)
static void stop_streaming(struct vb2_queue *vq)
{
	if (!dev->empress_started)
		return;
	struct saa7134_dmaqueue *dmaq = vq->drv_priv;
	struct saa7134_dev *dev = dmaq->dev;

	saa7134_ts_stop_streaming(vq);
	saa_writeb(SAA7134_SPECIAL_MODE, 0x00);
	msleep(10);
	msleep(20);
	saa_writeb(SAA7134_SPECIAL_MODE, 0x01);
	msleep(100);
	dev->empress_started = 0;
}

/* ------------------------------------------------------------------ */

static int ts_open(struct file *file)
{
	struct video_device *vdev = video_devdata(file);
	struct saa7134_dev *dev = video_drvdata(file);
	struct saa7134_fh *fh;

	/* allocate + initialize per filehandle data */
	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
	if (NULL == fh)
		return -ENOMEM;

	v4l2_fh_init(&fh->fh, vdev);
	file->private_data = fh;
	fh->is_empress = true;
	v4l2_fh_add(&fh->fh);

	/* Unmute audio */
	saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
		saa_readb(SAA7134_AUDIO_MUTE_CTRL) & ~(1 << 6));

	return 0;
}

static int ts_release(struct file *file)
{
	struct saa7134_dev *dev = video_drvdata(file);
	struct saa7134_fh *fh = file->private_data;

	if (res_check(fh, RESOURCE_EMPRESS)) {
		videobuf_stop(&dev->empress_vbq);
		videobuf_mmap_free(&dev->empress_vbq);

		/* stop the encoder */
		ts_reset_encoder(dev);

	/* Mute audio */
	saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
			saa_readb(SAA7134_AUDIO_MUTE_CTRL) | (1 << 6));
	dev->empress_started = 0;
}

	v4l2_fh_del(&fh->fh);
	v4l2_fh_exit(&fh->fh);
	return 0;
}

static ssize_t
ts_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
{
	struct saa7134_dev *dev = video_drvdata(file);

	if (res_locked(dev, RESOURCE_EMPRESS))
		return -EBUSY;
	if (!dev->empress_started)
		ts_init_encoder(dev);

	return videobuf_read_stream(&dev->empress_vbq,
				    data, count, ppos, 0,
				    file->f_flags & O_NONBLOCK);
}

static unsigned int
ts_poll(struct file *file, struct poll_table_struct *wait)
{
	unsigned long req_events = poll_requested_events(wait);
	struct saa7134_dev *dev = video_drvdata(file);
	struct saa7134_fh *fh = file->private_data;
	unsigned int rc = 0;

	if (v4l2_event_pending(&fh->fh))
		rc = POLLPRI;
	else if (req_events & POLLPRI)
		poll_wait(file, &fh->fh.wait, wait);
	return rc | videobuf_poll_stream(file, &dev->empress_vbq, wait);
}


static int
ts_mmap(struct file *file, struct vm_area_struct * vma)
{
	struct saa7134_dev *dev = video_drvdata(file);
static struct vb2_ops saa7134_empress_qops = {
	.queue_setup	= saa7134_ts_queue_setup,
	.buf_init	= saa7134_ts_buffer_init,
	.buf_prepare	= saa7134_ts_buffer_prepare,
	.buf_finish	= saa7134_ts_buffer_finish,
	.buf_queue	= saa7134_vb2_buffer_queue,
	.wait_prepare	= vb2_ops_wait_prepare,
	.wait_finish	= vb2_ops_wait_finish,
	.start_streaming = start_streaming,
	.stop_streaming = stop_streaming,
};

	return videobuf_mmap_mapper(&dev->empress_vbq, vma);
}
/* ------------------------------------------------------------------ */

static int empress_enum_fmt_vid_cap(struct file *file, void  *priv,
					struct v4l2_fmtdesc *f)
@@ -235,11 +174,11 @@ static int empress_try_fmt_vid_cap(struct file *file, void *priv,
static const struct v4l2_file_operations ts_fops =
{
	.owner	  = THIS_MODULE,
	.open	  = ts_open,
	.release  = ts_release,
	.read	  = ts_read,
	.poll	  = ts_poll,
	.mmap	  = ts_mmap,
	.open	  = v4l2_fh_open,
	.release  = vb2_fop_release,
	.read	  = vb2_fop_read,
	.poll	  = vb2_fop_poll,
	.mmap	  = vb2_fop_mmap,
	.ioctl	  = video_ioctl2,
};

@@ -249,12 +188,12 @@ static const struct v4l2_ioctl_ops ts_ioctl_ops = {
	.vidioc_try_fmt_vid_cap		= empress_try_fmt_vid_cap,
	.vidioc_s_fmt_vid_cap		= empress_s_fmt_vid_cap,
	.vidioc_g_fmt_vid_cap		= empress_g_fmt_vid_cap,
	.vidioc_reqbufs			= saa7134_reqbufs,
	.vidioc_querybuf		= saa7134_querybuf,
	.vidioc_qbuf			= saa7134_qbuf,
	.vidioc_dqbuf			= saa7134_dqbuf,
	.vidioc_streamon		= saa7134_streamon,
	.vidioc_streamoff		= saa7134_streamoff,
	.vidioc_reqbufs			= vb2_ioctl_reqbufs,
	.vidioc_querybuf		= vb2_ioctl_querybuf,
	.vidioc_qbuf			= vb2_ioctl_qbuf,
	.vidioc_dqbuf			= vb2_ioctl_dqbuf,
	.vidioc_streamon		= vb2_ioctl_streamon,
	.vidioc_streamoff		= vb2_ioctl_streamoff,
	.vidioc_g_frequency		= saa7134_g_frequency,
	.vidioc_s_frequency		= saa7134_s_frequency,
	.vidioc_g_tuner			= saa7134_g_tuner,
@@ -317,6 +256,7 @@ static bool empress_ctrl_filter(const struct v4l2_ctrl *ctrl)
static int empress_init(struct saa7134_dev *dev)
{
	struct v4l2_ctrl_handler *hdl = &dev->empress_ctrl_handler;
	struct vb2_queue *q;
	int err;

	dprintk("%s: %s\n",dev->name,__func__);
@@ -326,6 +266,7 @@ static int empress_init(struct saa7134_dev *dev)
	*(dev->empress_dev) = saa7134_empress_template;
	dev->empress_dev->v4l2_dev  = &dev->v4l2_dev;
	dev->empress_dev->release = video_device_release;
	dev->empress_dev->lock = &dev->lock;
	snprintf(dev->empress_dev->name, sizeof(dev->empress_dev->name),
		 "%s empress (%s)", dev->name,
		 saa7134_boards[dev->board].name);
@@ -342,6 +283,26 @@ static int empress_init(struct saa7134_dev *dev)

	INIT_WORK(&dev->empress_workqueue, empress_signal_update);

	q = &dev->empress_vbq;
	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	/*
	 * Do not add VB2_USERPTR: the saa7134 DMA engine cannot handle
	 * transfers that do not start at the beginning of a page. A USERPTR
	 * can start anywhere in a page, so USERPTR support is a no-go.
	 */
	q->io_modes = VB2_MMAP | VB2_READ;
	q->drv_priv = &dev->ts_q;
	q->ops = &saa7134_empress_qops;
	q->gfp_flags = GFP_DMA32;
	q->mem_ops = &vb2_dma_sg_memops;
	q->buf_struct_size = sizeof(struct saa7134_buf);
	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
	q->lock = &dev->lock;
	err = vb2_queue_init(q);
	if (err)
		return err;
	dev->empress_dev->queue = q;

	video_set_drvdata(dev->empress_dev, dev);
	err = video_register_device(dev->empress_dev,VFL_TYPE_GRABBER,
				    empress_nr[dev->nr]);
@@ -355,13 +316,6 @@ static int empress_init(struct saa7134_dev *dev)
	printk(KERN_INFO "%s: registered device %s [mpeg]\n",
	       dev->name, video_device_node_name(dev->empress_dev));

	videobuf_queue_sg_init(&dev->empress_vbq, &saa7134_ts_qops,
			    &dev->pci->dev, &dev->slock,
			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
			    V4L2_FIELD_ALTERNATE,
			    sizeof(struct saa7134_buf),
			    &dev->ts_q, NULL);

	empress_signal_update(&dev->empress_workqueue);
	return 0;
}
@@ -374,6 +328,7 @@ static int empress_fini(struct saa7134_dev *dev)
		return 0;
	flush_work(&dev->empress_workqueue);
	video_unregister_device(dev->empress_dev);
	vb2_queue_release(&dev->empress_vbq);
	v4l2_ctrl_handler_free(&dev->empress_ctrl_handler);
	dev->empress_dev = NULL;
	return 0;
+100 −71
Original line number Diff line number Diff line
@@ -39,26 +39,29 @@ MODULE_PARM_DESC(ts_debug,"enable debug messages [ts]");
	printk(KERN_DEBUG "%s/ts: " fmt, dev->name , ## arg)

/* ------------------------------------------------------------------ */

static int buffer_activate(struct saa7134_dev *dev,
			   struct saa7134_buf *buf,
			   struct saa7134_buf *next)
{

	dprintk("buffer_activate [%p]",buf);
	buf->vb.state = VIDEOBUF_ACTIVE;
	buf->top_seen = 0;

	if (!dev->ts_started)
		dev->ts_field = V4L2_FIELD_TOP;

	if (NULL == next)
		next = buf;
	if (V4L2_FIELD_TOP == buf->vb.field) {
	if (V4L2_FIELD_TOP == dev->ts_field) {
		dprintk("- [top]     buf=%p next=%p\n",buf,next);
		saa_writel(SAA7134_RS_BA1(5),saa7134_buffer_base(buf));
		saa_writel(SAA7134_RS_BA2(5),saa7134_buffer_base(next));
		dev->ts_field = V4L2_FIELD_BOTTOM;
	} else {
		dprintk("- [bottom]  buf=%p next=%p\n",buf,next);
		saa_writel(SAA7134_RS_BA1(5),saa7134_buffer_base(next));
		saa_writel(SAA7134_RS_BA2(5),saa7134_buffer_base(buf));
		dev->ts_field = V4L2_FIELD_TOP;
	}

	/* start DMA */
@@ -72,99 +75,123 @@ static int buffer_activate(struct saa7134_dev *dev,
	return 0;
}

static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
		enum v4l2_field field)
int saa7134_ts_buffer_init(struct vb2_buffer *vb2)
{
	struct saa7134_dmaqueue *dmaq = q->priv_data;
	struct saa7134_dmaqueue *dmaq = vb2->vb2_queue->drv_priv;
	struct saa7134_buf *buf = container_of(vb2, struct saa7134_buf, vb2);

	dmaq->curr = NULL;
	buf->activate = buffer_activate;

	return 0;
}
EXPORT_SYMBOL_GPL(saa7134_ts_buffer_init);

int saa7134_ts_buffer_prepare(struct vb2_buffer *vb2)
{
	struct saa7134_dmaqueue *dmaq = vb2->vb2_queue->drv_priv;
	struct saa7134_dev *dev = dmaq->dev;
	struct saa7134_buf *buf = container_of(vb, struct saa7134_buf, vb);
	struct saa7134_buf *buf = container_of(vb2, struct saa7134_buf, vb2);
	struct sg_table *dma = vb2_dma_sg_plane_desc(vb2, 0);
	unsigned int lines, llength, size;
	int err;
	int ret;

	dprintk("buffer_prepare [%p,%s]\n", buf, v4l2_field_names[field]);
	dprintk("buffer_prepare [%p]\n", buf);

	llength = TS_PACKET_SIZE;
	lines = dev->ts.nr_packets;

	size = lines * llength;
	if (0 != buf->vb.baddr  &&  buf->vb.bsize < size)
	if (vb2_plane_size(vb2, 0) < size)
		return -EINVAL;

	if (buf->vb.size != size) {
		saa7134_dma_free(q,buf);
	}

	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {

		struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
	vb2_set_plane_payload(vb2, 0, size);
	vb2->v4l2_buf.field = dev->field;

		dprintk("buffer_prepare: needs_init\n");

		buf->vb.width  = llength;
		buf->vb.height = lines;
		buf->vb.size   = size;

		err = videobuf_iolock(q,&buf->vb,NULL);
		if (err)
			goto oops;
		err = saa7134_pgtable_build(dev->pci, &dmaq->pt,
					    dma->sglist,
					    dma->sglen,
	ret = dma_map_sg(&dev->pci->dev, dma->sgl, dma->nents, DMA_FROM_DEVICE);
	if (!ret)
		return -EIO;
	return saa7134_pgtable_build(dev->pci, &dmaq->pt, dma->sgl, dma->nents,
				    saa7134_buffer_startpage(buf));
		if (err)
			goto oops;
}
EXPORT_SYMBOL_GPL(saa7134_ts_buffer_prepare);

	buf->vb.state = VIDEOBUF_PREPARED;
	buf->activate = buffer_activate;
	buf->vb.field = field;
	return 0;
void saa7134_ts_buffer_finish(struct vb2_buffer *vb2)
{
	struct saa7134_dmaqueue *dmaq = vb2->vb2_queue->drv_priv;
	struct saa7134_dev *dev = dmaq->dev;
	struct saa7134_buf *buf = container_of(vb2, struct saa7134_buf, vb2);
	struct sg_table *dma = vb2_dma_sg_plane_desc(&buf->vb2, 0);

 oops:
	saa7134_dma_free(q,buf);
	return err;
	dma_unmap_sg(&dev->pci->dev, dma->sgl, dma->nents, DMA_FROM_DEVICE);
}
EXPORT_SYMBOL_GPL(saa7134_ts_buffer_finish);

static int
buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
int saa7134_ts_queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
			   unsigned int *nbuffers, unsigned int *nplanes,
			   unsigned int sizes[], void *alloc_ctxs[])
{
	struct saa7134_dmaqueue *dmaq = q->priv_data;
	struct saa7134_dmaqueue *dmaq = q->drv_priv;
	struct saa7134_dev *dev = dmaq->dev;

	*size = TS_PACKET_SIZE * dev->ts.nr_packets;
	if (0 == *count)
		*count = dev->ts.nr_bufs;
	*count = saa7134_buffer_count(*size,*count);

	int size = TS_PACKET_SIZE * dev->ts.nr_packets;

	if (0 == *nbuffers)
		*nbuffers = dev->ts.nr_bufs;
	*nbuffers = saa7134_buffer_count(size, *nbuffers);
	if (*nbuffers < 3)
		*nbuffers = 3;
	*nplanes = 1;
	sizes[0] = size;
	return 0;
}
EXPORT_SYMBOL_GPL(saa7134_ts_queue_setup);

static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
int saa7134_ts_start_streaming(struct vb2_queue *vq, unsigned int count)
{
	struct saa7134_dmaqueue *dmaq = q->priv_data;
	struct saa7134_dmaqueue *dmaq = vq->drv_priv;
	struct saa7134_dev *dev = dmaq->dev;
	struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);

	saa7134_buffer_queue(dev,&dev->ts_q,buf);
	/*
	 * Planar video capture and TS share the same DMA channel,
	 * so only one can be active at a time.
	 */
	if (vb2_is_busy(&dev->video_vbq) && dev->fmt->planar) {
		struct saa7134_buf *buf, *tmp;

		list_for_each_entry_safe(buf, tmp, &dmaq->queue, entry) {
			list_del(&buf->entry);
			vb2_buffer_done(&buf->vb2, VB2_BUF_STATE_QUEUED);
		}
		if (dmaq->curr) {
			vb2_buffer_done(&dmaq->curr->vb2, VB2_BUF_STATE_QUEUED);
			dmaq->curr = NULL;
		}
		return -EBUSY;
	}
	dmaq->seq_nr = 0;
	return 0;
}
EXPORT_SYMBOL_GPL(saa7134_ts_start_streaming);

static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
void saa7134_ts_stop_streaming(struct vb2_queue *vq)
{
	struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
	struct saa7134_dmaqueue *dmaq = q->priv_data;
	struct saa7134_dmaqueue *dmaq = vq->drv_priv;
	struct saa7134_dev *dev = dmaq->dev;

	if (dev->ts_started)
	saa7134_ts_stop(dev);

	saa7134_dma_free(q,buf);
	saa7134_stop_streaming(dev, dmaq);
}

struct videobuf_queue_ops saa7134_ts_qops = {
	.buf_setup    = buffer_setup,
	.buf_prepare  = buffer_prepare,
	.buf_queue    = buffer_queue,
	.buf_release  = buffer_release,
EXPORT_SYMBOL_GPL(saa7134_ts_stop_streaming);

struct vb2_ops saa7134_ts_qops = {
	.queue_setup	= saa7134_ts_queue_setup,
	.buf_init	= saa7134_ts_buffer_init,
	.buf_prepare	= saa7134_ts_buffer_prepare,
	.buf_finish	= saa7134_ts_buffer_finish,
	.buf_queue	= saa7134_vb2_buffer_queue,
	.wait_prepare	= vb2_ops_wait_prepare,
	.wait_finish	= vb2_ops_wait_finish,
	.stop_streaming = saa7134_ts_stop_streaming,
};
EXPORT_SYMBOL_GPL(saa7134_ts_qops);

@@ -229,7 +256,8 @@ int saa7134_ts_stop(struct saa7134_dev *dev)
{
	dprintk("TS stop\n");

	BUG_ON(!dev->ts_started);
	if (!dev->ts_started)
		return 0;

	/* Stop TS stream */
	switch (saa7134_boards[dev->board].ts_type) {
@@ -250,7 +278,8 @@ int saa7134_ts_start(struct saa7134_dev *dev)
{
	dprintk("TS start\n");

	BUG_ON(dev->ts_started);
	if (WARN_ON(dev->ts_started))
		return 0;

	/* dma: setup channel 5 (= TS) */
	saa_writeb(SAA7134_TS_DMA0, (dev->ts.nr_packets - 1) & 0xff);
@@ -306,15 +335,15 @@ void saa7134_irq_ts_done(struct saa7134_dev *dev, unsigned long status)

	spin_lock(&dev->slock);
	if (dev->ts_q.curr) {
		field = dev->ts_q.curr->vb.field;
		if (field == V4L2_FIELD_TOP) {
		field = dev->ts_field;
		if (field != V4L2_FIELD_TOP) {
			if ((status & 0x100000) != 0x000000)
				goto done;
		} else {
			if ((status & 0x100000) != 0x100000)
				goto done;
		}
		saa7134_buffer_finish(dev, &dev->ts_q, VIDEOBUF_DONE);
		saa7134_buffer_finish(dev, &dev->ts_q, VB2_BUF_STATE_DONE);
	}
	saa7134_buffer_next(dev,&dev->ts_q);

Loading