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

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

[media] cx88: 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 blackbird, 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.

Signed-off-by: default avatarHans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@osg.samsung.com>
parent b2c75abd
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -3,7 +3,7 @@ config VIDEO_CX88
	depends on VIDEO_DEV && PCI && I2C && RC_CORE
	select I2C_ALGOBIT
	select VIDEO_BTCX
	select VIDEOBUF_DMA_SG
	select VIDEOBUF2_DMA_SG
	select VIDEO_TUNER
	select VIDEO_TVEEPROM
	select VIDEO_WM8775 if MEDIA_SUBDRV_AUTOSELECT
@@ -45,7 +45,7 @@ config VIDEO_CX88_BLACKBIRD
config VIDEO_CX88_DVB
	tristate "DVB/ATSC Support for cx2388x based TV cards"
	depends on VIDEO_CX88 && DVB_CORE
	select VIDEOBUF_DVB
	select VIDEOBUF2_DVB
	select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT
	select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT
	select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT
+180 −258
Original line number Diff line number Diff line
@@ -45,10 +45,6 @@ MODULE_AUTHOR("Jelle Foks <jelle@foks.us>, Gerd Knorr <kraxel@bytesex.org> [SuSE
MODULE_LICENSE("GPL");
MODULE_VERSION(CX88_VERSION);

static unsigned int mpegbufs = 32;
module_param(mpegbufs,int,0644);
MODULE_PARM_DESC(mpegbufs,"number of mpeg buffers, range 2-32");

static unsigned int debug;
module_param(debug,int,0644);
MODULE_PARM_DESC(debug,"enable debug messages [blackbird]");
@@ -589,9 +585,8 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev)
	return 0;
}

static int blackbird_start_codec(struct file *file, void *priv)
static int blackbird_start_codec(struct cx8802_dev *dev)
{
	struct cx8802_dev *dev  = ((struct cx8802_fh *)priv)->dev;
	struct cx88_core *core = dev->core;
	/* start capturing to the host interface */
	u32 reg;
@@ -647,45 +642,131 @@ static int blackbird_stop_codec(struct cx8802_dev *dev)

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

static int bb_buf_setup(struct videobuf_queue *q,
			unsigned int *count, unsigned int *size)
static int queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
			   unsigned int *num_buffers, unsigned int *num_planes,
			   unsigned int sizes[], void *alloc_ctxs[])
{
	struct cx8802_fh *fh = q->priv_data;

	fh->dev->ts_packet_size  = 188 * 4; /* was: 512 */
	fh->dev->ts_packet_count = mpegbufs; /* was: 100 */
	struct cx8802_dev *dev = q->drv_priv;

	*size = fh->dev->ts_packet_size * fh->dev->ts_packet_count;
	*count = fh->dev->ts_packet_count;
	*num_planes = 1;
	dev->ts_packet_size  = 188 * 4;
	dev->ts_packet_count  = 32;
	sizes[0] = dev->ts_packet_size * dev->ts_packet_count;
	return 0;
}

static int
bb_buf_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
	       enum v4l2_field field)
static int buffer_prepare(struct vb2_buffer *vb)
{
	struct cx8802_fh *fh = q->priv_data;
	return cx8802_buf_prepare(q, fh->dev, (struct cx88_buffer*)vb, field);
	struct cx8802_dev *dev = vb->vb2_queue->drv_priv;
	struct cx88_buffer *buf = container_of(vb, struct cx88_buffer, vb);

	return cx8802_buf_prepare(vb->vb2_queue, dev, buf, dev->field);
}

static void
bb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
static void buffer_finish(struct vb2_buffer *vb)
{
	struct cx8802_fh *fh = q->priv_data;
	cx8802_buf_queue(fh->dev, (struct cx88_buffer*)vb);
	struct cx8802_dev *dev = vb->vb2_queue->drv_priv;
	struct cx88_buffer *buf = container_of(vb, struct cx88_buffer, vb);
	struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);

	cx88_free_buffer(vb->vb2_queue, buf);

	dma_unmap_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
}

