All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] s2255drv: port to videobuf2
@ 2014-01-31 17:35 Dean Anderson
  2014-02-03  9:51 ` Hans Verkuil
  0 siblings, 1 reply; 7+ messages in thread
From: Dean Anderson @ 2014-01-31 17:35 UTC (permalink / raw)
  To: hverkuil, linux-dev, linux-media

Update s2255drv to use videobuf2 instead of videobuf. 
s2255_fh file handle removed and driver simplified.

Signed-off-by: Dean Anderson <linux-dev@sensoray.com>
---
 drivers/media/usb/s2255/s2255drv.c | 1170 +++++++++++++++---------------------
 1 file changed, 473 insertions(+), 697 deletions(-)

diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c
index c6bdccc..d6e9332 100644
--- a/drivers/media/usb/s2255/s2255drv.c
+++ b/drivers/media/usb/s2255/s2255drv.c
@@ -1,11 +1,9 @@
 /*
  *  s2255drv.c - a driver for the Sensoray 2255 USB video capture device
  *
- *   Copyright (C) 2007-2013 by Sensoray Company Inc.
+ *   Copyright (C) 2007-2014 by Sensoray Company Inc.
  *                              Dean Anderson
  *
- * Some video buffer code based on vivi driver:
- *
  * Sensoray 2255 device supports 4 simultaneous channels.
  * The channels are not "crossbar" inputs, they are physically
  * attached to separate video decoders.
@@ -45,14 +43,14 @@
 #include <linux/mm.h>
 #include <linux/vmalloc.h>
 #include <linux/usb.h>
-#include <media/videobuf-vmalloc.h>
+#include <media/videobuf2-vmalloc.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-event.h>
 
-#define S2255_VERSION		"1.23.1"
+#define S2255_VERSION "1.25.1"
 #define FIRMWARE_FILE_NAME "f2255usb.bin"
 
 /* default JPEG quality */
@@ -178,11 +176,6 @@ struct s2255_bufferi {
 			DEF_FDEC, DEF_BRIGHT, DEF_CONTRAST, DEF_SATURATION, \
 			DEF_HUE, 0, DEF_USB_BLOCK, 0}
 
-struct s2255_dmaqueue {
-	struct list_head	active;
-	struct s2255_dev	*dev;
-};
-
 /* for firmware loading, fw_state */
 #define S2255_FW_NOTLOADED	0
 #define S2255_FW_LOADED_DSPWAIT	1
@@ -214,69 +207,73 @@ struct s2255_pipeinfo {
 	u32 idx;
 };
 
-struct s2255_fmt; /*forward declaration */
+/*forward declarations */
+struct s2255_fmt;
 struct s2255_dev;
 
-struct s2255_channel {
-	struct s2255_dev        *dev;
-	struct video_device	vdev;
+/* 2255 video channel */
+struct s2255_vc {
+	struct v4l2_fh fh;
+	enum v4l2_buf_type type;
+	struct s2255_dev *dev;
+	struct video_device vdev;
 	struct v4l2_ctrl_handler hdl;
-	struct v4l2_ctrl	*jpegqual_ctrl;
-	int			resources;
-	struct s2255_dmaqueue	vidq;
-	struct s2255_bufferi	buffer;
-	struct s2255_mode	mode;
-	v4l2_std_id		std;
+	struct v4l2_ctrl *jpegqual_ctrl;
+	struct list_head buf_list;
+	struct s2255_bufferi buffer;
+	struct s2255_mode mode;
+	v4l2_std_id std;
 	/* jpeg compression */
-	unsigned		jpegqual;
+	unsigned jpegqual;
 	/* capture parameters (for high quality mode full size) */
 	struct v4l2_captureparm cap_parm;
-	int			cur_frame;
-	int			last_frame;
-
-	int			b_acquire;
+	int cur_frame;
+	int last_frame;
 	/* allocated image size */
-	unsigned long		req_image_size;
+	unsigned long req_image_size;
 	/* received packet size */
-	unsigned long		pkt_size;
-	int			bad_payload;
-	unsigned long		frame_count;
+	unsigned long pkt_size;
+	int bad_payload;
+	unsigned long frame_count;
 	/* if JPEG image */
-	int                     jpg_size;
+	int jpg_size;
 	/* if channel configured to default state */
-	int                     configured;
-	wait_queue_head_t       wait_setmode;
-	int                     setmode_ready;
+	int configured;
+	wait_queue_head_t wait_setmode;
+	int setmode_ready;
 	/* video status items */
-	int                     vidstatus;
-	wait_queue_head_t       wait_vidstatus;
-	int                     vidstatus_ready;
-	unsigned int		width;
-	unsigned int		height;
-	const struct s2255_fmt	*fmt;
+	int vidstatus;
+	wait_queue_head_t wait_vidstatus;
+	int vidstatus_ready;
+	unsigned int width;
+	unsigned int height;
+	enum v4l2_field field;
+	unsigned int field_count;
+	const struct s2255_fmt *fmt;
+	spinlock_t qlock; /* lock for buf_list */
 	int idx; /* channel number on device, 0-3 */
+	struct vb2_queue vb_vidq;
+	struct mutex vb_lock; /* streaming lock */
 };
 
-
 struct s2255_dev {
-	struct s2255_channel    channel[MAX_CHANNELS];
-	struct v4l2_device      v4l2_dev;
-	atomic_t                num_channels;
-	int			frames;
-	struct mutex		lock;	/* channels[].vdev.lock */
-	struct usb_device	*udev;
-	struct usb_interface	*interface;
-	u8			read_endpoint;
-	struct timer_list	timer;
+	struct s2255_vc vc[MAX_CHANNELS];
+	struct v4l2_device v4l2_dev;
+	atomic_t num_channels;
+	int frames;
+	struct mutex lock;	/* channels[].vdev.lock */
+	struct usb_device *udev;
+	struct usb_interface *interface;
+	u8 read_endpoint;
+	struct timer_list timer;
 	struct s2255_fw	*fw_data;
-	struct s2255_pipeinfo	pipe;
-	u32			cc;	/* current channel */
-	int			frame_ready;
-	int                     chn_ready;
-	spinlock_t              slock;
+	struct s2255_pipeinfo pipe;
+	u32 cc;	/* current channel */
+	int frame_ready;
+	int chn_ready;
 	/* dsp firmware version (f2255usb.bin) */
-	int                     dsp_fw_ver;
-	u16                     pid; /* product id */
+	int dsp_fw_ver;
+	u16 pid; /* product id */
 };
 
 static inline struct s2255_dev *to_s2255_dev(struct v4l2_device *v4l2_dev)
@@ -293,19 +290,11 @@ struct s2255_fmt {
 /* buffer for one video frame */
 struct s2255_buffer {
 	/* common v4l buffer stuff -- must be first */
-	struct videobuf_buffer vb;
+	struct vb2_buffer vb;
+	struct list_head list;
 	const struct s2255_fmt *fmt;
 };
 
-struct s2255_fh {
-	/* this must be the first field in this struct */
-	struct v4l2_fh		fh;
-	struct s2255_dev	*dev;
-	struct videobuf_queue	vb_vidq;
-	enum v4l2_buf_type	type;
-	struct s2255_channel	*channel;
-	int			resources;
-};
 
 /* current cypress EEPROM firmware version */
 #define S2255_CUR_USB_FWVER	((3 << 8) | 12)
@@ -356,11 +345,11 @@ static int debug;
 
 static int s2255_start_readpipe(struct s2255_dev *dev);
 static void s2255_stop_readpipe(struct s2255_dev *dev);
-static int s2255_start_acquire(struct s2255_channel *channel);
-static int s2255_stop_acquire(struct s2255_channel *channel);
-static void s2255_fillbuff(struct s2255_channel *chn, struct s2255_buffer *buf,
+static int s2255_start_acquire(struct s2255_vc *vc);
+static int s2255_stop_acquire(struct s2255_vc *vc);
+static void s2255_fillbuff(struct s2255_vc *vc, struct s2255_buffer *buf,
 			   int jpgsize);
-static int s2255_set_mode(struct s2255_channel *chan, struct s2255_mode *mode);
+static int s2255_set_mode(struct s2255_vc *vc, struct s2255_mode *mode);
 static int s2255_board_shutdown(struct s2255_dev *dev);
 static void s2255_fwload_start(struct s2255_dev *dev, int reset);
 static void s2255_destroy(struct s2255_dev *dev);
@@ -439,35 +428,30 @@ static const struct s2255_fmt formats[] = {
 	}
 };
 
-static int norm_maxw(struct s2255_channel *channel)
+static int norm_maxw(struct s2255_vc *vc)
 {
-	return (channel->std & V4L2_STD_525_60) ?
+	return (vc->std & V4L2_STD_525_60) ?
 	    LINE_SZ_4CIFS_NTSC : LINE_SZ_4CIFS_PAL;
 }
 
-static int norm_maxh(struct s2255_channel *channel)
+static int norm_maxh(struct s2255_vc *vc)
 {
-	return (channel->std & V4L2_STD_525_60) ?
+	return (vc->std & V4L2_STD_525_60) ?
 	    (NUM_LINES_1CIFS_NTSC * 2) : (NUM_LINES_1CIFS_PAL * 2);
 }
 
-static int norm_minw(struct s2255_channel *channel)
+static int norm_minw(struct s2255_vc *vc)
 {
-	return (channel->std & V4L2_STD_525_60) ?
+	return (vc->std & V4L2_STD_525_60) ?
 	    LINE_SZ_1CIFS_NTSC : LINE_SZ_1CIFS_PAL;
 }
 
-static int norm_minh(struct s2255_channel *channel)
+static int norm_minh(struct s2255_vc *vc)
 {
-	return (channel->std & V4L2_STD_525_60) ?
+	return (vc->std & V4L2_STD_525_60) ?
 	    (NUM_LINES_1CIFS_NTSC) : (NUM_LINES_1CIFS_PAL);
 }
 
-
-/*
- * TODO: fixme: move YUV reordering to hardware
- * converts 2255 planar format to yuyv or uyvy
- */
 static void planar422p_to_yuv_packed(const unsigned char *in,
 				     unsigned char *out,
 				     int width, int height,
@@ -572,29 +556,26 @@ static void s2255_fwchunk_complete(struct urb *urb)
 
 }
 
-static int s2255_got_frame(struct s2255_channel *channel, int jpgsize)
+static int s2255_got_frame(struct s2255_vc *vc, int jpgsize)
 {
-	struct s2255_dmaqueue *dma_q = &channel->vidq;
+
 	struct s2255_buffer *buf;
-	struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
+	struct s2255_dev *dev = to_s2255_dev(vc->vdev.v4l2_dev);
 	unsigned long flags = 0;
-	int rc = 0;
-	spin_lock_irqsave(&dev->slock, flags);
-	if (list_empty(&dma_q->active)) {
+
+	spin_lock_irqsave(&vc->qlock, flags);
+	if (list_empty(&vc->buf_list)) {
 		dprintk(dev, 1, "No active queue to serve\n");
-		rc = -1;
-		goto unlock;
-	}
-	buf = list_entry(dma_q->active.next,
-			 struct s2255_buffer, vb.queue);
-	list_del(&buf->vb.queue);
-	v4l2_get_timestamp(&buf->vb.ts);
-	s2255_fillbuff(channel, buf, jpgsize);
-	wake_up(&buf->vb.done);
-	dprintk(dev, 2, "%s: [buf/i] [%p/%d]\n", __func__, buf, buf->vb.i);
-unlock:
-	spin_unlock_irqrestore(&dev->slock, flags);
-	return rc;
+		spin_unlock_irqrestore(&vc->qlock, flags);
+		return -EINVAL;
+	}
+	buf = list_entry(vc->buf_list.next,
+			 struct s2255_buffer, list);
+	list_del(&buf->list);
+	spin_unlock_irqrestore(&vc->qlock, flags);
+	v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
+	s2255_fillbuff(vc, buf, jpgsize);
+	return 0;
 }
 
 static const struct s2255_fmt *format_by_fourcc(int fourcc)
@@ -612,53 +593,47 @@ static const struct s2255_fmt *format_by_fourcc(int fourcc)
 	return NULL;
 }
 
-/* video buffer vmalloc implementation based partly on VIVI driver which is
- *          Copyright (c) 2006 by
- *                  Mauro Carvalho Chehab <mchehab--a.t--infradead.org>
- *                  Ted Walther <ted--a.t--enumera.com>
- *                  John Sokol <sokol--a.t--videotechnology.com>
- *                  http://v4l.videotechnology.com/
- *
- */
-static void s2255_fillbuff(struct s2255_channel *channel,
+static void s2255_fillbuff(struct s2255_vc *vc,
 			   struct s2255_buffer *buf, int jpgsize)
 {
 	int pos = 0;
 	const char *tmpbuf;
-	char *vbuf = videobuf_to_vmalloc(&buf->vb);
+	char *vbuf;
 	unsigned long last_frame;
-	struct s2255_dev *dev = channel->dev;
+	struct s2255_dev *dev = vc->dev;
 
+	vbuf = vb2_plane_vaddr(&buf->vb, 0);
 	if (!vbuf)
 		return;
-	last_frame = channel->last_frame;
+
+	last_frame = vc->last_frame;
 	if (last_frame != -1) {
 		tmpbuf =
-		    (const char *)channel->buffer.frame[last_frame].lpvbits;
+		    (const char *)vc->buffer.frame[last_frame].lpvbits;
 		switch (buf->fmt->fourcc) {
 		case V4L2_PIX_FMT_YUYV:
 		case V4L2_PIX_FMT_UYVY:
 			planar422p_to_yuv_packed((const unsigned char *)tmpbuf,
-						 vbuf, buf->vb.width,
-						 buf->vb.height,
+						 vbuf, vc->width,
+						 vc->height,
 						 buf->fmt->fourcc);
 			break;
 		case V4L2_PIX_FMT_GREY:
-			memcpy(vbuf, tmpbuf, buf->vb.width * buf->vb.height);
+			memcpy(vbuf, tmpbuf, vc->width * vc->height);
 			break;
 		case V4L2_PIX_FMT_JPEG:
 		case V4L2_PIX_FMT_MJPEG:
-			buf->vb.size = jpgsize;
-			memcpy(vbuf, tmpbuf, buf->vb.size);
+			buf->vb.v4l2_buf.length = jpgsize;
+			memcpy(vbuf, tmpbuf, jpgsize);
 			break;
 		case V4L2_PIX_FMT_YUV422P:
 			memcpy(vbuf, tmpbuf,
-			       buf->vb.width * buf->vb.height * 2);
+			       vc->width * vc->height * 2);
 			break;
 		default:
 			pr_info("s2255: unknown format?\n");
 		}
-		channel->last_frame = -1;
+		vc->last_frame = -1;
 	} else {
 		pr_err("s2255: =======no frame\n");
 		return;
@@ -666,146 +641,131 @@ static void s2255_fillbuff(struct s2255_channel *channel,
 	dprintk(dev, 2, "s2255fill at : Buffer 0x%08lx size= %d\n",
 		(unsigned long)vbuf, pos);
 	/* tell v4l buffer was filled */
-	buf->vb.field_count = channel->frame_count * 2;
-	v4l2_get_timestamp(&buf->vb.ts);
-	buf->vb.state = VIDEOBUF_DONE;
+	vc->field_count = vc->frame_count * 2;
+	buf->vb.v4l2_buf.field = vc->field;
+	buf->vb.v4l2_buf.sequence = vc->field_count >> 1;
+	v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
+	vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
 }
 
+/*
+ * setup the contraints of the queue
+ */
+static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+				unsigned int *nbuffers, unsigned int *nplanes,
+				unsigned int sizes[], void *alloc_ctxs[])
+{
+	struct s2255_vc *vc = vb2_get_drv_priv(vq);
+	unsigned long size;
 
-/* ------------------------------------------------------------------
-   Videobuf operations
-   ------------------------------------------------------------------*/
+	size = vc->width * vc->height * (vc->fmt->depth >> 3);
 
-static int buffer_setup(struct videobuf_queue *vq, unsigned int *count,
-			unsigned int *size)
-{
-	struct s2255_fh *fh = vq->priv_data;
-	struct s2255_channel *channel = fh->channel;
-	*size = channel->width * channel->height * (channel->fmt->depth >> 3);
+	if (0 == *nbuffers)
+		*nbuffers = S2255_DEF_BUFS;
 
-	if (0 == *count)
-		*count = S2255_DEF_BUFS;
+	if (size * *nbuffers > vid_limit * 1024 * 1024)
+		*nbuffers = (vid_limit * 1024 * 1024) / size;
 
-	if (*size * *count > vid_limit * 1024 * 1024)
-		*count = (vid_limit * 1024 * 1024) / *size;
+	if (size == 0)
+		return -EINVAL;
 
+	*nplanes = 1;
+	sizes[0] = size;
 	return 0;
 }
 
-static void free_buffer(struct videobuf_queue *vq, struct s2255_buffer *buf)
-{
-	videobuf_vmalloc_free(&buf->vb);
-	buf->vb.state = VIDEOBUF_NEEDS_INIT;
-}
 
-static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
-			  enum v4l2_field field)
+static int buffer_prepare(struct vb2_buffer *vb)
 {
-	struct s2255_fh *fh = vq->priv_data;
-	struct s2255_channel *channel = fh->channel;
+	struct s2255_vc *vc = vb2_get_drv_priv(vb->vb2_queue);
 	struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb);
-	int rc;
-	int w = channel->width;
-	int h = channel->height;
-	dprintk(fh->dev, 4, "%s, field=%d\n", __func__, field);
-	if (channel->fmt == NULL)
-		return -EINVAL;
+	unsigned long size;
+	int w = vc->width;
+	int h = vc->height;
 
-	if ((w < norm_minw(channel)) ||
-	    (w > norm_maxw(channel)) ||
-	    (h < norm_minh(channel)) ||
-	    (h > norm_maxh(channel))) {
-		dprintk(fh->dev, 4, "invalid buffer prepare\n");
+	if (vc->fmt == NULL)
 		return -EINVAL;
-	}
-	buf->vb.size = w * h * (channel->fmt->depth >> 3);
-	if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) {
-		dprintk(fh->dev, 4, "invalid buffer prepare\n");
+
+	if ((w < norm_minw(vc)) ||
+	    (w > norm_maxw(vc)) ||
+	    (h < norm_minh(vc)) ||
+	    (h > norm_maxh(vc))) {
+		dprintk(vc->dev, 4, "invalid buffer prepare\n");
 		return -EINVAL;
 	}
+	size = w * h * (vc->fmt->depth >> 3);
 
-	buf->fmt = channel->fmt;
-	buf->vb.width = w;
-	buf->vb.height = h;
-	buf->vb.field = field;
-
-	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
-		rc = videobuf_iolock(vq, &buf->vb, NULL);
-		if (rc < 0)
-			goto fail;
-	}
+	if (vb2_plane_size(vb, 0) < size)
+		return -EINVAL;
 
-	buf->vb.state = VIDEOBUF_PREPARED;
+	vb2_set_plane_payload(&buf->vb, 0, size);
+	buf->fmt = vc->fmt;
 	return 0;
-fail:
-	free_buffer(vq, buf);
-	return rc;
 }
 
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+static void buffer_queue(struct vb2_buffer *vb)
 {
 	struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb);
-	struct s2255_fh *fh = vq->priv_data;
-	struct s2255_channel *channel = fh->channel;
-	struct s2255_dmaqueue *vidq = &channel->vidq;
-	dprintk(fh->dev, 1, "%s\n", __func__);
-	buf->vb.state = VIDEOBUF_QUEUED;
-	list_add_tail(&buf->vb.queue, &vidq->active);
-}
-
-static void buffer_release(struct videobuf_queue *vq,
-			   struct videobuf_buffer *vb)
-{
-	struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb);
-	struct s2255_fh *fh = vq->priv_data;
-	dprintk(fh->dev, 4, "%s %d\n", __func__, fh->channel->idx);
-	free_buffer(vq, buf);
-}
-
-static struct videobuf_queue_ops s2255_video_qops = {
-	.buf_setup = buffer_setup,
-	.buf_prepare = buffer_prepare,
-	.buf_queue = buffer_queue,
-	.buf_release = buffer_release,
-};
-
-
-static int res_get(struct s2255_fh *fh)
-{
-	struct s2255_channel *channel = fh->channel;
-	/* is it free? */
-	if (channel->resources)
-		return 0; /* no, someone else uses it */
-	/* it's free, grab it */
-	channel->resources = 1;
-	fh->resources = 1;
-	dprintk(fh->dev, 1, "s2255: res: get\n");
-	return 1;
+	struct s2255_vc *vc = vb2_get_drv_priv(vb->vb2_queue);
+	struct s2255_dev *dev = vc->dev;
+	unsigned long flags = 0;
+	dprintk(dev, 1, "%s\n", __func__);
+	spin_lock_irqsave(&vc->qlock, flags);
+	list_add_tail(&buf->list, &vc->buf_list);
+	spin_unlock_irqrestore(&vc->qlock, flags);
 }
 
-static int res_locked(struct s2255_fh *fh)
+/* begin streaming on a 2255 video channel */
+static int start_streaming(struct vb2_queue *vq, unsigned int count)
 {
-	return fh->channel->resources;
+	struct s2255_vc *vc = vb2_get_drv_priv(vq);
+	int j;
+	vc->last_frame = -1;
+	vc->bad_payload = 0;
+	vc->cur_frame = 0;
+	vc->frame_count = 0;
+	for (j = 0; j < SYS_FRAMES; j++) {
+		vc->buffer.frame[j].ulState = S2255_READ_IDLE;
+		vc->buffer.frame[j].cur_size = 0;
+	}
+	s2255_start_acquire(vc);
+	return 0;
 }
 
-static int res_check(struct s2255_fh *fh)
+/* abort streaming and wait for last buffer */
+static int stop_streaming(struct vb2_queue *vq)
 {
-	return fh->resources;
+	struct s2255_vc *vc = vb2_get_drv_priv(vq);
+	struct s2255_buffer *buf, *node;
+	unsigned long flags;
+	s2255_stop_acquire(vc);
+	spin_lock_irqsave(&vc->qlock, flags);
+	list_for_each_entry_safe(buf, node, &vc->buf_list, list) {
+		list_del(&buf->list);
+		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+		dprintk(vc->dev, 2, "[%p/%d] done\n",
+			buf, buf->vb.v4l2_buf.index);
+	}
+	spin_unlock_irqrestore(&vc->qlock, flags);
+	return 0;
 }
 
+static struct vb2_ops s2255_video_qops = {
+	.queue_setup = queue_setup,
+	.buf_prepare = buffer_prepare,
+	.buf_queue = buffer_queue,
+	.start_streaming = start_streaming,
+	.stop_streaming = stop_streaming,
+	.wait_prepare = vb2_ops_wait_prepare,
+	.wait_finish = vb2_ops_wait_finish,
 
-static void res_free(struct s2255_fh *fh)
-{
-	struct s2255_channel *channel = fh->channel;
-	channel->resources = 0;
-	fh->resources = 0;
-}
+};
 
 static int vidioc_querycap(struct file *file, void *priv,
 			   struct v4l2_capability *cap)
 {
-	struct s2255_fh *fh = file->private_data;
-	struct s2255_dev *dev = fh->dev;
+	struct s2255_vc *vc = video_drvdata(file);
+	struct s2255_dev *dev = vc->dev;
 
 	strlcpy(cap->driver, "s2255", sizeof(cap->driver));
 	strlcpy(cap->card, "s2255", sizeof(cap->card));
@@ -833,19 +793,18 @@ 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 s2255_fh *fh = priv;
-	struct s2255_channel *channel = fh->channel;
-	int is_ntsc = channel->std & V4L2_STD_525_60;
+	struct s2255_vc *vc = video_drvdata(file);
+	int is_ntsc = vc->std & V4L2_STD_525_60;
 
-	f->fmt.pix.width = channel->width;
-	f->fmt.pix.height = channel->height;
+	f->fmt.pix.width = vc->width;
+	f->fmt.pix.height = vc->height;
 	if (f->fmt.pix.height >=
 	    (is_ntsc ? NUM_LINES_1CIFS_NTSC : NUM_LINES_1CIFS_PAL) * 2)
 		f->fmt.pix.field = V4L2_FIELD_INTERLACED;
 	else
 		f->fmt.pix.field = V4L2_FIELD_TOP;
-	f->fmt.pix.pixelformat = channel->fmt->fourcc;
-	f->fmt.pix.bytesperline = f->fmt.pix.width * (channel->fmt->depth >> 3);
+	f->fmt.pix.pixelformat = vc->fmt->fourcc;
+	f->fmt.pix.bytesperline = f->fmt.pix.width * (vc->fmt->depth >> 3);
 	f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
 	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
 	f->fmt.pix.priv = 0;
@@ -857,9 +816,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
 {
 	const struct s2255_fmt *fmt;
 	enum v4l2_field field;
-	struct s2255_fh *fh = priv;
-	struct s2255_channel *channel = fh->channel;
-	int is_ntsc = channel->std & V4L2_STD_525_60;
+	struct s2255_vc *vc = video_drvdata(file);
+	int is_ntsc = vc->std & V4L2_STD_525_60;
 
 	fmt = format_by_fourcc(f->fmt.pix.pixelformat);
 
@@ -868,7 +826,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
 
 	field = f->fmt.pix.field;
 
-	dprintk(fh->dev, 50, "%s NTSC: %d suggested width: %d, height: %d\n",
+	dprintk(vc->dev, 50, "%s NTSC: %d suggested width: %d, height: %d\n",
 		__func__, is_ntsc, f->fmt.pix.width, f->fmt.pix.height);
 	if (is_ntsc) {
 		/* NTSC */
@@ -910,7 +868,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
 	f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
 	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
 	f->fmt.pix.priv = 0;
-	dprintk(fh->dev, 50, "%s: set width %d height %d field %d\n", __func__,
+	f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	dprintk(vc->dev, 50, "%s: set width %d height %d field %d\n", __func__,
 		f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
 	return 0;
 }
@@ -918,14 +877,13 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
 static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
 			    struct v4l2_format *f)
 {
-	struct s2255_fh *fh = priv;
-	struct s2255_channel *channel = fh->channel;
+	struct s2255_vc *vc = video_drvdata(file);
 	const struct s2255_fmt *fmt;
-	struct videobuf_queue *q = &fh->vb_vidq;
+	struct vb2_queue *q = &vc->vb_vidq;
 	struct s2255_mode mode;
 	int ret;
 
-	ret = vidioc_try_fmt_vid_cap(file, fh, f);
+	ret = vidioc_try_fmt_vid_cap(file, vc, f);
 
 	if (ret < 0)
 		return ret;
@@ -934,29 +892,24 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
 
 	if (fmt == NULL)
 		return -EINVAL;
+	/*
+	 * It is not allowed to change the format while buffers for use with
+	 * streaming have already been allocated.
+	 */
+	if (vb2_is_busy(q))
+		return -EBUSY;
 
-	mutex_lock(&q->vb_lock);
-
-	if (videobuf_queue_is_busy(&fh->vb_vidq)) {
-		dprintk(fh->dev, 1, "queue busy\n");
-		ret = -EBUSY;
-		goto out_s_fmt;
-	}
-
-	if (res_locked(fh)) {
-		dprintk(fh->dev, 1, "%s: channel busy\n", __func__);
-		ret = -EBUSY;
-		goto out_s_fmt;
-	}
-	mode = channel->mode;
-	channel->fmt = fmt;
-	channel->width = f->fmt.pix.width;
-	channel->height = f->fmt.pix.height;
-	fh->vb_vidq.field = f->fmt.pix.field;
-	fh->type = f->type;
-	if (channel->width > norm_minw(channel)) {
-		if (channel->height > norm_minh(channel)) {
-			if (channel->cap_parm.capturemode &
+	/* change format */
+	mode = vc->mode;
+	vc->fmt = fmt;
+	vc->width = f->fmt.pix.width;
+	vc->height = f->fmt.pix.height;
+	vc->field = f->fmt.pix.field;
+	vc->type = f->type;
+
+	if (vc->width > norm_minw(vc)) {
+		if (vc->height > norm_minh(vc)) {
+			if (vc->cap_parm.capturemode &
 			    V4L2_MODE_HIGHQUALITY)
 				mode.scale = SCALE_4CIFSI;
 			else
@@ -968,7 +921,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
 		mode.scale = SCALE_1CIFS;
 	}
 	/* color mode */
-	switch (channel->fmt->fourcc) {
+	switch (vc->fmt->fourcc) {
 	case V4L2_PIX_FMT_GREY:
 		mode.color &= ~MASK_COLOR;
 		mode.color |= COLOR_Y8;
@@ -977,7 +930,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
 	case V4L2_PIX_FMT_MJPEG:
 		mode.color &= ~MASK_COLOR;
 		mode.color |= COLOR_JPG;
-		mode.color |= (channel->jpegqual << 8);
+		mode.color |= (vc->jpegqual << 8);
 		break;
 	case V4L2_PIX_FMT_YUV422P:
 		mode.color &= ~MASK_COLOR;
@@ -990,51 +943,15 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
 		mode.color |= COLOR_YUVPK;
 		break;
 	}
-	if ((mode.color & MASK_COLOR) != (channel->mode.color & MASK_COLOR))
+	if ((mode.color & MASK_COLOR) != (vc->mode.color & MASK_COLOR))
 		mode.restart = 1;
-	else if (mode.scale != channel->mode.scale)
+	else if (mode.scale != vc->mode.scale)
 		mode.restart = 1;
-	else if (mode.format != channel->mode.format)
+	else if (mode.format != vc->mode.format)
 		mode.restart = 1;
-	channel->mode = mode;
-	(void) s2255_set_mode(channel, &mode);
-	ret = 0;
-out_s_fmt:
-	mutex_unlock(&q->vb_lock);
-	return ret;
-}
-
-static int vidioc_reqbufs(struct file *file, void *priv,
-			  struct v4l2_requestbuffers *p)
-{
-	int rc;
-	struct s2255_fh *fh = priv;
-	rc = videobuf_reqbufs(&fh->vb_vidq, p);
-	return rc;
-}
-
-static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
-	int rc;
-	struct s2255_fh *fh = priv;
-	rc = videobuf_querybuf(&fh->vb_vidq, p);
-	return rc;
-}
-
-static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
-	int rc;
-	struct s2255_fh *fh = priv;
-	rc = videobuf_qbuf(&fh->vb_vidq, p);
-	return rc;
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
-	int rc;
-	struct s2255_fh *fh = priv;
-	rc = videobuf_dqbuf(&fh->vb_vidq, p, file->f_flags & O_NONBLOCK);
-	return rc;
+	vc->mode = mode;
+	(void) s2255_set_mode(vc, &mode);
+	return 0;
 }
 
 /* write to the configuration pipe, synchronously */
@@ -1115,16 +1032,6 @@ static u32 get_transfer_size(struct s2255_mode *mode)
 	return usbInSize;
 }
 
-static void s2255_print_cfg(struct s2255_dev *sdev, struct s2255_mode *mode)
-{
-	struct device *dev = &sdev->udev->dev;
-	dev_info(dev, "------------------------------------------------\n");
-	dev_info(dev, "format: %d\nscale %d\n", mode->format, mode->scale);
-	dev_info(dev, "fdec: %d\ncolor %d\n", mode->fdec, mode->color);
-	dev_info(dev, "bright: 0x%x\n", mode->bright);
-	dev_info(dev, "------------------------------------------------\n");
-}
-
 /*
  * set mode is the function which controls the DSP.
  * the restart parameter in struct s2255_mode should be set whenever
@@ -1133,28 +1040,28 @@ static void s2255_print_cfg(struct s2255_dev *sdev, struct s2255_mode *mode)
  * When the restart parameter is set, we sleep for ONE frame to allow the
  * DSP time to get the new frame
  */
-static int s2255_set_mode(struct s2255_channel *channel,
+static int s2255_set_mode(struct s2255_vc *vc,
 			  struct s2255_mode *mode)
 {
 	int res;
 	__le32 *buffer;
 	unsigned long chn_rev;
-	struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
+	struct s2255_dev *dev = to_s2255_dev(vc->vdev.v4l2_dev);
 	int i;
 
-	chn_rev = G_chnmap[channel->idx];
-	dprintk(dev, 3, "%s channel: %d\n", __func__, channel->idx);
+	chn_rev = G_chnmap[vc->idx];
+	dprintk(dev, 3, "%s channel: %d\n", __func__, vc->idx);
 	/* if JPEG, set the quality */
 	if ((mode->color & MASK_COLOR) == COLOR_JPG) {
 		mode->color &= ~MASK_COLOR;
 		mode->color |= COLOR_JPG;
 		mode->color &= ~MASK_JPG_QUALITY;
-		mode->color |= (channel->jpegqual << 8);
+		mode->color |= (vc->jpegqual << 8);
 	}
 	/* save the mode */
-	channel->mode = *mode;
-	channel->req_image_size = get_transfer_size(mode);
-	dprintk(dev, 1, "%s: reqsize %ld\n", __func__, channel->req_image_size);
+	vc->mode = *mode;
+	vc->req_image_size = get_transfer_size(mode);
+	dprintk(dev, 1, "%s: reqsize %ld\n", __func__, vc->req_image_size);
 	buffer = kzalloc(512, GFP_KERNEL);
 	if (buffer == NULL) {
 		dev_err(&dev->udev->dev, "out of mem\n");
@@ -1165,36 +1072,38 @@ static int s2255_set_mode(struct s2255_channel *channel,
 	buffer[1] = (__le32) cpu_to_le32(chn_rev);
 	buffer[2] = CMD_SET_MODE;
 	for (i = 0; i < sizeof(struct s2255_mode) / sizeof(u32); i++)
-		buffer[3 + i] = cpu_to_le32(((u32 *)&channel->mode)[i]);
-	channel->setmode_ready = 0;
+		buffer[3 + i] = cpu_to_le32(((u32 *)&vc->mode)[i]);
+	vc->setmode_ready = 0;
 	res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512);
-	if (debug)
-		s2255_print_cfg(dev, mode);
+
+	dprintk(dev, 1, "format: %d\nscale %d\n", mode->format, mode->scale);
+	dprintk(dev, 1, "fdec: %d\ncolor %d\n", mode->fdec, mode->color);
+
 	kfree(buffer);
 	/* wait at least 3 frames before continuing */
 	if (mode->restart) {
-		wait_event_timeout(channel->wait_setmode,
-				   (channel->setmode_ready != 0),
+		wait_event_timeout(vc->wait_setmode,
+				   (vc->setmode_ready != 0),
 				   msecs_to_jiffies(S2255_SETMODE_TIMEOUT));
-		if (channel->setmode_ready != 1) {
+		if (vc->setmode_ready != 1) {
 			dprintk(dev, 0, "s2255: no set mode response\n");
 			res = -EFAULT;
 		}
 	}
 	/* clear the restart flag */
-	channel->mode.restart = 0;
-	dprintk(dev, 1, "%s chn %d, result: %d\n", __func__, channel->idx, res);
+	vc->mode.restart = 0;
+	dprintk(dev, 1, "%s chn %d, result: %d\n", __func__, vc->idx, res);
 	return res;
 }
 
-static int s2255_cmd_status(struct s2255_channel *channel, u32 *pstatus)
+static int s2255_cmd_status(struct s2255_vc *vc, u32 *pstatus)
 {
 	int res;
 	__le32 *buffer;
 	u32 chn_rev;
-	struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
-	chn_rev = G_chnmap[channel->idx];
-	dprintk(dev, 4, "%s chan %d\n", __func__, channel->idx);
+	struct s2255_dev *dev = to_s2255_dev(vc->vdev.v4l2_dev);
+	chn_rev = G_chnmap[vc->idx];
+	dprintk(dev, 4, "%s chan %d\n", __func__, vc->idx);
 	buffer = kzalloc(512, GFP_KERNEL);
 	if (buffer == NULL) {
 		dev_err(&dev->udev->dev, "out of mem\n");
@@ -1205,127 +1114,70 @@ static int s2255_cmd_status(struct s2255_channel *channel, u32 *pstatus)
 	buffer[1] = (__le32) cpu_to_le32(chn_rev);
 	buffer[2] = CMD_STATUS;
 	*pstatus = 0;
-	channel->vidstatus_ready = 0;
+	vc->vidstatus_ready = 0;
 	res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512);
 	kfree(buffer);
-	wait_event_timeout(channel->wait_vidstatus,
-			   (channel->vidstatus_ready != 0),
+	wait_event_timeout(vc->wait_vidstatus,
+			   (vc->vidstatus_ready != 0),
 			   msecs_to_jiffies(S2255_VIDSTATUS_TIMEOUT));
-	if (channel->vidstatus_ready != 1) {
+	if (vc->vidstatus_ready != 1) {
 		dprintk(dev, 0, "s2255: no vidstatus response\n");
 		res = -EFAULT;
 	}
-	*pstatus = channel->vidstatus;
+	*pstatus = vc->vidstatus;
 	dprintk(dev, 4, "%s, vid status %d\n", __func__, *pstatus);
 	return res;
 }
 
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-	int res;
-	struct s2255_fh *fh = priv;
-	struct s2255_dev *dev = fh->dev;
-	struct s2255_channel *channel = fh->channel;
-	int j;
-	dprintk(dev, 4, "%s\n", __func__);
-	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-		dev_err(&dev->udev->dev, "invalid fh type0\n");
-		return -EINVAL;
-	}
-	if (i != fh->type) {
-		dev_err(&dev->udev->dev, "invalid fh type1\n");
-		return -EINVAL;
-	}
-
-	if (!res_get(fh)) {
-		s2255_dev_err(&dev->udev->dev, "stream busy\n");
-		return -EBUSY;
-	}
-	channel->last_frame = -1;
-	channel->bad_payload = 0;
-	channel->cur_frame = 0;
-	channel->frame_count = 0;
-	for (j = 0; j < SYS_FRAMES; j++) {
-		channel->buffer.frame[j].ulState = S2255_READ_IDLE;
-		channel->buffer.frame[j].cur_size = 0;
-	}
-	res = videobuf_streamon(&fh->vb_vidq);
-	if (res == 0) {
-		s2255_start_acquire(channel);
-		channel->b_acquire = 1;
-	} else
-		res_free(fh);
-
-	return res;
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-	struct s2255_fh *fh = priv;
-	dprintk(fh->dev, 4, "%s\n, channel: %d", __func__, fh->channel->idx);
-	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-		dprintk(fh->dev, 1, "invalid fh type0\n");
-		return -EINVAL;
-	}
-	if (i != fh->type)
-		return -EINVAL;
-	s2255_stop_acquire(fh->channel);
-	videobuf_streamoff(&fh->vb_vidq);
-	res_free(fh);
-	return 0;
-}
-
 static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id i)
 {
-	struct s2255_fh *fh = priv;
 	struct s2255_mode mode;
-	struct videobuf_queue *q = &fh->vb_vidq;
-	struct s2255_channel *channel = fh->channel;
+	struct s2255_vc *vc = video_drvdata(file);
+	struct vb2_queue *q = &vc->vb_vidq;
 	int ret = 0;
 
-	mutex_lock(&q->vb_lock);
-	if (res_locked(fh)) {
-		dprintk(fh->dev, 1, "can't change standard after started\n");
-		ret = -EBUSY;
-		goto out_s_std;
-	}
-	mode = fh->channel->mode;
+	/*
+	 * Changing the standard implies a format change, which is not allowed
+	 * while buffers for use with streaming have already been allocated.
+	 */
+	if (vb2_is_busy(q))
+		return -EBUSY;
+
+	mode = vc->mode;
 	if (i & V4L2_STD_525_60) {
-		dprintk(fh->dev, 4, "%s 60 Hz\n", __func__);
+		dprintk(vc->dev, 4, "%s 60 Hz\n", __func__);
 		/* if changing format, reset frame decimation/intervals */
 		if (mode.format != FORMAT_NTSC) {
 			mode.restart = 1;
 			mode.format = FORMAT_NTSC;
 			mode.fdec = FDEC_1;
-			channel->width = LINE_SZ_4CIFS_NTSC;
-			channel->height = NUM_LINES_4CIFS_NTSC * 2;
+			vc->width = LINE_SZ_4CIFS_NTSC;
+			vc->height = NUM_LINES_4CIFS_NTSC * 2;
 		}
 	} else if (i & V4L2_STD_625_50) {
-		dprintk(fh->dev, 4, "%s 50 Hz\n", __func__);
+		dprintk(vc->dev, 4, "%s 50 Hz\n", __func__);
 		if (mode.format != FORMAT_PAL) {
 			mode.restart = 1;
 			mode.format = FORMAT_PAL;
 			mode.fdec = FDEC_1;
-			channel->width = LINE_SZ_4CIFS_PAL;
-			channel->height = NUM_LINES_4CIFS_PAL * 2;
+			vc->width = LINE_SZ_4CIFS_PAL;
+			vc->height = NUM_LINES_4CIFS_PAL * 2;
 		}
 	} else {
 		ret = -EINVAL;
 		goto out_s_std;
 	}
-	fh->channel->std = i;
+	vc->std = i;
 	if (mode.restart)
-		s2255_set_mode(fh->channel, &mode);
+		s2255_set_mode(vc, &mode);
 out_s_std:
-	mutex_unlock(&q->vb_lock);
 	return ret;
 }
 
 static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *i)
 {
-	struct s2255_fh *fh = priv;
-
-	*i = fh->channel->std;
+	struct s2255_vc *vc = video_drvdata(file);
+	*i = vc->std;
 	return 0;
 }
 
@@ -1339,9 +1191,8 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *i)
 static int vidioc_enum_input(struct file *file, void *priv,
 			     struct v4l2_input *inp)
 {
-	struct s2255_fh *fh = priv;
-	struct s2255_dev *dev = fh->dev;
-	struct s2255_channel *channel = fh->channel;
+	struct s2255_vc *vc = video_drvdata(file);
+	struct s2255_dev *dev = vc->dev;
 	u32 status = 0;
 	if (inp->index != 0)
 		return -EINVAL;
@@ -1350,7 +1201,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
 	inp->status = 0;
 	if (dev->dsp_fw_ver >= S2255_MIN_DSP_STATUS) {
 		int rc;
-		rc = s2255_cmd_status(fh->channel, &status);
+		rc = s2255_cmd_status(vc, &status);
 		dprintk(dev, 4, "s2255_cmd_status rc: %d status %x\n",
 			rc, status);
 		if (rc == 0)
@@ -1363,7 +1214,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
 		strlcpy(inp->name, "Composite", sizeof(inp->name));
 		break;
 	case 0x2257:
-		strlcpy(inp->name, (channel->idx < 2) ? "Composite" : "S-Video",
+		strlcpy(inp->name, (vc->idx < 2) ? "Composite" : "S-Video",
 			sizeof(inp->name));
 		break;
 	}
@@ -1384,10 +1235,10 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
 
 static int s2255_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-	struct s2255_channel *channel =
-		container_of(ctrl->handler, struct s2255_channel, hdl);
+	struct s2255_vc *vc =
+		container_of(ctrl->handler, struct s2255_vc, hdl);
 	struct s2255_mode mode;
-	mode = channel->mode;
+	mode = vc->mode;
 	/* update the mode to the corresponding value */
 	switch (ctrl->id) {
 	case V4L2_CID_BRIGHTNESS:
@@ -1407,7 +1258,7 @@ static int s2255_s_ctrl(struct v4l2_ctrl *ctrl)
 		mode.color |= !ctrl->val << 16;
 		break;
 	case V4L2_CID_JPEG_COMPRESSION_QUALITY:
-		channel->jpegqual = ctrl->val;
+		vc->jpegqual = ctrl->val;
 		return 0;
 	default:
 		return -EINVAL;
@@ -1417,48 +1268,44 @@ static int s2255_s_ctrl(struct v4l2_ctrl *ctrl)
 	   some V4L programs restart stream unnecessarily
 	   after a s_crtl.
 	*/
-	s2255_set_mode(channel, &mode);
+	s2255_set_mode(vc, &mode);
 	return 0;
 }
 
 static int vidioc_g_jpegcomp(struct file *file, void *priv,
 			 struct v4l2_jpegcompression *jc)
 {
-	struct s2255_fh *fh = priv;
-	struct s2255_channel *channel = fh->channel;
-
+	struct s2255_vc *vc = video_drvdata(file);
 	memset(jc, 0, sizeof(*jc));
-	jc->quality = channel->jpegqual;
-	dprintk(fh->dev, 2, "%s: quality %d\n", __func__, jc->quality);
+	jc->quality = vc->jpegqual;
+	dprintk(vc->dev, 2, "%s: quality %d\n", __func__, jc->quality);
 	return 0;
 }
 
 static int vidioc_s_jpegcomp(struct file *file, void *priv,
 			 const struct v4l2_jpegcompression *jc)
 {
-	struct s2255_fh *fh = priv;
-	struct s2255_channel *channel = fh->channel;
+	struct s2255_vc *vc = video_drvdata(file);
 	if (jc->quality < 0 || jc->quality > 100)
 		return -EINVAL;
-	v4l2_ctrl_s_ctrl(channel->jpegqual_ctrl, jc->quality);
-	dprintk(fh->dev, 2, "%s: quality %d\n", __func__, jc->quality);
+	v4l2_ctrl_s_ctrl(vc->jpegqual_ctrl, jc->quality);
+	dprintk(vc->dev, 2, "%s: quality %d\n", __func__, jc->quality);
 	return 0;
 }
 
 static int vidioc_g_parm(struct file *file, void *priv,
 			 struct v4l2_streamparm *sp)
 {
-	struct s2255_fh *fh = priv;
+	struct s2255_vc *vc = video_drvdata(file);
 	__u32 def_num, def_dem;
-	struct s2255_channel *channel = fh->channel;
 	if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
 	sp->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
-	sp->parm.capture.capturemode = channel->cap_parm.capturemode;
-	def_num = (channel->mode.format == FORMAT_NTSC) ? 1001 : 1000;
-	def_dem = (channel->mode.format == FORMAT_NTSC) ? 30000 : 25000;
+	sp->parm.capture.capturemode = vc->cap_parm.capturemode;
+	def_num = (vc->mode.format == FORMAT_NTSC) ? 1001 : 1000;
+	def_dem = (vc->mode.format == FORMAT_NTSC) ? 30000 : 25000;
 	sp->parm.capture.timeperframe.denominator = def_dem;
-	switch (channel->mode.fdec) {
+	switch (vc->mode.fdec) {
 	default:
 	case FDEC_1:
 		sp->parm.capture.timeperframe.numerator = def_num;
@@ -1473,7 +1320,7 @@ static int vidioc_g_parm(struct file *file, void *priv,
 		sp->parm.capture.timeperframe.numerator = def_num * 5;
 		break;
 	}
-	dprintk(fh->dev, 4, "%s capture mode, %d timeperframe %d/%d\n",
+	dprintk(vc->dev, 4, "%s capture mode, %d timeperframe %d/%d\n",
 		__func__,
 		sp->parm.capture.capturemode,
 		sp->parm.capture.timeperframe.numerator,
@@ -1484,18 +1331,19 @@ static int vidioc_g_parm(struct file *file, void *priv,
 static int vidioc_s_parm(struct file *file, void *priv,
 			 struct v4l2_streamparm *sp)
 {
-	struct s2255_fh *fh = priv;
-	struct s2255_channel *channel = fh->channel;
+	struct s2255_vc *vc = video_drvdata(file);
 	struct s2255_mode mode;
 	int fdec = FDEC_1;
 	__u32 def_num, def_dem;
 	if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
-	mode = channel->mode;
+	mode = vc->mode;
 	/* high quality capture mode requires a stream restart */
-	if (channel->cap_parm.capturemode
-	    != sp->parm.capture.capturemode && res_locked(fh))
+	if ((vc->cap_parm.capturemode != sp->parm.capture.capturemode)
+	    && vb2_is_busy(&vc->vb_vidq))
 		return -EBUSY;
+
+	vc->cap_parm.capturemode = sp->parm.capture.capturemode;
 	def_num = (mode.format == FORMAT_NTSC) ? 1001 : 1000;
 	def_dem = (mode.format == FORMAT_NTSC) ? 30000 : 25000;
 	if (def_dem != sp->parm.capture.timeperframe.denominator)
@@ -1514,8 +1362,8 @@ static int vidioc_s_parm(struct file *file, void *priv,
 	}
 	mode.fdec = fdec;
 	sp->parm.capture.timeperframe.denominator = def_dem;
-	s2255_set_mode(channel, &mode);
-	dprintk(fh->dev, 4, "%s capture mode, %d timeperframe %d/%d, fdec %d\n",
+	s2255_set_mode(vc, &mode);
+	dprintk(vc->dev, 4, "%s capture mode, %d timeperframe %d/%d, fdec %d\n",
 		__func__,
 		sp->parm.capture.capturemode,
 		sp->parm.capture.timeperframe.numerator,
@@ -1538,9 +1386,8 @@ static const struct v4l2_frmsize_discrete pal_sizes[] = {
 static int vidioc_enum_framesizes(struct file *file, void *priv,
 			    struct v4l2_frmsizeenum *fe)
 {
-	struct s2255_fh *fh = priv;
-	struct s2255_channel *channel = fh->channel;
-	int is_ntsc = channel->std & V4L2_STD_525_60;
+	struct s2255_vc *vc = video_drvdata(file);
+	int is_ntsc = vc->std & V4L2_STD_525_60;
 	const struct s2255_fmt *fmt;
 
 	if (fe->index >= NUM_SIZE_ENUMS)
@@ -1557,11 +1404,10 @@ static int vidioc_enum_framesizes(struct file *file, void *priv,
 static int vidioc_enum_frameintervals(struct file *file, void *priv,
 			    struct v4l2_frmivalenum *fe)
 {
-	struct s2255_fh *fh = priv;
-	struct s2255_channel *channel = fh->channel;
+	struct s2255_vc *vc = video_drvdata(file);
 	const struct s2255_fmt *fmt;
 	const struct v4l2_frmsize_discrete *sizes;
-	int is_ntsc = channel->std & V4L2_STD_525_60;
+	int is_ntsc = vc->std & V4L2_STD_525_60;
 #define NUM_FRAME_ENUMS 4
 	int frm_dec[NUM_FRAME_ENUMS] = {1, 2, 3, 5};
 	int i;
@@ -1584,22 +1430,25 @@ static int vidioc_enum_frameintervals(struct file *file, void *priv,
 	fe->type = V4L2_FRMIVAL_TYPE_DISCRETE;
 	fe->discrete.denominator = is_ntsc ? 30000 : 25000;
 	fe->discrete.numerator = (is_ntsc ? 1001 : 1000) * frm_dec[fe->index];
-	dprintk(fh->dev, 4, "%s discrete %d/%d\n", __func__,
+	dprintk(vc->dev, 4, "%s discrete %d/%d\n", __func__,
 		fe->discrete.numerator,
 		fe->discrete.denominator);
 	return 0;
 }
 
-static int __s2255_open(struct file *file)
+static int s2255_open(struct file *file)
 {
-	struct video_device *vdev = video_devdata(file);
-	struct s2255_channel *channel = video_drvdata(file);
-	struct s2255_dev *dev = to_s2255_dev(vdev->v4l2_dev);
-	struct s2255_fh *fh;
-	enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	struct s2255_vc *vc = video_drvdata(file);
+	struct s2255_dev *dev = vc->dev;
 	int state;
-	dprintk(dev, 1, "s2255: open called (dev=%s)\n",
-		video_device_node_name(vdev));
+	int rc = 0;
+
+	/* allocate + initialize per filehandle data */
+	rc = v4l2_fh_open(file);
+	if (rc != 0)
+		return rc;
+
+	/* load firmware */
 	state = atomic_read(&dev->fw_data->fw_state);
 	switch (state) {
 	case S2255_FW_DISCONNECTING:
@@ -1661,66 +1510,23 @@ static int __s2255_open(struct file *file)
 		pr_info("%s: unknown state\n", __func__);
 		return -EFAULT;
 	}
-	/* allocate + initialize per filehandle data */
-	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-	if (NULL == fh)
-		return -ENOMEM;
-	v4l2_fh_init(&fh->fh, vdev);
-	v4l2_fh_add(&fh->fh);
-	file->private_data = &fh->fh;
-	fh->dev = dev;
-	fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-	fh->channel = channel;
-	if (!channel->configured) {
+
+	if (!vc->configured) {
+		int rc;
 		/* configure channel to default state */
-		channel->fmt = &formats[0];
-		s2255_set_mode(channel, &channel->mode);
-		channel->configured = 1;
-	}
-	dprintk(dev, 1, "%s: dev=%s type=%s\n", __func__,
-		video_device_node_name(vdev), v4l2_type_names[type]);
-	dprintk(dev, 2, "%s: fh=0x%08lx, dev=0x%08lx, vidq=0x%08lx\n", __func__,
-		(unsigned long)fh, (unsigned long)dev,
-		(unsigned long)&channel->vidq);
-	dprintk(dev, 4, "%s: list_empty active=%d\n", __func__,
-		list_empty(&channel->vidq.active));
-	videobuf_queue_vmalloc_init(&fh->vb_vidq, &s2255_video_qops,
-				    NULL, &dev->slock,
-				    fh->type,
-				    V4L2_FIELD_INTERLACED,
-				    sizeof(struct s2255_buffer),
-				    fh, vdev->lock);
+		vc->fmt = &formats[0];
+		rc = s2255_set_mode(vc, &vc->mode);
+		if (rc != 0) {
+			/* resend set mode. */
+			rc = s2255_set_mode(vc, &vc->mode);
+		}
+		if (rc == 0)
+			vc->configured = 1;
+	}
+	dprintk(dev, 2, "%s:\n", __func__);
 	return 0;
 }
 
-static int s2255_open(struct file *file)
-{
-	struct video_device *vdev = video_devdata(file);
-	int ret;
-
-	if (mutex_lock_interruptible(vdev->lock))
-		return -ERESTARTSYS;
-	ret = __s2255_open(file);
-	mutex_unlock(vdev->lock);
-	return ret;
-}
-
-static unsigned int s2255_poll(struct file *file,
-			       struct poll_table_struct *wait)
-{
-	struct s2255_fh *fh = file->private_data;
-	struct s2255_dev *dev = fh->dev;
-	int rc = v4l2_ctrl_poll(file, wait);
-
-	dprintk(dev, 100, "%s\n", __func__);
-	if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
-		return POLLERR;
-	mutex_lock(&dev->lock);
-	rc |= videobuf_poll_stream(file, &fh->vb_vidq, wait);
-	mutex_unlock(&dev->lock);
-	return rc;
-}
-
 static void s2255_destroy(struct s2255_dev *dev)
 {
 	dprintk(dev, 1, "%s", __func__);
@@ -1744,57 +1550,14 @@ static void s2255_destroy(struct s2255_dev *dev)
 	kfree(dev);
 }
 
-static int s2255_release(struct file *file)
-{
-	struct s2255_fh *fh = file->private_data;
-	struct s2255_dev *dev = fh->dev;
-	struct video_device *vdev = video_devdata(file);
-	struct s2255_channel *channel = fh->channel;
-	if (!dev)
-		return -ENODEV;
-	mutex_lock(&dev->lock);
-	/* turn off stream */
-	if (res_check(fh)) {
-		if (channel->b_acquire)
-			s2255_stop_acquire(fh->channel);
-		videobuf_streamoff(&fh->vb_vidq);
-		res_free(fh);
-	}
-	videobuf_mmap_free(&fh->vb_vidq);
-	mutex_unlock(&dev->lock);
-	dprintk(dev, 1, "%s[%s]\n", __func__, video_device_node_name(vdev));
-	v4l2_fh_del(&fh->fh);
-	v4l2_fh_exit(&fh->fh);
-	kfree(fh);
-	return 0;
-}
-
-static int s2255_mmap_v4l(struct file *file, struct vm_area_struct *vma)
-{
-	struct s2255_fh *fh = file->private_data;
-	struct s2255_dev *dev;
-	int ret;
-	if (!fh)
-		return -ENODEV;
-	dev = fh->dev;
-	dprintk(dev, 4, "%s, vma=0x%08lx\n", __func__, (unsigned long)vma);
-	if (mutex_lock_interruptible(&dev->lock))
-		return -ERESTARTSYS;
-	ret = videobuf_mmap_mapper(&fh->vb_vidq, vma);
-	mutex_unlock(&dev->lock);
-	dprintk(dev, 4, "%s vma start=0x%08lx, size=%ld, ret=%d\n", __func__,
-		(unsigned long)vma->vm_start,
-		(unsigned long)vma->vm_end - (unsigned long)vma->vm_start, ret);
-	return ret;
-}
-
 static const struct v4l2_file_operations s2255_fops_v4l = {
 	.owner = THIS_MODULE,
 	.open = s2255_open,
-	.release = s2255_release,
-	.poll = s2255_poll,
-	.unlocked_ioctl = video_ioctl2,	/* V4L2 ioctl handler */
-	.mmap = s2255_mmap_v4l,
+	.release = vb2_fop_release,
+	.unlocked_ioctl = video_ioctl2,
+	.read = vb2_fop_read,
+	.mmap = vb2_fop_mmap,
+	.poll = vb2_fop_poll,
 };
 
 static const struct v4l2_ioctl_ops s2255_ioctl_ops = {
@@ -1803,17 +1566,17 @@ static const struct v4l2_ioctl_ops s2255_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_reqbufs =  vb2_ioctl_reqbufs,
+	.vidioc_querybuf = vb2_ioctl_querybuf,
+	.vidioc_qbuf = vb2_ioctl_qbuf,
+	.vidioc_dqbuf = vb2_ioctl_dqbuf,
 	.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_streamon = vidioc_streamon,
-	.vidioc_streamoff = vidioc_streamoff,
+	.vidioc_streamon = vb2_ioctl_streamon,
+	.vidioc_streamoff = vb2_ioctl_streamoff,
 	.vidioc_s_jpegcomp = vidioc_s_jpegcomp,
 	.vidioc_g_jpegcomp = vidioc_g_jpegcomp,
 	.vidioc_s_parm = vidioc_s_parm,
@@ -1828,13 +1591,13 @@ static const struct v4l2_ioctl_ops s2255_ioctl_ops = {
 static void s2255_video_device_release(struct video_device *vdev)
 {
 	struct s2255_dev *dev = to_s2255_dev(vdev->v4l2_dev);
-	struct s2255_channel *channel =
-		container_of(vdev, struct s2255_channel, vdev);
+	struct s2255_vc *vc =
+		container_of(vdev, struct s2255_vc, vdev);
 
 	dprintk(dev, 4, "%s, chnls: %d\n", __func__,
 		atomic_read(&dev->num_channels));
 
-	v4l2_ctrl_handler_free(&channel->hdl);
+	v4l2_ctrl_handler_free(&vc->hdl);
 
 	if (atomic_dec_and_test(&dev->num_channels))
 		s2255_destroy(dev);
@@ -1868,64 +1631,82 @@ static int s2255_probe_v4l(struct s2255_dev *dev)
 	int ret;
 	int i;
 	int cur_nr = video_nr;
-	struct s2255_channel *channel;
+	struct vb2_queue *q;
+	struct s2255_vc *vc;
 	ret = v4l2_device_register(&dev->interface->dev, &dev->v4l2_dev);
 	if (ret)
 		return ret;
 	/* initialize all video 4 linux */
 	/* register 4 video devices */
 	for (i = 0; i < MAX_CHANNELS; i++) {
-		channel = &dev->channel[i];
-		INIT_LIST_HEAD(&channel->vidq.active);
+		vc = &dev->vc[i];
+		INIT_LIST_HEAD(&vc->buf_list);
 
-		v4l2_ctrl_handler_init(&channel->hdl, 6);
-		v4l2_ctrl_new_std(&channel->hdl, &s2255_ctrl_ops,
+		v4l2_ctrl_handler_init(&vc->hdl, 6);
+		v4l2_ctrl_new_std(&vc->hdl, &s2255_ctrl_ops,
 				V4L2_CID_BRIGHTNESS, -127, 127, 1, DEF_BRIGHT);
-		v4l2_ctrl_new_std(&channel->hdl, &s2255_ctrl_ops,
+		v4l2_ctrl_new_std(&vc->hdl, &s2255_ctrl_ops,
 				V4L2_CID_CONTRAST, 0, 255, 1, DEF_CONTRAST);
-		v4l2_ctrl_new_std(&channel->hdl, &s2255_ctrl_ops,
+		v4l2_ctrl_new_std(&vc->hdl, &s2255_ctrl_ops,
 				V4L2_CID_SATURATION, 0, 255, 1, DEF_SATURATION);
-		v4l2_ctrl_new_std(&channel->hdl, &s2255_ctrl_ops,
+		v4l2_ctrl_new_std(&vc->hdl, &s2255_ctrl_ops,
 				V4L2_CID_HUE, 0, 255, 1, DEF_HUE);
-		channel->jpegqual_ctrl = v4l2_ctrl_new_std(&channel->hdl,
+		vc->jpegqual_ctrl = v4l2_ctrl_new_std(&vc->hdl,
 				&s2255_ctrl_ops,
 				V4L2_CID_JPEG_COMPRESSION_QUALITY,
 				0, 100, 1, S2255_DEF_JPEG_QUAL);
 		if (dev->dsp_fw_ver >= S2255_MIN_DSP_COLORFILTER &&
-		    (dev->pid != 0x2257 || channel->idx <= 1))
-			v4l2_ctrl_new_custom(&channel->hdl, &color_filter_ctrl,
+		    (dev->pid != 0x2257 || vc->idx <= 1))
+			v4l2_ctrl_new_custom(&vc->hdl, &color_filter_ctrl,
 					     NULL);
-		if (channel->hdl.error) {
-			ret = channel->hdl.error;
-			v4l2_ctrl_handler_free(&channel->hdl);
+		if (vc->hdl.error) {
+			ret = vc->hdl.error;
+			v4l2_ctrl_handler_free(&vc->hdl);
 			dev_err(&dev->udev->dev, "couldn't register control\n");
 			break;
 		}
-		channel->vidq.dev = dev;
+		q = &vc->vb_vidq;
+		memset(q, 0, sizeof(vc->vb_vidq));
+		q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		q->io_modes = VB2_MMAP | VB2_READ;
+		q->drv_priv = vc;
+		q->lock = &vc->vb_lock;
+		q->buf_struct_size = sizeof(struct s2255_buffer);
+		q->mem_ops = &vb2_vmalloc_memops;
+		q->ops = &s2255_video_qops;
+		q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+		ret = vb2_queue_init(q);
+		if (ret != 0) {
+			dev_err(&dev->udev->dev,
+				"%s vb2_queue_init err: 0x%x\n", __func__, ret);
+			break;
+		}
 		/* register 4 video devices */
-		channel->vdev = template;
-		channel->vdev.ctrl_handler = &channel->hdl;
-		channel->vdev.lock = &dev->lock;
-		channel->vdev.v4l2_dev = &dev->v4l2_dev;
-		set_bit(V4L2_FL_USE_FH_PRIO, &channel->vdev.flags);
-		video_set_drvdata(&channel->vdev, channel);
+		vc->vdev = template;
+		vc->vdev.queue = q;
+		vc->vdev.ctrl_handler = &vc->hdl;
+		/* main device lock */
+		vc->vdev.lock = &dev->lock;
+		vc->vdev.v4l2_dev = &dev->v4l2_dev;
+		set_bit(V4L2_FL_USE_FH_PRIO, &vc->vdev.flags);
+		video_set_drvdata(&vc->vdev, vc);
 		if (video_nr == -1)
-			ret = video_register_device(&channel->vdev,
+			ret = video_register_device(&vc->vdev,
 						    VFL_TYPE_GRABBER,
 						    video_nr);
 		else
-			ret = video_register_device(&channel->vdev,
+			ret = video_register_device(&vc->vdev,
 						    VFL_TYPE_GRABBER,
 						    cur_nr + i);
 
 		if (ret) {
 			dev_err(&dev->udev->dev,
-				"failed to register video device!\n");
+				"failed to register vid device: 0x%x!\n", ret);
 			break;
 		}
 		atomic_inc(&dev->num_channels);
 		v4l2_info(&dev->v4l2_dev, "V4L2 device registered as %s\n",
-			  video_device_node_name(&channel->vdev));
+			  video_device_node_name(&vc->vdev));
 
 	}
 	pr_info("Sensoray 2255 V4L driver Revision: %s\n",
@@ -1962,11 +1743,11 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
 	s32 idx = -1;
 	struct s2255_framei *frm;
 	unsigned char *pdata;
-	struct s2255_channel *ch;
+	struct s2255_vc *vc;
 	dprintk(dev, 100, "buffer to user\n");
-	ch = &dev->channel[dev->cc];
-	idx = ch->cur_frame;
-	frm = &ch->buffer.frame[idx];
+	vc = &dev->vc[dev->cc];
+	idx = vc->cur_frame;
+	frm = &vc->buffer.frame[idx];
 	if (frm->ulState == S2255_READ_IDLE) {
 		int jj;
 		unsigned int cc;
@@ -1990,15 +1771,15 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
 				}
 				/* reverse it */
 				dev->cc = G_chnmap[cc];
-				ch = &dev->channel[dev->cc];
+				vc = &dev->vc[dev->cc];
 				payload =  le32_to_cpu(pdword[3]);
-				if (payload > ch->req_image_size) {
-					ch->bad_payload++;
+				if (payload > vc->req_image_size) {
+					vc->bad_payload++;
 					/* discard the bad frame */
 					return -EINVAL;
 				}
-				ch->pkt_size = payload;
-				ch->jpg_size = le32_to_cpu(pdword[4]);
+				vc->pkt_size = payload;
+				vc->jpg_size = le32_to_cpu(pdword[4]);
 				break;
 			case S2255_MARKER_RESPONSE:
 
@@ -2009,13 +1790,13 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
 				cc = G_chnmap[le32_to_cpu(pdword[1])];
 				if (cc >= MAX_CHANNELS)
 					break;
-				ch = &dev->channel[cc];
+				vc = &dev->vc[cc];
 				switch (pdword[2]) {
 				case S2255_RESPONSE_SETMODE:
 					/* check if channel valid */
 					/* set mode ready */
-					ch->setmode_ready = 1;
-					wake_up(&ch->wait_setmode);
+					vc->setmode_ready = 1;
+					wake_up(&vc->wait_setmode);
 					dprintk(dev, 5, "setmode rdy %d\n", cc);
 					break;
 				case S2255_RESPONSE_FW:
@@ -2029,9 +1810,9 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
 					wake_up(&dev->fw_data->wait_fw);
 					break;
 				case S2255_RESPONSE_STATUS:
-					ch->vidstatus = le32_to_cpu(pdword[3]);
-					ch->vidstatus_ready = 1;
-					wake_up(&ch->wait_vidstatus);
+					vc->vidstatus = le32_to_cpu(pdword[3]);
+					vc->vidstatus_ready = 1;
+					wake_up(&vc->wait_vidstatus);
 					dprintk(dev, 5, "vstat %x chan %d\n",
 						le32_to_cpu(pdword[3]), cc);
 					break;
@@ -2048,11 +1829,12 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
 		if (!bframe)
 			return -EINVAL;
 	}
-	ch = &dev->channel[dev->cc];
-	idx = ch->cur_frame;
-	frm = &ch->buffer.frame[idx];
+	vc = &dev->vc[dev->cc];
+	idx = vc->cur_frame;
+	frm = &vc->buffer.frame[idx];
+
 	/* search done.  now find out if should be acquiring on this channel */
-	if (!ch->b_acquire) {
+	if (!vb2_is_streaming(&vc->vb_vidq)) {
 		/* we found a frame, but this channel is turned off */
 		frm->ulState = S2255_READ_IDLE;
 		return -EINVAL;
@@ -2066,7 +1848,6 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
 	/* skip the marker 512 bytes (and offset if out of sync) */
 	psrc = (u8 *)pipe_info->transfer_buffer + offset;
 
-
 	if (frm->lpvbits == NULL) {
 		dprintk(dev, 1, "s2255 frame buffer == NULL.%p %p %d %d",
 			frm, dev, dev->cc, idx);
@@ -2074,13 +1855,11 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
 	}
 
 	pdest = frm->lpvbits + frm->cur_size;
-
 	copy_size = (pipe_info->cur_transfer_size - offset);
-
-	size = ch->pkt_size - PREFIX_SIZE;
+	size = vc->pkt_size - PREFIX_SIZE;
 
 	/* sanity check on pdest */
-	if ((copy_size + frm->cur_size) < ch->req_image_size)
+	if ((copy_size + frm->cur_size) < vc->req_image_size)
 		memcpy(pdest, psrc, copy_size);
 
 	frm->cur_size += copy_size;
@@ -2089,19 +1868,18 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
 	if (frm->cur_size >= size) {
 		dprintk(dev, 2, "******[%d]Buffer[%d]full*******\n",
 			dev->cc, idx);
-		ch->last_frame = ch->cur_frame;
-		ch->cur_frame++;
+		vc->last_frame = vc->cur_frame;
+		vc->cur_frame++;
 		/* end of system frame ring buffer, start at zero */
-		if ((ch->cur_frame == SYS_FRAMES) ||
-		    (ch->cur_frame == ch->buffer.dwFrames))
-			ch->cur_frame = 0;
+		if ((vc->cur_frame == SYS_FRAMES) ||
+		    (vc->cur_frame == vc->buffer.dwFrames))
+			vc->cur_frame = 0;
 		/* frame ready */
-		if (ch->b_acquire)
-			s2255_got_frame(ch, ch->jpg_size);
-		ch->frame_count++;
+		if (vb2_is_streaming(&vc->vb_vidq))
+			s2255_got_frame(vc, vc->jpg_size);
+		vc->frame_count++;
 		frm->ulState = S2255_READ_IDLE;
 		frm->cur_size = 0;
-
 	}
 	/* done successfully */
 	return 0;
@@ -2121,7 +1899,7 @@ static void s2255_read_video_callback(struct s2255_dev *dev,
 	/* otherwise copy to the system buffers */
 	res = save_frame(dev, pipe_info);
 	if (res != 0)
-		dprintk(dev, 4, "s2255: read callback failed\n");
+		dprintk(dev, 50, "s2255: read callback: %d\n", res);
 
 	dprintk(dev, 50, "callback read video done\n");
 	return;
@@ -2171,11 +1949,11 @@ static int s2255_get_fx2fw(struct s2255_dev *dev)
  * Create the system ring buffer to copy frames into from the
  * usb read pipe.
  */
-static int s2255_create_sys_buffers(struct s2255_channel *channel)
+static int s2255_create_sys_buffers(struct s2255_vc *vc)
 {
 	unsigned long i;
 	unsigned long reqsize;
-	channel->buffer.dwFrames = SYS_FRAMES;
+	vc->buffer.dwFrames = SYS_FRAMES;
 	/* always allocate maximum size(PAL) for system buffers */
 	reqsize = SYS_FRAMES_MAXSIZE;
 
@@ -2184,33 +1962,33 @@ static int s2255_create_sys_buffers(struct s2255_channel *channel)
 
 	for (i = 0; i < SYS_FRAMES; i++) {
 		/* allocate the frames */
-		channel->buffer.frame[i].lpvbits = vmalloc(reqsize);
-		channel->buffer.frame[i].size = reqsize;
-		if (channel->buffer.frame[i].lpvbits == NULL) {
+		vc->buffer.frame[i].lpvbits = vmalloc(reqsize);
+		vc->buffer.frame[i].size = reqsize;
+		if (vc->buffer.frame[i].lpvbits == NULL) {
 			pr_info("out of memory.  using less frames\n");
-			channel->buffer.dwFrames = i;
+			vc->buffer.dwFrames = i;
 			break;
 		}
 	}
 
 	/* make sure internal states are set */
 	for (i = 0; i < SYS_FRAMES; i++) {
-		channel->buffer.frame[i].ulState = 0;
-		channel->buffer.frame[i].cur_size = 0;
+		vc->buffer.frame[i].ulState = 0;
+		vc->buffer.frame[i].cur_size = 0;
 	}
 
-	channel->cur_frame = 0;
-	channel->last_frame = -1;
+	vc->cur_frame = 0;
+	vc->last_frame = -1;
 	return 0;
 }
 
-static int s2255_release_sys_buffers(struct s2255_channel *channel)
+static int s2255_release_sys_buffers(struct s2255_vc *vc)
 {
 	unsigned long i;
 	for (i = 0; i < SYS_FRAMES; i++) {
-		if (channel->buffer.frame[i].lpvbits)
-			vfree(channel->buffer.frame[i].lpvbits);
-		channel->buffer.frame[i].lpvbits = NULL;
+		if (vc->buffer.frame[i].lpvbits)
+			vfree(vc->buffer.frame[i].lpvbits);
+		vc->buffer.frame[i].lpvbits = NULL;
 	}
 	return 0;
 }
@@ -2244,21 +2022,20 @@ static int s2255_board_init(struct s2255_dev *dev)
 		pr_info("s2255: newer USB firmware available\n");
 
 	for (j = 0; j < MAX_CHANNELS; j++) {
-		struct s2255_channel *channel = &dev->channel[j];
-		channel->b_acquire = 0;
-		channel->mode = mode_def;
+		struct s2255_vc *vc = &dev->vc[j];
+		vc->mode = mode_def;
 		if (dev->pid == 0x2257 && j > 1)
-			channel->mode.color |= (1 << 16);
-		channel->jpegqual = S2255_DEF_JPEG_QUAL;
-		channel->width = LINE_SZ_4CIFS_NTSC;
-		channel->height = NUM_LINES_4CIFS_NTSC * 2;
-		channel->std = V4L2_STD_NTSC_M;
-		channel->fmt = &formats[0];
-		channel->mode.restart = 1;
-		channel->req_image_size = get_transfer_size(&mode_def);
-		channel->frame_count = 0;
+			vc->mode.color |= (1 << 16);
+		vc->jpegqual = S2255_DEF_JPEG_QUAL;
+		vc->width = LINE_SZ_4CIFS_NTSC;
+		vc->height = NUM_LINES_4CIFS_NTSC * 2;
+		vc->std = V4L2_STD_NTSC_M;
+		vc->fmt = &formats[0];
+		vc->mode.restart = 1;
+		vc->req_image_size = get_transfer_size(&mode_def);
+		vc->frame_count = 0;
 		/* create the system buffers */
-		s2255_create_sys_buffers(channel);
+		s2255_create_sys_buffers(vc);
 	}
 	/* start read pipe */
 	s2255_start_readpipe(dev);
@@ -2270,14 +2047,13 @@ static int s2255_board_shutdown(struct s2255_dev *dev)
 {
 	u32 i;
 	dprintk(dev, 1, "%s: dev: %p", __func__,  dev);
-
 	for (i = 0; i < MAX_CHANNELS; i++) {
-		if (dev->channel[i].b_acquire)
-			s2255_stop_acquire(&dev->channel[i]);
+		if (vb2_is_streaming(&dev->vc[i].vb_vidq))
+			s2255_stop_acquire(&dev->vc[i]);
 	}
 	s2255_stop_readpipe(dev);
 	for (i = 0; i < MAX_CHANNELS; i++)
-		s2255_release_sys_buffers(&dev->channel[i]);
+		s2255_release_sys_buffers(&dev->vc[i]);
 	/* release transfer buffer */
 	kfree(dev->pipe.transfer_buffer);
 	return 0;
@@ -2366,26 +2142,26 @@ static int s2255_start_readpipe(struct s2255_dev *dev)
 }
 
 /* starts acquisition process */
-static int s2255_start_acquire(struct s2255_channel *channel)
+static int s2255_start_acquire(struct s2255_vc *vc)
 {
 	unsigned char *buffer;
 	int res;
 	unsigned long chn_rev;
 	int j;
-	struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
-	chn_rev = G_chnmap[channel->idx];
+	struct s2255_dev *dev = to_s2255_dev(vc->vdev.v4l2_dev);
+	chn_rev = G_chnmap[vc->idx];
 	buffer = kzalloc(512, GFP_KERNEL);
 	if (buffer == NULL) {
 		dev_err(&dev->udev->dev, "out of mem\n");
 		return -ENOMEM;
 	}
 
-	channel->last_frame = -1;
-	channel->bad_payload = 0;
-	channel->cur_frame = 0;
+	vc->last_frame = -1;
+	vc->bad_payload = 0;
+	vc->cur_frame = 0;
 	for (j = 0; j < SYS_FRAMES; j++) {
-		channel->buffer.frame[j].ulState = 0;
-		channel->buffer.frame[j].cur_size = 0;
+		vc->buffer.frame[j].ulState = 0;
+		vc->buffer.frame[j].cur_size = 0;
 	}
 
 	/* send the start command */
@@ -2396,18 +2172,18 @@ static int s2255_start_acquire(struct s2255_channel *channel)
 	if (res != 0)
 		dev_err(&dev->udev->dev, "CMD_START error\n");
 
-	dprintk(dev, 2, "start acquire exit[%d] %d\n", channel->idx, res);
+	dprintk(dev, 2, "start acquire exit[%d] %d\n", vc->idx, res);
 	kfree(buffer);
 	return 0;
 }
 
-static int s2255_stop_acquire(struct s2255_channel *channel)
+static int s2255_stop_acquire(struct s2255_vc *vc)
 {
 	unsigned char *buffer;
 	int res;
 	unsigned long chn_rev;
-	struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
-	chn_rev = G_chnmap[channel->idx];
+	struct s2255_dev *dev = to_s2255_dev(vc->vdev.v4l2_dev);
+	chn_rev = G_chnmap[vc->idx];
 	buffer = kzalloc(512, GFP_KERNEL);
 	if (buffer == NULL) {
 		dev_err(&dev->udev->dev, "out of mem\n");
@@ -2421,8 +2197,7 @@ static int s2255_stop_acquire(struct s2255_channel *channel)
 	if (res != 0)
 		dev_err(&dev->udev->dev, "CMD_STOP error\n");
 	kfree(buffer);
-	channel->b_acquire = 0;
-	dprintk(dev, 4, "%s: chn %d, res %d\n", __func__, channel->idx, res);
+	dprintk(dev, 4, "%s: chn %d, res %d\n", __func__, vc->idx, res);
 	return res;
 }
 
@@ -2512,11 +2287,13 @@ static int s2255_probe(struct usb_interface *interface,
 	dev->timer.data = (unsigned long)dev->fw_data;
 	init_waitqueue_head(&dev->fw_data->wait_fw);
 	for (i = 0; i < MAX_CHANNELS; i++) {
-		struct s2255_channel *channel = &dev->channel[i];
-		channel->idx = i;
-		channel->dev = dev;
-		init_waitqueue_head(&channel->wait_setmode);
-		init_waitqueue_head(&channel->wait_vidstatus);
+		struct s2255_vc *vc = &dev->vc[i];
+		vc->idx = i;
+		vc->dev = dev;
+		init_waitqueue_head(&vc->wait_setmode);
+		init_waitqueue_head(&vc->wait_vidstatus);
+		spin_lock_init(&vc->qlock);
+		mutex_init(&vc->vb_lock);
 	}
 
 	dev->fw_data->fw_urb = usb_alloc_urb(0, GFP_KERNEL);
@@ -2562,8 +2339,7 @@ static int s2255_probe(struct usb_interface *interface,
 	retval = s2255_board_init(dev);
 	if (retval)
 		goto errorBOARDINIT;
-	spin_lock_init(&dev->slock);
-	s2255_fwload_start(dev, 0);
+	s2255_fwload_start(dev, 1);
 	/* loads v4l specific */
 	retval = s2255_probe_v4l(dev);
 	if (retval)
@@ -2604,15 +2380,15 @@ static void s2255_disconnect(struct usb_interface *interface)
 	atomic_inc(&dev->num_channels);
 	/* unregister each video device. */
 	for (i = 0; i < channels; i++)
-		video_unregister_device(&dev->channel[i].vdev);
+		video_unregister_device(&dev->vc[i].vdev);
 	/* wake up any of our timers */
 	atomic_set(&dev->fw_data->fw_state, S2255_FW_DISCONNECTING);
 	wake_up(&dev->fw_data->wait_fw);
 	for (i = 0; i < MAX_CHANNELS; i++) {
-		dev->channel[i].setmode_ready = 1;
-		wake_up(&dev->channel[i].wait_setmode);
-		dev->channel[i].vidstatus_ready = 1;
-		wake_up(&dev->channel[i].wait_vidstatus);
+		dev->vc[i].setmode_ready = 1;
+		wake_up(&dev->vc[i].wait_setmode);
+		dev->vc[i].vidstatus_ready = 1;
+		wake_up(&dev->vc[i].wait_vidstatus);
 	}
 	if (atomic_dec_and_test(&dev->num_channels))
 		s2255_destroy(dev);
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH] s2255drv: port to videobuf2
  2014-01-31 17:35 [PATCH] s2255drv: port to videobuf2 Dean Anderson
@ 2014-02-03  9:51 ` Hans Verkuil
  2014-02-03 17:06   ` Dean Anderson
  0 siblings, 1 reply; 7+ messages in thread
From: Hans Verkuil @ 2014-02-03  9:51 UTC (permalink / raw)
  To: Dean Anderson; +Cc: linux-media

Hi Dean,

Some specific comments below, but first two general comments:

It is easier to review if at least the removal of the old s2255_fh struct
was done as a separate patch. It's always good to try and keep the changes
in patches as small as possible. The actual vb2 conversion is always a
'big bang' patch, that's unavoidable, but it's easier if it isn't mixed in
with other changes that are not directly related to the vb2 conversion.

And did you also run the v4l2-compliance utility for this driver? That's
useful to check that everything it still correct.

On 01/31/2014 06:35 PM, Dean Anderson wrote:
> Update s2255drv to use videobuf2 instead of videobuf. 
> s2255_fh file handle removed and driver simplified.
> 
> Signed-off-by: Dean Anderson <linux-dev@sensoray.com>
> ---
>  drivers/media/usb/s2255/s2255drv.c | 1170 +++++++++++++++---------------------
>  1 file changed, 473 insertions(+), 697 deletions(-)
> 
> diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c
> index c6bdccc..d6e9332 100644
> --- a/drivers/media/usb/s2255/s2255drv.c
> +++ b/drivers/media/usb/s2255/s2255drv.c

<snip>

> @@ -666,146 +641,131 @@ static void s2255_fillbuff(struct s2255_channel *channel,
>  	dprintk(dev, 2, "s2255fill at : Buffer 0x%08lx size= %d\n",
>  		(unsigned long)vbuf, pos);
>  	/* tell v4l buffer was filled */
> -	buf->vb.field_count = channel->frame_count * 2;
> -	v4l2_get_timestamp(&buf->vb.ts);
> -	buf->vb.state = VIDEOBUF_DONE;
> +	vc->field_count = vc->frame_count * 2;
> +	buf->vb.v4l2_buf.field = vc->field;
> +	buf->vb.v4l2_buf.sequence = vc->field_count >> 1;

Just drop field_count (left-over from vivi) and use frame_count directly.

> +	v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
> +	vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
>  }
>  
> +/*
> + * setup the contraints of the queue
> + */
> +static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
> +				unsigned int *nbuffers, unsigned int *nplanes,
> +				unsigned int sizes[], void *alloc_ctxs[])
> +{
> +	struct s2255_vc *vc = vb2_get_drv_priv(vq);
> +	unsigned long size;
>  
> -/* ------------------------------------------------------------------
> -   Videobuf operations
> -   ------------------------------------------------------------------*/
> +	size = vc->width * vc->height * (vc->fmt->depth >> 3);
>  
> -static int buffer_setup(struct videobuf_queue *vq, unsigned int *count,
> -			unsigned int *size)
> -{
> -	struct s2255_fh *fh = vq->priv_data;
> -	struct s2255_channel *channel = fh->channel;
> -	*size = channel->width * channel->height * (channel->fmt->depth >> 3);
> +	if (0 == *nbuffers)
> +		*nbuffers = S2255_DEF_BUFS;

Unfortunately vivi was a bad example to use for this (I'm going to post patches
to fix vivi to avoid this in the future).

What really needs to happen is that you test against the minimum number of
buffers required to stream (usually somewhere between 1 and 3, test with e.g.
qv4l2 or v4l2-ctl) and if it is less, set *nbuffers to that minimum.

>  
> -	if (0 == *count)
> -		*count = S2255_DEF_BUFS;
> +	if (size * *nbuffers > vid_limit * 1024 * 1024)
> +		*nbuffers = (vid_limit * 1024 * 1024) / size;
>  
> -	if (*size * *count > vid_limit * 1024 * 1024)
> -		*count = (vid_limit * 1024 * 1024) / *size;

This vid_limit makes no sense. If the application wants 32 buffers (the maximum),
then it should be able to get 32 buffers if there is enough memory. Having a
vid_limit is pointless. I plan on removing this from vivi as well.

> +	if (size == 0)
> +		return -EINVAL;
>  
> +	*nplanes = 1;
> +	sizes[0] = size;
>  	return 0;
>  }
>  
> -static void free_buffer(struct videobuf_queue *vq, struct s2255_buffer *buf)
> -{
> -	videobuf_vmalloc_free(&buf->vb);
> -	buf->vb.state = VIDEOBUF_NEEDS_INIT;
> -}
>  
> -static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
> -			  enum v4l2_field field)
> +static int buffer_prepare(struct vb2_buffer *vb)
>  {
> -	struct s2255_fh *fh = vq->priv_data;
> -	struct s2255_channel *channel = fh->channel;
> +	struct s2255_vc *vc = vb2_get_drv_priv(vb->vb2_queue);
>  	struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb);
> -	int rc;
> -	int w = channel->width;
> -	int h = channel->height;
> -	dprintk(fh->dev, 4, "%s, field=%d\n", __func__, field);
> -	if (channel->fmt == NULL)
> -		return -EINVAL;
> +	unsigned long size;
> +	int w = vc->width;
> +	int h = vc->height;
>  
> -	if ((w < norm_minw(channel)) ||
> -	    (w > norm_maxw(channel)) ||
> -	    (h < norm_minh(channel)) ||
> -	    (h > norm_maxh(channel))) {
> -		dprintk(fh->dev, 4, "invalid buffer prepare\n");
> +	if (vc->fmt == NULL)
>  		return -EINVAL;
> -	}
> -	buf->vb.size = w * h * (channel->fmt->depth >> 3);
> -	if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) {
> -		dprintk(fh->dev, 4, "invalid buffer prepare\n");
> +
> +	if ((w < norm_minw(vc)) ||
> +	    (w > norm_maxw(vc)) ||
> +	    (h < norm_minh(vc)) ||
> +	    (h > norm_maxh(vc))) {
> +		dprintk(vc->dev, 4, "invalid buffer prepare\n");
>  		return -EINVAL;
>  	}
> +	size = w * h * (vc->fmt->depth >> 3);
>  
> -	buf->fmt = channel->fmt;
> -	buf->vb.width = w;
> -	buf->vb.height = h;
> -	buf->vb.field = field;
> -
> -	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
> -		rc = videobuf_iolock(vq, &buf->vb, NULL);
> -		if (rc < 0)
> -			goto fail;
> -	}
> +	if (vb2_plane_size(vb, 0) < size)
> +		return -EINVAL;
>  
> -	buf->vb.state = VIDEOBUF_PREPARED;
> +	vb2_set_plane_payload(&buf->vb, 0, size);
> +	buf->fmt = vc->fmt;

buf->fmt can be dropped. It's used in only one place, and there vc->fmt can be
used as well. I need to remove that in vivi as well.

>  	return 0;
> -fail:
> -	free_buffer(vq, buf);
> -	return rc;
>  }
>  
> -static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
> +static void buffer_queue(struct vb2_buffer *vb)
>  {
>  	struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb);
> -	struct s2255_fh *fh = vq->priv_data;
> -	struct s2255_channel *channel = fh->channel;
> -	struct s2255_dmaqueue *vidq = &channel->vidq;
> -	dprintk(fh->dev, 1, "%s\n", __func__);
> -	buf->vb.state = VIDEOBUF_QUEUED;
> -	list_add_tail(&buf->vb.queue, &vidq->active);
> -}
> -
> -static void buffer_release(struct videobuf_queue *vq,
> -			   struct videobuf_buffer *vb)
> -{
> -	struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb);
> -	struct s2255_fh *fh = vq->priv_data;
> -	dprintk(fh->dev, 4, "%s %d\n", __func__, fh->channel->idx);
> -	free_buffer(vq, buf);
> -}
> -
> -static struct videobuf_queue_ops s2255_video_qops = {
> -	.buf_setup = buffer_setup,
> -	.buf_prepare = buffer_prepare,
> -	.buf_queue = buffer_queue,
> -	.buf_release = buffer_release,
> -};
> -
> -
> -static int res_get(struct s2255_fh *fh)
> -{
> -	struct s2255_channel *channel = fh->channel;
> -	/* is it free? */
> -	if (channel->resources)
> -		return 0; /* no, someone else uses it */
> -	/* it's free, grab it */
> -	channel->resources = 1;
> -	fh->resources = 1;
> -	dprintk(fh->dev, 1, "s2255: res: get\n");
> -	return 1;
> +	struct s2255_vc *vc = vb2_get_drv_priv(vb->vb2_queue);
> +	struct s2255_dev *dev = vc->dev;
> +	unsigned long flags = 0;

Please add an empty line here to make it more readable. In general, after
declaring variables add a newline before starting the actual code.

> +	dprintk(dev, 1, "%s\n", __func__);
> +	spin_lock_irqsave(&vc->qlock, flags);
> +	list_add_tail(&buf->list, &vc->buf_list);
> +	spin_unlock_irqrestore(&vc->qlock, flags);
>  }
>  
> -static int res_locked(struct s2255_fh *fh)
> +/* begin streaming on a 2255 video channel */
> +static int start_streaming(struct vb2_queue *vq, unsigned int count)
>  {
> -	return fh->channel->resources;
> +	struct s2255_vc *vc = vb2_get_drv_priv(vq);
> +	int j;
> +	vc->last_frame = -1;
> +	vc->bad_payload = 0;
> +	vc->cur_frame = 0;
> +	vc->frame_count = 0;
> +	for (j = 0; j < SYS_FRAMES; j++) {
> +		vc->buffer.frame[j].ulState = S2255_READ_IDLE;
> +		vc->buffer.frame[j].cur_size = 0;
> +	}
> +	s2255_start_acquire(vc);

I noticed that s2255_start_acquire can fail and that that is not checked here.
In fact, s2255_start_acquire also ignores an error from s2255_write_config().
Several s2255 functions allocate a 512 buffer and release it again after use.
Would it not make more sense to allocate that buffer in probe() and use that
everywhere?

> +	return 0;
>  }
>  
> -static int res_check(struct s2255_fh *fh)
> +/* abort streaming and wait for last buffer */
> +static int stop_streaming(struct vb2_queue *vq)
>  {
> -	return fh->resources;
> +	struct s2255_vc *vc = vb2_get_drv_priv(vq);
> +	struct s2255_buffer *buf, *node;
> +	unsigned long flags;
> +	s2255_stop_acquire(vc);
> +	spin_lock_irqsave(&vc->qlock, flags);
> +	list_for_each_entry_safe(buf, node, &vc->buf_list, list) {
> +		list_del(&buf->list);
> +		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
> +		dprintk(vc->dev, 2, "[%p/%d] done\n",
> +			buf, buf->vb.v4l2_buf.index);
> +	}
> +	spin_unlock_irqrestore(&vc->qlock, flags);
> +	return 0;
>  }
>  
> +static struct vb2_ops s2255_video_qops = {
> +	.queue_setup = queue_setup,
> +	.buf_prepare = buffer_prepare,
> +	.buf_queue = buffer_queue,
> +	.start_streaming = start_streaming,
> +	.stop_streaming = stop_streaming,
> +	.wait_prepare = vb2_ops_wait_prepare,
> +	.wait_finish = vb2_ops_wait_finish,
>  
> -static void res_free(struct s2255_fh *fh)
> -{
> -	struct s2255_channel *channel = fh->channel;
> -	channel->resources = 0;
> -	fh->resources = 0;
> -}
> +};
>  
>  static int vidioc_querycap(struct file *file, void *priv,
>  			   struct v4l2_capability *cap)
>  {
> -	struct s2255_fh *fh = file->private_data;
> -	struct s2255_dev *dev = fh->dev;
> +	struct s2255_vc *vc = video_drvdata(file);
> +	struct s2255_dev *dev = vc->dev;
>  
>  	strlcpy(cap->driver, "s2255", sizeof(cap->driver));
>  	strlcpy(cap->card, "s2255", sizeof(cap->card));
> @@ -833,19 +793,18 @@ 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 s2255_fh *fh = priv;
> -	struct s2255_channel *channel = fh->channel;
> -	int is_ntsc = channel->std & V4L2_STD_525_60;
> +	struct s2255_vc *vc = video_drvdata(file);
> +	int is_ntsc = vc->std & V4L2_STD_525_60;
>  
> -	f->fmt.pix.width = channel->width;
> -	f->fmt.pix.height = channel->height;
> +	f->fmt.pix.width = vc->width;
> +	f->fmt.pix.height = vc->height;
>  	if (f->fmt.pix.height >=
>  	    (is_ntsc ? NUM_LINES_1CIFS_NTSC : NUM_LINES_1CIFS_PAL) * 2)
>  		f->fmt.pix.field = V4L2_FIELD_INTERLACED;
>  	else
>  		f->fmt.pix.field = V4L2_FIELD_TOP;
> -	f->fmt.pix.pixelformat = channel->fmt->fourcc;
> -	f->fmt.pix.bytesperline = f->fmt.pix.width * (channel->fmt->depth >> 3);
> +	f->fmt.pix.pixelformat = vc->fmt->fourcc;
> +	f->fmt.pix.bytesperline = f->fmt.pix.width * (vc->fmt->depth >> 3);
>  	f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
>  	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
>  	f->fmt.pix.priv = 0;
> @@ -857,9 +816,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
>  {
>  	const struct s2255_fmt *fmt;
>  	enum v4l2_field field;
> -	struct s2255_fh *fh = priv;
> -	struct s2255_channel *channel = fh->channel;
> -	int is_ntsc = channel->std & V4L2_STD_525_60;
> +	struct s2255_vc *vc = video_drvdata(file);
> +	int is_ntsc = vc->std & V4L2_STD_525_60;
>  
>  	fmt = format_by_fourcc(f->fmt.pix.pixelformat);
>  
> @@ -868,7 +826,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
>  
>  	field = f->fmt.pix.field;
>  
> -	dprintk(fh->dev, 50, "%s NTSC: %d suggested width: %d, height: %d\n",
> +	dprintk(vc->dev, 50, "%s NTSC: %d suggested width: %d, height: %d\n",
>  		__func__, is_ntsc, f->fmt.pix.width, f->fmt.pix.height);
>  	if (is_ntsc) {
>  		/* NTSC */
> @@ -910,7 +868,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
>  	f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
>  	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
>  	f->fmt.pix.priv = 0;
> -	dprintk(fh->dev, 50, "%s: set width %d height %d field %d\n", __func__,
> +	f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> +	dprintk(vc->dev, 50, "%s: set width %d height %d field %d\n", __func__,
>  		f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
>  	return 0;
>  }
> @@ -918,14 +877,13 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
>  static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
>  			    struct v4l2_format *f)
>  {
> -	struct s2255_fh *fh = priv;
> -	struct s2255_channel *channel = fh->channel;
> +	struct s2255_vc *vc = video_drvdata(file);
>  	const struct s2255_fmt *fmt;
> -	struct videobuf_queue *q = &fh->vb_vidq;
> +	struct vb2_queue *q = &vc->vb_vidq;
>  	struct s2255_mode mode;
>  	int ret;
>  
> -	ret = vidioc_try_fmt_vid_cap(file, fh, f);
> +	ret = vidioc_try_fmt_vid_cap(file, vc, f);
>  
>  	if (ret < 0)
>  		return ret;
> @@ -934,29 +892,24 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
>  
>  	if (fmt == NULL)
>  		return -EINVAL;
> +	/*
> +	 * It is not allowed to change the format while buffers for use with
> +	 * streaming have already been allocated.
> +	 */
> +	if (vb2_is_busy(q))
> +		return -EBUSY;
>  
> -	mutex_lock(&q->vb_lock);
> -
> -	if (videobuf_queue_is_busy(&fh->vb_vidq)) {
> -		dprintk(fh->dev, 1, "queue busy\n");
> -		ret = -EBUSY;
> -		goto out_s_fmt;
> -	}
> -
> -	if (res_locked(fh)) {
> -		dprintk(fh->dev, 1, "%s: channel busy\n", __func__);
> -		ret = -EBUSY;
> -		goto out_s_fmt;
> -	}
> -	mode = channel->mode;
> -	channel->fmt = fmt;
> -	channel->width = f->fmt.pix.width;
> -	channel->height = f->fmt.pix.height;
> -	fh->vb_vidq.field = f->fmt.pix.field;
> -	fh->type = f->type;
> -	if (channel->width > norm_minw(channel)) {
> -		if (channel->height > norm_minh(channel)) {
> -			if (channel->cap_parm.capturemode &
> +	/* change format */
> +	mode = vc->mode;
> +	vc->fmt = fmt;
> +	vc->width = f->fmt.pix.width;
> +	vc->height = f->fmt.pix.height;
> +	vc->field = f->fmt.pix.field;
> +	vc->type = f->type;
> +
> +	if (vc->width > norm_minw(vc)) {
> +		if (vc->height > norm_minh(vc)) {
> +			if (vc->cap_parm.capturemode &
>  			    V4L2_MODE_HIGHQUALITY)
>  				mode.scale = SCALE_4CIFSI;
>  			else
> @@ -968,7 +921,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
>  		mode.scale = SCALE_1CIFS;
>  	}
>  	/* color mode */
> -	switch (channel->fmt->fourcc) {
> +	switch (vc->fmt->fourcc) {
>  	case V4L2_PIX_FMT_GREY:
>  		mode.color &= ~MASK_COLOR;
>  		mode.color |= COLOR_Y8;
> @@ -977,7 +930,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
>  	case V4L2_PIX_FMT_MJPEG:
>  		mode.color &= ~MASK_COLOR;
>  		mode.color |= COLOR_JPG;
> -		mode.color |= (channel->jpegqual << 8);
> +		mode.color |= (vc->jpegqual << 8);
>  		break;
>  	case V4L2_PIX_FMT_YUV422P:
>  		mode.color &= ~MASK_COLOR;
> @@ -990,51 +943,15 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
>  		mode.color |= COLOR_YUVPK;
>  		break;
>  	}
> -	if ((mode.color & MASK_COLOR) != (channel->mode.color & MASK_COLOR))
> +	if ((mode.color & MASK_COLOR) != (vc->mode.color & MASK_COLOR))
>  		mode.restart = 1;
> -	else if (mode.scale != channel->mode.scale)
> +	else if (mode.scale != vc->mode.scale)
>  		mode.restart = 1;
> -	else if (mode.format != channel->mode.format)
> +	else if (mode.format != vc->mode.format)
>  		mode.restart = 1;
> -	channel->mode = mode;
> -	(void) s2255_set_mode(channel, &mode);
> -	ret = 0;
> -out_s_fmt:
> -	mutex_unlock(&q->vb_lock);
> -	return ret;
> -}
> -
> -static int vidioc_reqbufs(struct file *file, void *priv,
> -			  struct v4l2_requestbuffers *p)
> -{
> -	int rc;
> -	struct s2255_fh *fh = priv;
> -	rc = videobuf_reqbufs(&fh->vb_vidq, p);
> -	return rc;
> -}
> -
> -static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
> -{
> -	int rc;
> -	struct s2255_fh *fh = priv;
> -	rc = videobuf_querybuf(&fh->vb_vidq, p);
> -	return rc;
> -}
> -
> -static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
> -{
> -	int rc;
> -	struct s2255_fh *fh = priv;
> -	rc = videobuf_qbuf(&fh->vb_vidq, p);
> -	return rc;
> -}
> -
> -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
> -{
> -	int rc;
> -	struct s2255_fh *fh = priv;
> -	rc = videobuf_dqbuf(&fh->vb_vidq, p, file->f_flags & O_NONBLOCK);
> -	return rc;
> +	vc->mode = mode;
> +	(void) s2255_set_mode(vc, &mode);
> +	return 0;
>  }
>  
>  /* write to the configuration pipe, synchronously */
> @@ -1115,16 +1032,6 @@ static u32 get_transfer_size(struct s2255_mode *mode)
>  	return usbInSize;
>  }
>  
> -static void s2255_print_cfg(struct s2255_dev *sdev, struct s2255_mode *mode)
> -{
> -	struct device *dev = &sdev->udev->dev;
> -	dev_info(dev, "------------------------------------------------\n");
> -	dev_info(dev, "format: %d\nscale %d\n", mode->format, mode->scale);
> -	dev_info(dev, "fdec: %d\ncolor %d\n", mode->fdec, mode->color);
> -	dev_info(dev, "bright: 0x%x\n", mode->bright);
> -	dev_info(dev, "------------------------------------------------\n");
> -}
> -
>  /*
>   * set mode is the function which controls the DSP.
>   * the restart parameter in struct s2255_mode should be set whenever
> @@ -1133,28 +1040,28 @@ static void s2255_print_cfg(struct s2255_dev *sdev, struct s2255_mode *mode)
>   * When the restart parameter is set, we sleep for ONE frame to allow the
>   * DSP time to get the new frame
>   */
> -static int s2255_set_mode(struct s2255_channel *channel,
> +static int s2255_set_mode(struct s2255_vc *vc,
>  			  struct s2255_mode *mode)
>  {
>  	int res;
>  	__le32 *buffer;
>  	unsigned long chn_rev;
> -	struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
> +	struct s2255_dev *dev = to_s2255_dev(vc->vdev.v4l2_dev);
>  	int i;
>  
> -	chn_rev = G_chnmap[channel->idx];
> -	dprintk(dev, 3, "%s channel: %d\n", __func__, channel->idx);
> +	chn_rev = G_chnmap[vc->idx];
> +	dprintk(dev, 3, "%s channel: %d\n", __func__, vc->idx);
>  	/* if JPEG, set the quality */
>  	if ((mode->color & MASK_COLOR) == COLOR_JPG) {
>  		mode->color &= ~MASK_COLOR;
>  		mode->color |= COLOR_JPG;
>  		mode->color &= ~MASK_JPG_QUALITY;
> -		mode->color |= (channel->jpegqual << 8);
> +		mode->color |= (vc->jpegqual << 8);
>  	}
>  	/* save the mode */
> -	channel->mode = *mode;
> -	channel->req_image_size = get_transfer_size(mode);
> -	dprintk(dev, 1, "%s: reqsize %ld\n", __func__, channel->req_image_size);
> +	vc->mode = *mode;
> +	vc->req_image_size = get_transfer_size(mode);
> +	dprintk(dev, 1, "%s: reqsize %ld\n", __func__, vc->req_image_size);
>  	buffer = kzalloc(512, GFP_KERNEL);
>  	if (buffer == NULL) {
>  		dev_err(&dev->udev->dev, "out of mem\n");
> @@ -1165,36 +1072,38 @@ static int s2255_set_mode(struct s2255_channel *channel,
>  	buffer[1] = (__le32) cpu_to_le32(chn_rev);
>  	buffer[2] = CMD_SET_MODE;
>  	for (i = 0; i < sizeof(struct s2255_mode) / sizeof(u32); i++)
> -		buffer[3 + i] = cpu_to_le32(((u32 *)&channel->mode)[i]);
> -	channel->setmode_ready = 0;
> +		buffer[3 + i] = cpu_to_le32(((u32 *)&vc->mode)[i]);
> +	vc->setmode_ready = 0;
>  	res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512);
> -	if (debug)
> -		s2255_print_cfg(dev, mode);
> +
> +	dprintk(dev, 1, "format: %d\nscale %d\n", mode->format, mode->scale);
> +	dprintk(dev, 1, "fdec: %d\ncolor %d\n", mode->fdec, mode->color);
> +
>  	kfree(buffer);
>  	/* wait at least 3 frames before continuing */
>  	if (mode->restart) {
> -		wait_event_timeout(channel->wait_setmode,
> -				   (channel->setmode_ready != 0),
> +		wait_event_timeout(vc->wait_setmode,
> +				   (vc->setmode_ready != 0),
>  				   msecs_to_jiffies(S2255_SETMODE_TIMEOUT));
> -		if (channel->setmode_ready != 1) {
> +		if (vc->setmode_ready != 1) {
>  			dprintk(dev, 0, "s2255: no set mode response\n");
>  			res = -EFAULT;
>  		}
>  	}
>  	/* clear the restart flag */
> -	channel->mode.restart = 0;
> -	dprintk(dev, 1, "%s chn %d, result: %d\n", __func__, channel->idx, res);
> +	vc->mode.restart = 0;
> +	dprintk(dev, 1, "%s chn %d, result: %d\n", __func__, vc->idx, res);
>  	return res;
>  }
>  
> -static int s2255_cmd_status(struct s2255_channel *channel, u32 *pstatus)
> +static int s2255_cmd_status(struct s2255_vc *vc, u32 *pstatus)
>  {
>  	int res;
>  	__le32 *buffer;
>  	u32 chn_rev;
> -	struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
> -	chn_rev = G_chnmap[channel->idx];
> -	dprintk(dev, 4, "%s chan %d\n", __func__, channel->idx);
> +	struct s2255_dev *dev = to_s2255_dev(vc->vdev.v4l2_dev);
> +	chn_rev = G_chnmap[vc->idx];
> +	dprintk(dev, 4, "%s chan %d\n", __func__, vc->idx);
>  	buffer = kzalloc(512, GFP_KERNEL);
>  	if (buffer == NULL) {
>  		dev_err(&dev->udev->dev, "out of mem\n");
> @@ -1205,127 +1114,70 @@ static int s2255_cmd_status(struct s2255_channel *channel, u32 *pstatus)
>  	buffer[1] = (__le32) cpu_to_le32(chn_rev);
>  	buffer[2] = CMD_STATUS;
>  	*pstatus = 0;
> -	channel->vidstatus_ready = 0;
> +	vc->vidstatus_ready = 0;
>  	res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512);
>  	kfree(buffer);
> -	wait_event_timeout(channel->wait_vidstatus,
> -			   (channel->vidstatus_ready != 0),
> +	wait_event_timeout(vc->wait_vidstatus,
> +			   (vc->vidstatus_ready != 0),
>  			   msecs_to_jiffies(S2255_VIDSTATUS_TIMEOUT));
> -	if (channel->vidstatus_ready != 1) {
> +	if (vc->vidstatus_ready != 1) {
>  		dprintk(dev, 0, "s2255: no vidstatus response\n");
>  		res = -EFAULT;
>  	}
> -	*pstatus = channel->vidstatus;
> +	*pstatus = vc->vidstatus;
>  	dprintk(dev, 4, "%s, vid status %d\n", __func__, *pstatus);
>  	return res;
>  }
>  
> -static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
> -{
> -	int res;
> -	struct s2255_fh *fh = priv;
> -	struct s2255_dev *dev = fh->dev;
> -	struct s2255_channel *channel = fh->channel;
> -	int j;
> -	dprintk(dev, 4, "%s\n", __func__);
> -	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
> -		dev_err(&dev->udev->dev, "invalid fh type0\n");
> -		return -EINVAL;
> -	}
> -	if (i != fh->type) {
> -		dev_err(&dev->udev->dev, "invalid fh type1\n");
> -		return -EINVAL;
> -	}
> -
> -	if (!res_get(fh)) {
> -		s2255_dev_err(&dev->udev->dev, "stream busy\n");
> -		return -EBUSY;
> -	}
> -	channel->last_frame = -1;
> -	channel->bad_payload = 0;
> -	channel->cur_frame = 0;
> -	channel->frame_count = 0;
> -	for (j = 0; j < SYS_FRAMES; j++) {
> -		channel->buffer.frame[j].ulState = S2255_READ_IDLE;
> -		channel->buffer.frame[j].cur_size = 0;
> -	}
> -	res = videobuf_streamon(&fh->vb_vidq);
> -	if (res == 0) {
> -		s2255_start_acquire(channel);
> -		channel->b_acquire = 1;
> -	} else
> -		res_free(fh);
> -
> -	return res;
> -}
> -
> -static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
> -{
> -	struct s2255_fh *fh = priv;
> -	dprintk(fh->dev, 4, "%s\n, channel: %d", __func__, fh->channel->idx);
> -	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
> -		dprintk(fh->dev, 1, "invalid fh type0\n");
> -		return -EINVAL;
> -	}
> -	if (i != fh->type)
> -		return -EINVAL;
> -	s2255_stop_acquire(fh->channel);
> -	videobuf_streamoff(&fh->vb_vidq);
> -	res_free(fh);
> -	return 0;
> -}
> -
>  static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id i)
>  {
> -	struct s2255_fh *fh = priv;
>  	struct s2255_mode mode;
> -	struct videobuf_queue *q = &fh->vb_vidq;
> -	struct s2255_channel *channel = fh->channel;
> +	struct s2255_vc *vc = video_drvdata(file);
> +	struct vb2_queue *q = &vc->vb_vidq;
>  	int ret = 0;
>  
> -	mutex_lock(&q->vb_lock);
> -	if (res_locked(fh)) {
> -		dprintk(fh->dev, 1, "can't change standard after started\n");
> -		ret = -EBUSY;
> -		goto out_s_std;
> -	}
> -	mode = fh->channel->mode;
> +	/*
> +	 * Changing the standard implies a format change, which is not allowed
> +	 * while buffers for use with streaming have already been allocated.
> +	 */
> +	if (vb2_is_busy(q))
> +		return -EBUSY;
> +
> +	mode = vc->mode;
>  	if (i & V4L2_STD_525_60) {
> -		dprintk(fh->dev, 4, "%s 60 Hz\n", __func__);
> +		dprintk(vc->dev, 4, "%s 60 Hz\n", __func__);
>  		/* if changing format, reset frame decimation/intervals */
>  		if (mode.format != FORMAT_NTSC) {
>  			mode.restart = 1;
>  			mode.format = FORMAT_NTSC;
>  			mode.fdec = FDEC_1;
> -			channel->width = LINE_SZ_4CIFS_NTSC;
> -			channel->height = NUM_LINES_4CIFS_NTSC * 2;
> +			vc->width = LINE_SZ_4CIFS_NTSC;
> +			vc->height = NUM_LINES_4CIFS_NTSC * 2;
>  		}
>  	} else if (i & V4L2_STD_625_50) {
> -		dprintk(fh->dev, 4, "%s 50 Hz\n", __func__);
> +		dprintk(vc->dev, 4, "%s 50 Hz\n", __func__);
>  		if (mode.format != FORMAT_PAL) {
>  			mode.restart = 1;
>  			mode.format = FORMAT_PAL;
>  			mode.fdec = FDEC_1;
> -			channel->width = LINE_SZ_4CIFS_PAL;
> -			channel->height = NUM_LINES_4CIFS_PAL * 2;
> +			vc->width = LINE_SZ_4CIFS_PAL;
> +			vc->height = NUM_LINES_4CIFS_PAL * 2;
>  		}
>  	} else {
>  		ret = -EINVAL;
>  		goto out_s_std;
>  	}
> -	fh->channel->std = i;
> +	vc->std = i;
>  	if (mode.restart)
> -		s2255_set_mode(fh->channel, &mode);
> +		s2255_set_mode(vc, &mode);
>  out_s_std:
> -	mutex_unlock(&q->vb_lock);
>  	return ret;
>  }
>  
>  static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *i)
>  {
> -	struct s2255_fh *fh = priv;
> -
> -	*i = fh->channel->std;
> +	struct s2255_vc *vc = video_drvdata(file);
> +	*i = vc->std;
>  	return 0;
>  }
>  
> @@ -1339,9 +1191,8 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *i)
>  static int vidioc_enum_input(struct file *file, void *priv,
>  			     struct v4l2_input *inp)
>  {
> -	struct s2255_fh *fh = priv;
> -	struct s2255_dev *dev = fh->dev;
> -	struct s2255_channel *channel = fh->channel;
> +	struct s2255_vc *vc = video_drvdata(file);
> +	struct s2255_dev *dev = vc->dev;
>  	u32 status = 0;
>  	if (inp->index != 0)
>  		return -EINVAL;
> @@ -1350,7 +1201,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
>  	inp->status = 0;
>  	if (dev->dsp_fw_ver >= S2255_MIN_DSP_STATUS) {
>  		int rc;
> -		rc = s2255_cmd_status(fh->channel, &status);
> +		rc = s2255_cmd_status(vc, &status);
>  		dprintk(dev, 4, "s2255_cmd_status rc: %d status %x\n",
>  			rc, status);
>  		if (rc == 0)
> @@ -1363,7 +1214,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
>  		strlcpy(inp->name, "Composite", sizeof(inp->name));
>  		break;
>  	case 0x2257:
> -		strlcpy(inp->name, (channel->idx < 2) ? "Composite" : "S-Video",
> +		strlcpy(inp->name, (vc->idx < 2) ? "Composite" : "S-Video",
>  			sizeof(inp->name));
>  		break;
>  	}
> @@ -1384,10 +1235,10 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
>  
>  static int s2255_s_ctrl(struct v4l2_ctrl *ctrl)
>  {
> -	struct s2255_channel *channel =
> -		container_of(ctrl->handler, struct s2255_channel, hdl);
> +	struct s2255_vc *vc =
> +		container_of(ctrl->handler, struct s2255_vc, hdl);
>  	struct s2255_mode mode;
> -	mode = channel->mode;
> +	mode = vc->mode;
>  	/* update the mode to the corresponding value */
>  	switch (ctrl->id) {
>  	case V4L2_CID_BRIGHTNESS:
> @@ -1407,7 +1258,7 @@ static int s2255_s_ctrl(struct v4l2_ctrl *ctrl)
>  		mode.color |= !ctrl->val << 16;
>  		break;
>  	case V4L2_CID_JPEG_COMPRESSION_QUALITY:
> -		channel->jpegqual = ctrl->val;
> +		vc->jpegqual = ctrl->val;
>  		return 0;
>  	default:
>  		return -EINVAL;
> @@ -1417,48 +1268,44 @@ static int s2255_s_ctrl(struct v4l2_ctrl *ctrl)
>  	   some V4L programs restart stream unnecessarily
>  	   after a s_crtl.
>  	*/
> -	s2255_set_mode(channel, &mode);
> +	s2255_set_mode(vc, &mode);
>  	return 0;
>  }
>  
>  static int vidioc_g_jpegcomp(struct file *file, void *priv,
>  			 struct v4l2_jpegcompression *jc)
>  {
> -	struct s2255_fh *fh = priv;
> -	struct s2255_channel *channel = fh->channel;
> -
> +	struct s2255_vc *vc = video_drvdata(file);
>  	memset(jc, 0, sizeof(*jc));
> -	jc->quality = channel->jpegqual;
> -	dprintk(fh->dev, 2, "%s: quality %d\n", __func__, jc->quality);
> +	jc->quality = vc->jpegqual;
> +	dprintk(vc->dev, 2, "%s: quality %d\n", __func__, jc->quality);
>  	return 0;
>  }
>  
>  static int vidioc_s_jpegcomp(struct file *file, void *priv,
>  			 const struct v4l2_jpegcompression *jc)
>  {
> -	struct s2255_fh *fh = priv;
> -	struct s2255_channel *channel = fh->channel;
> +	struct s2255_vc *vc = video_drvdata(file);
>  	if (jc->quality < 0 || jc->quality > 100)
>  		return -EINVAL;
> -	v4l2_ctrl_s_ctrl(channel->jpegqual_ctrl, jc->quality);
> -	dprintk(fh->dev, 2, "%s: quality %d\n", __func__, jc->quality);
> +	v4l2_ctrl_s_ctrl(vc->jpegqual_ctrl, jc->quality);
> +	dprintk(vc->dev, 2, "%s: quality %d\n", __func__, jc->quality);
>  	return 0;
>  }
>  
>  static int vidioc_g_parm(struct file *file, void *priv,
>  			 struct v4l2_streamparm *sp)
>  {
> -	struct s2255_fh *fh = priv;
> +	struct s2255_vc *vc = video_drvdata(file);
>  	__u32 def_num, def_dem;
> -	struct s2255_channel *channel = fh->channel;
>  	if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
>  		return -EINVAL;
>  	sp->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
> -	sp->parm.capture.capturemode = channel->cap_parm.capturemode;
> -	def_num = (channel->mode.format == FORMAT_NTSC) ? 1001 : 1000;
> -	def_dem = (channel->mode.format == FORMAT_NTSC) ? 30000 : 25000;
> +	sp->parm.capture.capturemode = vc->cap_parm.capturemode;
> +	def_num = (vc->mode.format == FORMAT_NTSC) ? 1001 : 1000;
> +	def_dem = (vc->mode.format == FORMAT_NTSC) ? 30000 : 25000;
>  	sp->parm.capture.timeperframe.denominator = def_dem;
> -	switch (channel->mode.fdec) {
> +	switch (vc->mode.fdec) {
>  	default:
>  	case FDEC_1:
>  		sp->parm.capture.timeperframe.numerator = def_num;
> @@ -1473,7 +1320,7 @@ static int vidioc_g_parm(struct file *file, void *priv,
>  		sp->parm.capture.timeperframe.numerator = def_num * 5;
>  		break;
>  	}
> -	dprintk(fh->dev, 4, "%s capture mode, %d timeperframe %d/%d\n",
> +	dprintk(vc->dev, 4, "%s capture mode, %d timeperframe %d/%d\n",
>  		__func__,
>  		sp->parm.capture.capturemode,
>  		sp->parm.capture.timeperframe.numerator,
> @@ -1484,18 +1331,19 @@ static int vidioc_g_parm(struct file *file, void *priv,
>  static int vidioc_s_parm(struct file *file, void *priv,
>  			 struct v4l2_streamparm *sp)
>  {
> -	struct s2255_fh *fh = priv;
> -	struct s2255_channel *channel = fh->channel;
> +	struct s2255_vc *vc = video_drvdata(file);
>  	struct s2255_mode mode;
>  	int fdec = FDEC_1;
>  	__u32 def_num, def_dem;
>  	if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
>  		return -EINVAL;
> -	mode = channel->mode;
> +	mode = vc->mode;
>  	/* high quality capture mode requires a stream restart */
> -	if (channel->cap_parm.capturemode
> -	    != sp->parm.capture.capturemode && res_locked(fh))
> +	if ((vc->cap_parm.capturemode != sp->parm.capture.capturemode)
> +	    && vb2_is_busy(&vc->vb_vidq))
>  		return -EBUSY;
> +
> +	vc->cap_parm.capturemode = sp->parm.capture.capturemode;
>  	def_num = (mode.format == FORMAT_NTSC) ? 1001 : 1000;
>  	def_dem = (mode.format == FORMAT_NTSC) ? 30000 : 25000;
>  	if (def_dem != sp->parm.capture.timeperframe.denominator)
> @@ -1514,8 +1362,8 @@ static int vidioc_s_parm(struct file *file, void *priv,
>  	}
>  	mode.fdec = fdec;
>  	sp->parm.capture.timeperframe.denominator = def_dem;
> -	s2255_set_mode(channel, &mode);
> -	dprintk(fh->dev, 4, "%s capture mode, %d timeperframe %d/%d, fdec %d\n",
> +	s2255_set_mode(vc, &mode);
> +	dprintk(vc->dev, 4, "%s capture mode, %d timeperframe %d/%d, fdec %d\n",
>  		__func__,
>  		sp->parm.capture.capturemode,
>  		sp->parm.capture.timeperframe.numerator,
> @@ -1538,9 +1386,8 @@ static const struct v4l2_frmsize_discrete pal_sizes[] = {
>  static int vidioc_enum_framesizes(struct file *file, void *priv,
>  			    struct v4l2_frmsizeenum *fe)
>  {
> -	struct s2255_fh *fh = priv;
> -	struct s2255_channel *channel = fh->channel;
> -	int is_ntsc = channel->std & V4L2_STD_525_60;
> +	struct s2255_vc *vc = video_drvdata(file);
> +	int is_ntsc = vc->std & V4L2_STD_525_60;
>  	const struct s2255_fmt *fmt;
>  
>  	if (fe->index >= NUM_SIZE_ENUMS)
> @@ -1557,11 +1404,10 @@ static int vidioc_enum_framesizes(struct file *file, void *priv,
>  static int vidioc_enum_frameintervals(struct file *file, void *priv,
>  			    struct v4l2_frmivalenum *fe)
>  {
> -	struct s2255_fh *fh = priv;
> -	struct s2255_channel *channel = fh->channel;
> +	struct s2255_vc *vc = video_drvdata(file);
>  	const struct s2255_fmt *fmt;
>  	const struct v4l2_frmsize_discrete *sizes;
> -	int is_ntsc = channel->std & V4L2_STD_525_60;
> +	int is_ntsc = vc->std & V4L2_STD_525_60;
>  #define NUM_FRAME_ENUMS 4
>  	int frm_dec[NUM_FRAME_ENUMS] = {1, 2, 3, 5};
>  	int i;
> @@ -1584,22 +1430,25 @@ static int vidioc_enum_frameintervals(struct file *file, void *priv,
>  	fe->type = V4L2_FRMIVAL_TYPE_DISCRETE;
>  	fe->discrete.denominator = is_ntsc ? 30000 : 25000;
>  	fe->discrete.numerator = (is_ntsc ? 1001 : 1000) * frm_dec[fe->index];
> -	dprintk(fh->dev, 4, "%s discrete %d/%d\n", __func__,
> +	dprintk(vc->dev, 4, "%s discrete %d/%d\n", __func__,
>  		fe->discrete.numerator,
>  		fe->discrete.denominator);
>  	return 0;
>  }
>  
> -static int __s2255_open(struct file *file)
> +static int s2255_open(struct file *file)
>  {
> -	struct video_device *vdev = video_devdata(file);
> -	struct s2255_channel *channel = video_drvdata(file);
> -	struct s2255_dev *dev = to_s2255_dev(vdev->v4l2_dev);
> -	struct s2255_fh *fh;
> -	enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> +	struct s2255_vc *vc = video_drvdata(file);
> +	struct s2255_dev *dev = vc->dev;
>  	int state;
> -	dprintk(dev, 1, "s2255: open called (dev=%s)\n",
> -		video_device_node_name(vdev));
> +	int rc = 0;
> +
> +	/* allocate + initialize per filehandle data */
> +	rc = v4l2_fh_open(file);
> +	if (rc != 0)
> +		return rc;
> +
> +	/* load firmware */
>  	state = atomic_read(&dev->fw_data->fw_state);
>  	switch (state) {
>  	case S2255_FW_DISCONNECTING:
> @@ -1661,66 +1510,23 @@ static int __s2255_open(struct file *file)
>  		pr_info("%s: unknown state\n", __func__);
>  		return -EFAULT;
>  	}
> -	/* allocate + initialize per filehandle data */
> -	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
> -	if (NULL == fh)
> -		return -ENOMEM;
> -	v4l2_fh_init(&fh->fh, vdev);
> -	v4l2_fh_add(&fh->fh);
> -	file->private_data = &fh->fh;
> -	fh->dev = dev;
> -	fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> -	fh->channel = channel;
> -	if (!channel->configured) {
> +
> +	if (!vc->configured) {
> +		int rc;
>  		/* configure channel to default state */
> -		channel->fmt = &formats[0];
> -		s2255_set_mode(channel, &channel->mode);
> -		channel->configured = 1;
> -	}
> -	dprintk(dev, 1, "%s: dev=%s type=%s\n", __func__,
> -		video_device_node_name(vdev), v4l2_type_names[type]);
> -	dprintk(dev, 2, "%s: fh=0x%08lx, dev=0x%08lx, vidq=0x%08lx\n", __func__,
> -		(unsigned long)fh, (unsigned long)dev,
> -		(unsigned long)&channel->vidq);
> -	dprintk(dev, 4, "%s: list_empty active=%d\n", __func__,
> -		list_empty(&channel->vidq.active));
> -	videobuf_queue_vmalloc_init(&fh->vb_vidq, &s2255_video_qops,
> -				    NULL, &dev->slock,
> -				    fh->type,
> -				    V4L2_FIELD_INTERLACED,
> -				    sizeof(struct s2255_buffer),
> -				    fh, vdev->lock);
> +		vc->fmt = &formats[0];
> +		rc = s2255_set_mode(vc, &vc->mode);
> +		if (rc != 0) {
> +			/* resend set mode. */
> +			rc = s2255_set_mode(vc, &vc->mode);
> +		}
> +		if (rc == 0)
> +			vc->configured = 1;
> +	}
> +	dprintk(dev, 2, "%s:\n", __func__);
>  	return 0;
>  }
>  
> -static int s2255_open(struct file *file)
> -{
> -	struct video_device *vdev = video_devdata(file);
> -	int ret;
> -
> -	if (mutex_lock_interruptible(vdev->lock))
> -		return -ERESTARTSYS;
> -	ret = __s2255_open(file);
> -	mutex_unlock(vdev->lock);
> -	return ret;
> -}
> -
> -static unsigned int s2255_poll(struct file *file,
> -			       struct poll_table_struct *wait)
> -{
> -	struct s2255_fh *fh = file->private_data;
> -	struct s2255_dev *dev = fh->dev;
> -	int rc = v4l2_ctrl_poll(file, wait);
> -
> -	dprintk(dev, 100, "%s\n", __func__);
> -	if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
> -		return POLLERR;
> -	mutex_lock(&dev->lock);
> -	rc |= videobuf_poll_stream(file, &fh->vb_vidq, wait);
> -	mutex_unlock(&dev->lock);
> -	return rc;
> -}
> -
>  static void s2255_destroy(struct s2255_dev *dev)
>  {
>  	dprintk(dev, 1, "%s", __func__);
> @@ -1744,57 +1550,14 @@ static void s2255_destroy(struct s2255_dev *dev)
>  	kfree(dev);
>  }
>  
> -static int s2255_release(struct file *file)
> -{
> -	struct s2255_fh *fh = file->private_data;
> -	struct s2255_dev *dev = fh->dev;
> -	struct video_device *vdev = video_devdata(file);
> -	struct s2255_channel *channel = fh->channel;
> -	if (!dev)
> -		return -ENODEV;
> -	mutex_lock(&dev->lock);
> -	/* turn off stream */
> -	if (res_check(fh)) {
> -		if (channel->b_acquire)
> -			s2255_stop_acquire(fh->channel);
> -		videobuf_streamoff(&fh->vb_vidq);
> -		res_free(fh);
> -	}
> -	videobuf_mmap_free(&fh->vb_vidq);
> -	mutex_unlock(&dev->lock);
> -	dprintk(dev, 1, "%s[%s]\n", __func__, video_device_node_name(vdev));
> -	v4l2_fh_del(&fh->fh);
> -	v4l2_fh_exit(&fh->fh);
> -	kfree(fh);
> -	return 0;
> -}
> -
> -static int s2255_mmap_v4l(struct file *file, struct vm_area_struct *vma)
> -{
> -	struct s2255_fh *fh = file->private_data;
> -	struct s2255_dev *dev;
> -	int ret;
> -	if (!fh)
> -		return -ENODEV;
> -	dev = fh->dev;
> -	dprintk(dev, 4, "%s, vma=0x%08lx\n", __func__, (unsigned long)vma);
> -	if (mutex_lock_interruptible(&dev->lock))
> -		return -ERESTARTSYS;
> -	ret = videobuf_mmap_mapper(&fh->vb_vidq, vma);
> -	mutex_unlock(&dev->lock);
> -	dprintk(dev, 4, "%s vma start=0x%08lx, size=%ld, ret=%d\n", __func__,
> -		(unsigned long)vma->vm_start,
> -		(unsigned long)vma->vm_end - (unsigned long)vma->vm_start, ret);
> -	return ret;
> -}
> -
>  static const struct v4l2_file_operations s2255_fops_v4l = {
>  	.owner = THIS_MODULE,
>  	.open = s2255_open,
> -	.release = s2255_release,
> -	.poll = s2255_poll,
> -	.unlocked_ioctl = video_ioctl2,	/* V4L2 ioctl handler */
> -	.mmap = s2255_mmap_v4l,
> +	.release = vb2_fop_release,
> +	.unlocked_ioctl = video_ioctl2,
> +	.read = vb2_fop_read,
> +	.mmap = vb2_fop_mmap,
> +	.poll = vb2_fop_poll,
>  };
>  
>  static const struct v4l2_ioctl_ops s2255_ioctl_ops = {
> @@ -1803,17 +1566,17 @@ static const struct v4l2_ioctl_ops s2255_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_reqbufs =  vb2_ioctl_reqbufs,
> +	.vidioc_querybuf = vb2_ioctl_querybuf,
> +	.vidioc_qbuf = vb2_ioctl_qbuf,
> +	.vidioc_dqbuf = vb2_ioctl_dqbuf,
>  	.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_streamon = vidioc_streamon,
> -	.vidioc_streamoff = vidioc_streamoff,
> +	.vidioc_streamon = vb2_ioctl_streamon,
> +	.vidioc_streamoff = vb2_ioctl_streamoff,
>  	.vidioc_s_jpegcomp = vidioc_s_jpegcomp,
>  	.vidioc_g_jpegcomp = vidioc_g_jpegcomp,
>  	.vidioc_s_parm = vidioc_s_parm,
> @@ -1828,13 +1591,13 @@ static const struct v4l2_ioctl_ops s2255_ioctl_ops = {
>  static void s2255_video_device_release(struct video_device *vdev)
>  {
>  	struct s2255_dev *dev = to_s2255_dev(vdev->v4l2_dev);
> -	struct s2255_channel *channel =
> -		container_of(vdev, struct s2255_channel, vdev);
> +	struct s2255_vc *vc =
> +		container_of(vdev, struct s2255_vc, vdev);
>  
>  	dprintk(dev, 4, "%s, chnls: %d\n", __func__,
>  		atomic_read(&dev->num_channels));
>  
> -	v4l2_ctrl_handler_free(&channel->hdl);
> +	v4l2_ctrl_handler_free(&vc->hdl);
>  
>  	if (atomic_dec_and_test(&dev->num_channels))
>  		s2255_destroy(dev);
> @@ -1868,64 +1631,82 @@ static int s2255_probe_v4l(struct s2255_dev *dev)
>  	int ret;
>  	int i;
>  	int cur_nr = video_nr;
> -	struct s2255_channel *channel;
> +	struct vb2_queue *q;
> +	struct s2255_vc *vc;
>  	ret = v4l2_device_register(&dev->interface->dev, &dev->v4l2_dev);
>  	if (ret)
>  		return ret;
>  	/* initialize all video 4 linux */
>  	/* register 4 video devices */
>  	for (i = 0; i < MAX_CHANNELS; i++) {
> -		channel = &dev->channel[i];
> -		INIT_LIST_HEAD(&channel->vidq.active);
> +		vc = &dev->vc[i];
> +		INIT_LIST_HEAD(&vc->buf_list);
>  
> -		v4l2_ctrl_handler_init(&channel->hdl, 6);
> -		v4l2_ctrl_new_std(&channel->hdl, &s2255_ctrl_ops,
> +		v4l2_ctrl_handler_init(&vc->hdl, 6);
> +		v4l2_ctrl_new_std(&vc->hdl, &s2255_ctrl_ops,
>  				V4L2_CID_BRIGHTNESS, -127, 127, 1, DEF_BRIGHT);
> -		v4l2_ctrl_new_std(&channel->hdl, &s2255_ctrl_ops,
> +		v4l2_ctrl_new_std(&vc->hdl, &s2255_ctrl_ops,
>  				V4L2_CID_CONTRAST, 0, 255, 1, DEF_CONTRAST);
> -		v4l2_ctrl_new_std(&channel->hdl, &s2255_ctrl_ops,
> +		v4l2_ctrl_new_std(&vc->hdl, &s2255_ctrl_ops,
>  				V4L2_CID_SATURATION, 0, 255, 1, DEF_SATURATION);
> -		v4l2_ctrl_new_std(&channel->hdl, &s2255_ctrl_ops,
> +		v4l2_ctrl_new_std(&vc->hdl, &s2255_ctrl_ops,
>  				V4L2_CID_HUE, 0, 255, 1, DEF_HUE);
> -		channel->jpegqual_ctrl = v4l2_ctrl_new_std(&channel->hdl,
> +		vc->jpegqual_ctrl = v4l2_ctrl_new_std(&vc->hdl,
>  				&s2255_ctrl_ops,
>  				V4L2_CID_JPEG_COMPRESSION_QUALITY,
>  				0, 100, 1, S2255_DEF_JPEG_QUAL);
>  		if (dev->dsp_fw_ver >= S2255_MIN_DSP_COLORFILTER &&
> -		    (dev->pid != 0x2257 || channel->idx <= 1))
> -			v4l2_ctrl_new_custom(&channel->hdl, &color_filter_ctrl,
> +		    (dev->pid != 0x2257 || vc->idx <= 1))
> +			v4l2_ctrl_new_custom(&vc->hdl, &color_filter_ctrl,
>  					     NULL);
> -		if (channel->hdl.error) {
> -			ret = channel->hdl.error;
> -			v4l2_ctrl_handler_free(&channel->hdl);
> +		if (vc->hdl.error) {
> +			ret = vc->hdl.error;
> +			v4l2_ctrl_handler_free(&vc->hdl);
>  			dev_err(&dev->udev->dev, "couldn't register control\n");
>  			break;
>  		}
> -		channel->vidq.dev = dev;
> +		q = &vc->vb_vidq;
> +		memset(q, 0, sizeof(vc->vb_vidq));
> +		q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> +		q->io_modes = VB2_MMAP | VB2_READ;

You can add VB2_USERPTR here as well, that should work out-of-the-box.

> +		q->drv_priv = vc;
> +		q->lock = &vc->vb_lock;
> +		q->buf_struct_size = sizeof(struct s2255_buffer);
> +		q->mem_ops = &vb2_vmalloc_memops;
> +		q->ops = &s2255_video_qops;
> +		q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
> +		ret = vb2_queue_init(q);
> +		if (ret != 0) {
> +			dev_err(&dev->udev->dev,
> +				"%s vb2_queue_init err: 0x%x\n", __func__, ret);
> +			break;
> +		}
>  		/* register 4 video devices */
> -		channel->vdev = template;
> -		channel->vdev.ctrl_handler = &channel->hdl;
> -		channel->vdev.lock = &dev->lock;
> -		channel->vdev.v4l2_dev = &dev->v4l2_dev;
> -		set_bit(V4L2_FL_USE_FH_PRIO, &channel->vdev.flags);
> -		video_set_drvdata(&channel->vdev, channel);
> +		vc->vdev = template;
> +		vc->vdev.queue = q;
> +		vc->vdev.ctrl_handler = &vc->hdl;
> +		/* main device lock */
> +		vc->vdev.lock = &dev->lock;
> +		vc->vdev.v4l2_dev = &dev->v4l2_dev;
> +		set_bit(V4L2_FL_USE_FH_PRIO, &vc->vdev.flags);
> +		video_set_drvdata(&vc->vdev, vc);
>  		if (video_nr == -1)
> -			ret = video_register_device(&channel->vdev,
> +			ret = video_register_device(&vc->vdev,
>  						    VFL_TYPE_GRABBER,
>  						    video_nr);
>  		else
> -			ret = video_register_device(&channel->vdev,
> +			ret = video_register_device(&vc->vdev,
>  						    VFL_TYPE_GRABBER,
>  						    cur_nr + i);
>  
>  		if (ret) {
>  			dev_err(&dev->udev->dev,
> -				"failed to register video device!\n");
> +				"failed to register vid device: 0x%x!\n", ret);
>  			break;
>  		}
>  		atomic_inc(&dev->num_channels);
>  		v4l2_info(&dev->v4l2_dev, "V4L2 device registered as %s\n",
> -			  video_device_node_name(&channel->vdev));
> +			  video_device_node_name(&vc->vdev));
>  
>  	}
>  	pr_info("Sensoray 2255 V4L driver Revision: %s\n",
> @@ -1962,11 +1743,11 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
>  	s32 idx = -1;
>  	struct s2255_framei *frm;
>  	unsigned char *pdata;
> -	struct s2255_channel *ch;
> +	struct s2255_vc *vc;
>  	dprintk(dev, 100, "buffer to user\n");
> -	ch = &dev->channel[dev->cc];
> -	idx = ch->cur_frame;
> -	frm = &ch->buffer.frame[idx];
> +	vc = &dev->vc[dev->cc];
> +	idx = vc->cur_frame;
> +	frm = &vc->buffer.frame[idx];
>  	if (frm->ulState == S2255_READ_IDLE) {
>  		int jj;
>  		unsigned int cc;
> @@ -1990,15 +1771,15 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
>  				}
>  				/* reverse it */
>  				dev->cc = G_chnmap[cc];
> -				ch = &dev->channel[dev->cc];
> +				vc = &dev->vc[dev->cc];
>  				payload =  le32_to_cpu(pdword[3]);
> -				if (payload > ch->req_image_size) {
> -					ch->bad_payload++;
> +				if (payload > vc->req_image_size) {
> +					vc->bad_payload++;
>  					/* discard the bad frame */
>  					return -EINVAL;
>  				}
> -				ch->pkt_size = payload;
> -				ch->jpg_size = le32_to_cpu(pdword[4]);
> +				vc->pkt_size = payload;
> +				vc->jpg_size = le32_to_cpu(pdword[4]);
>  				break;
>  			case S2255_MARKER_RESPONSE:
>  
> @@ -2009,13 +1790,13 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
>  				cc = G_chnmap[le32_to_cpu(pdword[1])];
>  				if (cc >= MAX_CHANNELS)
>  					break;
> -				ch = &dev->channel[cc];
> +				vc = &dev->vc[cc];
>  				switch (pdword[2]) {
>  				case S2255_RESPONSE_SETMODE:
>  					/* check if channel valid */
>  					/* set mode ready */
> -					ch->setmode_ready = 1;
> -					wake_up(&ch->wait_setmode);
> +					vc->setmode_ready = 1;
> +					wake_up(&vc->wait_setmode);
>  					dprintk(dev, 5, "setmode rdy %d\n", cc);
>  					break;
>  				case S2255_RESPONSE_FW:
> @@ -2029,9 +1810,9 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
>  					wake_up(&dev->fw_data->wait_fw);
>  					break;
>  				case S2255_RESPONSE_STATUS:
> -					ch->vidstatus = le32_to_cpu(pdword[3]);
> -					ch->vidstatus_ready = 1;
> -					wake_up(&ch->wait_vidstatus);
> +					vc->vidstatus = le32_to_cpu(pdword[3]);
> +					vc->vidstatus_ready = 1;
> +					wake_up(&vc->wait_vidstatus);
>  					dprintk(dev, 5, "vstat %x chan %d\n",
>  						le32_to_cpu(pdword[3]), cc);
>  					break;
> @@ -2048,11 +1829,12 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
>  		if (!bframe)
>  			return -EINVAL;
>  	}
> -	ch = &dev->channel[dev->cc];
> -	idx = ch->cur_frame;
> -	frm = &ch->buffer.frame[idx];
> +	vc = &dev->vc[dev->cc];
> +	idx = vc->cur_frame;
> +	frm = &vc->buffer.frame[idx];
> +
>  	/* search done.  now find out if should be acquiring on this channel */
> -	if (!ch->b_acquire) {
> +	if (!vb2_is_streaming(&vc->vb_vidq)) {
>  		/* we found a frame, but this channel is turned off */
>  		frm->ulState = S2255_READ_IDLE;
>  		return -EINVAL;
> @@ -2066,7 +1848,6 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
>  	/* skip the marker 512 bytes (and offset if out of sync) */
>  	psrc = (u8 *)pipe_info->transfer_buffer + offset;
>  
> -
>  	if (frm->lpvbits == NULL) {
>  		dprintk(dev, 1, "s2255 frame buffer == NULL.%p %p %d %d",
>  			frm, dev, dev->cc, idx);
> @@ -2074,13 +1855,11 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
>  	}
>  
>  	pdest = frm->lpvbits + frm->cur_size;
> -
>  	copy_size = (pipe_info->cur_transfer_size - offset);
> -
> -	size = ch->pkt_size - PREFIX_SIZE;
> +	size = vc->pkt_size - PREFIX_SIZE;
>  
>  	/* sanity check on pdest */
> -	if ((copy_size + frm->cur_size) < ch->req_image_size)
> +	if ((copy_size + frm->cur_size) < vc->req_image_size)
>  		memcpy(pdest, psrc, copy_size);
>  
>  	frm->cur_size += copy_size;
> @@ -2089,19 +1868,18 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
>  	if (frm->cur_size >= size) {
>  		dprintk(dev, 2, "******[%d]Buffer[%d]full*******\n",
>  			dev->cc, idx);
> -		ch->last_frame = ch->cur_frame;
> -		ch->cur_frame++;
> +		vc->last_frame = vc->cur_frame;
> +		vc->cur_frame++;
>  		/* end of system frame ring buffer, start at zero */
> -		if ((ch->cur_frame == SYS_FRAMES) ||
> -		    (ch->cur_frame == ch->buffer.dwFrames))
> -			ch->cur_frame = 0;
> +		if ((vc->cur_frame == SYS_FRAMES) ||
> +		    (vc->cur_frame == vc->buffer.dwFrames))
> +			vc->cur_frame = 0;
>  		/* frame ready */
> -		if (ch->b_acquire)
> -			s2255_got_frame(ch, ch->jpg_size);
> -		ch->frame_count++;
> +		if (vb2_is_streaming(&vc->vb_vidq))
> +			s2255_got_frame(vc, vc->jpg_size);
> +		vc->frame_count++;
>  		frm->ulState = S2255_READ_IDLE;
>  		frm->cur_size = 0;
> -
>  	}
>  	/* done successfully */
>  	return 0;
> @@ -2121,7 +1899,7 @@ static void s2255_read_video_callback(struct s2255_dev *dev,
>  	/* otherwise copy to the system buffers */
>  	res = save_frame(dev, pipe_info);
>  	if (res != 0)
> -		dprintk(dev, 4, "s2255: read callback failed\n");
> +		dprintk(dev, 50, "s2255: read callback: %d\n", res);
>  
>  	dprintk(dev, 50, "callback read video done\n");
>  	return;
> @@ -2171,11 +1949,11 @@ static int s2255_get_fx2fw(struct s2255_dev *dev)
>   * Create the system ring buffer to copy frames into from the
>   * usb read pipe.
>   */
> -static int s2255_create_sys_buffers(struct s2255_channel *channel)
> +static int s2255_create_sys_buffers(struct s2255_vc *vc)
>  {
>  	unsigned long i;
>  	unsigned long reqsize;
> -	channel->buffer.dwFrames = SYS_FRAMES;
> +	vc->buffer.dwFrames = SYS_FRAMES;
>  	/* always allocate maximum size(PAL) for system buffers */
>  	reqsize = SYS_FRAMES_MAXSIZE;
>  
> @@ -2184,33 +1962,33 @@ static int s2255_create_sys_buffers(struct s2255_channel *channel)
>  
>  	for (i = 0; i < SYS_FRAMES; i++) {
>  		/* allocate the frames */
> -		channel->buffer.frame[i].lpvbits = vmalloc(reqsize);
> -		channel->buffer.frame[i].size = reqsize;
> -		if (channel->buffer.frame[i].lpvbits == NULL) {
> +		vc->buffer.frame[i].lpvbits = vmalloc(reqsize);
> +		vc->buffer.frame[i].size = reqsize;
> +		if (vc->buffer.frame[i].lpvbits == NULL) {
>  			pr_info("out of memory.  using less frames\n");
> -			channel->buffer.dwFrames = i;
> +			vc->buffer.dwFrames = i;
>  			break;
>  		}
>  	}
>  
>  	/* make sure internal states are set */
>  	for (i = 0; i < SYS_FRAMES; i++) {
> -		channel->buffer.frame[i].ulState = 0;
> -		channel->buffer.frame[i].cur_size = 0;
> +		vc->buffer.frame[i].ulState = 0;
> +		vc->buffer.frame[i].cur_size = 0;
>  	}
>  
> -	channel->cur_frame = 0;
> -	channel->last_frame = -1;
> +	vc->cur_frame = 0;
> +	vc->last_frame = -1;
>  	return 0;
>  }
>  
> -static int s2255_release_sys_buffers(struct s2255_channel *channel)
> +static int s2255_release_sys_buffers(struct s2255_vc *vc)
>  {
>  	unsigned long i;
>  	for (i = 0; i < SYS_FRAMES; i++) {
> -		if (channel->buffer.frame[i].lpvbits)
> -			vfree(channel->buffer.frame[i].lpvbits);
> -		channel->buffer.frame[i].lpvbits = NULL;
> +		if (vc->buffer.frame[i].lpvbits)
> +			vfree(vc->buffer.frame[i].lpvbits);
> +		vc->buffer.frame[i].lpvbits = NULL;
>  	}
>  	return 0;
>  }
> @@ -2244,21 +2022,20 @@ static int s2255_board_init(struct s2255_dev *dev)
>  		pr_info("s2255: newer USB firmware available\n");
>  
>  	for (j = 0; j < MAX_CHANNELS; j++) {
> -		struct s2255_channel *channel = &dev->channel[j];
> -		channel->b_acquire = 0;
> -		channel->mode = mode_def;
> +		struct s2255_vc *vc = &dev->vc[j];
> +		vc->mode = mode_def;
>  		if (dev->pid == 0x2257 && j > 1)
> -			channel->mode.color |= (1 << 16);
> -		channel->jpegqual = S2255_DEF_JPEG_QUAL;
> -		channel->width = LINE_SZ_4CIFS_NTSC;
> -		channel->height = NUM_LINES_4CIFS_NTSC * 2;
> -		channel->std = V4L2_STD_NTSC_M;
> -		channel->fmt = &formats[0];
> -		channel->mode.restart = 1;
> -		channel->req_image_size = get_transfer_size(&mode_def);
> -		channel->frame_count = 0;
> +			vc->mode.color |= (1 << 16);
> +		vc->jpegqual = S2255_DEF_JPEG_QUAL;
> +		vc->width = LINE_SZ_4CIFS_NTSC;
> +		vc->height = NUM_LINES_4CIFS_NTSC * 2;
> +		vc->std = V4L2_STD_NTSC_M;
> +		vc->fmt = &formats[0];
> +		vc->mode.restart = 1;
> +		vc->req_image_size = get_transfer_size(&mode_def);
> +		vc->frame_count = 0;
>  		/* create the system buffers */
> -		s2255_create_sys_buffers(channel);
> +		s2255_create_sys_buffers(vc);
>  	}
>  	/* start read pipe */
>  	s2255_start_readpipe(dev);
> @@ -2270,14 +2047,13 @@ static int s2255_board_shutdown(struct s2255_dev *dev)
>  {
>  	u32 i;
>  	dprintk(dev, 1, "%s: dev: %p", __func__,  dev);
> -
>  	for (i = 0; i < MAX_CHANNELS; i++) {
> -		if (dev->channel[i].b_acquire)
> -			s2255_stop_acquire(&dev->channel[i]);
> +		if (vb2_is_streaming(&dev->vc[i].vb_vidq))
> +			s2255_stop_acquire(&dev->vc[i]);
>  	}
>  	s2255_stop_readpipe(dev);
>  	for (i = 0; i < MAX_CHANNELS; i++)
> -		s2255_release_sys_buffers(&dev->channel[i]);
> +		s2255_release_sys_buffers(&dev->vc[i]);
>  	/* release transfer buffer */
>  	kfree(dev->pipe.transfer_buffer);
>  	return 0;
> @@ -2366,26 +2142,26 @@ static int s2255_start_readpipe(struct s2255_dev *dev)
>  }
>  
>  /* starts acquisition process */
> -static int s2255_start_acquire(struct s2255_channel *channel)
> +static int s2255_start_acquire(struct s2255_vc *vc)
>  {
>  	unsigned char *buffer;
>  	int res;
>  	unsigned long chn_rev;
>  	int j;
> -	struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
> -	chn_rev = G_chnmap[channel->idx];
> +	struct s2255_dev *dev = to_s2255_dev(vc->vdev.v4l2_dev);
> +	chn_rev = G_chnmap[vc->idx];
>  	buffer = kzalloc(512, GFP_KERNEL);
>  	if (buffer == NULL) {
>  		dev_err(&dev->udev->dev, "out of mem\n");
>  		return -ENOMEM;
>  	}
>  
> -	channel->last_frame = -1;
> -	channel->bad_payload = 0;
> -	channel->cur_frame = 0;
> +	vc->last_frame = -1;
> +	vc->bad_payload = 0;
> +	vc->cur_frame = 0;
>  	for (j = 0; j < SYS_FRAMES; j++) {
> -		channel->buffer.frame[j].ulState = 0;
> -		channel->buffer.frame[j].cur_size = 0;
> +		vc->buffer.frame[j].ulState = 0;
> +		vc->buffer.frame[j].cur_size = 0;
>  	}
>  
>  	/* send the start command */
> @@ -2396,18 +2172,18 @@ static int s2255_start_acquire(struct s2255_channel *channel)
>  	if (res != 0)
>  		dev_err(&dev->udev->dev, "CMD_START error\n");
>  
> -	dprintk(dev, 2, "start acquire exit[%d] %d\n", channel->idx, res);
> +	dprintk(dev, 2, "start acquire exit[%d] %d\n", vc->idx, res);
>  	kfree(buffer);
>  	return 0;
>  }
>  
> -static int s2255_stop_acquire(struct s2255_channel *channel)
> +static int s2255_stop_acquire(struct s2255_vc *vc)
>  {
>  	unsigned char *buffer;
>  	int res;
>  	unsigned long chn_rev;
> -	struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
> -	chn_rev = G_chnmap[channel->idx];
> +	struct s2255_dev *dev = to_s2255_dev(vc->vdev.v4l2_dev);
> +	chn_rev = G_chnmap[vc->idx];
>  	buffer = kzalloc(512, GFP_KERNEL);
>  	if (buffer == NULL) {
>  		dev_err(&dev->udev->dev, "out of mem\n");
> @@ -2421,8 +2197,7 @@ static int s2255_stop_acquire(struct s2255_channel *channel)
>  	if (res != 0)
>  		dev_err(&dev->udev->dev, "CMD_STOP error\n");
>  	kfree(buffer);
> -	channel->b_acquire = 0;
> -	dprintk(dev, 4, "%s: chn %d, res %d\n", __func__, channel->idx, res);
> +	dprintk(dev, 4, "%s: chn %d, res %d\n", __func__, vc->idx, res);
>  	return res;
>  }
>  
> @@ -2512,11 +2287,13 @@ static int s2255_probe(struct usb_interface *interface,
>  	dev->timer.data = (unsigned long)dev->fw_data;
>  	init_waitqueue_head(&dev->fw_data->wait_fw);
>  	for (i = 0; i < MAX_CHANNELS; i++) {
> -		struct s2255_channel *channel = &dev->channel[i];
> -		channel->idx = i;
> -		channel->dev = dev;
> -		init_waitqueue_head(&channel->wait_setmode);
> -		init_waitqueue_head(&channel->wait_vidstatus);
> +		struct s2255_vc *vc = &dev->vc[i];
> +		vc->idx = i;
> +		vc->dev = dev;
> +		init_waitqueue_head(&vc->wait_setmode);
> +		init_waitqueue_head(&vc->wait_vidstatus);
> +		spin_lock_init(&vc->qlock);
> +		mutex_init(&vc->vb_lock);
>  	}
>  
>  	dev->fw_data->fw_urb = usb_alloc_urb(0, GFP_KERNEL);
> @@ -2562,8 +2339,7 @@ static int s2255_probe(struct usb_interface *interface,
>  	retval = s2255_board_init(dev);
>  	if (retval)
>  		goto errorBOARDINIT;
> -	spin_lock_init(&dev->slock);
> -	s2255_fwload_start(dev, 0);
> +	s2255_fwload_start(dev, 1);
>  	/* loads v4l specific */
>  	retval = s2255_probe_v4l(dev);
>  	if (retval)
> @@ -2604,15 +2380,15 @@ static void s2255_disconnect(struct usb_interface *interface)
>  	atomic_inc(&dev->num_channels);
>  	/* unregister each video device. */
>  	for (i = 0; i < channels; i++)
> -		video_unregister_device(&dev->channel[i].vdev);
> +		video_unregister_device(&dev->vc[i].vdev);
>  	/* wake up any of our timers */
>  	atomic_set(&dev->fw_data->fw_state, S2255_FW_DISCONNECTING);
>  	wake_up(&dev->fw_data->wait_fw);
>  	for (i = 0; i < MAX_CHANNELS; i++) {
> -		dev->channel[i].setmode_ready = 1;
> -		wake_up(&dev->channel[i].wait_setmode);
> -		dev->channel[i].vidstatus_ready = 1;
> -		wake_up(&dev->channel[i].wait_vidstatus);
> +		dev->vc[i].setmode_ready = 1;
> +		wake_up(&dev->vc[i].wait_setmode);
> +		dev->vc[i].vidstatus_ready = 1;
> +		wake_up(&dev->vc[i].wait_vidstatus);
>  	}
>  	if (atomic_dec_and_test(&dev->num_channels))
>  		s2255_destroy(dev);
> 

Regards,

	Hans

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] s2255drv: port to videobuf2
  2014-02-03  9:51 ` Hans Verkuil