static void
bb_buf_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
static void buffer_queue(struct vb2_buffer *vb)
{
	cx88_free_buffer(q, (struct cx88_buffer*)vb);
	struct cx8802_dev *dev = vb->vb2_queue->drv_priv;
	struct cx88_buffer    *buf = container_of(vb, struct cx88_buffer, vb);

	cx8802_buf_queue(dev, buf);
}

static int start_streaming(struct vb2_queue *q, unsigned int count)
{
	struct cx8802_dev *dev = q->drv_priv;
	struct cx88_dmaqueue *dmaq = &dev->mpegq;
	struct cx8802_driver *drv;
	struct cx88_buffer *buf;
	unsigned long flags;
	int err;

	/* Make sure we can acquire the hardware */
	drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD);
	if (!drv) {
		dprintk(1, "%s: blackbird driver is not loaded\n", __func__);
		err = -ENODEV;
		goto fail;
	}

	err = drv->request_acquire(drv);
	if (err != 0) {
		dprintk(1, "%s: Unable to acquire hardware, %d\n", __func__, err);
		goto fail;
	}

static struct videobuf_queue_ops blackbird_qops = {
	.buf_setup    = bb_buf_setup,
	.buf_prepare  = bb_buf_prepare,
	.buf_queue    = bb_buf_queue,
	.buf_release  = bb_buf_release,
	if (blackbird_initialize_codec(dev) < 0) {
		drv->request_release(drv);
		err = -EINVAL;
		goto fail;
	}

	err = blackbird_start_codec(dev);
	if (err == 0) {
		buf = list_entry(dmaq->active.next, struct cx88_buffer, list);
		cx8802_start_dma(dev, dmaq, buf);
		return 0;
	}

fail:
	spin_lock_irqsave(&dev->slock, flags);
	while (!list_empty(&dmaq->active)) {
		struct cx88_buffer *buf = list_entry(dmaq->active.next,
			struct cx88_buffer, list);

		list_del(&buf->list);
		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED);
	}
	spin_unlock_irqrestore(&dev->slock, flags);
	return err;
}

static void stop_streaming(struct vb2_queue *q)
{
	struct cx8802_dev *dev = q->drv_priv;
	struct cx88_dmaqueue *dmaq = &dev->mpegq;
	struct cx8802_driver *drv = NULL;
	unsigned long flags;

	cx8802_cancel_buffers(dev);
	blackbird_stop_codec(dev);

	/* Make sure we release the hardware */
	drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD);
	WARN_ON(!drv);
	if (drv)
		drv->request_release(drv);

	spin_lock_irqsave(&dev->slock, flags);
	while (!list_empty(&dmaq->active)) {
		struct cx88_buffer *buf = list_entry(dmaq->active.next,
			struct cx88_buffer, list);

		list_del(&buf->list);
		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
	}
	spin_unlock_irqrestore(&dev->slock, flags);
}

static struct vb2_ops blackbird_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 = start_streaming,
	.stop_streaming = stop_streaming,
};