@ 2014-02-03 17:06   ` Dean Anderson
  2014-02-04 10:04     ` Hans Verkuil
  0 siblings, 1 reply; 7+ messages in thread
From: Dean Anderson @ 2014-02-03 17:06 UTC (permalink / raw)
  To: Hans Verkuil; +Cc: linux-media

On 2014-02-03 03:51, Hans Verkuil wrote:
> Hi Dean,
> 
> Some specific comments below, but first two general comments:
> 
> It is easier to review if at least the removal of the old s2255_fh 
> struct
> was done as a separate patch. It's always good to try and keep the 
> changes
> in patches as small as possible. The actual vb2 conversion is always a
> 'big bang' patch, that's unavoidable, but it's easier if it isn't 
> mixed in
> with other changes that are not directly related to the vb2 
> conversion.


I figured removal of s2255_fh was a natural part of the videobuf2 
conversion process, but I can break it up.
I also did change some formatting and naming changes (s2255_channel to 
s2255_vc) that can be postponed.

> 
> And did you also run the v4l2-compliance utility for this driver? 
> That's
> useful to check that everything it still correct.

Thanks for the comments.  I'll do a v2 soon with v4l2-compliance fully 
tested too.

I added some comments below too.



> On 01/31/2014 06:35 PM, Dean Anderson wrote:
>> Update s2255drv to use videobuf2 instead of videobuf.
>> s2255_fh file handle removed and driver simplified.
>> 
>> Signed-off-by: Dean Anderson <linux-dev@sensoray.com>
>> ---
>>  drivers/media/usb/s2255/s2255drv.c | 1170 
>> +++++++++++++++---------------------
>>  1 file changed, 473 insertions(+), 697 deletions(-)
>> 
>> diff --git a/drivers/media/usb/s2255/s2255drv.c 
>> b/drivers/media/usb/s2255/s2255drv.c
>> index c6bdccc..d6e9332 100644
>> --- a/drivers/media/usb/s2255/s2255drv.c
>> +++ b/drivers/media/usb/s2255/s2255drv.c
> 
> <snip>
> 
>> @@ -666,146 +641,131 @@ static void s2255_fillbuff(struct 
>> s2255_channel *channel,
>>  	dprintk(dev, 2, "s2255fill at : Buffer 0x%08lx size= %d\n",
>>  		(unsigned long)vbuf, pos);
>>  	/* tell v4l buffer was filled */
>> -	buf->vb.field_count = channel->frame_count * 2;
>> -	v4l2_get_timestamp(&buf->vb.ts);
>> -	buf->vb.state = VIDEOBUF_DONE;
>> +	vc->field_count = vc->frame_count * 2;
>> +	buf->vb.v4l2_buf.field = vc->field;
>> +	buf->vb.v4l2_buf.sequence = vc->field_count >> 1;
> 
> Just drop field_count (left-over from vivi) and use frame_count 
> directly.
> 
>> +	v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
>> +	vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
>>  }
>> 
>> +/*
>> + * setup the contraints of the queue
>> + */
>> +static int queue_setup(struct vb2_queue *vq, const struct 
>> v4l2_format *fmt,
>> +				unsigned int *nbuffers, unsigned int *nplanes,
>> +				unsigned int sizes[], void *alloc_ctxs[])
>> +{
>> +	struct s2255_vc *vc = vb2_get_drv_priv(vq);
>> +	unsigned long size;
>> 
>> -/* 
>> ------------------------------------------------------------------
>> -   Videobuf operations
>> -   
>> ------------------------------------------------------------------*/
>> +	size = vc->width * vc->height * (vc->fmt->depth >> 3);
>> 
>> -static int buffer_setup(struct videobuf_queue *vq, unsigned int 
>> *count,
>> -			unsigned int *size)
>> -{
>> -	struct s2255_fh *fh = vq->priv_data;
>> -	struct s2255_channel *channel = fh->channel;
>> -	*size = channel->width * channel->height * (channel->fmt->depth >> 
>> 3);
>> +	if (0 == *nbuffers)
>> +		*nbuffers = S2255_DEF_BUFS;
> 
> Unfortunately vivi was a bad example to use for this (I'm going to 
> post patches
> to fix vivi to avoid this in the future).
> 
> What really needs to happen is that you test against the minimum 
> number of
> buffers required to stream (usually somewhere between 1 and 3, test 
> with e.g.
> qv4l2 or v4l2-ctl) and if it is less, set *nbuffers to that minimum.
> 
>> 
>> -	if (0 == *count)
>> -		*count = S2255_DEF_BUFS;
>> +	if (size * *nbuffers > vid_limit * 1024 * 1024)
>> +		*nbuffers = (vid_limit * 1024 * 1024) / size;
>> 
>> -	if (*size * *count > vid_limit * 1024 * 1024)
>> -		*count = (vid_limit * 1024 * 1024) / *size;
> 
> This vid_limit makes no sense. If the application wants 32 buffers
> (the maximum),
> then it should be able to get 32 buffers if there is enough memory. 
> Having a
> vid_limit is pointless. I plan on removing this from vivi as well.
> 
>> +	if (size == 0)
>> +		return -EINVAL;
>> 
>> +	*nplanes = 1;
>> +	sizes[0] = size;
>>  	return 0;
>>  }
>> 
>> -static void free_buffer(struct videobuf_queue *vq, struct 
>> s2255_buffer *buf)
>> -{
>> -	videobuf_vmalloc_free(&buf->vb);
>> -	buf->vb.state = VIDEOBUF_NEEDS_INIT;
>> -}
>> 
>> -static int buffer_prepare(struct videobuf_queue *vq, struct 
>> videobuf_buffer *vb,
>> -			  enum v4l2_field field)
>> +static int buffer_prepare(struct vb2_buffer *vb)
>>  {
>> -	struct s2255_fh *fh = vq->priv_data;
>> -	struct s2255_channel *channel = fh->channel;
>> +	struct s2255_vc *vc = vb2_get_drv_priv(vb->vb2_queue);
>>  	struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, 
>> vb);
>> -	int rc;
>> -	int w = channel->width;
>> -	int h = channel->height;
>> -	dprintk(fh->dev, 4, "%s, field=%d\n", __func__, field);
>> -	if (channel->fmt == NULL)
>> -		return -EINVAL;
>> +	unsigned long size;
>> +	int w = vc->width;
>> +	int h = vc->height;
>> 
>> -	if ((w < norm_minw(channel)) ||
>> -	    (w > norm_maxw(channel)) ||
>> -	    (h < norm_minh(channel)) ||
>> -	    (h > norm_maxh(channel))) {
>> -		dprintk(fh->dev, 4, "invalid buffer prepare\n");
>> +	if (vc->fmt == NULL)
>>  		return -EINVAL;
>> -	}
>> -	buf->vb.size = w * h * (channel->fmt->depth >> 3);
>> -	if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) {
>> -		dprintk(fh->dev, 4, "invalid buffer prepare\n");
>> +
>> +	if ((w < norm_minw(vc)) ||
>> +	    (w > norm_maxw(vc)) ||
>> +	    (h < norm_minh(vc)) ||
>> +	    (h > norm_maxh(vc))) {
>> +		dprintk(vc->dev, 4, "invalid buffer prepare\n");
>>  		return -EINVAL;
>>  	}
>> +	size = w * h * (vc->fmt->depth >> 3);
>> 
>> -	buf->fmt = channel->fmt;
>> -	buf->vb.width = w;
>> -	buf->vb.height = h;
>> -	buf->vb.field = field;
>> -
>> -	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
>> -		rc = videobuf_iolock(vq, &buf->vb, NULL);
>> -		if (rc < 0)
>> -			goto fail;
>> -	}
>> +	if (vb2_plane_size(vb, 0) < size)
>> +		return -EINVAL;
>> 
>> -	buf->vb.state = VIDEOBUF_PREPARED;
>> +	vb2_set_plane_payload(&buf->vb, 0, size);
>> +	buf->fmt = vc->fmt;
> 
> buf->fmt can be dropped. It's used in only one place, and there 
> vc->fmt can be
> used as well. I need to remove that in vivi as well.
> 
>>  	return 0;
>> -fail:
>> -	free_buffer(vq, buf);
>> -	return rc;
>>  }
>> 
>> -static void buffer_queue(struct videobuf_queue *vq, struct 
>> videobuf_buffer *vb)
>> +static void buffer_queue(struct vb2_buffer *vb)
>>  {
>>  	struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, 
>> vb);
>> -	struct s2255_fh *fh = vq->priv_data;
>> -	struct s2255_channel *channel = fh->channel;
>> -	struct s2255_dmaqueue *vidq = &channel->vidq;
>> -	dprintk(fh->dev, 1, "%s\n", __func__);
>> -	buf->vb.state = VIDEOBUF_QUEUED;
>> -	list_add_tail(&buf->vb.queue, &vidq->active);
>> -}
>> -
>> -static void buffer_release(struct videobuf_queue *vq,
>> -			   struct videobuf_buffer *vb)
>> -{
>> -	struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, 
>> vb);
>> -	struct s2255_fh *fh = vq->priv_data;
>> -	dprintk(fh->dev, 4, "%s %d\n", __func__, fh->channel->idx);
>> -	free_buffer(vq, buf);
>> -}
>> -
>> -static struct videobuf_queue_ops s2255_video_qops = {
>> -	.buf_setup = buffer_setup,
>> -	.buf_prepare = buffer_prepare,
>> -	.buf_queue = buffer_queue,
>> -	.buf_release = buffer_release,
>> -};
>> -
>> -
>> -static int res_get(struct s2255_fh *fh)
>> -{
>> -	struct s2255_channel *channel = fh->channel;
>> -	/* is it free? */
>> -	if (channel->resources)
>> -		return 0; /* no, someone else uses it */
>> -	/* it's free, grab it */
>> -	channel->resources = 1;
>> -	fh->resources = 1;
>> -	dprintk(fh->dev, 1, "s2255: res: get\n");
>> -	return 1;
>> +	struct s2255_vc *vc = vb2_get_drv_priv(vb->vb2_queue);
>> +	struct s2255_dev *dev = vc->dev;
>> +	unsigned long flags = 0;
> 
> Please add an empty line here to make it more readable. In general, 
> after
> declaring variables add a newline before starting the actual code.
> 
>> +	dprintk(dev, 1, "%s\n", __func__);
>> +	spin_lock_irqsave(&vc->qlock, flags);
>> +	list_add_tail(&buf->list, &vc->buf_list);
>> +	spin_unlock_irqrestore(&vc->qlock, flags);
>>  }
>> 
>> -static int res_locked(struct s2255_fh *fh)
>> +/* begin streaming on a 2255 video channel */
>> +static int start_streaming(struct vb2_queue *vq, unsigned int count)
>>  {
>> -	return fh->channel->resources;
>> +	struct s2255_vc *vc = vb2_get_drv_priv(vq);
>> +	int j;
>> +	vc->last_frame = -1;
>> +	vc->bad_payload = 0;
>> +	vc->cur_frame = 0;
>> +	vc->frame_count = 0;
>> +	for (j = 0; j < SYS_FRAMES; j++) {
>> +		vc->buffer.frame[j].ulState = S2255_READ_IDLE;
>> +		vc->buffer.frame[j].cur_size = 0;
>> +	}
>> +	s2255_start_acquire(vc);
> 
> I noticed that s2255_start_acquire can fail and that that is not 
> checked here.
> In fact, s2255_start_acquire also ignores an error from 
> s2255_write_config().
> Several s2255 functions allocate a 512 buffer and release it again 
> after use.
> Would it not make more sense to allocate that buffer in probe() and 
> use that
> everywhere?


I don't like this dynamic memory allocation either.  I'll make a 
separate patch after the videobuf2 change.


> 
>> +	return 0;
>>  }
>> 
>> -static int res_check(struct s2255_fh *fh)
>> +/* abort streaming and wait for last buffer */
>> +static int stop_streaming(struct vb2_queue *vq)
>>  {
>> -	return fh->resources;
>> +	struct s2255_vc *vc = vb2_get_drv_priv(vq);
>> +	struct s2255_buffer *buf, *node;
>> +	unsigned long flags;
>> +	s2255_stop_acquire(vc);
>> +	spin_lock_irqsave(&vc->qlock, flags);
>> +	list_for_each_entry_safe(buf, node, &vc->buf_list, list) {
>> +		list_del(&buf->list);
>> +		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
>> +		dprintk(vc->dev, 2, "[%p/%d] done\n",
>> +			buf, buf->vb.v4l2_buf.index);
>> +	}
>> +	spin_unlock_irqrestore(&vc->qlock, flags);
>> +	return 0;
>>  }
>> 
>> +static struct vb2_ops s2255_video_qops = {
>> +	.queue_setup = queue_setup,
>> +	.buf_prepare = buffer_prepare,
>> +	.buf_queue = buffer_queue,
>> +	.start_streaming = start_streaming,
>> +	.stop_streaming = stop_streaming,
>> +	.wait_prepare = vb2_ops_wait_prepare,
>> +	.wait_finish = vb2_ops_wait_finish,
>> 
>> -static void res_free(struct s2255_fh *fh)
>> -{
>> -	struct s2255_channel *channel = fh->channel;
>> -	channel->resources = 0;
>> -	fh->resources = 0;
>> -}
>> +};
>> 
>>  static int vidioc_querycap(struct file *file, void *priv,
>>  			   struct v4l2_capability *cap)
>>  {
>> -	struct s2255_fh *fh = file->private_data;
>> -	struct s2255_dev *dev = fh->dev;
>> +	struct s2255_vc *vc = video_drvdata(file);
>> +	struct s2255_dev *dev = vc->dev;
>> 
>>  	strlcpy(cap->driver, "s2255", sizeof(cap->driver));
>>  	strlcpy(cap->card, "s2255", sizeof(cap->card));
>> @@ -833,19 +793,18 @@ 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 s2255_fh *fh = priv;
>> -	struct s2255_channel *channel = fh->channel;
>> -	int is_ntsc = channel->std & V4L2_STD_525_60;
>> +	struct s2255_vc *vc = video_drvdata(file);
>> +	int is_ntsc = vc->std & V4L2_STD_525_60;
>> 
>> -	f->fmt.pix.width = channel->width;
>> -	f->fmt.pix.height = channel->height;
>> +	f->fmt.pix.width = vc->width;
>> +	f->fmt.pix.height = vc->height;
>>  	if (f->fmt.pix.height >=
>>  	    (is_ntsc ? NUM_LINES_1CIFS_NTSC : NUM_LINES_1CIFS_PAL) * 2)
>>  		f->fmt.pix.field = V4L2_FIELD_INTERLACED;
>>  	else
>>  		f->fmt.pix.field = V4L2_FIELD_TOP;
>> -	f->fmt.pix.pixelformat = channel->fmt->fourcc;
>> -	f->fmt.pix.bytesperline = f->fmt.pix.width * (channel->fmt->depth 
>> >> 3);
>> +	f->fmt.pix.pixelformat = vc->fmt->fourcc;
>> +	f->fmt.pix.bytesperline = f->fmt.pix.width * (vc->fmt->depth >> 3);
>>  	f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
>>  	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
>>  	f->fmt.pix.priv = 0;
>> @@ -857,9 +816,8 @@ static int vidioc_try_fmt_vid_cap(struct file 
>> *file, void *priv,
>>  {
>>  	const struct s2255_fmt *fmt;
>>  	enum v4l2_field field;
>> -	struct s2255_fh *fh = priv;
>> -	struct s2255_channel *channel = fh->channel;
>> -	int is_ntsc = channel->std & V4L2_STD_525_60;
>> +	struct s2255_vc *vc = video_drvdata(file);
>> +	int is_ntsc = vc->std & V4L2_STD_525_60;
>> 
>>  	fmt = format_by_fourcc(f->fmt.pix.pixelformat);
>> 
>> @@ -868,7 +826,7 @@ static int vidioc_try_fmt_vid_cap(struct file 
>> *file, void *priv,
>> 
>>  	field = f->fmt.pix.field;
>> 
>> -	dprintk(fh->dev, 50, "%s NTSC: %d suggested width: %d, height: 
>> %d\n",
>> +	dprintk(vc->dev, 50, "%s NTSC: %d suggested width: %d, height: 
>> %d\n",
>>  		__func__, is_ntsc, f->fmt.pix.width, f->fmt.pix.height);
>>  	if (is_ntsc) {
>>  		/* NTSC */
>> @@ -910,7 +868,8 @@ static int vidioc_try_fmt_vid_cap(struct file 
>> *file, void *priv,
>>  	f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
>>  	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
>>  	f->fmt.pix.priv = 0;
>> -	dprintk(fh->dev, 50, "%s: set width %d height %d field %d\n", 
>> __func__,
>> +	f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
>> +	dprintk(vc->dev, 50, "%s: set width %d height %d field %d\n", 
>> __func__,
>>  		f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
>>  	return 0;
>>  }
>> @@ -918,14 +877,13 @@ static int vidioc_try_fmt_vid_cap(struct file 
>> *file, void *priv,
>>  static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
>>  			    struct v4l2_format *f)
>>  {
>> -	struct s2255_fh *fh = priv;
>> -	struct s2255_channel *channel = fh->channel;
>> +	struct s2255_vc *vc = video_drvdata(file);
>>  	const struct s2255_fmt *fmt;
>> -	struct videobuf_queue *q = &fh->vb_vidq;
>> +	struct vb2_queue *q = &vc->vb_vidq;
>>  	struct s2255_mode mode;
>>  	int ret;
>> 
>> -	ret = vidioc_try_fmt_vid_cap(file, fh, f);
>> +	ret = vidioc_try_fmt_vid_cap(file, vc, f);
>> 
>>  	if (ret < 0)
>>  		return ret;
>> @@ -934,29 +892,24 @@ static int vidioc_s_fmt_vid_cap(struct file 
>> *file, void *priv,
>> 
>>  	if (fmt == NULL)
>>  		return -EINVAL;
>> +	/*
>> +	 * It is not allowed to change the format while buffers for use 
>> with
>> +	 * streaming have already been allocated.
>> +	 */
>> +	if (vb2_is_busy(q))
>> +		return -EBUSY;
>> 
>> -	mutex_lock(&q->vb_lock);
>> -
>> -	if (videobuf_queue_is_busy(&fh->vb_vidq)) {
>> -		dprintk(fh->dev, 1, "queue busy\n");
>> -		ret = -EBUSY;
>> -		goto out_s_fmt;
>> -	}
>> -
>> -	if (res_locked(fh)) {
>> -		dprintk(fh->dev, 1, "%s: channel busy\n", __func__);
>> -		ret = -EBUSY;
>> -		goto out_s_fmt;
>> -	}
>> -	mode = channel->mode;
>> -	channel->fmt = fmt;
>> -	channel->width = f->fmt.pix.width;
>> -	channel->height = f->fmt.pix.height;
>> -	fh->vb_vidq.field = f->fmt.pix.field;
>> -	fh->type = f->type;
>> -	if (channel->width > norm_minw(channel)) {
>> -		if (channel->height > norm_minh(channel)) {
>> -			if (channel->cap_parm.capturemode &
>> +	/* change format */
>> +	mode = vc->mode;
>> +	vc->fmt = fmt;
>> +	vc->width = f->fmt.pix.width;
>> +	vc->height = f->fmt.pix.height;
>> +	vc->field = f->fmt.pix.field;
>> +	vc->type = f->type;
>> +
>> +	if (vc->width > norm_minw(vc)) {
>> +		if (vc->height > norm_minh(vc)) {
>> +			if (vc->cap_parm.capturemode &
>>  			    V4L2_MODE_HIGHQUALITY)
>>  				mode.scale = SCALE_4CIFSI;
>>  			else
>> @@ -968,7 +921,7 @@ static int vidioc_s_fmt_vid_cap(struct file 
>> *file, void *priv,
>>  		mode.scale = SCALE_1CIFS;
>>  	}
>>  	/* color mode */
>> -	switch (channel->fmt->fourcc) {
>> +	switch (vc->fmt->fourcc) {
>>  	case V4L2_PIX_FMT_GREY:
>>  		mode.color &= ~MASK_COLOR;
>>  		mode.color |= COLOR_Y8;
>> @@ -977,7 +930,7 @@ static int vidioc_s_fmt_vid_cap(struct file 
>> *file, void *priv,
>>  	case V4L2_PIX_FMT_MJPEG:
>>  		mode.color &= ~MASK_COLOR;
>>  		mode.color |= COLOR_JPG;
>> -		mode.color |= (channel->jpegqual << 8);
>> +		mode.color |= (vc->jpegqual << 8);
>>  		break;
>>  	case V4L2_PIX_FMT_YUV422P:
>>  		mode.color &= ~MASK_COLOR;
>> @@ -990,51 +943,15 @@ static int vidioc_s_fmt_vid_cap(struct file 
>> *file, void *priv,
>>  		mode.color |= COLOR_YUVPK;
>>  		break;
>>  	}
>> -	if ((mode.color & MASK_COLOR) != (channel->mode.color & 
>> MASK_COLOR))
>> +	if ((mode.color & MASK_COLOR) != (vc->mode.color & MASK_COLOR))
>>  		mode.restart = 1;
>> -	else if (mode.scale != channel->mode.scale)
>> +	else if (mode.scale != vc->mode.scale)
>>  		mode.restart = 1;
>> -	else if (mode.format != channel->mode.format)
>> +	else if (mode.format != vc->mode.format)
>>  		mode.restart = 1;
>> -	channel->mode = mode;
>> -	(void) s2255_set_mode(channel, &mode);
>> -	ret = 0;
>> -out_s_fmt:
>> -	mutex_unlock(&q->vb_lock);
>> -	return ret;
>> -}
>> -
>> -static int vidioc_reqbufs(struct file *file, void *priv,
>> -			  struct v4l2_requestbuffers *p)
>> -{
>> -	int rc;
>> -	struct s2255_fh *fh = priv;
>> -	rc = videobuf_reqbufs(&fh->vb_vidq, p);
>> -	return rc;
>> -}
>> -
>> -static int vidioc_querybuf(struct file *file, void *priv, struct 
>> v4l2_buffer *p)
>> -{
>> -	int rc;
>> -	struct s2255_fh *fh = priv;
>> -	rc = videobuf_querybuf(&fh->vb_vidq, p);
>> -	return rc;
>> -}
>> -
>> -static int vidioc_qbuf(struct file *file, void *priv, struct 
>> v4l2_buffer *p)
>> -{
>> -	int rc;
>> -	struct s2255_fh *fh = priv;
>> -	rc = videobuf_qbuf(&fh->vb_vidq, p);
>> -	return rc;
>> -}
>> -
>> -static int vidioc_dqbuf(struct file *file, void *priv, struct 
>> v4l2_buffer *p)
>> -{
>> -	int rc;
>> -	struct s2255_fh *fh = priv;
>> -	rc = videobuf_dqbuf(&fh->vb_vidq, p, file->f_flags & O_NONBLOCK);
>> -	return rc;
>> +	vc->mode = mode;
>> +	(void) s2255_set_mode(vc, &mode);
>> +	return 0;
>>  }
>> 
>>  /* write to the configuration pipe, synchronously */
>> @@ -1115,16 +1032,6 @@ static u32 get_transfer_size(struct s2255_mode 
>> *mode)
>>  	return usbInSize;
>>  }
>> 
>> -static void s2255_print_cfg(struct s2255_dev *sdev, struct 
>> s2255_mode *mode)
>> -{
>> -	struct device *dev = &sdev->udev->dev;
>> -	dev_info(dev, 
>> "------------------------------------------------\n");
>> -	dev_info(dev, "format: %d\nscale %d\n", mode->format, mode->scale);
>> -	dev_info(dev, "fdec: %d\ncolor %d\n", mode->fdec, mode->color);
>> -	dev_info(dev, "bright: 0x%x\n", mode->bright);
>> -	dev_info(dev, 
>> "------------------------------------------------\n");
>> -}
>> -
>>  /*
>>   * set mode is the function which controls the DSP.
>>   * the restart parameter in struct s2255_mode should be set whenever
>> @@ -1133,28 +1040,28 @@ static void s2255_print_cfg(struct s2255_dev 
>> *sdev, struct s2255_mode *mode)
>>   * When the restart parameter is set, we sleep for ONE frame to 
>> allow the
>>   * DSP time to get the new frame
>>   */
>> -static int s2255_set_mode(struct s2255_channel *channel,
>> +static int s2255_set_mode(struct s2255_vc *vc,
>>  			  struct s2255_mode *mode)
>>  {
>>  	int res;
>>  	__le32 *buffer;
>>  	unsigned long chn_rev;
>> -	struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
>> +	struct s2255_dev *dev = to_s2255_dev(vc->vdev.v4l2_dev);
>>  	int i;
>> 
>> -	chn_rev = G_chnmap[channel->idx];
>> -	dprintk(dev, 3, "%s channel: %d\n", __func__, channel->idx);
>> +	chn_rev = G_chnmap[vc->idx];
>> +	dprintk(dev, 3, "%s channel: %d\n", __func__, vc->idx);
>>  	/* if JPEG, set the quality */
>>  	if ((mode->color & MASK_COLOR) == COLOR_JPG) {
>>  		mode->color &= ~MASK_COLOR;
>>  		mode->color |= COLOR_JPG;
>>  		mode->color &= ~MASK_JPG_QUALITY;
>> -		mode->color |= (channel->jpegqual << 8);
>> +		mode->color |= (vc->jpegqual << 8);
>>  	}
>>  	/* save the mode */
>> -	channel->mode = *mode;
>> -	channel->req_image_size = get_transfer_size(mode);
>> -	dprintk(dev, 1, "%s: reqsize %ld\n", __func__, 
>> channel->req_image_size);
>> +	vc->mode = *mode;
>> +	vc->req_image_size = get_transfer_size(mode);
>> +	dprintk(dev, 1, "%s: reqsize %ld\n", __func__, vc->req_image_size);
>>  	buffer = kzalloc(512, GFP_KERNEL);
>>  	if (buffer == NULL) {
>>  		dev_err(&dev->udev->dev, "out of mem\n");
>> @@ -1165,36 +1072,38 @@ static int s2255_set_mode(struct 
>> s2255_channel *channel,
>>  	buffer[1] = (__le32) cpu_to_le32(chn_rev);
>>  	buffer[2] = CMD_SET_MODE;
>>  	for (i = 0; i < sizeof(struct s2255_mode) / sizeof(u32); i++)
>> -		buffer[3 + i] = cpu_to_le32(((u32 *)&channel->mode)[i]);
>> -	channel->setmode_ready = 0;
>> +		buffer[3 + i] = cpu_to_le32(((u32 *)&vc->mode)[i]);
>> +	vc->setmode_ready = 0;
>>  	res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512);
>> -	if (debug)
>> -		s2255_print_cfg(dev, mode);
>> +
>> +	dprintk(dev, 1, "format: %d\nscale %d\n", mode->format, 
>> mode->scale);
>> +	dprintk(dev, 1, "fdec: %d\ncolor %d\n", mode->fdec, mode->color);
>> +
>>  	kfree(buffer);
>>  	/* wait at least 3 frames before continuing */
>>  	if (mode->restart) {
>> -		wait_event_timeout(channel->wait_setmode,
>> -				   (channel->setmode_ready != 0),
>> +		wait_event_timeout(vc->wait_setmode,
>> +				   (vc->setmode_ready != 0),
>>  				   msecs_to_jiffies(S2255_SETMODE_TIMEOUT));
>> -		if (channel->setmode_ready != 1) {
>> +		if (vc->setmode_ready != 1) {
>>  			dprintk(dev, 0, "s2255: no set mode response\n");
>>  			res = -EFAULT;
>>  		}
>>  	}
>>  	/* clear the restart flag */
>> -	channel->mode.restart = 0;
>> -	dprintk(dev, 1, "%s chn %d, result: %d\n", __func__, channel->idx, 
>> res);
>> +	vc->mode.restart = 0;
>> +	dprintk(dev, 1, "%s chn %d, result: %d\n", __func__, vc->idx, res);
>>  	return res;
>>  }
>> 
>> -static int s2255_cmd_status(struct s2255_channel *channel, u32 
>> *pstatus)
>> +static int s2255_cmd_status(struct s2255_vc *vc, u32 *pstatus)
>>  {
>>  	int res;
>>  	__le32 *buffer;
>>  	u32 chn_rev;
>> -	struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
>> -	chn_rev = G_chnmap[channel->idx];
>> -	dprintk(dev, 4, "%s chan %d\n", __func__, channel->idx);
>> +	struct s2255_dev *dev = to_s2255_dev(vc->vdev.v4l2_dev);
>> +	chn_rev = G_chnmap[vc->idx];
>> +	dprintk(dev, 4, "%s chan %d\n", __func__, vc->idx);
>>  	buffer = kzalloc(512, GFP_KERNEL);
>>  	if (buffer == NULL) {
>>  		dev_err(&dev->udev->dev, "out of mem\n");
>> @@ -1205,127 +1114,70 @@ static int s2255_cmd_status(struct 
>> s2255_channel *channel, u32 *pstatus)
>>  	buffer[1] = (__le32) cpu_to_le32(chn_rev);
>>  	buffer[2] = CMD_STATUS;
>>  	*pstatus = 0;
>> -	channel->vidstatus_ready = 0;
>> +	vc->vidstatus_ready = 0;
>>  	res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512);
>>  	kfree(buffer);
>> -	wait_event_timeout(channel->wait_vidstatus,
>> -			   (channel->vidstatus_ready != 0),
>> +	wait_event_timeout(vc->wait_vidstatus,
>> +			   (vc->vidstatus_ready != 0),
>>  			   msecs_to_jiffies(S2255_VIDSTATUS_TIMEOUT));
>> -	if (channel->vidstatus_ready != 1) {
>> +	if (vc->vidstatus_ready != 1) {
>>  		dprintk(dev, 0, "s2255: no vidstatus response\n");
>>  		res = -EFAULT;
>>  	}
>> -	*pstatus = channel->vidstatus;
>> +	*pstatus = vc->vidstatus;
>>  	dprintk(dev, 4, "%s, vid status %d\n", __func__, *pstatus);
>>  	return res;
>>  }
>> 
>> -static int vidioc_streamon(struct file *file, void *priv, enum 
>> v4l2_buf_type i)
>> -{
>> -	int res;
>> -	struct s2255_fh *fh = priv;
>> -	struct s2255_dev *dev = fh->dev;
>> -	struct s2255_channel *channel = fh->channel;
>> -	int j;
>> -	dprintk(dev, 4, "%s\n", __func__);
>> -	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
>> -		dev_err(&dev->udev->dev, "invalid fh type0\n");
>> -		return -EINVAL;
>> -	}
>> -	if (i != fh->type) {
>> -		dev_err(&dev->udev->dev, "invalid fh type1\n");
>> -		return -EINVAL;
>> -	}
>> -
>> -	if (!res_get(fh)) {
>> -		s2255_dev_err(&dev->udev->dev, "stream busy\n");
>> -		return -EBUSY;
>> -	}
>> -	channel->last_frame = -1;
>> -	channel->bad_payload = 0;
>> -	channel->cur_frame = 0;
>> -	channel->frame_count = 0;
>> -	for (j = 0; j < SYS_FRAMES; j++) {
>> -		channel->buffer.frame[j].ulState = S2255_READ_IDLE;
>> -		channel->buffer.frame[j].cur_size = 0;
>> -	}
>> -	res = videobuf_streamon(&fh->vb_vidq);
>> -	if (res == 0) {
>> -		s2255_start_acquire(channel);
>> -		channel->b_acquire = 1;
>> -	} else
>> -		res_free(fh);
>> -
>> -	return res;
>> -}
>> -
>> -static int vidioc_streamoff(struct file *file, void *priv, enum 
>> v4l2_buf_type i)
>> -{
>> -	struct s2255_fh *fh = priv;
>> -	dprintk(fh->dev, 4, "%s\n, channel: %d", __func__, 
>> fh->channel->idx);
>> -	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
>> -		dprintk(fh->dev, 1, "invalid fh type0\n");
>> -		return -EINVAL;
>> -	}
>> -	if (i != fh->type)
>> -		return -EINVAL;
>> -	s2255_stop_acquire(fh->channel);
>> -	videobuf_streamoff(&fh->vb_vidq);
>> -	res_free(fh);
>> -	return 0;
>> -}
>> -
>>  static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id 
>> i)
>>  {
>> -	struct s2255_fh *fh = priv;
>>  	struct s2255_mode mode;
>> -	struct videobuf_queue *q = &fh->vb_vidq;
>> -	struct s2255_channel *channel = fh->channel;
>> +	struct s2255_vc *vc = video_drvdata(file);
>> +	struct vb2_queue *q = &vc->vb_vidq;
>>  	int ret = 0;
>> 
>> -	mutex_lock(&q->vb_lock);
>> -	if (res_locked(fh)) {
>> -		dprintk(fh->dev, 1, "can't change standard after started\n");
>> -		ret = -EBUSY;
>> -		goto out_s_std;
>> -	}
>> -	mode = fh->channel->mode;
>> +	/*
>> +	 * Changing the standard implies a format change, which is not 
>> allowed
>> +	 * while buffers for use with streaming have already been 
>> allocated.
>> +	 */
>> +	if (vb2_is_busy(q))
>> +		return -EBUSY;
>> +
>> +	mode = vc->mode;
>>  	if (i & V4L2_STD_525_60) {
>> -		dprintk(fh->dev, 4, "%s 60 Hz\n", __func__);
>> +		dprintk(vc->dev, 4, "%s 60 Hz\n", __func__);
>>  		/* if changing format, reset frame decimation/intervals */
>>  		if (mode.format != FORMAT_NTSC) {
>>  			mode.restart = 1;
>>  			mode.format = FORMAT_NTSC;
>>  			mode.fdec = FDEC_1;
>> -			channel->width = LINE_SZ_4CIFS_NTSC;
>> -			channel->height = NUM_LINES_4CIFS_NTSC * 2;
>> +			vc->width = LINE_SZ_4CIFS_NTSC;
>> +			vc->height = NUM_LINES_4CIFS_NTSC * 2;
>>  		}
>>  	} else if (i & V4L2_STD_625_50) {
>> -		dprintk(fh->dev, 4, "%s 50 Hz\n", __func__);
>> +		dprintk(vc->dev, 4, "%s 50 Hz\n", __func__);
>>  		if (mode.format != FORMAT_PAL) {
>>  			mode.restart = 1;
>>  			mode.format = FORMAT_PAL;
>>  			mode.fdec = FDEC_1;
>> -			channel->width = LINE_SZ_4CIFS_PAL;
>> -			channel->height = NUM_LINES_4CIFS_PAL * 2;
>> +			vc->width = LINE_SZ_4CIFS_PAL;
>> +			vc->height = NUM_LINES_4CIFS_PAL * 2;
>>  		}
>>  	} else {
>>  		ret = -EINVAL;
>>  		goto out_s_std;
>>  	}
>> -	fh->channel->std = i;
>> +	vc->std = i;
>>  	if (mode.restart)
>> -		s2255_set_mode(fh->channel, &mode);
>> +		s2255_set_mode(vc, &mode);
>>  out_s_std:
>> -	mutex_unlock(&q->vb_lock);
>>  	return ret;
>>  }
>> 
>>  static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id 
>> *i)
>>  {
>> -	struct s2255_fh *fh = priv;
>> -
>> -	*i = fh->channel->std;
>> +	struct s2255_vc *vc = video_drvdata(file);
>> +	*i = vc->std;
>>  	return 0;
>>  }
>> 
>> @@ -1339,9 +1191,8 @@ static int vidioc_g_std(struct file *file, void 
>> *priv, v4l2_std_id *i)
>>  static int vidioc_enum_input(struct file *file, void *priv,
>>  			     struct v4l2_input *inp)
>>  {
>> -	struct s2255_fh *fh = priv;
>> -	struct s2255_dev *dev = fh->dev;
>> -	struct s2255_channel *channel = fh->channel;
>> +	struct s2255_vc *vc = video_drvdata(file);
>> +	struct s2255_dev *dev = vc->dev;
>>  	u32 status = 0;
>>  	if (inp->index != 0)
>>  		return -EINVAL;
>> @@ -1350,7 +1201,7 @@ static int vidioc_enum_input(struct file *file, 
>> void *priv,
>>  	inp->status = 0;
>>  	if (dev->dsp_fw_ver >= S2255_MIN_DSP_STATUS) {
>>  		int rc;
>> -		rc = s2255_cmd_status(fh->channel, &status);
>> +		rc = s2255_cmd_status(vc, &status);
>>  		dprintk(dev, 4, "s2255_cmd_status rc: %d status %x\n",
>>  			rc, status);
>>  		if (rc == 0)
>> @@ -1363,7 +1214,7 @@ static int vidioc_enum_input(struct file *file, 
>> void *priv,
>>  		strlcpy(inp->name, "Composite", sizeof(inp->name));
>>  		break;
>>  	case 0x2257:
>> -		strlcpy(inp->name, (channel->idx < 2) ? "Composite" : "S-Video",
>> +		strlcpy(inp->name, (vc->idx < 2) ? "Composite" : "S-Video",
>>  			sizeof(inp->name));
>>  		break;
>>  	}
>> @@ -1384,10 +1235,10 @@ static int vidioc_s_input(struct file *file, 
>> void *priv, unsigned int i)
>> 
>>  static int s2255_s_ctrl(struct v4l2_ctrl *ctrl)
>>  {
>> -	struct s2255_channel *channel =
>> -		container_of(ctrl->handler, struct s2255_channel, hdl);
>> +	struct s2255_vc *vc =
>> +		container_of(ctrl->handler, struct s2255_vc, hdl);
>>  	struct s2255_mode mode;
>> -	mode = channel->mode;
>> +	mode = vc->mode;
>>  	/* update the mode to the corresponding value */
>>  	switch (ctrl->id) {
>>  	case V4L2_CID_BRIGHTNESS:
>> @@ -1407,7 +1258,7 @@ static int s2255_s_ctrl(struct v4l2_ctrl *ctrl)
>>  		mode.color |= !ctrl->val << 16;
>>  		break;
>>  	case V4L2_CID_JPEG_COMPRESSION_QUALITY:
>> -		channel->jpegqual = ctrl->val;
>> +		vc->jpegqual = ctrl->val;
>>  		return 0;
>>  	default:
>>  		return -EINVAL;
>> @@ -1417,48 +1268,44 @@ static int s2255_s_ctrl(struct v4l2_ctrl 
>> *ctrl)
>>  	   some V4L programs restart stream unnecessarily
>>  	   after a s_crtl.
>>  	*/
>> -	s2255_set_mode(channel, &mode);
>> +	s2255_set_mode(vc, &mode);
>>  	return 0;
>>  }
>> 
>>  static int vidioc_g_jpegcomp(struct file *file, void *priv,
>>  			 struct v4l2_jpegcompression *jc)
>>  {
>> -	struct s2255_fh *fh = priv;
>> -	struct s2255_channel *channel = fh->channel;
>> -
>> +	struct s2255_vc *vc = video_drvdata(file);
>>  	memset(jc, 0, sizeof(*jc));
>> -	jc->quality = channel->jpegqual;
>> -	dprintk(fh->dev, 2, "%s: quality %d\n", __func__, jc->quality);
>> +	jc->quality = vc->jpegqual;
>> +	dprintk(vc->dev, 2, "%s: quality %d\n", __func__, jc->quality);
>>  	return 0;
>>  }
>> 
>>  static int vidioc_s_jpegcomp(struct file *file, void *priv,
>>  			 const struct v4l2_jpegcompression *jc)
>>  {
>> -	struct s2255_fh *fh = priv;
>> -	struct s2255_channel *channel = fh->channel;
>> +	struct s2255_vc *vc = video_drvdata(file);
>>  	if (jc->quality < 0 || jc->quality > 100)
>>  		return -EINVAL;
>> -	v4l2_ctrl_s_ctrl(channel->jpegqual_ctrl, jc->quality);
>> -	dprintk(fh->dev, 2, "%s: quality %d\n", __func__, jc->quality);
>> +	v4l2_ctrl_s_ctrl(vc->jpegqual_ctrl, jc->quality);
>> +	dprintk(vc->dev, 2, "%s: quality %d\n", __func__, jc->quality);
>>  	return 0;
>>  }
>> 
>>  static int vidioc_g_parm(struct file *file, void *priv,
>>  			 struct v4l2_streamparm *sp)
>>  {
>> -	struct s2255_fh *fh = priv;
>> +	struct s2255_vc *vc = video_drvdata(file);
>>  	__u32 def_num, def_dem;
>> -	struct s2255_channel *channel = fh->channel;
>>  	if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
>>  		return -EINVAL;
>>  	sp->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
>> -	sp->parm.capture.capturemode = channel->cap_parm.capturemode;
>> -	def_num = (channel->mode.format == FORMAT_NTSC) ? 1001 : 1000;
>> -	def_dem = (channel->mode.format == FORMAT_NTSC) ? 30000 : 25000;
>> +	sp->parm.capture.capturemode = vc->cap_parm.capturemode;
>> +	def_num = (vc->mode.format == FORMAT_NTSC) ? 1001 : 1000;
>> +	def_dem = (vc->mode.format == FORMAT_NTSC) ? 30000 : 25000;
>>  	sp->parm.capture.timeperframe.denominator = def_dem;
>> -	switch (channel->mode.fdec) {
>> +	switch (vc->mode.fdec) {
>>  	default:
>>  	case FDEC_1:
>>  		sp->parm.capture.timeperframe.numerator = def_num;
>> @@ -1473,7 +1320,7 @@ static int vidioc_g_parm(struct file *file, 
>> void *priv,
>>  		sp->parm.capture.timeperframe.numerator = def_num * 5;
>>  		break;
>>  	}
>> -	dprintk(fh->dev, 4, "%s capture mode, %d timeperframe %d/%d\n",
>> +	dprintk(vc->dev, 4, "%s capture mode, %d timeperframe %d/%d\n",
>>  		__func__,
>>  		sp->parm.capture.capturemode,
>>  		sp->parm.capture.timeperframe.numerator,
>> @@ -1484,18 +1331,19 @@ static int vidioc_g_parm(struct file *file, 
>> void *priv,
>>  static int vidioc_s_parm(struct file *file, void *priv,
>>  			 struct v4l2_streamparm *sp)
>>  {
>> -	struct s2255_fh *fh = priv;
>> -	struct s2255_channel *channel = fh->channel;
>> +	struct s2255_vc *vc = video_drvdata(file);
>>  	struct s2255_mode mode;
>>  	int fdec = FDEC_1;
>>  	__u32 def_num, def_dem;
>>  	if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
>>  		return -EINVAL;
>> -	mode = channel->mode;
>> +	mode = vc->mode;
>>  	/* high quality capture mode requires a stream restart */
>> -	if (channel->cap_parm.capturemode
>> -	    != sp->parm.capture.capturemode && res_locked(fh))
>> +	if ((vc->cap_parm.capturemode != sp->parm.capture.capturemode)
>> +	    && vb2_is_busy(&vc->vb_vidq))
>>  		return -EBUSY;
>> +
>> +	vc->cap_parm.capturemode = sp->parm.capture.capturemode;
>>  	def_num = (mode.format == FORMAT_NTSC) ? 1001 : 1000;
>>  	def_dem = (mode.format == FORMAT_NTSC) ? 30000 : 25000;
>>  	if (def_dem != sp->parm.capture.timeperframe.denominator)
>> @@ -1514,8 +1362,8 @@ static int vidioc_s_parm(struct file *file, 
>> void *priv,
>>  	}
>>  	mode.fdec = fdec;
>>  	sp->parm.capture.timeperframe.denominator = def_dem;
>> -	s2255_set_mode(channel, &mode);
>> -	dprintk(fh->dev, 4, "%s capture mode, %d timeperframe %d/%d, fdec 
>> %d\n",
>> +	s2255_set_mode(vc, &mode);
>> +	dprintk(vc->dev, 4, "%s capture mode, %d timeperframe %d/%d, fdec 
>> %d\n",
>>  		__func__,
>>  		sp->parm.capture.capturemode,
>>  		sp->parm.capture.timeperframe.numerator,
>> @@ -1538,9 +1386,8 @@ static const struct v4l2_frmsize_discrete 
>> pal_sizes[] = {
>>  static int vidioc_enum_framesizes(struct file *file, void *priv,
>>  			    struct v4l2_frmsizeenum *fe)
>>  {
>> -	struct s2255_fh *fh = priv;
>> -	struct s2255_channel *channel = fh->channel;
>> -	int is_ntsc = channel->std & V4L2_STD_525_60;
>> +	struct s2255_vc *vc = video_drvdata(file);
>> +	int is_ntsc = vc->std & V4L2_STD_525_60;
>>  	const struct s2255_fmt *fmt;
>> 
>>  	if (fe->index >= NUM_SIZE_ENUMS)
>> @@ -1557,11 +1404,10 @@ static int vidioc_enum_framesizes(struct file 
>> *file, void *priv,
>>  static int vidioc_enum_frameintervals(struct file *file, void *priv,
>>  			    struct v4l2_frmivalenum *fe)
>>  {
>> -	struct s2255_fh *fh = priv;
>> -	struct s2255_channel *channel = fh->channel;
>> +	struct s2255_vc *vc = video_drvdata(file);
>>  	const struct s2255_fmt *fmt;
>>  	const struct v4l2_frmsize_discrete *sizes;
>> -	int is_ntsc = channel->std & V4L2_STD_525_60;
>> +	int is_ntsc = vc->std & V4L2_STD_525_60;
>>  #define NUM_FRAME_ENUMS 4
>>  	int frm_dec[NUM_FRAME_ENUMS] = {1, 2, 3, 5};
>>  	int i;
>> @@ -1584,22 +1430,25 @@ static int vidioc_enum_frameintervals(struct 
>> file *file, void *priv,
>>  	fe->type = V4L2_FRMIVAL_TYPE_DISCRETE;
>>  	fe->discrete.denominator = is_ntsc ? 30000 : 25000;
>>  	fe->discrete.numerator = (is_ntsc ? 1001 : 1000) * 
>> frm_dec[fe->index];
>> -	dprintk(fh->dev, 4, "%s discrete %d/%d\n", __func__,
>> +	dprintk(vc->dev, 4, "%s discrete %d/%d\n", __func__,
>>  		fe->discrete.numerator,
>>  		fe->discrete.denominator);
>>  	return 0;
>>  }
>> 
>> -static int __s2255_open(struct file *file)
>> +static int s2255_open(struct file *file)
>>  {
>> -	struct video_device *vdev = video_devdata(file);
>> -	struct s2255_channel *channel = video_drvdata(file);
>> -	struct s2255_dev *dev = to_s2255_dev(vdev->v4l2_dev);
>> -	struct s2255_fh *fh;
>> -	enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
>> +	struct s2255_vc *vc = video_drvdata(file);
>> +	struct s2255_dev *dev = vc->dev;
>>  	int state;
>> -	dprintk(dev, 1, "s2255: open called (dev=%s)\n",
>> -		video_device_node_name(vdev));
>> +	int rc = 0;
>> +
>> +	/* allocate + initialize per filehandle data */
>> +	rc = v4l2_fh_open(file);
>> +	if (rc != 0)
>> +		return rc;
>> +
>> +	/* load firmware */
>>  	state = atomic_read(&dev->fw_data->fw_state);
>>  	switch (state) {
>>  	case S2255_FW_DISCONNECTING:
>> @@ -1661,66 +1510,23 @@ static int __s2255_open(struct file *file)
>>  		pr_info("%s: unknown state\n", __func__);
>>  		return -EFAULT;
>>  	}
>> -	/* allocate + initialize per filehandle data */
>> -	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
>> -	if (NULL == fh)
>> -		return -ENOMEM;
>> -	v4l2_fh_init(&fh->fh, vdev);
>> -	v4l2_fh_add(&fh->fh);
>> -	file->private_data = &fh->fh;
>> -	fh->dev = dev;
>> -	fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
>> -	fh->channel = channel;
>> -	if (!channel->configured) {
>> +
>> +	if (!vc->configured) {
>> +		int rc;
>>  		/* configure channel to default state */
>> -		channel->fmt = &formats[0];
>> -		s2255_set_mode(channel, &channel->mode);
>> -		channel->configured = 1;
>> -	}
>> -	dprintk(dev, 1, "%s: dev=%s type=%s\n", __func__,
>> -		video_device_node_name(vdev), v4l2_type_names[type]);
>> -	dprintk(dev, 2, "%s: fh=0x%08lx, dev=0x%08lx, vidq=0x%08lx\n", 
>> __func__,
>> -		(unsigned long)fh, (unsigned long)dev,
>> -		(unsigned long)&channel->vidq);
>> -	dprintk(dev, 4, "%s: list_empty active=%d\n", __func__,
>> -		list_empty(&channel->vidq.active));
>> -	videobuf_queue_vmalloc_init(&fh->vb_vidq, &s2255_video_qops,
>> -				    NULL, &dev->slock,
>> -				    fh->type,
>> -				    V4L2_FIELD_INTERLACED,
>> -				    sizeof(struct s2255_buffer),
>> -				    fh, vdev->lock);
>> +		vc->fmt = &formats[0];
>> +		rc = s2255_set_mode(vc, &vc->mode);
>> +		if (rc != 0) {
>> +			/* resend set mode. */
>> +			rc = s2255_set_mode(vc, &vc->mode);
>> +		}
>> +		if (rc == 0)
>> +			vc->configured = 1;
>> +	}
>> +	dprintk(dev, 2, "%s:\n", __func__);
>>  	return 0;
>>  }
>> 
>> -static int s2255_open(struct file *file)
>> -{
>> -	struct video_device *vdev = video_devdata(file);
>> -	int ret;
>> -
>> -	if (mutex_lock_interruptible(vdev->lock))
>> -		return -ERESTARTSYS;
>> -	ret = __s2255_open(file);
>> -	mutex_unlock(vdev->lock);
>> -	return ret;
>> -}
>> -
>> -static unsigned int s2255_poll(struct file *file,
>> -			       struct poll_table_struct *wait)
>> -{
>> -	struct s2255_fh *fh = file->private_data;
>> -	struct s2255_dev *dev = fh->dev;
>> -	int rc = v4l2_ctrl_poll(file, wait);
>> -
>> -	dprintk(dev, 100, "%s\n", __func__);
>> -	if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
>> -		return POLLERR;
>> -	mutex_lock(&dev->lock);
>> -	rc |= videobuf_poll_stream(file, &fh->vb_vidq, wait);
>> -	mutex_unlock(&dev->lock);
>> -	return rc;
>> -}
>> -
>>  static void s2255_destroy(struct s2255_dev *dev)
>>  {
>>  	dprintk(dev, 1, "%s", __func__);
>> @@ -1744,57 +1550,14 @@ static void s2255_destroy(struct s2255_dev 
>> *dev)
>>  	kfree(dev);
>>  }
>> 
>> -static int s2255_release(struct file *file)
>> -{
>> -	struct s2255_fh *fh = file->private_data;
>> -	struct s2255_dev *dev = fh->dev;
>> -	struct video_device *vdev = video_devdata(file);
>> -	struct s2255_channel *channel = fh->channel;
>> -	if (!dev)
>> -		return -ENODEV;
>> -	mutex_lock(&dev->lock);
>> -	/* turn off stream */
>> -	if (res_check(fh)) {
>> -		if (channel->b_acquire)
>> -			s2255_stop_acquire(fh->channel);
>> -		videobuf_streamoff(&fh->vb_vidq);
>> -		res_free(fh);
>> -	}
>> -	videobuf_mmap_free(&fh->vb_vidq);
>> -	mutex_unlock(&dev->lock);
>> -	dprintk(dev, 1, "%s[%s]\n", __func__, 
>> video_device_node_name(vdev));
>> -	v4l2_fh_del(&fh->fh);
>> -	v4l2_fh_exit(&fh->fh);
>> -	kfree(fh);
>> -	return 0;
>> -}
>> -
>> -static int s2255_mmap_v4l(struct file *file, struct vm_area_struct 
>> *vma)
>> -{
>> -	struct s2255_fh *fh = file->private_data;
>> -	struct s2255_dev *dev;
>> -	int ret;
>> -	if (!fh)
>> -		return -ENODEV;
>> -	dev = fh->dev;
>> -	dprintk(dev, 4, "%s, vma=0x%08lx\n", __func__, (unsigned long)vma);
>> -	if (mutex_lock_interruptible(&dev->lock))
>> -		return -ERESTARTSYS;
>> -	ret = videobuf_mmap_mapper(&fh->vb_vidq, vma);
>> -	mutex_unlock(&dev->lock);
>> -	dprintk(dev, 4, "%s vma start=0x%08lx, size=%ld, ret=%d\n", 
>> __func__,
>> -		(unsigned long)vma->vm_start,
>> -		(unsigned long)vma->vm_end - (unsigned long)vma->vm_start, ret);
>> -	return ret;
>> -}
>> -
>>  static const struct v4l2_file_operations s2255_fops_v4l = {
>>  	.owner = THIS_MODULE,
>>  	.open = s2255_open,
>> -	.release = s2255_release,
>> -	.poll = s2255_poll,
>> -	.unlocked_ioctl = video_ioctl2,	/* V4L2 ioctl handler */
>> -	.mmap = s2255_mmap_v4l,
>> +	.release = vb2_fop_release,
>> +	.unlocked_ioctl = video_ioctl2,
>> +	.read = vb2_fop_read,
>> +	.mmap = vb2_fop_mmap,
>> +	.poll = vb2_fop_poll,
>>  };
>> 
>>  static const struct v4l2_ioctl_ops s2255_ioctl_ops = {
>> @@ -1803,17 +1566,17 @@ static const struct v4l2_ioctl_ops 
>> s2255_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_reqbufs =  vb2_ioctl_reqbufs,
>> +	.vidioc_querybuf = vb2_ioctl_querybuf,
>> +	.vidioc_qbuf = vb2_ioctl_qbuf,
>> +	.vidioc_dqbuf = vb2_ioctl_dqbuf,
>>  	.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_streamon = vidioc_streamon,
>> -	.vidioc_streamoff = vidioc_streamoff,
>> +	.vidioc_streamon = vb2_ioctl_streamon,
>> +	.vidioc_streamoff = vb2_ioctl_streamoff,
>>  	.vidioc_s_jpegcomp = vidioc_s_jpegcomp,
>>  	.vidioc_g_jpegcomp = vidioc_g_jpegcomp,
>>  	.vidioc_s_parm = vidioc_s_parm,
>> @@ -1828,13 +1591,13 @@ static const struct v4l2_ioctl_ops 
>> s2255_ioctl_ops = {
>>  static void s2255_video_device_release(struct video_device *vdev)
>>  {
>>  	struct s2255_dev *dev = to_s2255_dev(vdev->v4l2_dev);
>> -	struct s2255_channel *channel =
>> -		container_of(vdev, struct s2255_channel, vdev);
>> +	struct s2255_vc *vc =
>> +		container_of(vdev, struct s2255_vc, vdev);
>> 
>>  	dprintk(dev, 4, "%s, chnls: %d\n", __func__,
>>  		atomic_read(&dev->num_channels));
>> 
>> -	v4l2_ctrl_handler_free(&channel->hdl);
>> +	v4l2_ctrl_handler_free(&vc->hdl);
>> 
>>  	if (atomic_dec_and_test(&dev->num_channels))
>>  		s2255_destroy(dev);
>> @@ -1868,64 +1631,82 @@ static int s2255_probe_v4l(struct s2255_dev 
>> *dev)
>>  	int ret;
>>  	int i;
>>  	int cur_nr = video_nr;
>> -	struct s2255_channel *channel;
>> +	struct vb2_queue *q;
>> +	struct s2255_vc *vc;
>>  	ret = v4l2_device_register(&dev->interface->dev, &dev->v4l2_dev);
>>  	if (ret)
>>  		return ret;
>>  	/* initialize all video 4 linux */
>>  	/* register 4 video devices */
>>  	for (i = 0; i < MAX_CHANNELS; i++) {
>> -		channel = &dev->channel[i];
>> -		INIT_LIST_HEAD(&channel->vidq.active);
>> +		vc = &dev->vc[i];
>> +		INIT_LIST_HEAD(&vc->buf_list);
>> 
>> -		v4l2_ctrl_handler_init(&channel->hdl, 6);
>> -		v4l2_ctrl_new_std(&channel->hdl, &s2255_ctrl_ops,
>> +		v4l2_ctrl_handler_init(&vc->hdl, 6);
>> +		v4l2_ctrl_new_std(&vc->hdl, &s2255_ctrl_ops,
>>  				V4L2_CID_BRIGHTNESS, -127, 127, 1, DEF_BRIGHT);
>> -		v4l2_ctrl_new_std(&channel->hdl, &s2255_ctrl_ops,
>> +		v4l2_ctrl_new_std(&vc->hdl, &s2255_ctrl_ops,
>>  				V4L2_CID_CONTRAST, 0, 255, 1, DEF_CONTRAST);
>> -		v4l2_ctrl_new_std(&channel->hdl, &s2255_ctrl_ops,
>> +		v4l2_ctrl_new_std(&vc->hdl, &s2255_ctrl_ops,
>>  				V4L2_CID_SATURATION, 0, 255, 1, DEF_SATURATION);
>> -		v4l2_ctrl_new_std(&channel->hdl, &s2255_ctrl_ops,
>> +		v4l2_ctrl_new_std(&vc->hdl, &s2255_ctrl_ops,
>>  				V4L2_CID_HUE, 0, 255, 1, DEF_HUE);
>> -		channel->jpegqual_ctrl = v4l2_ctrl_new_std(&channel->hdl,
>> +		vc->jpegqual_ctrl = v4l2_ctrl_new_std(&vc->hdl,
>>  				&s2255_ctrl_ops,
>>  				V4L2_CID_JPEG_COMPRESSION_QUALITY,
>>  				0, 100, 1, S2255_DEF_JPEG_QUAL);
>>  		if (dev->dsp_fw_ver >= S2255_MIN_DSP_COLORFILTER &&
>> -		    (dev->pid != 0x2257 || channel->idx <= 1))
>> -			v4l2_ctrl_new_custom(&channel->hdl, &color_filter_ctrl,
>> +		    (dev->pid != 0x2257 || vc->idx <= 1))
>> +			v4l2_ctrl_new_custom(&vc->hdl, &color_filter_ctrl,
>>  					     NULL);
>> -		if (channel->hdl.error) {
>> -			ret = channel->hdl.error;
>> -			v4l2_ctrl_handler_free(&channel->hdl);
>> +		if (vc->hdl.error) {
>> +			ret = vc->hdl.error;
>> +			v4l2_ctrl_handler_free(&vc->hdl);
>>  			dev_err(&dev->udev->dev, "couldn't register control\n");
>>  			break;
>>  		}
>> -		channel->vidq.dev = dev;
>> +		q = &vc->vb_vidq;
>> +		memset(q, 0, sizeof(vc->vb_vidq));
>> +		q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
>> +		q->io_modes = VB2_MMAP | VB2_READ;
> 
> You can add VB2_USERPTR here as well, that should work out-of-the-box.
> 
>> +		q->drv_priv = vc;
>> +		q->lock = &vc->vb_lock;
>> +		q->buf_struct_size = sizeof(struct s2255_buffer);
>> +		q->mem_ops = &vb2_vmalloc_memops;
>> +		q->ops = &s2255_video_qops;
>> +		q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
>> +		ret = vb2_queue_init(q);
>> +		if (ret != 0) {
>> +			dev_err(&dev->udev->dev,
>> +				"%s vb2_queue_init err: 0x%x\n", __func__, ret);
>> +			break;
>> +		}
>>  		/* register 4 video devices */
>> -		channel->vdev = template;
>> -		channel->vdev.ctrl_handler = &channel->hdl;
>> -		channel->vdev.lock = &dev->lock;
>> -		channel->vdev.v4l2_dev = &dev->v4l2_dev;
>> -		set_bit(V4L2_FL_USE_FH_PRIO, &channel->vdev.flags);
>> -		video_set_drvdata(&channel->vdev, channel);
>> +		vc->vdev = template;
>> +		vc->vdev.queue = q;
>> +		vc->vdev.ctrl_handler = &vc->hdl;
>> +		/* main device lock */
>> +		vc->vdev.lock = &dev->lock;
>> +		vc->vdev.v4l2_dev = &dev->v4l2_dev;
>> +		set_bit(V4L2_FL_USE_FH_PRIO, &vc->vdev.flags);
>> +		video_set_drvdata(&vc->vdev, vc);
>>  		if (video_nr == -1)
>> -			ret = video_register_device(&channel->vdev,
>> +			ret = video_register_device(&vc->vdev,
>>  						    VFL_TYPE_GRABBER,
>>  						    video_nr);
>>  		else
>> -			ret = video_register_device(&channel->vdev,
>> +			ret = video_register_device(&vc->vdev,
>>  						    VFL_TYPE_GRABBER,
>>  						    cur_nr + i);
>> 
>>  		if (ret) {
>>  			dev_err(&dev->udev->dev,
>> -				"failed to register video device!\n");
>> +				"failed to register vid device: 0x%x!\n", ret);
>>  			break;
>>  		}
>>  		atomic_inc(&dev->num_channels);
>>  		v4l2_info(&dev->v4l2_dev, "V4L2 device registered as %s\n",
>> -			  video_device_node_name(&channel->vdev));
>> +			  video_device_node_name(&vc->vdev));
>> 
>>  	}
>>  	pr_info("Sensoray 2255 V4L driver Revision: %s\n",
>> @@ -1962,11 +1743,11 @@ static int save_frame(struct s2255_dev *dev, 
>> struct s2255_pipeinfo *pipe_info)
>>  	s32 idx = -1;
>>  	struct s2255_framei *frm;
>>  	unsigned char *pdata;
>> -	struct s2255_channel *ch;
>> +	struct s2255_vc *vc;
>>  	dprintk(dev, 100, "buffer to user\n");
>> -	ch = &dev->channel[dev->cc];
>> -	idx = ch->cur_frame;
>> -	frm = &ch->buffer.frame[idx];
>> +	vc = &dev->vc[dev->cc];
>> +	idx = vc->cur_frame;
>> +	frm = &vc->buffer.frame[idx];
>>  	if (frm->ulState == S2255_READ_IDLE) {
>>  		int jj;
>>  		unsigned int cc;
>> @@ -1990,15 +1771,15 @@ static int save_frame(struct s2255_dev *dev, 
>> struct s2255_pipeinfo *pipe_info)
>>  				}
>>  				/* reverse it */
>>  				dev->cc = G_chnmap[cc];
>> -				ch = &dev->channel[dev->cc];
>> +				vc = &dev->vc[dev->cc];
>>  				payload =  le32_to_cpu(pdword[3]);
>> -				if (payload > ch->req_image_size) {
>> -					ch->bad_payload++;
>> +				if (payload > vc->req_image_size) {
>> +					vc->bad_payload++;
>>  					/* discard the bad frame */
>>  					return -EINVAL;
>>  				}
>> -				ch->pkt_size = payload;
>> -				ch->jpg_size = le32_to_cpu(pdword[4]);
>> +				vc->pkt_size = payload;
>> +				vc->jpg_size = le32_to_cpu(pdword[4]);
>>  				break;
>>  			case S2255_MARKER_RESPONSE:
>> 
>> @@ -2009,13 +1790,13 @@ static int save_frame(struct s2255_dev *dev, 
>> struct s2255_pipeinfo *pipe_info)
>>  				cc = G_chnmap[le32_to_cpu(pdword[1])];
>>  				if (cc >= MAX_CHANNELS)
>>  					break;
>> -				ch = &dev->channel[cc];
>> +				vc = &dev->vc[cc];
>>  				switch (pdword[2]) {
>>  				case S2255_RESPONSE_SETMODE:
>>  					/* check if channel valid */
>>  					/* set mode ready */
>> -					ch->setmode_ready = 1;
>> -					wake_up(&ch->wait_setmode);
>> +					vc->setmode_ready = 1;
>> +					wake_up(&vc->wait_setmode);
>>  					dprintk(dev, 5, "setmode rdy %d\n", cc);
>>  					break;
>>  				case S2255_RESPONSE_FW:
>> @@ -2029,9 +1810,9 @@ static int save_frame(struct s2255_dev *dev, 
>> struct s2255_pipeinfo *pipe_info)
>>  					wake_up(&dev->fw_data->wait_fw);
>>  					break;
>>  				case S2255_RESPONSE_STATUS:
>> -					ch->vidstatus = le32_to_cpu(pdword[3]);
>> -					ch->vidstatus_ready = 1;
>> -					wake_up(&ch->wait_vidstatus);
>> +					vc->vidstatus = le32_to_cpu(pdword[3]);
>> +					vc->vidstatus_ready = 1;
>> +					wake_up(&vc->wait_vidstatus);
>>  					dprintk(dev, 5, "vstat %x chan %d\n",
>>  						le32_to_cpu(pdword[3]), cc);
>>  					break;
>> @@ -2048,11 +1829,12 @@ static int save_frame(struct s2255_dev *dev, 
>> struct s2255_pipeinfo *pipe_info)
>>  		if (!bframe)
>>  			return -EINVAL;
>>  	}
>> -	ch = &dev->channel[dev->cc];
>> -	idx = ch->cur_frame;
>> -	frm = &ch->buffer.frame[idx];
>> +	vc = &dev->vc[dev->cc];
>> +	idx = vc->cur_frame;
>> +	frm = &vc->buffer.frame[idx];
>> +
>>  	/* search done.  now find out if should be acquiring on this 
>> channel */
>> -	if (!ch->b_acquire) {
>> +	if (!vb2_is_streaming(&vc->vb_vidq)) {
>>  		/* we found a frame, but this channel is turned off */
>>  		frm->ulState = S2255_READ_IDLE;
>>  		return -EINVAL;
>> @@ -2066,7 +1848,6 @@ static int save_frame(struct s2255_dev *dev, 
>> struct s2255_pipeinfo *pipe_info)
>>  	/* skip the marker 512 bytes (and offset if out of sync) */
>>  	psrc = (u8 *)pipe_info->transfer_buffer + offset;
>> 
>> -
>>  	if (frm->lpvbits == NULL) {
>>  		dprintk(dev, 1, "s2255 frame buffer == NULL.%p %p %d %d",
>>  			frm, dev, dev->cc, idx);
>> @@ -2074,13 +1855,11 @@ static int save_frame(struct s2255_dev *dev, 
>> struct s2255_pipeinfo *pipe_info)
>>  	}
>> 
>>  	pdest = frm->lpvbits + frm->cur_size;
>> -
>>  	copy_size = (pipe_info->cur_transfer_size - offset);
>> -
>> -	size = ch->pkt_size - PREFIX_SIZE;
>> +	size = vc->pkt_size - PREFIX_SIZE;
>> 
>>  	/* sanity check on pdest */
>> -	if ((copy_size + frm->cur_size) < ch->req_image_size)
>> +	if ((copy_size + frm->cur_size) < vc->req_image_size)
>>  		memcpy(pdest, psrc, copy_size);
>> 
>>  	frm->cur_size += copy_size;
>> @@ -2089,19 +1868,18 @@ static int save_frame(struct s2255_dev *dev, 
>> struct s2255_pipeinfo *pipe_info)
>>  	if (frm->cur_size >= size) {
>>  		dprintk(dev, 2, "******[%d]Buffer[%d]full*******\n",
>>  			dev->cc, idx);
>> -		ch->last_frame = ch->cur_frame;
>> -		ch->cur_frame++;
>> +		vc->last_frame = vc->cur_frame;
>> +		vc->cur_frame++;
>>  		/* end of system frame ring buffer, start at zero */
>> -		if ((ch->cur_frame == SYS_FRAMES) ||
>> -		    (ch->cur_frame == ch->buffer.dwFrames))
>> -			ch->cur_frame = 0;
>> +		if ((vc->cur_frame == SYS_FRAMES) ||
>> +		    (vc->cur_frame == vc->buffer.dwFrames))
>> +			vc->cur_frame = 0;
>>  		/* frame ready */
>> -		if (ch->b_acquire)
>> -			s2255_got_frame(ch, ch->jpg_size);
>> -		ch->frame_count++;
>> +		if (vb2_is_streaming(&vc->vb_vidq))
>> +			s2255_got_frame(vc, vc->jpg_size);
>> +		vc->frame_count++;
>>  		frm->ulState = S2255_READ_IDLE;
>>  		frm->cur_size = 0;
>> -
>>  	}
>>  	/* done successfully */
>>  	return 0;
>> @@ -2121,7 +1899,7 @@ static void s2255_read_video_callback(struct 
>> s2255_dev *dev,
>>  	/* otherwise copy to the system buffers */
>>  	res = save_frame(dev, pipe_info);
>>  	if (res != 0)
>> -		dprintk(dev, 4, "s2255: read callback failed\n");
>> +		dprintk(dev, 50, "s2255: read callback: %d\n", res);
>> 
>>  	dprintk(dev, 50, "callback read video done\n");
>>  	return;
>> @@ -2171,11 +1949,11 @@ static int s2255_get_fx2fw(struct s2255_dev 
>> *dev)
>>   * Create the system ring buffer to copy frames into from the
>>   * usb read pipe.
>>   */
>> -static int s2255_create_sys_buffers(struct s2255_channel *channel)
>> +static int s2255_create_sys_buffers(struct s2255_vc *vc)
>>  {
>>  	unsigned long i;
>>  	unsigned long reqsize;
>> -	channel->buffer.dwFrames = SYS_FRAMES;
>> +	vc->buffer.dwFrames = SYS_FRAMES;
>>  	/* always allocate maximum size(PAL) for system buffers */
>>  	reqsize = SYS_FRAMES_MAXSIZE;
>> 
>> @@ -2184,33 +1962,33 @@ static int s2255_create_sys_buffers(struct 
>> s2255_channel *channel)
>> 
>>  	for (i = 0; i < SYS_FRAMES; i++) {
>>  		/* allocate the frames */
>> -		channel->buffer.frame[i].lpvbits = vmalloc(reqsize);
>> -		channel->buffer.frame[i].size = reqsize;
>> -		if (channel->buffer.frame[i].lpvbits == NULL) {
>> +		vc->buffer.frame[i].lpvbits = vmalloc(reqsize);
>> +		vc->buffer.frame[i].size = reqsize;
>> +		if (vc->buffer.frame[i].lpvbits == NULL) {
>>  			pr_info("out of memory.  using less frames\n");
>> -			channel->buffer.dwFrames = i;
>> +			vc->buffer.dwFrames = i;
>>  			break;
>>  		}
>>  	}
>> 
>>  	/* make sure internal states are set */
>>  	for (i = 0; i < SYS_FRAMES; i++) {
>> -		channel->buffer.frame[i].ulState = 0;
>> -		channel->buffer.frame[i].cur_size = 0;
>> +		vc->buffer.frame[i].ulState = 0;
>> +		vc->buffer.frame[i].cur_size = 0;
>>  	}
>> 
>> -	channel->cur_frame = 0;
>> -	channel->last_frame = -1;
>> +	vc->cur_frame = 0;
>> +	vc->last_frame = -1;
>>  	return 0;
>>  }
>> 
>> -static int s2255_release_sys_buffers(struct s2255_channel *channel)
>> +static int s2255_release_sys_buffers(struct s2255_vc *vc)
>>  {
>>  	unsigned long i;
>>  	for (i = 0; i < SYS_FRAMES; i++) {
>> -		if (channel->buffer.frame[i].lpvbits)
>> -			vfree(channel->buffer.frame[i].lpvbits);
>> -		channel->buffer.frame[i].lpvbits = NULL;
>> +		if (vc->buffer.frame[i].lpvbits)
>> +			vfree(vc->buffer.frame[i].lpvbits);
>> +		vc->buffer.frame[i].lpvbits = NULL;
>>  	}
>>  	return 0;
>>  }
>> @@ -2244,21 +2022,20 @@ static int s2255_board_init(struct s2255_dev 
>> *dev)
>>  		pr_info("s2255: newer USB firmware available\n");
>> 
>>  	for (j = 0; j < MAX_CHANNELS; j++) {
>> -		struct s2255_channel *channel = &dev->channel[j];
>> -		channel->b_acquire = 0;
>> -		channel->mode = mode_def;
>> +		struct s2255_vc *vc = &dev->vc[j];
>> +		vc->mode = mode_def;
>>  		if (dev->pid == 0x2257 && j > 1)
>> -			channel->mode.color |= (1 << 16);
>> -		channel->jpegqual = S2255_DEF_JPEG_QUAL;
>> -		channel->width = LINE_SZ_4CIFS_NTSC;
>> -		channel->height = NUM_LINES_4CIFS_NTSC * 2;
>> -		channel->std = V4L2_STD_NTSC_M;
>> -		channel->fmt = &formats[0];
>> -		channel->mode.restart = 1;
>> -		channel->req_image_size = get_transfer_size(&mode_def);
>> -		channel->frame_count = 0;
>> +			vc->mode.color |= (1 << 16);
>> +		vc->jpegqual = S2255_DEF_JPEG_QUAL;
>> +		vc->width = LINE_SZ_4CIFS_NTSC;
>> +		vc->height = NUM_LINES_4CIFS_NTSC * 2;
>> +		vc->std = V4L2_STD_NTSC_M;
>> +		vc->fmt = &formats[0];
>> +		vc->mode.restart = 1;
>> +		vc->req_image_size = get_transfer_size(&mode_def);
>> +		vc->frame_count = 0;
>>  		/* create the system buffers */
>> -		s2255_create_sys_buffers(channel);
>> +		s2255_create_sys_buffers(vc);
>>  	}
>>  	/* start read pipe */
>>  	s2255_start_readpipe(dev);
>> @@ -2270,14 +2047,13 @@ static int s2255_board_shutdown(struct 
>> s2255_dev *dev)
>>  {
>>  	u32 i;
>>  	dprintk(dev, 1, "%s: dev: %p", __func__,  dev);
>> -
>>  	for (i = 0; i < MAX_CHANNELS; i++) {
>> -		if (dev->channel[i].b_acquire)
>> -			s2255_stop_acquire(&dev->channel[i]);
>> +		if (vb2_is_streaming(&dev->vc[i].vb_vidq))
>> +			s2255_stop_acquire(&dev->vc[i]);
>>  	}
>>  	s2255_stop_readpipe(dev);
>>  	for (i = 0; i < MAX_CHANNELS; i++)
>> -		s2255_release_sys_buffers(&dev->channel[i]);
>> +		s2255_release_sys_buffers(&dev->vc[i]);
>>  	/* release transfer buffer */
>>  	kfree(dev->pipe.transfer_buffer);
>>  	return 0;
>> @@ -2366,26 +2142,26 @@ static int s2255_start_readpipe(struct 
>> s2255_dev *dev)
>>  }
>> 
>>  /* starts acquisition process */
>> -static int s2255_start_acquire(struct s2255_channel *channel)
>> +static int s2255_start_acquire(struct s2255_vc *vc)
>>  {
>>  	unsigned char *buffer;
>>  	int res;
>>  	unsigned long chn_rev;
>>  	int j;
>> -	struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
>> -	chn_rev = G_chnmap[channel->idx];
>> +	struct s2255_dev *dev = to_s2255_dev(vc->vdev.v4l2_dev);
>> +	chn_rev = G_chnmap[vc->idx];
>>  	buffer = kzalloc(512, GFP_KERNEL);
>>  	if (buffer == NULL) {
>>  		dev_err(&dev->udev->dev, "out of mem\n");
>>  		return -ENOMEM;
>>  	}
>> 
>> -	channel->last_frame = -1;
>> -	channel->bad_payload = 0;
>> -	channel->cur_frame = 0;
>> +	vc->last_frame = -1;
>> +	vc->bad_payload = 0;
>> +	vc->cur_frame = 0;
>>  	for (j = 0; j < SYS_FRAMES; j++) {
>> -		channel->buffer.frame[j].ulState = 0;
>> -		channel->buffer.frame[j].cur_size = 0;
>> +		vc->buffer.frame[j].ulState = 0;
>> +		vc->buffer.frame[j].cur_size = 0;
>>  	}
>> 
>>  	/* send the start command */
>> @@ -2396,18 +2172,18 @@ static int s2255_start_acquire(struct 
>> s2255_channel *channel)
>>  	if (res != 0)
>>  		dev_err(&dev->udev->dev, "CMD_START error\n");
>> 
>> -	dprintk(dev, 2, "start acquire exit[%d] %d\n", channel->idx, res);
>> +	dprintk(dev, 2, "start acquire exit[%d] %d\n", vc->idx, res);
>>  	kfree(buffer);
>>  	return 0;
>>  }
>> 
>> -static int s2255_stop_acquire(struct s2255_channel *channel)
>> +static int s2255_stop_acquire(struct s2255_vc *vc)
>>  {
>>  	unsigned char *buffer;
>>  	int res;
>>  	unsigned long chn_rev;
>> -	struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
>> -	chn_rev = G_chnmap[channel->idx];
>> +	struct s2255_dev *dev = to_s2255_dev(vc->vdev.v4l2_dev);
>> +	chn_rev = G_chnmap[vc->idx];
>>  	buffer = kzalloc(512, GFP_KERNEL);
>>  	if (buffer == NULL) {
>>  		dev_err(&dev->udev->dev, "out of mem\n");
>> @@ -2421,8 +2197,7 @@ static int s2255_stop_acquire(struct 
>> s2255_channel *channel)
>>  	if (res != 0)
>>  		dev_err(&dev->udev->dev, "CMD_STOP error\n");
>>  	kfree(buffer);
>> -	channel->b_acquire = 0;
>> -	dprintk(dev, 4, "%s: chn %d, res %d\n", __func__, channel->idx, 
>> res);
>> +	dprintk(dev, 4, "%s: chn %d, res %d\n", __func__, vc->idx, res);
>>  	return res;
>>  }
>> 
>> @@ -2512,11 +2287,13 @@ static int s2255_probe(struct usb_interface 
>> *interface,
>>  	dev->timer.data = (unsigned long)dev->fw_data;
>>  	init_waitqueue_head(&dev->fw_data->wait_fw);
>>  	for (i = 0; i < MAX_CHANNELS; i++) {
>> -		struct s2255_channel *channel = &dev->channel[i];
>> -		channel->idx = i;
>> -		channel->dev = dev;
>> -		init_waitqueue_head(&channel->wait_setmode);
>> -		init_waitqueue_head(&channel->wait_vidstatus);
>> +		struct s2255_vc *vc = &dev->vc[i];
>> +		vc->idx = i;
>> +		vc->dev = dev;
>> +		init_waitqueue_head(&vc->wait_setmode);
>> +		init_waitqueue_head(&vc->wait_vidstatus);
>> +		spin_lock_init(&vc->qlock);
>> +		mutex_init(&vc->vb_lock);
>>  	}
>> 
>>  	dev->fw_data->fw_urb = usb_alloc_urb(0, GFP_KERNEL);
>> @@ -2562,8 +2339,7 @@ static int s2255_probe(struct usb_interface 
>> *interface,
>>  	retval = s2255_board_init(dev);
>>  	if (retval)
>>  		goto errorBOARDINIT;
>> -	spin_lock_init(&dev->slock);
>> -	s2255_fwload_start(dev, 0);
>> +	s2255_fwload_start(dev, 1);
>>  	/* loads v4l specific */
>>  	retval = s2255_probe_v4l(dev);
>>  	if (retval)
>> @@ -2604,15 +2380,15 @@ static void s2255_disconnect(struct 
>> usb_interface *interface)
>>  	atomic_inc(&dev->num_channels);
>>  	/* unregister each video device. */
>>  	for (i = 0; i < channels; i++)
>> -		video_unregister_device(&dev->channel[i].vdev);
>> +		video_unregister_device(&dev->vc[i].vdev);
>>  	/* wake up any of our timers */
>>  	atomic_set(&dev->fw_data->fw_state, S2255_FW_DISCONNECTING);
>>  	wake_up(&dev->fw_data->wait_fw);
>>  	for (i = 0; i < MAX_CHANNELS; i++) {
>> -		dev->channel[i].setmode_ready = 1;
>> -		wake_up(&dev->channel[i].wait_setmode);
>> -		dev->channel[i].vidstatus_ready = 1;
>> -		wake_up(&dev->channel[i].wait_vidstatus);
>> +		dev->vc[i].setmode_ready = 1;
>> +		wake_up(&dev->vc[i].wait_setmode);
>> +		dev->vc[i].vidstatus_ready = 1;
>> +		wake_up(&dev->vc[i].wait_vidstatus);
>>  	}
>>  	if (atomic_dec_and_test(&dev->num_channels))
>>  		s2255_destroy(dev);
>> 
> 
> Regards,
> 
> 	Hans

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] s2255drv: port to videobuf2
  2014-02-03 17:06   ` Dean Anderson
@ 2014-02-04 10:04     ` Hans Verkuil
  2014-02-04 19:09       ` Dean Anderson
  2014-02-05 21:44       ` Dean Anderson
  0 siblings, 2 replies; 7+ messages in thread
From: Hans Verkuil @ 2014-02-04 10:04 UTC (permalink / raw)
  To: Dean Anderson; +Cc: linux-media

Hi Dean,

On 02/03/14 18:06, Dean Anderson wrote:
> On 2014-02-03 03:51, Hans Verkuil wrote:
>> Hi Dean,
>>
>> Some specific comments below, but first two general comments:
>>
>> It is easier to review if at least the removal of the old s2255_fh struct
>> was done as a separate patch. It's always good to try and keep the changes
>> in patches as small as possible. The actual vb2 conversion is always a
>> 'big bang' patch, that's unavoidable, but it's easier if it isn't mixed in
>> with other changes that are not directly related to the vb2 conversion.
> 
> 
> I figured removal of s2255_fh was a natural part of the videobuf2 conversion process, but I can break it up.

It's more like the first phase of a vb2 conversion. It really is wrong
for videobuf as well, so it makes sense to do that first.

> I also did change some formatting and naming changes (s2255_channel to s2255_vc) that can be postponed.

Just put it in a separate patch either before or after the patch that does
the vb2 conversion.

> 
>>
>> And did you also run the v4l2-compliance utility for this driver? That's
>> useful to check that everything it still correct.
> 
> Thanks for the comments.  I'll do a v2 soon with v4l2-compliance fully tested too.

Rather than the standard v4l2-compliance from v4l-utils, can you use this
from my own tree:

http://git.linuxtv.org/hverkuil/v4l-utils.git/shortlog/refs/heads/streaming

I've started work to add tests for streaming to v4l2-compliance. While not
complete it should cover what the s2255 driver needs. I'm very interested
in what it finds (or, as the case might be, what it doesn't find).

In order to do the streaming tests you have to run it with option -s.

Regards,

	Hans


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] s2255drv: port to videobuf2
  2014-02-04 10:04     ` Hans Verkuil
@ 2014-02-04 19:09       ` Dean Anderson
  2014-02-05 21:44       ` Dean Anderson
  1 sibling, 0 replies; 7+ messages in thread
From: Dean Anderson @ 2014-02-04 19:09 UTC (permalink / raw)
  To: Hans Verkuil; +Cc: linux-media

On 2014-02-04 04:04, Hans Verkuil wrote:
> Hi Dean,
> 
> On 02/03/14 18:06, Dean Anderson wrote:
>> On 2014-02-03 03:51, Hans Verkuil wrote:
>>> Hi Dean,
>>> 
>>> Some specific comments below, but first two general comments:
>>> 
>>> It is easier to review if at least the removal of the old s2255_fh 
>>> struct
>>> was done as a separate patch. It's always good to try and keep the 
>>> changes
>>> in patches as small as possible. The actual vb2 conversion is always 
>>> a
>>> 'big bang' patch, that's unavoidable, but it's easier if it isn't 
>>> mixed in
>>> with other changes that are not directly related to the vb2 
>>> conversion.
>> 
>> 
>> I figured removal of s2255_fh was a natural part of the videobuf2 
>> conversion process, but I can break it up.
> 
> It's more like the first phase of a vb2 conversion. It really is wrong
> for videobuf as well, so it makes sense to do that first.

Hans, if it's ok with you, I'd prefer to do it after the vb2 
conversion.  Right now, it's using SAA7134-style locking with resources 
in fh.  I could use "videobuf_queue_is_busy" from videobuf-core.c, but 
it has this comment "/* Locking: Only usage in bttv unsafe find way to 
remove */".

Thanks,

Dean




> 
>> I also did change some formatting and naming changes (s2255_channel 
>> to s2255_vc) that can be postponed.
> 
> Just put it in a separate patch either before or after the patch that 
> does
> the vb2 conversion.
> 
>> 
>>> 
>>> And did you also run the v4l2-compliance utility for this driver? 
>>> That's
>>> useful to check that everything it still correct.
>> 
>> Thanks for the comments.  I'll do a v2 soon with v4l2-compliance 
>> fully tested too.
> 
> Rather than the standard v4l2-compliance from v4l-utils, can you use 
> this
> from my own tree:
> 
> http://git.linuxtv.org/hverkuil/v4l-utils.git/shortlog/refs/heads/streaming
> 
> I've started work to add tests for streaming to v4l2-compliance. While 
> not
> complete it should cover what the s2255 driver needs. I'm very 
> interested
> in what it finds (or, as the case might be, what it doesn't find).
> 
> In order to do the streaming tests you have to run it with option -s.
> 
> Regards,
> 
> 	Hans

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] s2255drv: port to videobuf2
  2014-02-04 10:04     ` Hans Verkuil
  2014-02-04 19:09       ` Dean Anderson
@ 2014-02-05 21:44       ` Dean Anderson
  2014-02-05 22:10         ` Hans Verkuil
  1 sibling, 1 reply; 7+ messages in thread
From: Dean Anderson @ 2014-02-05 21:44 UTC (permalink / raw)
  To: Hans Verkuil; +Cc: linux-media

On 2014-02-04 04:04, Hans Verkuil wrote:
> Hi Dean,
> 
> On 02/03/14 18:06, Dean Anderson wrote:
>> On 2014-02-03 03:51, Hans Verkuil wrote:
>>> Hi Dean,
>>> 
>>> Some specific comments below, but first two general comments:
>>> 
>>> It is easier to review if at least the removal of the old s2255_fh 
>>> struct
>>> was done as a separate patch. It's always good to try and keep the 
>>> changes
>>> in patches as small as possible. The actual vb2 conversion is always 
>>> a
>>> 'big bang' patch, that's unavoidable, but it's easier if it isn't 
>>> mixed in
>>> with other changes that are not directly related to the vb2 
>>> conversion.
>> 
>> 
>> I figured removal of s2255_fh was a natural part of the videobuf2 
>> conversion process, but I can break it up.
> 
> It's more like the first phase of a vb2 conversion. It really is wrong
> for videobuf as well, so it makes sense to do that first.
> 
>> I also did change some formatting and naming changes (s2255_channel 
>> to s2255_vc) that can be postponed.
> 
> Just put it in a separate patch either before or after the patch that 
> does
> the vb2 conversion.
> 
>> 
>>> 
>>> And did you also run the v4l2-compliance utility for this driver? 
>>> That's
>>> useful to check that everything it still correct.
>> 
>> Thanks for the comments.  I'll do a v2 soon with v4l2-compliance 
>> fully tested too.
> 
> Rather than the standard v4l2-compliance from v4l-utils, can you use 
> this
> from my own tree:
> 
> http://git.linuxtv.org/hverkuil/v4l-utils.git/shortlog/refs/heads/streaming
> 
> I've started work to add tests for streaming to v4l2-compliance. While 
> not
> complete it should cover what the s2255 driver needs. I'm very 
> interested
> in what it finds (or, as the case might be, what it doesn't find).
> 
> In order to do the streaming tests you have to run it with option -s.
> 

The current driver before the videobuf2 patch has 3 errors and 8 
warnings with option "-s".  The warnings are "msg5650" warnings that 
will break existing applications if fixed.

Here's what is causing at least two of the errors (the other is 
unsupported USERPTR, which will be fixed in VB2):

Vidioc_reqbufs calls videobuf_reqbufs, which returns a fail if 
req->count = 0.

IE:

if (req->count < 1) {
	dprintk(1, "reqbufs: count invalid (%d)\n", req->count);
	return -EINVAL;
}

Are drivers using videobuf required to check if 
v4l2_requestbuffers->count == 0 before calling videobuf_reqbufs? That 
seems unlikely and inefficient, so this could be an issue with 
videobuf-core.c..

Thanks,






> Regards,
> 
> 	Hans

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] s2255drv: port to videobuf2
  2014-02-05 21:44       ` Dean Anderson
@ 2014-02-05 22:10         ` Hans Verkuil
  0 siblings, 0 replies; 7+ messages in thread
From: Hans Verkuil @ 2014-02-05 22:10 UTC (permalink / raw)
  To: Dean Anderson; +Cc: linux-media

On 02/05/2014 10:44 PM, Dean Anderson wrote:
> On 2014-02-04 04:04, Hans Verkuil wrote:
>> Hi Dean,
>>
>> On 02/03/14 18:06, Dean Anderson wrote:
>>> On 2014-02-03 03:51, Hans Verkuil wrote:
>>>> Hi Dean,
>>>>
>>>> Some specific comments below, but first two general comments:
>>>>
>>>> It is easier to review if at least the removal of the old s2255_fh 
>>>> struct
>>>> was done as a separate patch. It's always good to try and keep the 
>>>> changes
>>>> in patches as small as possible. The actual vb2 conversion is always 
>>>> a
>>>> 'big bang' patch, that's unavoidable, but it's easier if it isn't 
>>>> mixed in
>>>> with other changes that are not directly related to the vb2 
>>>> conversion.
>>>
>>>
>>> I figured removal of s2255_fh was a natural part of the videobuf2 
>>> conversion process, but I can break it up.
>>
>> It's more like the first phase of a vb2 conversion. It really is wrong
>> for videobuf as well, so it makes sense to do that first.
>>
>>> I also did change some formatting and naming changes (s2255_channel 
>>> to s2255_vc) that can be postponed.
>>
>> Just put it in a separate patch either before or after the patch that 
>> does
>> the vb2 conversion.
>>
>>>
>>>>
>>>> And did you also run the v4l2-compliance utility for this driver? 
>>>> That's
>>>> useful to check that everything it still correct.
>>>
>>> Thanks for the comments.  I'll do a v2 soon with v4l2-compliance 
>>> fully tested too.
>>
>> Rather than the standard v4l2-compliance from v4l-utils, can you use 
>> this
>> from my own tree:
>>
>> http://git.linuxtv.org/hverkuil/v4l-utils.git/shortlog/refs/heads/streaming
>>
>> I've started work to add tests for streaming to v4l2-compliance. While 
>> not
>> complete it should cover what the s2255 driver needs. I'm very 
>> interested
>> in what it finds (or, as the case might be, what it doesn't find).
>>
>> In order to do the streaming tests you have to run it with option -s.
>>
> 
> The current driver before the videobuf2 patch has 3 errors and 8 
> warnings with option "-s".  The warnings are "msg5650" warnings that 
> will break existing applications if fixed.
> 
> Here's what is causing at least two of the errors (the other is 
> unsupported USERPTR, which will be fixed in VB2):
> 
> Vidioc_reqbufs calls videobuf_reqbufs, which returns a fail if 
> req->count = 0.
> 
> IE:
> 
> if (req->count < 1) {
> 	dprintk(1, "reqbufs: count invalid (%d)\n", req->count);
> 	return -EINVAL;
> }
> 
> Are drivers using videobuf required to check if 
> v4l2_requestbuffers->count == 0 before calling videobuf_reqbufs? That 
> seems unlikely and inefficient, so this could be an issue with 
> videobuf-core.c..

videobuf has always handled REQBUFS with a count of 0 wrong. One of the
many bad things about videobuf. Any driver using videobuf will fail the
v4l2-compliance test so that is not surprising.

Regards,

	Hans

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2014-02-05 22:10 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-01-31 17:35 [PATCH] s2255drv: port to videobuf2 Dean Anderson
2014-02-03  9:51 ` Hans Verkuil
2014-02-03 17:06   ` Dean Anderson
2014-02-04 10:04     ` Hans Verkuil
2014-02-04 19:09       ` Dean Anderson
2014-02-05 21:44       ` Dean Anderson
2014-02-05 22:10         ` Hans Verkuil

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.