/* ------------------------------------------------------------------ */
@@ -693,7 +774,7 @@ static struct videobuf_queue_ops blackbird_qops = {
static int vidioc_querycap(struct file *file, void  *priv,
					struct v4l2_capability *cap)
{
	struct cx8802_dev *dev  = ((struct cx8802_fh *)priv)->dev;
	struct cx8802_dev *dev = video_drvdata(file);
	struct cx88_core *core = dev->core;

	strcpy(cap->driver, "cx88_blackbird");
@@ -717,50 +798,47 @@ static int vidioc_enum_fmt_vid_cap (struct file *file, void *priv,
static int vidioc_g_fmt_vid_cap (struct file *file, void *priv,
					struct v4l2_format *f)
{
	struct cx8802_fh  *fh   = priv;
	struct cx8802_dev *dev  = fh->dev;
	struct cx8802_dev *dev = video_drvdata(file);

	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
	f->fmt.pix.bytesperline = 0;
	f->fmt.pix.sizeimage    = 188 * 4 * mpegbufs; /* 188 * 4 * 1024; */
	f->fmt.pix.sizeimage    = dev->ts_packet_size * dev->ts_packet_count;
	f->fmt.pix.colorspace   = V4L2_COLORSPACE_SMPTE170M;
	f->fmt.pix.width        = dev->width;
	f->fmt.pix.height       = dev->height;
	f->fmt.pix.field        = fh->mpegq.field;
	f->fmt.pix.field        = dev->field;
	dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d, f: %d\n",
		dev->width, dev->height, fh->mpegq.field );
		dev->width, dev->height, dev->field);
	return 0;
}

static int vidioc_try_fmt_vid_cap (struct file *file, void *priv,
			struct v4l2_format *f)
{
	struct cx8802_fh  *fh   = priv;
	struct cx8802_dev *dev  = fh->dev;
	struct cx8802_dev *dev = video_drvdata(file);

	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
	f->fmt.pix.bytesperline = 0;
	f->fmt.pix.sizeimage    = 188 * 4 * mpegbufs; /* 188 * 4 * 1024; */
	f->fmt.pix.sizeimage    = dev->ts_packet_size * dev->ts_packet_count;
	f->fmt.pix.colorspace   = V4L2_COLORSPACE_SMPTE170M;
	dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n",
		dev->width, dev->height, fh->mpegq.field );
		dev->width, dev->height, dev->field);
	return 0;
}

static int vidioc_s_fmt_vid_cap (struct file *file, void *priv,
					struct v4l2_format *f)
{
	struct cx8802_fh  *fh   = priv;
	struct cx8802_dev *dev  = fh->dev;
	struct cx8802_dev *dev = video_drvdata(file);
	struct cx88_core  *core = dev->core;

	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
	f->fmt.pix.bytesperline = 0;
	f->fmt.pix.sizeimage    = 188 * 4 * mpegbufs; /* 188 * 4 * 1024; */
	f->fmt.pix.sizeimage    = dev->ts_packet_size * dev->ts_packet_count;
	f->fmt.pix.colorspace   = V4L2_COLORSPACE_SMPTE170M;
	dev->width              = f->fmt.pix.width;
	dev->height             = f->fmt.pix.height;
	fh->mpegq.field         = f->fmt.pix.field;
	dev->field         = f->fmt.pix.field;
	cx88_set_scale(core, f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
	blackbird_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0,
				f->fmt.pix.height, f->fmt.pix.width);
@@ -769,56 +847,10 @@ static int vidioc_s_fmt_vid_cap (struct file *file, void *priv,
	return 0;
}

static int vidioc_reqbufs (struct file *file, void *priv, struct v4l2_requestbuffers *p)
{
	struct cx8802_fh  *fh   = priv;
	return (videobuf_reqbufs(&fh->mpegq, p));
}

static int vidioc_querybuf (struct file *file, void *priv, struct v4l2_buffer *p)
{
	struct cx8802_fh  *fh   = priv;
	return (videobuf_querybuf(&fh->mpegq, p));
}

static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p)
{
	struct cx8802_fh  *fh   = priv;
	return (videobuf_qbuf(&fh->mpegq, p));
}

static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p)
{
	struct cx8802_fh  *fh   = priv;
	return (videobuf_dqbuf(&fh->mpegq, p,
				file->f_flags & O_NONBLOCK));
}

static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
{
	struct cx8802_fh  *fh   = priv;
	struct cx8802_dev *dev  = fh->dev;

	if (!dev->mpeg_active)
		blackbird_start_codec(file, fh);
	return videobuf_streamon(&fh->mpegq);
}

static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
{
	struct cx8802_fh  *fh   = priv;
	struct cx8802_dev *dev  = fh->dev;

	if (dev->mpeg_active)
		blackbird_stop_codec(dev);
	return videobuf_streamoff(&fh->mpegq);
}

static int vidioc_s_frequency (struct file *file, void *priv,
				const struct v4l2_frequency *f)
{
	struct cx8802_fh  *fh   = priv;
	struct cx8802_dev *dev  = fh->dev;
	struct cx8802_dev *dev = video_drvdata(file);
	struct cx88_core *core = dev->core;

	if (unlikely(UNSET == core->board.tuner_type))
@@ -831,13 +863,13 @@ static int vidioc_s_frequency (struct file *file, void *priv,
	cx88_set_freq (core,f);
	blackbird_initialize_codec(dev);
	cx88_set_scale(dev->core, dev->width, dev->height,
			fh->mpegq.field);
			dev->field);
	return 0;
}

static int vidioc_log_status (struct file *file, void *priv)
{
	struct cx8802_dev *dev  = ((struct cx8802_fh *)priv)->dev;
	struct cx8802_dev *dev = video_drvdata(file);
	struct cx88_core *core = dev->core;
	char name[32 + 2];

@@ -850,15 +882,16 @@ static int vidioc_log_status (struct file *file, void *priv)
static int vidioc_enum_input (struct file *file, void *priv,
				struct v4l2_input *i)
{
	struct cx88_core  *core = ((struct cx8802_fh *)priv)->dev->core;
	struct cx8802_dev *dev = video_drvdata(file);
	struct cx88_core *core = dev->core;
	return cx88_enum_input (core,i);
}

static int vidioc_g_frequency (struct file *file, void *priv,
				struct v4l2_frequency *f)
{
	struct cx8802_fh  *fh   = priv;
	struct cx88_core  *core = fh->dev->core;
	struct cx8802_dev *dev = video_drvdata(file);
	struct cx88_core *core = dev->core;

	if (unlikely(UNSET == core->board.tuner_type))
		return -EINVAL;
@@ -873,7 +906,8 @@ static int vidioc_g_frequency (struct file *file, void *priv,

static int vidioc_g_input (struct file *file, void *priv, unsigned int *i)
{
	struct cx88_core  *core = ((struct cx8802_fh *)priv)->dev->core;
	struct cx8802_dev *dev = video_drvdata(file);
	struct cx88_core *core = dev->core;

	*i = core->input;
	return 0;
@@ -881,24 +915,24 @@ static int vidioc_g_input (struct file *file, void *priv, unsigned int *i)

static int vidioc_s_input (struct file *file, void *priv, unsigned int i)
{
	struct cx88_core  *core = ((struct cx8802_fh *)priv)->dev->core;
	struct cx8802_dev *dev = video_drvdata(file);
	struct cx88_core *core = dev->core;

	if (i >= 4)
		return -EINVAL;
	if (0 == INPUT(i).type)
		return -EINVAL;

	mutex_lock(&core->lock);
	cx88_newstation(core);
	cx88_video_mux(core,i);
	mutex_unlock(&core->lock);
	return 0;
}

static int vidioc_g_tuner (struct file *file, void *priv,
				struct v4l2_tuner *t)
{
	struct cx88_core  *core = ((struct cx8802_fh *)priv)->dev->core;
	struct cx8802_dev *dev = video_drvdata(file);
	struct cx88_core *core = dev->core;
	u32 reg;

	if (unlikely(UNSET == core->board.tuner_type))
@@ -920,7 +954,8 @@ static int vidioc_g_tuner (struct file *file, void *priv,
static int vidioc_s_tuner (struct file *file, void *priv,
				const struct v4l2_tuner *t)
{
	struct cx88_core  *core = ((struct cx8802_fh *)priv)->dev->core;
	struct cx8802_dev *dev = video_drvdata(file);
	struct cx88_core *core = dev->core;

	if (UNSET == core->board.tuner_type)
		return -EINVAL;
@@ -933,7 +968,8 @@ static int vidioc_s_tuner (struct file *file, void *priv,

static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *tvnorm)
{
	struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
	struct cx8802_dev *dev = video_drvdata(file);
	struct cx88_core *core = dev->core;

	*tvnorm = core->tvnorm;
	return 0;
@@ -941,155 +977,21 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *tvnorm)

static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id)
{
	struct cx88_core  *core = ((struct cx8802_fh *)priv)->dev->core;

	mutex_lock(&core->lock);
	cx88_set_tvnorm(core, id);
	mutex_unlock(&core->lock);
	return 0;
}

/* FIXME: cx88_ioctl_hook not implemented */

static int mpeg_open(struct file *file)
{
	struct video_device *vdev = video_devdata(file);
	struct cx8802_dev *dev = video_drvdata(file);
	struct cx8802_fh *fh;
	struct cx8802_driver *drv = NULL;
	int err;

	dprintk( 1, "%s\n", __func__);

	mutex_lock(&dev->core->lock);

	/* Make sure we can acquire the hardware */
	drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD);
	if (!drv) {
		dprintk(1, "%s: blackbird driver is not loaded\n", __func__);
		mutex_unlock(&dev->core->lock);
		return -ENODEV;
	}

	err = drv->request_acquire(drv);
	if (err != 0) {
		dprintk(1,"%s: Unable to acquire hardware, %d\n", __func__, err);
		mutex_unlock(&dev->core->lock);
		return err;
	}

	if (!dev->core->mpeg_users && blackbird_initialize_codec(dev) < 0) {
		drv->request_release(drv);
		mutex_unlock(&dev->core->lock);
		return -EINVAL;
	}
	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) {
		drv->request_release(drv);
		mutex_unlock(&dev->core->lock);
		return -ENOMEM;
	}
	v4l2_fh_init(&fh->fh, vdev);
	file->private_data = fh;
	fh->dev      = dev;

	videobuf_queue_sg_init(&fh->mpegq, &blackbird_qops,
			    &dev->pci->dev, &dev->slock,
			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
			    V4L2_FIELD_INTERLACED,
			    sizeof(struct cx88_buffer),
			    fh, NULL);

	/* FIXME: locking against other video device */
	cx88_set_scale(dev->core, dev->width, dev->height,
			fh->mpegq.field);

	dev->core->mpeg_users++;
	mutex_unlock(&dev->core->lock);
	v4l2_fh_add(&fh->fh);
	return 0;
}

static int mpeg_release(struct file *file)
{
	struct cx8802_fh  *fh  = file->private_data;
	struct cx8802_dev *dev = fh->dev;
	struct cx8802_driver *drv = NULL;

	mutex_lock(&dev->core->lock);

	if (dev->mpeg_active && dev->core->mpeg_users == 1)
		blackbird_stop_codec(dev);

	cx8802_cancel_buffers(fh->dev);
	/* stop mpeg capture */
	videobuf_stop(&fh->mpegq);

	videobuf_mmap_free(&fh->mpegq);

	v4l2_fh_del(&fh->fh);
	v4l2_fh_exit(&fh->fh);
	file->private_data = NULL;
	kfree(fh);

	/* Make sure we release the hardware */
	drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD);
	WARN_ON(!drv);
	if (drv)
		drv->request_release(drv);

	dev->core->mpeg_users--;

	mutex_unlock(&dev->core->lock);
	struct cx88_core *core = dev->core;

	cx88_set_tvnorm(core, id);
	return 0;
}

static ssize_t
mpeg_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
{
	struct cx8802_fh *fh = file->private_data;
	struct cx8802_dev *dev = fh->dev;

	if (!dev->mpeg_active)
		blackbird_start_codec(file, fh);

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

static unsigned int
mpeg_poll(struct file *file, struct poll_table_struct *wait)
{
	unsigned long req_events = poll_requested_events(wait);
	struct cx8802_fh *fh = file->private_data;
	struct cx8802_dev *dev = fh->dev;

	if (!dev->mpeg_active && (req_events & (POLLIN | POLLRDNORM)))
		blackbird_start_codec(file, fh);

	return v4l2_ctrl_poll(file, wait) | videobuf_poll_stream(file, &fh->mpegq, wait);
}

static int
mpeg_mmap(struct file *file, struct vm_area_struct * vma)
{
	struct cx8802_fh *fh = file->private_data;

	return videobuf_mmap_mapper(&fh->mpegq, vma);
}

static const struct v4l2_file_operations mpeg_fops =
{
	.owner	       = THIS_MODULE,
	.open	       = mpeg_open,
	.release       = mpeg_release,
	.read	       = mpeg_read,
	.poll          = mpeg_poll,
	.mmap	       = mpeg_mmap,
	.open	       = v4l2_fh_open,
	.release       = vb2_fop_release,
	.read	       = vb2_fop_read,
	.poll          = vb2_fop_poll,
	.mmap	       = vb2_fop_mmap,
	.unlocked_ioctl = video_ioctl2,
};

@@ -1099,12 +1001,12 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
	.vidioc_g_fmt_vid_cap     = vidioc_g_fmt_vid_cap,
	.vidioc_try_fmt_vid_cap   = vidioc_try_fmt_vid_cap,
	.vidioc_s_fmt_vid_cap     = vidioc_s_fmt_vid_cap,
	.vidioc_reqbufs       = vidioc_reqbufs,
	.vidioc_querybuf      = vidioc_querybuf,
	.vidioc_qbuf          = vidioc_qbuf,
	.vidioc_dqbuf         = vidioc_dqbuf,
	.vidioc_streamon      = vidioc_streamon,
	.vidioc_streamoff     = vidioc_streamoff,
	.vidioc_reqbufs       = vb2_ioctl_reqbufs,
	.vidioc_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_frequency   = vidioc_s_frequency,
	.vidioc_log_status    = vidioc_log_status,
	.vidioc_enum_input    = vidioc_enum_input,
@@ -1193,6 +1095,7 @@ static int blackbird_register_video(struct cx8802_dev *dev)
				       &cx8802_mpeg_template, "mpeg");
	dev->mpeg_dev->ctrl_handler = &dev->cxhdl.hdl;
	video_set_drvdata(dev->mpeg_dev, dev);
	dev->mpeg_dev->queue = &dev->vb2_mpegq;
	err = video_register_device(dev->mpeg_dev, VFL_TYPE_GRABBER, -1);
	if (err < 0) {
		printk(KERN_INFO "%s/2: can't register mpeg device\n",
@@ -1210,6 +1113,7 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv)
{
	struct cx88_core *core = drv->core;
	struct cx8802_dev *dev = core->dvbdev;
	struct vb2_queue *q;
	int err;

	dprintk( 1, "%s\n", __func__);
@@ -1229,6 +1133,7 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv)
	} else {
		dev->height = 576;
	}
	dev->field = V4L2_FIELD_INTERLACED;
	dev->cxhdl.port = CX2341X_PORT_STREAMING;
	dev->cxhdl.width = dev->width;
	dev->cxhdl.height = dev->height;
@@ -1252,6 +1157,23 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv)
	cx88_video_mux(core,0);
	cx2341x_handler_set_50hz(&dev->cxhdl, dev->height == 576);
	cx2341x_handler_setup(&dev->cxhdl);

	q = &dev->vb2_mpegq;
	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
	q->gfp_flags = GFP_DMA32;
	q->min_buffers_needed = 2;
	q->drv_priv = dev;
	q->buf_struct_size = sizeof(struct cx88_buffer);
	q->ops = &blackbird_qops;
	q->mem_ops = &vb2_dma_sg_memops;
	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
	q->lock = &core->lock;

	err = vb2_queue_init(q);
	if (err < 0)
		goto fail_core;

	blackbird_register_video(dev);

	return 0;
+20 −63
Original line number Diff line number Diff line
@@ -76,11 +76,16 @@ static DEFINE_MUTEX(devlist);
static __le32* cx88_risc_field(__le32 *rp, struct scatterlist *sglist,
			    unsigned int offset, u32 sync_line,
			    unsigned int bpl, unsigned int padding,
			    unsigned int lines, unsigned int lpi)
			    unsigned int lines, unsigned int lpi, bool jump)
{
	struct scatterlist *sg;
	unsigned int line,todo,sol;

	if (jump) {
		(*rp++) = cpu_to_le32(RISC_JUMP);
		(*rp++) = 0;
	}

	/* sync instruction */
	if (sync_line != NO_SYNC_LINE)
		*(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
@@ -147,7 +152,7 @@ int cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
	   can cause next bpl to start close to a page border.  First DMA
	   region may be smaller than PAGE_SIZE */
	instructions  = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines);
	instructions += 2;
	instructions += 4;
	if ((rc = btcx_riscmem_alloc(pci,risc,instructions*8)) < 0)
		return rc;

@@ -155,10 +160,10 @@ int cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
	rp = risc->cpu;
	if (UNSET != top_offset)
		rp = cx88_risc_field(rp, sglist, top_offset, 0,
				     bpl, padding, lines, 0);
				     bpl, padding, lines, 0, true);
	if (UNSET != bottom_offset)
		rp = cx88_risc_field(rp, sglist, bottom_offset, 0x200,
				     bpl, padding, lines, 0);
				     bpl, padding, lines, 0, top_offset == UNSET);

	/* save pointer to jmp instruction address */
	risc->jmp = rp;
@@ -179,13 +184,13 @@ int cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
	   there is no padding and no sync.  First DMA region may be smaller
	   than PAGE_SIZE */
	instructions  = 1 + (bpl * lines) / PAGE_SIZE + lines;
	instructions += 1;
	instructions += 3;
	if ((rc = btcx_riscmem_alloc(pci,risc,instructions*8)) < 0)
		return rc;

	/* write risc instructions */
	rp = risc->cpu;
	rp = cx88_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, lines, lpi);
	rp = cx88_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, lines, lpi, !lpi);

	/* save pointer to jmp instruction address */
	risc->jmp = rp;
@@ -193,37 +198,10 @@ int cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
	return 0;
}

int cx88_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
		      u32 reg, u32 mask, u32 value)
{
	__le32 *rp;
	int rc;

	if ((rc = btcx_riscmem_alloc(pci, risc, 4*16)) < 0)
		return rc;

	/* write risc instructions */
	rp = risc->cpu;
	*(rp++) = cpu_to_le32(RISC_WRITECR  | RISC_IRQ2 | RISC_IMM);
	*(rp++) = cpu_to_le32(reg);
	*(rp++) = cpu_to_le32(value);
	*(rp++) = cpu_to_le32(mask);
	*(rp++) = cpu_to_le32(RISC_JUMP);
	*(rp++) = cpu_to_le32(risc->dma);
	return 0;
}

void
cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf)
cx88_free_buffer(struct vb2_queue *q, struct cx88_buffer *buf)
{
	struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);

	BUG_ON(in_interrupt());
	videobuf_waiton(q, &buf->vb, 0, 0);
	videobuf_dma_unmap(q->dev, dma);
	videobuf_dma_free(dma);
	btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc);
	buf->vb.state = VIDEOBUF_NEEDS_INIT;
	btcx_riscmem_free(to_pci_dev(q->drv_priv), &buf->risc);
}

/* ------------------------------------------------------------------ */
@@ -539,33 +517,12 @@ void cx88_wakeup(struct cx88_core *core,
		 struct cx88_dmaqueue *q, u32 count)
{
	struct cx88_buffer *buf;
	int bc;

	for (bc = 0;; bc++) {
		if (list_empty(&q->active))
			break;
	buf = list_entry(q->active.next,
				 struct cx88_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)
		dprintk(2, "%s: %d buffers handled (should be 1)\n",
			__func__, bc);
			 struct cx88_buffer, list);
	v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
	list_del(&buf->list);
	vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
}

void cx88_shutdown(struct cx88_core *core)
@@ -1043,6 +1000,7 @@ struct video_device *cx88_vdev_init(struct cx88_core *core,
	vfd->v4l2_dev = &core->v4l2_dev;
	vfd->dev_parent = &pci->dev;
	vfd->release = video_device_release;
	vfd->lock = &core->lock;
	snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
		 core->name, type, core->board.name);
	return vfd;
@@ -1114,7 +1072,6 @@ EXPORT_SYMBOL(cx88_shutdown);

EXPORT_SYMBOL(cx88_risc_buffer);
EXPORT_SYMBOL(cx88_risc_databuffer);
EXPORT_SYMBOL(cx88_risc_stopper);
EXPORT_SYMBOL(cx88_free_buffer);

EXPORT_SYMBOL(cx88_sram_channels);
+105 −50

File changed.

Preview size limit exceeded, changes collapsed.

+32 −85

File changed.

Preview size limit exceeded, changes collapsed.

Loading