All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/15] em28xx VBI2 port and v4l2-compliance fixes
@ 2013-01-04 20:59 Devin Heitmueller
  2013-01-04 20:59 ` [PATCH 01/15] em28xx: fix querycap Devin Heitmueller
                   ` (15 more replies)
  0 siblings, 16 replies; 22+ messages in thread
From: Devin Heitmueller @ 2013-01-04 20:59 UTC (permalink / raw)
  To: linux-media; +Cc: Devin Heitmueller

This patch series converts the em28xx driver to videobuf2 and fixes
a number of issues found with v4l2-compliance on em28xx.

Devin Heitmueller (1):
  em28xx: convert to videobuf2

Hans Verkuil (14):
  em28xx: fix querycap.
  em28xx: remove bogus input/audio ioctls for the radio device.
  em28xx: fix VIDIOC_DBG_G_CHIP_IDENT compliance errors.
  em28xx: fix tuner/frequency handling
  v4l2-ctrls: add a notify callback.
  em28xx: convert to the control framework.
  em28xx: convert to v4l2_fh, fix priority handling.
  em28xx: add support for control events.
  em28xx: fill in readbuffers and fix incorrect return code.
  em28xx: fix broken TRY_FMT.
  tvp5150: remove compat control ops.
  em28xx: std fixes: don't implement in webcam mode, and fix std
    changes.
  em28xx: remove sliced VBI support.
  em28xx: zero vbi_format reserved array and add try_vbi_fmt.

 Documentation/video4linux/v4l2-controls.txt |   22 +-
 drivers/media/i2c/tvp5150.c                 |    7 -
 drivers/media/usb/em28xx/Kconfig            |    3 +-
 drivers/media/usb/em28xx/em28xx-cards.c     |   31 +-
 drivers/media/usb/em28xx/em28xx-dvb.c       |    4 +-
 drivers/media/usb/em28xx/em28xx-vbi.c       |  123 ++-
 drivers/media/usb/em28xx/em28xx-video.c     | 1159 ++++++++-------------------
 drivers/media/usb/em28xx/em28xx.h           |   38 +-
 drivers/media/v4l2-core/v4l2-ctrls.c        |   18 +
 include/media/v4l2-ctrls.h                  |   25 +
 10 files changed, 504 insertions(+), 926 deletions(-)

-- 
1.7.9.5


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

* [PATCH 01/15] em28xx: fix querycap.
  2013-01-04 20:59 [PATCH 00/15] em28xx VBI2 port and v4l2-compliance fixes Devin Heitmueller
@ 2013-01-04 20:59 ` Devin Heitmueller
  2013-01-04 20:59 ` [PATCH 02/15] em28xx: remove bogus input/audio ioctls for the radio device Devin Heitmueller
                   ` (14 subsequent siblings)
  15 siblings, 0 replies; 22+ messages in thread
From: Devin Heitmueller @ 2013-01-04 20:59 UTC (permalink / raw)
  To: linux-media; +Cc: Devin Heitmueller, Hans Verkuil

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Devin Heitmueller <dheitmueller@kernellabs.com>
---
 drivers/media/usb/em28xx/em28xx-video.c |   42 ++++++++++++++-----------------
 1 file changed, 19 insertions(+), 23 deletions(-)

diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index 4c1726d..fb9ee46 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -1577,6 +1577,7 @@ static int vidioc_streamoff(struct file *file, void *priv,
 static int vidioc_querycap(struct file *file, void  *priv,
 					struct v4l2_capability *cap)
 {
+	struct video_device *vdev = video_devdata(file);
 	struct em28xx_fh      *fh  = priv;
 	struct em28xx         *dev = fh->dev;
 
@@ -1584,20 +1585,28 @@ static int vidioc_querycap(struct file *file, void  *priv,
 	strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card));
 	usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
 
-	cap->capabilities =
-			V4L2_CAP_SLICED_VBI_CAPTURE |
-			V4L2_CAP_VIDEO_CAPTURE |
-			V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
-
-	if (dev->vbi_dev)
-		cap->capabilities |= V4L2_CAP_VBI_CAPTURE;
+	if (vdev->vfl_type == VFL_TYPE_GRABBER)
+		cap->device_caps = V4L2_CAP_READWRITE |
+			V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+	else if (vdev->vfl_type == VFL_TYPE_RADIO)
+		cap->device_caps = V4L2_CAP_RADIO;
+	else
+		cap->device_caps = V4L2_CAP_READWRITE |
+			V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE;
 
 	if (dev->audio_mode.has_audio)
-		cap->capabilities |= V4L2_CAP_AUDIO;
+		cap->device_caps |= V4L2_CAP_AUDIO;
 
 	if (dev->tuner_type != TUNER_ABSENT)
-		cap->capabilities |= V4L2_CAP_TUNER;
+		cap->device_caps |= V4L2_CAP_TUNER;
 
+	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS |
+		V4L2_CAP_READWRITE | V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+	if (dev->vbi_dev)
+		cap->capabilities |=
+			V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE;
+	if (dev->radio_dev)
+		cap->capabilities |= V4L2_CAP_RADIO;
 	return 0;
 }
 
@@ -1831,19 +1840,6 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
 /* RADIO ESPECIFIC IOCTLS                                      */
 /* ----------------------------------------------------------- */
 
-static int radio_querycap(struct file *file, void  *priv,
-			  struct v4l2_capability *cap)
-{
-	struct em28xx *dev = ((struct em28xx_fh *)priv)->dev;
-
-	strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
-	strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card));
-	usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
-
-	cap->capabilities = V4L2_CAP_TUNER;
-	return 0;
-}
-
 static int radio_g_tuner(struct file *file, void *priv,
 			 struct v4l2_tuner *t)
 {
@@ -2281,7 +2277,7 @@ static const struct v4l2_file_operations radio_fops = {
 };
 
 static const struct v4l2_ioctl_ops radio_ioctl_ops = {
-	.vidioc_querycap      = radio_querycap,
+	.vidioc_querycap      = vidioc_querycap,
 	.vidioc_g_tuner       = radio_g_tuner,
 	.vidioc_enum_input    = radio_enum_input,
 	.vidioc_g_audio       = radio_g_audio,
-- 
1.7.9.5


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

* [PATCH 02/15] em28xx: remove bogus input/audio ioctls for the radio device.
  2013-01-04 20:59 [PATCH 00/15] em28xx VBI2 port and v4l2-compliance fixes Devin Heitmueller
  2013-01-04 20:59 ` [PATCH 01/15] em28xx: fix querycap Devin Heitmueller
@ 2013-01-04 20:59 ` Devin Heitmueller
  2013-01-04 20:59 ` [PATCH 03/15] em28xx: fix VIDIOC_DBG_G_CHIP_IDENT compliance errors Devin Heitmueller
                   ` (13 subsequent siblings)
  15 siblings, 0 replies; 22+ messages in thread
From: Devin Heitmueller @ 2013-01-04 20:59 UTC (permalink / raw)
  To: linux-media; +Cc: Devin Heitmueller, Hans Verkuil

Radio devices should not implement those ioctls.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Devin Heitmueller <dheitmueller@kernellabs.com>
---
 drivers/media/usb/em28xx/em28xx-video.c |   35 -------------------------------
 1 file changed, 35 deletions(-)

diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index fb9ee46..f025440 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -1856,26 +1856,6 @@ static int radio_g_tuner(struct file *file, void *priv,
 	return 0;
 }
 
-static int radio_enum_input(struct file *file, void *priv,
-			    struct v4l2_input *i)
-{
-	if (i->index != 0)
-		return -EINVAL;
-	strcpy(i->name, "Radio");
-	i->type = V4L2_INPUT_TYPE_TUNER;
-
-	return 0;
-}
-
-static int radio_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
-{
-	if (unlikely(a->index))
-		return -EINVAL;
-
-	strcpy(a->name, "Radio");
-	return 0;
-}
-
 static int radio_s_tuner(struct file *file, void *priv,
 			 struct v4l2_tuner *t)
 {
@@ -1889,17 +1869,6 @@ static int radio_s_tuner(struct file *file, void *priv,
 	return 0;
 }
 
-static int radio_s_audio(struct file *file, void *fh,
-			 const struct v4l2_audio *a)
-{
-	return 0;
-}
-
-static int radio_s_input(struct file *file, void *fh, unsigned int i)
-{
-	return 0;
-}
-
 static int radio_queryctrl(struct file *file, void *priv,
 			   struct v4l2_queryctrl *qc)
 {
@@ -2279,11 +2248,7 @@ static const struct v4l2_file_operations radio_fops = {
 static const struct v4l2_ioctl_ops radio_ioctl_ops = {
 	.vidioc_querycap      = vidioc_querycap,
 	.vidioc_g_tuner       = radio_g_tuner,
-	.vidioc_enum_input    = radio_enum_input,
-	.vidioc_g_audio       = radio_g_audio,
 	.vidioc_s_tuner       = radio_s_tuner,
-	.vidioc_s_audio       = radio_s_audio,
-	.vidioc_s_input       = radio_s_input,
 	.vidioc_queryctrl     = radio_queryctrl,
 	.vidioc_g_ctrl        = vidioc_g_ctrl,
 	.vidioc_s_ctrl        = vidioc_s_ctrl,
-- 
1.7.9.5


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

* [PATCH 03/15] em28xx: fix VIDIOC_DBG_G_CHIP_IDENT compliance errors.
  2013-01-04 20:59 [PATCH 00/15] em28xx VBI2 port and v4l2-compliance fixes Devin Heitmueller
  2013-01-04 20:59 ` [PATCH 01/15] em28xx: fix querycap Devin Heitmueller
  2013-01-04 20:59 ` [PATCH 02/15] em28xx: remove bogus input/audio ioctls for the radio device Devin Heitmueller
@ 2013-01-04 20:59 ` Devin Heitmueller
  2013-01-04 20:59 ` [PATCH 04/15] em28xx: fix tuner/frequency handling Devin Heitmueller
                   ` (12 subsequent siblings)
  15 siblings, 0 replies; 22+ messages in thread
From: Devin Heitmueller @ 2013-01-04 20:59 UTC (permalink / raw)
  To: linux-media; +Cc: Devin Heitmueller, Hans Verkuil

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Devin Heitmueller <dheitmueller@kernellabs.com>
---
 drivers/media/usb/em28xx/em28xx-video.c |    8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index f025440..b71df42 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -1403,6 +1403,14 @@ static int vidioc_g_chip_ident(struct file *file, void *priv,
 
 	chip->ident = V4L2_IDENT_NONE;
 	chip->revision = 0;
+	if (chip->match.type == V4L2_CHIP_MATCH_HOST) {
+		if (v4l2_chip_match_host(&chip->match))
+			chip->ident = V4L2_IDENT_NONE;
+		return 0;
+	}
+	if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER &&
+	    chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
+		return -EINVAL;
 
 	v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_chip_ident, chip);
 
-- 
1.7.9.5


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

* [PATCH 04/15] em28xx: fix tuner/frequency handling
  2013-01-04 20:59 [PATCH 00/15] em28xx VBI2 port and v4l2-compliance fixes Devin Heitmueller
                   ` (2 preceding siblings ...)
  2013-01-04 20:59 ` [PATCH 03/15] em28xx: fix VIDIOC_DBG_G_CHIP_IDENT compliance errors Devin Heitmueller
@ 2013-01-04 20:59 ` Devin Heitmueller
  2013-01-04 20:59 ` [PATCH 05/15] v4l2-ctrls: add a notify callback Devin Heitmueller
                   ` (11 subsequent siblings)
  15 siblings, 0 replies; 22+ messages in thread
From: Devin Heitmueller @ 2013-01-04 20:59 UTC (permalink / raw)
  To: linux-media; +Cc: Devin Heitmueller, Hans Verkuil

v4l2-compliance found problems with frequency clamping that wasn't
reported correctly and missing tuner index checks.

Also removed unnecessary tuner type checks (these are now done by the
v4l2 core).

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Devin Heitmueller <dheitmueller@kernellabs.com>
---
 drivers/media/usb/em28xx/em28xx-video.c |   13 +++++--------
 1 file changed, 5 insertions(+), 8 deletions(-)

diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index b71df42..89cbfaf 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -1322,7 +1322,6 @@ static int vidioc_g_tuner(struct file *file, void *priv,
 		return -EINVAL;
 
 	strcpy(t->name, "Tuner");
-	t->type = V4L2_TUNER_ANALOG_TV;
 
 	v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
 	return 0;
@@ -1352,7 +1351,9 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 	struct em28xx_fh      *fh  = priv;
 	struct em28xx         *dev = fh->dev;
 
-	f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+	if (0 != f->tuner)
+		return -EINVAL;
+
 	f->frequency = dev->ctl_freq;
 	return 0;
 }
@@ -1371,13 +1372,9 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 	if (0 != f->tuner)
 		return -EINVAL;
 
-	if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV))
-		return -EINVAL;
-	if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO))
-		return -EINVAL;
-
-	dev->ctl_freq = f->frequency;
 	v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, f);
+	v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_frequency, f);
+	dev->ctl_freq = f->frequency;
 
 	return 0;
 }
-- 
1.7.9.5


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

* [PATCH 05/15] v4l2-ctrls: add a notify callback.
  2013-01-04 20:59 [PATCH 00/15] em28xx VBI2 port and v4l2-compliance fixes Devin Heitmueller
                   ` (3 preceding siblings ...)
  2013-01-04 20:59 ` [PATCH 04/15] em28xx: fix tuner/frequency handling Devin Heitmueller
@ 2013-01-04 20:59 ` Devin Heitmueller
  2013-01-04 20:59 ` [PATCH 06/15] em28xx: convert to the control framework Devin Heitmueller
                   ` (10 subsequent siblings)
  15 siblings, 0 replies; 22+ messages in thread
From: Devin Heitmueller @ 2013-01-04 20:59 UTC (permalink / raw)
  To: linux-media; +Cc: Devin Heitmueller, Hans Verkuil

Sometimes platform/bridge drivers need to be notified when a control from
a sub-device changes value. In order to support this a notify callback was
added.

djh - fix merge conflict in v4l2-ctrls.c

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Devin Heitmueller <dheitmueller@kernellabs.com>
---
 Documentation/video4linux/v4l2-controls.txt |   22 ++++++++++++++--------
 drivers/media/v4l2-core/v4l2-ctrls.c        |   18 ++++++++++++++++++
 include/media/v4l2-ctrls.h                  |   25 +++++++++++++++++++++++++
 3 files changed, 57 insertions(+), 8 deletions(-)

diff --git a/Documentation/video4linux/v4l2-controls.txt b/Documentation/video4linux/v4l2-controls.txt
index cfe52c7..676f873 100644
--- a/Documentation/video4linux/v4l2-controls.txt
+++ b/Documentation/video4linux/v4l2-controls.txt
@@ -715,14 +715,20 @@ a control of this type whenever the first control belonging to a new control
 class is added.
 
 
-Proposals for Extensions
-========================
+Adding Notify Callbacks
+=======================
+
+Sometimes the platform or bridge driver needs to be notified when a control
+from a sub-device driver changes. You can set a notify callback by calling
+this function:
 
-Some ideas for future extensions to the spec:
+void v4l2_ctrl_notify(struct v4l2_ctrl *ctrl,
+	void (*notify)(struct v4l2_ctrl *ctrl, void *priv), void *priv);
 
-1) Add a V4L2_CTRL_FLAG_HEX to have values shown as hexadecimal instead of
-decimal. Useful for e.g. video_mute_yuv.
+Whenever the give control changes value the notify callback will be called
+with a pointer to the control and the priv pointer that was passed with
+v4l2_ctrl_notify. Note that the control's handler lock is held when the
+notify function is called.
 
-2) It is possible to mark in the controls array which controls have been
-successfully written and which failed by for example adding a bit to the
-control ID. Not sure if it is worth the effort, though.
+There can be only one notify function per control handler. Any attempt
+to set another notify function will cause a WARN_ON.
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index f6ee201..fa02363 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1204,6 +1204,8 @@ static void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl,
 		send_event(fh, ctrl,
 			(changed ? V4L2_EVENT_CTRL_CH_VALUE : 0) |
 			(update_inactive ? V4L2_EVENT_CTRL_CH_FLAGS : 0));
+		if (ctrl->call_notify && changed && ctrl->handler->notify)
+			ctrl->handler->notify(ctrl, ctrl->handler->notify_priv);
 	}
 }
 
@@ -2725,6 +2727,22 @@ int v4l2_ctrl_s_ctrl_int64(struct v4l2_ctrl *ctrl, s64 val)
 }
 EXPORT_SYMBOL(v4l2_ctrl_s_ctrl_int64);
 
+void v4l2_ctrl_notify(struct v4l2_ctrl *ctrl, v4l2_ctrl_notify_fnc notify, void *priv)
+{
+	if (ctrl == NULL)
+		return;
+	if (notify == NULL) {
+		ctrl->call_notify = 0;
+		return;
+	}
+	if (WARN_ON(ctrl->handler->notify && ctrl->handler->notify != notify))
+		return;
+	ctrl->handler->notify = notify;
+	ctrl->handler->notify_priv = priv;
+	ctrl->call_notify = 1;
+}
+EXPORT_SYMBOL(v4l2_ctrl_notify);
+
 static int v4l2_ctrl_add_event(struct v4l2_subscribed_event *sev, unsigned elems)
 {
 	struct v4l2_ctrl *ctrl = v4l2_ctrl_find(sev->fh->ctrl_handler, sev->id);
diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
index 9650911..c4cc041 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -53,6 +53,8 @@ struct v4l2_ctrl_ops {
 	int (*s_ctrl)(struct v4l2_ctrl *ctrl);
 };
 
+typedef void (*v4l2_ctrl_notify_fnc)(struct v4l2_ctrl *ctrl, void *priv);
+
 /** struct v4l2_ctrl - The control structure.
   * @node:	The list node.
   * @ev_subs:	The list of control event subscriptions.
@@ -72,6 +74,8 @@ struct v4l2_ctrl_ops {
   *		set this flag directly.
   * @has_volatiles: If set, then one or more members of the cluster are volatile.
   *		Drivers should never touch this flag.
+  * @call_notify: If set, then call the handler's notify function whenever the
+  *		control's value changes.
   * @manual_mode_value: If the is_auto flag is set, then this is the value
   *		of the auto control that determines if that control is in
   *		manual mode. So if the value of the auto control equals this
@@ -119,6 +123,7 @@ struct v4l2_ctrl {
 	unsigned int is_private:1;
 	unsigned int is_auto:1;
 	unsigned int has_volatiles:1;
+	unsigned int call_notify:1;
 	unsigned int manual_mode_value:8;
 
 	const struct v4l2_ctrl_ops *ops;
@@ -177,6 +182,10 @@ struct v4l2_ctrl_ref {
   *		control is needed multiple times, so this is a simple
   *		optimization.
   * @buckets:	Buckets for the hashing. Allows for quick control lookup.
+  * @notify:	A notify callback that is called whenever the control changes value.
+  *		Note that the handler's lock is held when the notify function
+  *		is called!
+  * @notify_priv: Passed as argument to the v4l2_ctrl notify callback.
   * @nr_of_buckets: Total number of buckets in the array.
   * @error:	The error code of the first failed control addition.
   */
@@ -187,6 +196,8 @@ struct v4l2_ctrl_handler {
 	struct list_head ctrl_refs;
 	struct v4l2_ctrl_ref *cached;
 	struct v4l2_ctrl_ref **buckets;
+	v4l2_ctrl_notify_fnc notify;
+	void *notify_priv;
 	u16 nr_of_buckets;
 	int error;
 };
@@ -525,6 +536,20 @@ static inline void v4l2_ctrl_unlock(struct v4l2_ctrl *ctrl)
 	mutex_unlock(ctrl->handler->lock);
 }
 
+/** v4l2_ctrl_notify() - Function to set a notify callback for a control.
+  * @ctrl:	The control.
+  * @notify:	The callback function.
+  * @priv:	The callback private handle, passed as argument to the callback.
+  *
+  * This function sets a callback function for the control. If @ctrl is NULL,
+  * then it will do nothing. If @notify is NULL, then the notify callback will
+  * be removed.
+  *
+  * There can be only one notify. If another already exists, then a WARN_ON
+  * will be issued and the function will do nothing.
+  */
+void v4l2_ctrl_notify(struct v4l2_ctrl *ctrl, v4l2_ctrl_notify_fnc notify, void *priv);
+
 /** v4l2_ctrl_g_ctrl() - Helper function to get the control's value from within a driver.
   * @ctrl:	The control.
   *
-- 
1.7.9.5


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

* [PATCH 06/15] em28xx: convert to the control framework.
  2013-01-04 20:59 [PATCH 00/15] em28xx VBI2 port and v4l2-compliance fixes Devin Heitmueller
                   ` (4 preceding siblings ...)
  2013-01-04 20:59 ` [PATCH 05/15] v4l2-ctrls: add a notify callback Devin Heitmueller
@ 2013-01-04 20:59 ` Devin Heitmueller
  2013-01-04 20:59 ` [PATCH 07/15] em28xx: convert to v4l2_fh, fix priority handling Devin Heitmueller
                   ` (9 subsequent siblings)
  15 siblings, 0 replies; 22+ messages in thread
From: Devin Heitmueller @ 2013-01-04 20:59 UTC (permalink / raw)
  To: linux-media; +Cc: Devin Heitmueller, Hans Verkuil

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Devin Heitmueller <dheitmueller@kernellabs.com>
---
 drivers/media/usb/em28xx/em28xx-cards.c |   24 +++
 drivers/media/usb/em28xx/em28xx-video.c |  248 +++----------------------------
 drivers/media/usb/em28xx/em28xx.h       |    6 +
 3 files changed, 53 insertions(+), 225 deletions(-)

diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index f5cac47..4117d38 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -2941,6 +2941,8 @@ void em28xx_release_resources(struct em28xx *dev)
 
 	em28xx_i2c_unregister(dev);
 
+	v4l2_ctrl_handler_free(&dev->ctrl_handler);
+
 	v4l2_device_unregister(&dev->v4l2_dev);
 
 	usb_put_dev(dev->udev);
@@ -2957,6 +2959,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
 			   struct usb_interface *interface,
 			   int minor)
 {
+	struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
 	int retval;
 	static const char *default_chip_name = "em28xx";
 	const char *chip_name = default_chip_name;
@@ -3084,6 +3087,9 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
 		return retval;
 	}
 
+	v4l2_ctrl_handler_init(hdl, 4);
+	dev->v4l2_dev.ctrl_handler = hdl;
+
 	/* register i2c bus */
 	retval = em28xx_i2c_register(dev);
 	if (retval < 0) {
@@ -3109,6 +3115,18 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
 			__func__, retval);
 		goto fail;
 	}
+	if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
+		v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
+			V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
+		v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
+			V4L2_CID_AUDIO_VOLUME, 0, 0x1f, 1, 0x1f);
+	} else {
+		/* install the em28xx notify callback */
+		v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_MUTE),
+				em28xx_ctrl_notify, dev);
+		v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_VOLUME),
+				em28xx_ctrl_notify, dev);
+	}
 
 	/* wake i2c devices */
 	em28xx_wake_i2c(dev);
@@ -3138,6 +3156,11 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
 		msleep(3);
 	}
 
+	v4l2_ctrl_handler_setup(&dev->ctrl_handler);
+	retval = dev->ctrl_handler.error;
+	if (retval)
+		goto fail;
+
 	retval = em28xx_register_analog_devices(dev);
 	if (retval < 0) {
 		goto fail;
@@ -3150,6 +3173,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
 
 fail:
 	em28xx_i2c_unregister(dev);
+	v4l2_ctrl_handler_free(&dev->ctrl_handler);
 
 unregister_dev:
 	v4l2_device_unregister(&dev->v4l2_dev);
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index 89cbfaf..ebbf775 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -125,30 +125,6 @@ static struct em28xx_fmt format[] = {
 	},
 };
 
-/* supported controls */
-/* Common to all boards */
-static struct v4l2_queryctrl ac97_qctrl[] = {
-	{
-		.id = V4L2_CID_AUDIO_VOLUME,
-		.type = V4L2_CTRL_TYPE_INTEGER,
-		.name = "Volume",
-		.minimum = 0x0,
-		.maximum = 0x1f,
-		.step = 0x1,
-		.default_value = 0x1f,
-		.flags = V4L2_CTRL_FLAG_SLIDER,
-	}, {
-		.id = V4L2_CID_AUDIO_MUTE,
-		.type = V4L2_CTRL_TYPE_BOOLEAN,
-		.name = "Mute",
-		.minimum = 0,
-		.maximum = 1,
-		.step = 1,
-		.default_value = 1,
-		.flags = 0,
-	}
-};
-
 /* ------------------------------------------------------------------
 	DMA and thread functions
    ------------------------------------------------------------------*/
@@ -718,76 +694,48 @@ static int get_ressource(struct em28xx_fh *fh)
 	}
 }
 
-/*
- * ac97_queryctrl()
- * return the ac97 supported controls
- */
-static int ac97_queryctrl(struct v4l2_queryctrl *qc)
+void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv)
 {
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(ac97_qctrl); i++) {
-		if (qc->id && qc->id == ac97_qctrl[i].id) {
-			memcpy(qc, &(ac97_qctrl[i]), sizeof(*qc));
-			return 0;
-		}
-	}
-
-	/* Control is not ac97 related */
-	return 1;
-}
+	struct em28xx *dev = priv;
 
-/*
- * ac97_get_ctrl()
- * return the current values for ac97 mute and volume
- */
-static int ac97_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
-{
+	/*
+	 * In the case of non-AC97 volume controls, we still need
+	 * to do some setups at em28xx, in order to mute/unmute
+	 * and to adjust audio volume. However, the value ranges
+	 * should be checked by the corresponding V4L subdriver.
+	 */
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_MUTE:
-		ctrl->value = dev->mute;
-		return 0;
+		dev->mute = ctrl->val;
+		em28xx_audio_analog_set(dev);
+		break;
 	case V4L2_CID_AUDIO_VOLUME:
-		ctrl->value = dev->volume;
-		return 0;
-	default:
-		/* Control is not ac97 related */
-		return 1;
+		dev->volume = ctrl->val;
+		em28xx_audio_analog_set(dev);
+		break;
 	}
 }
 
-/*
- * ac97_set_ctrl()
- * set values for ac97 mute and volume
- */
-static int ac97_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
+static int em28xx_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(ac97_qctrl); i++)
-		if (ctrl->id == ac97_qctrl[i].id)
-			goto handle;
-
-	/* Announce that hasn't handle it */
-	return 1;
-
-handle:
-	if (ctrl->value < ac97_qctrl[i].minimum ||
-	    ctrl->value > ac97_qctrl[i].maximum)
-		return -ERANGE;
+	struct em28xx *dev = container_of(ctrl->handler, struct em28xx, ctrl_handler);
 
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_MUTE:
-		dev->mute = ctrl->value;
+		dev->mute = ctrl->val;
 		break;
 	case V4L2_CID_AUDIO_VOLUME:
-		dev->volume = ctrl->value;
+		dev->volume = ctrl->val;
 		break;
 	}
 
 	return em28xx_audio_analog_set(dev);
 }
 
+const struct v4l2_ctrl_ops em28xx_ctrl_ops = {
+	.s_ctrl = em28xx_s_ctrl,
+};
+
 static int check_dev(struct em28xx *dev)
 {
 	if (dev->state & DEV_DISCONNECTED) {
@@ -1182,131 +1130,6 @@ static int vidioc_s_audio(struct file *file, void *priv, const struct v4l2_audio
 	return 0;
 }
 
-static int vidioc_queryctrl(struct file *file, void *priv,
-				struct v4l2_queryctrl *qc)
-{
-	struct em28xx_fh      *fh  = priv;
-	struct em28xx         *dev = fh->dev;
-	int                   id  = qc->id;
-	int                   rc;
-
-	rc = check_dev(dev);
-	if (rc < 0)
-		return rc;
-
-	memset(qc, 0, sizeof(*qc));
-
-	qc->id = id;
-
-	/* enumerate AC97 controls */
-	if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
-		rc = ac97_queryctrl(qc);
-		if (!rc)
-			return 0;
-	}
-
-	/* enumerate V4L2 device controls */
-	v4l2_device_call_all(&dev->v4l2_dev, 0, core, queryctrl, qc);
-
-	if (qc->type)
-		return 0;
-	else
-		return -EINVAL;
-}
-
-/*
- * FIXME: This is an indirect way to check if a control exists at a
- * subdev. Instead of that hack, maybe the better would be to change all
- * subdevs to return -ENOIOCTLCMD, if an ioctl is not supported.
- */
-static int check_subdev_ctrl(struct em28xx *dev, int id)
-{
-	struct v4l2_queryctrl qc;
-
-	memset(&qc, 0, sizeof(qc));
-	qc.id = id;
-
-	/* enumerate V4L2 device controls */
-	v4l2_device_call_all(&dev->v4l2_dev, 0, core, queryctrl, &qc);
-
-	if (qc.type)
-		return 0;
-	else
-		return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
-				struct v4l2_control *ctrl)
-{
-	struct em28xx_fh      *fh  = priv;
-	struct em28xx         *dev = fh->dev;
-	int                   rc;
-
-	rc = check_dev(dev);
-	if (rc < 0)
-		return rc;
-	rc = 0;
-
-	/* Set an AC97 control */
-	if (dev->audio_mode.ac97 != EM28XX_NO_AC97)
-		rc = ac97_get_ctrl(dev, ctrl);
-	else
-		rc = 1;
-
-	/* It were not an AC97 control. Sends it to the v4l2 dev interface */
-	if (rc == 1) {
-		if (check_subdev_ctrl(dev, ctrl->id))
-			return -EINVAL;
-
-		v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_ctrl, ctrl);
-		rc = 0;
-	}
-
-	return rc;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-				struct v4l2_control *ctrl)
-{
-	struct em28xx_fh      *fh  = priv;
-	struct em28xx         *dev = fh->dev;
-	int                   rc;
-
-	rc = check_dev(dev);
-	if (rc < 0)
-		return rc;
-
-	/* Set an AC97 control */
-	if (dev->audio_mode.ac97 != EM28XX_NO_AC97)
-		rc = ac97_set_ctrl(dev, ctrl);
-	else
-		rc = 1;
-
-	/* It isn't an AC97 control. Sends it to the v4l2 dev interface */
-	if (rc == 1) {
-		rc = check_subdev_ctrl(dev, ctrl->id);
-		if (!rc)
-			v4l2_device_call_all(&dev->v4l2_dev, 0,
-					     core, s_ctrl, ctrl);
-		/*
-		 * In the case of non-AC97 volume controls, we still need
-		 * to do some setups at em28xx, in order to mute/unmute
-		 * and to adjust audio volume. However, the value ranges
-		 * should be checked by the corresponding V4L subdriver.
-		 */
-		switch (ctrl->id) {
-		case V4L2_CID_AUDIO_MUTE:
-			dev->mute = ctrl->value;
-			rc = em28xx_audio_analog_set(dev);
-			break;
-		case V4L2_CID_AUDIO_VOLUME:
-			dev->volume = ctrl->value;
-			rc = em28xx_audio_analog_set(dev);
-		}
-	}
-	return (rc < 0) ? rc : 0;
-}
-
 static int vidioc_g_tuner(struct file *file, void *priv,
 				struct v4l2_tuner *t)
 {
@@ -1874,25 +1697,6 @@ static int radio_s_tuner(struct file *file, void *priv,
 	return 0;
 }
 
-static int radio_queryctrl(struct file *file, void *priv,
-			   struct v4l2_queryctrl *qc)
-{
-	int i;
-
-	if (qc->id <  V4L2_CID_BASE ||
-		qc->id >= V4L2_CID_LASTP1)
-		return -EINVAL;
-
-	for (i = 0; i < ARRAY_SIZE(ac97_qctrl); i++) {
-		if (qc->id && qc->id == ac97_qctrl[i].id) {
-			memcpy(qc, &(ac97_qctrl[i]), sizeof(*qc));
-			return 0;
-		}
-	}
-
-	return -EINVAL;
-}
-
 /*
  * em28xx_v4l2_open()
  * inits the device and starts isoc transfer
@@ -2218,9 +2022,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
 	.vidioc_enum_input          = vidioc_enum_input,
 	.vidioc_g_input             = vidioc_g_input,
 	.vidioc_s_input             = vidioc_s_input,
-	.vidioc_queryctrl           = vidioc_queryctrl,
-	.vidioc_g_ctrl              = vidioc_g_ctrl,
-	.vidioc_s_ctrl              = vidioc_s_ctrl,
 	.vidioc_streamon            = vidioc_streamon,
 	.vidioc_streamoff           = vidioc_streamoff,
 	.vidioc_g_tuner             = vidioc_g_tuner,
@@ -2254,9 +2055,6 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = {
 	.vidioc_querycap      = vidioc_querycap,
 	.vidioc_g_tuner       = radio_g_tuner,
 	.vidioc_s_tuner       = radio_s_tuner,
-	.vidioc_queryctrl     = radio_queryctrl,
-	.vidioc_g_ctrl        = vidioc_g_ctrl,
-	.vidioc_s_ctrl        = vidioc_s_ctrl,
 	.vidioc_g_frequency   = vidioc_g_frequency,
 	.vidioc_s_frequency   = vidioc_s_frequency,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -2300,7 +2098,7 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev,
 
 int em28xx_register_analog_devices(struct em28xx *dev)
 {
-      u8 val;
+	u8 val;
 	int ret;
 	unsigned int maxw;
 
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index 062841e..707319e 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -33,6 +33,7 @@
 
 #include <media/videobuf-vmalloc.h>
 #include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
 #include <media/ir-kbd-i2c.h>
 #include <media/rc-core.h>
 #if defined(CONFIG_VIDEO_EM28XX_DVB) || defined(CONFIG_VIDEO_EM28XX_DVB_MODULE)
@@ -497,6 +498,9 @@ struct em28xx {
 	int audio_ifnum;
 
 	struct v4l2_device v4l2_dev;
+	struct v4l2_ctrl_handler ctrl_handler;
+	/* provides ac97 mute and volume overrides */
+	struct v4l2_ctrl_handler ac97_ctrl_handler;
 	struct em28xx_board board;
 
 	/* Webcam specific fields */
@@ -705,6 +709,8 @@ void em28xx_close_extension(struct em28xx *dev);
 /* Provided by em28xx-video.c */
 int em28xx_register_analog_devices(struct em28xx *dev);
 void em28xx_release_analog_resources(struct em28xx *dev);
+void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv);
+extern const struct v4l2_ctrl_ops em28xx_ctrl_ops;
 
 /* Provided by em28xx-cards.c */
 extern int em2800_variant_detect(struct usb_device *udev, int model);
-- 
1.7.9.5


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

* [PATCH 07/15] em28xx: convert to v4l2_fh, fix priority handling.
  2013-01-04 20:59 [PATCH 00/15] em28xx VBI2 port and v4l2-compliance fixes Devin Heitmueller
                   ` (5 preceding siblings ...)
  2013-01-04 20:59 ` [PATCH 06/15] em28xx: convert to the control framework Devin Heitmueller
@ 2013-01-04 20:59 ` Devin Heitmueller
  2013-01-04 20:59 ` [PATCH 08/15] em28xx: add support for control events Devin Heitmueller
                   ` (8 subsequent siblings)
  15 siblings, 0 replies; 22+ messages in thread
From: Devin Heitmueller @ 2013-01-04 20:59 UTC (permalink / raw)
  To: linux-media; +Cc: Devin Heitmueller, Hans Verkuil

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Devin Heitmueller <dheitmueller@kernellabs.com>
---
 drivers/media/usb/em28xx/em28xx-video.c |    5 +++++
 drivers/media/usb/em28xx/em28xx.h       |    2 ++
 2 files changed, 7 insertions(+)

diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index ebbf775..c67ff8d 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -1735,6 +1735,7 @@ static int em28xx_v4l2_open(struct file *filp)
 		mutex_unlock(&dev->lock);
 		return -ENOMEM;
 	}
+	v4l2_fh_init(&fh->fh, vdev);
 	fh->dev = dev;
 	fh->radio = radio;
 	fh->type = fh_type;
@@ -1774,6 +1775,7 @@ static int em28xx_v4l2_open(struct file *filp)
 				    V4L2_FIELD_SEQ_TB,
 				    sizeof(struct em28xx_buffer), fh, &dev->lock);
 	mutex_unlock(&dev->lock);
+	v4l2_fh_add(&fh->fh);
 
 	return errCode;
 }
@@ -1867,6 +1869,8 @@ static int em28xx_v4l2_close(struct file *filp)
 					"0 (error=%i)\n", errCode);
 		}
 	}
+	v4l2_fh_del(&fh->fh);
+	v4l2_fh_exit(&fh->fh);
 
 	videobuf_mmap_free(&fh->vb_vidq);
 	videobuf_mmap_free(&fh->vb_vbiq);
@@ -2088,6 +2092,7 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev,
 	vfd->release	= video_device_release;
 	vfd->debug	= video_debug;
 	vfd->lock	= &dev->lock;
+	set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
 
 	snprintf(vfd->name, sizeof(vfd->name), "%s %s",
 		 dev->name, type_name);
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index 707319e..7432be4 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -34,6 +34,7 @@
 #include <media/videobuf-vmalloc.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ctrls.h>
+#include <media/v4l2-fh.h>
 #include <media/ir-kbd-i2c.h>
 #include <media/rc-core.h>
 #if defined(CONFIG_VIDEO_EM28XX_DVB) || defined(CONFIG_VIDEO_EM28XX_DVB_MODULE)
@@ -477,6 +478,7 @@ struct em28xx_audio {
 struct em28xx;
 
 struct em28xx_fh {
+	struct v4l2_fh fh;
 	struct em28xx *dev;
 	int           radio;
 	unsigned int  resources;
-- 
1.7.9.5


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

* [PATCH 08/15] em28xx: add support for control events.
  2013-01-04 20:59 [PATCH 00/15] em28xx VBI2 port and v4l2-compliance fixes Devin Heitmueller
                   ` (6 preceding siblings ...)
  2013-01-04 20:59 ` [PATCH 07/15] em28xx: convert to v4l2_fh, fix priority handling Devin Heitmueller
@ 2013-01-04 20:59 ` Devin Heitmueller
  2013-01-04 20:59 ` [PATCH 09/15] em28xx: fill in readbuffers and fix incorrect return code Devin Heitmueller
                   ` (7 subsequent siblings)
  15 siblings, 0 replies; 22+ messages in thread
From: Devin Heitmueller @ 2013-01-04 20:59 UTC (permalink / raw)
  To: linux-media; +Cc: Devin Heitmueller, Hans Verkuil

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Devin Heitmueller <dheitmueller@kernellabs.com>
---
 drivers/media/usb/em28xx/em28xx-video.c |   38 +++++++++++++++++++++----------
 1 file changed, 26 insertions(+), 12 deletions(-)

diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index c67ff8d..acdb434 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -40,6 +40,7 @@
 #include "em28xx.h"
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
 #include <media/v4l2-chip-ident.h>
 #include <media/msp3400.h>
 #include <media/tuner.h>
@@ -1927,24 +1928,33 @@ em28xx_v4l2_read(struct file *filp, char __user *buf, size_t count,
 static unsigned int em28xx_poll(struct file *filp, poll_table *wait)
 {
 	struct em28xx_fh *fh = filp->private_data;
+	unsigned long req_events = poll_requested_events(wait);
 	struct em28xx *dev = fh->dev;
+	unsigned int res = 0;
 	int rc;
 
 	rc = check_dev(dev);
 	if (rc < 0)
-		return rc;
-
-	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-		if (!res_get(fh, EM28XX_RESOURCE_VIDEO))
-			return POLLERR;
-		return videobuf_poll_stream(filp, &fh->vb_vidq, wait);
-	} else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
-		if (!res_get(fh, EM28XX_RESOURCE_VBI))
-			return POLLERR;
-		return videobuf_poll_stream(filp, &fh->vb_vbiq, wait);
-	} else {
-		return POLLERR;
+		return DEFAULT_POLLMASK;
+
+	if (v4l2_event_pending(&fh->fh))
+		res = POLLPRI;
+	else if (req_events & POLLPRI)
+		poll_wait(filp, &fh->fh.wait, wait);
+
+	if (req_events & (POLLIN | POLLRDNORM)) {
+		if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+			if (!res_get(fh, EM28XX_RESOURCE_VIDEO))
+				return res | POLLERR;
+			return videobuf_poll_stream(filp, &fh->vb_vidq, wait);
+		}
+		if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+			if (!res_get(fh, EM28XX_RESOURCE_VBI))
+				return res | POLLERR;
+			return res | videobuf_poll_stream(filp, &fh->vb_vbiq, wait);
+		}
 	}
+	return res;
 }
 
 static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table *wait)
@@ -2032,6 +2042,8 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
 	.vidioc_s_tuner             = vidioc_s_tuner,
 	.vidioc_g_frequency         = vidioc_g_frequency,
 	.vidioc_s_frequency         = vidioc_s_frequency,
+	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 	.vidioc_g_register          = vidioc_g_register,
 	.vidioc_s_register          = vidioc_s_register,
@@ -2061,6 +2073,8 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = {
 	.vidioc_s_tuner       = radio_s_tuner,
 	.vidioc_g_frequency   = vidioc_g_frequency,
 	.vidioc_s_frequency   = vidioc_s_frequency,
+	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 	.vidioc_g_register    = vidioc_g_register,
 	.vidioc_s_register    = vidioc_s_register,
-- 
1.7.9.5


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

* [PATCH 09/15] em28xx: fill in readbuffers and fix incorrect return code.
  2013-01-04 20:59 [PATCH 00/15] em28xx VBI2 port and v4l2-compliance fixes Devin Heitmueller
                   ` (7 preceding siblings ...)
  2013-01-04 20:59 ` [PATCH 08/15] em28xx: add support for control events Devin Heitmueller
@ 2013-01-04 20:59 ` Devin Heitmueller
  2013-01-04 20:59 ` [PATCH 10/15] em28xx: fix broken TRY_FMT Devin Heitmueller
                   ` (6 subsequent siblings)
  15 siblings, 0 replies; 22+ messages in thread
From: Devin Heitmueller @ 2013-01-04 20:59 UTC (permalink / raw)
  To: linux-media; +Cc: Devin Heitmueller, Hans Verkuil

g/s_parm should fill in readbuffers.
For non-webcams s_parm should return -ENOTTY instead of -EINVAL.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Devin Heitmueller <dheitmueller@kernellabs.com>
---
 drivers/media/usb/em28xx/em28xx-video.c |    4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index acdb434..a91a248 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -972,6 +972,7 @@ static int vidioc_g_parm(struct file *file, void *priv,
 	if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
 
+	p->parm.capture.readbuffers = EM28XX_MIN_BUF;
 	if (dev->board.is_webcam)
 		rc = v4l2_device_call_until_err(&dev->v4l2_dev, 0,
 						video, g_parm, p);
@@ -989,11 +990,12 @@ static int vidioc_s_parm(struct file *file, void *priv,
 	struct em28xx      *dev = fh->dev;
 
 	if (!dev->board.is_webcam)
-		return -EINVAL;
+		return -ENOTTY;
 
 	if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
 
+	p->parm.capture.readbuffers = EM28XX_MIN_BUF;
 	return v4l2_device_call_until_err(&dev->v4l2_dev, 0, video, s_parm, p);
 }
 
-- 
1.7.9.5


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

* [PATCH 10/15] em28xx: fix broken TRY_FMT.
  2013-01-04 20:59 [PATCH 00/15] em28xx VBI2 port and v4l2-compliance fixes Devin Heitmueller
                   ` (8 preceding siblings ...)
  2013-01-04 20:59 ` [PATCH 09/15] em28xx: fill in readbuffers and fix incorrect return code Devin Heitmueller
@ 2013-01-04 20:59 ` Devin Heitmueller
  2013-01-05  2:54   ` Mauro Carvalho Chehab
  2013-01-04 20:59 ` [PATCH 11/15] tvp5150: remove compat control ops Devin Heitmueller
                   ` (5 subsequent siblings)
  15 siblings, 1 reply; 22+ messages in thread
From: Devin Heitmueller @ 2013-01-04 20:59 UTC (permalink / raw)
  To: linux-media; +Cc: Devin Heitmueller, Hans Verkuil

TRY_FMT should not return an error if a pixelformat is unsupported. Instead just
pick a common pixelformat.

Also the bytesperline calculation was incorrect: it used the old width instead of
the provided with, and it miscalculated the bytesperline value for the depth == 12
case.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Devin Heitmueller <dheitmueller@kernellabs.com>
---
 drivers/media/usb/em28xx/em28xx-video.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index a91a248..7c09b55 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -821,7 +821,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
 	if (!fmt) {
 		em28xx_videodbg("Fourcc format (%08x) invalid.\n",
 				f->fmt.pix.pixelformat);
-		return -EINVAL;
+		fmt = format_by_fourcc(V4L2_PIX_FMT_YUYV);
 	}
 
 	if (dev->board.is_em2800) {
@@ -847,7 +847,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
 	f->fmt.pix.width = width;
 	f->fmt.pix.height = height;
 	f->fmt.pix.pixelformat = fmt->fourcc;
-	f->fmt.pix.bytesperline = (dev->width * fmt->depth + 7) >> 3;
+	f->fmt.pix.bytesperline = width * ((fmt->depth + 7) >> 3);
 	f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * height;
 	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
 	if (dev->progressive)
-- 
1.7.9.5


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

* [PATCH 11/15] tvp5150: remove compat control ops.
  2013-01-04 20:59 [PATCH 00/15] em28xx VBI2 port and v4l2-compliance fixes Devin Heitmueller
                   ` (9 preceding siblings ...)
  2013-01-04 20:59 ` [PATCH 10/15] em28xx: fix broken TRY_FMT Devin Heitmueller
@ 2013-01-04 20:59 ` Devin Heitmueller
  2013-01-04 20:59 ` [PATCH 12/15] em28xx: std fixes: don't implement in webcam mode, and fix std changes Devin Heitmueller
                   ` (4 subsequent siblings)
  15 siblings, 0 replies; 22+ messages in thread
From: Devin Heitmueller @ 2013-01-04 20:59 UTC (permalink / raw)
  To: linux-media; +Cc: Devin Heitmueller, Hans Verkuil

No longer needed now that em28xx has been converted to the control framework.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Devin Heitmueller <dheitmueller@kernellabs.com>
---
 drivers/media/i2c/tvp5150.c |    7 -------
 1 file changed, 7 deletions(-)

diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
index 31104a9..5967e1a0 100644
--- a/drivers/media/i2c/tvp5150.c
+++ b/drivers/media/i2c/tvp5150.c
@@ -1096,13 +1096,6 @@ static const struct v4l2_ctrl_ops tvp5150_ctrl_ops = {
 
 static const struct v4l2_subdev_core_ops tvp5150_core_ops = {
 	.log_status = tvp5150_log_status,
-	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
-	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
-	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
-	.g_ctrl = v4l2_subdev_g_ctrl,
-	.s_ctrl = v4l2_subdev_s_ctrl,
-	.queryctrl = v4l2_subdev_queryctrl,
-	.querymenu = v4l2_subdev_querymenu,
 	.s_std = tvp5150_s_std,
 	.reset = tvp5150_reset,
 	.g_chip_ident = tvp5150_g_chip_ident,
-- 
1.7.9.5


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

* [PATCH 12/15] em28xx: std fixes: don't implement in webcam mode, and fix std changes.
  2013-01-04 20:59 [PATCH 00/15] em28xx VBI2 port and v4l2-compliance fixes Devin Heitmueller
                   ` (10 preceding siblings ...)
  2013-01-04 20:59 ` [PATCH 11/15] tvp5150: remove compat control ops Devin Heitmueller
@ 2013-01-04 20:59 ` Devin Heitmueller
  2013-01-04 20:59 ` [PATCH 13/15] em28xx: remove sliced VBI support Devin Heitmueller
                   ` (3 subsequent siblings)
  15 siblings, 0 replies; 22+ messages in thread
From: Devin Heitmueller @ 2013-01-04 20:59 UTC (permalink / raw)
  To: linux-media; +Cc: Devin Heitmueller, Hans Verkuil

When in webcam mode the STD API shouldn't be implemented.

When changing the standard the resolution wasn't updated, and there was no
check against streaming-in-progress.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Devin Heitmueller <dheitmueller@kernellabs.com>
---
 drivers/media/usb/em28xx/em28xx-video.c |   25 +++++++++++++++++++++----
 1 file changed, 21 insertions(+), 4 deletions(-)

diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index 7c09b55..ae713a0 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -909,6 +909,8 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm)
 	struct em28xx      *dev = fh->dev;
 	int                rc;
 
+	if (dev->board.is_webcam)
+		return -ENOTTY;
 	rc = check_dev(dev);
 	if (rc < 0)
 		return rc;
@@ -924,6 +926,8 @@ static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *norm)
 	struct em28xx      *dev = fh->dev;
 	int                rc;
 
+	if (dev->board.is_webcam)
+		return -ENOTTY;
 	rc = check_dev(dev);
 	if (rc < 0)
 		return rc;
@@ -940,15 +944,24 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
 	struct v4l2_format f;
 	int                rc;
 
+	if (dev->board.is_webcam)
+		return -ENOTTY;
+	if (*norm == dev->norm)
+		return 0;
 	rc = check_dev(dev);
 	if (rc < 0)
 		return rc;
 
+	if (videobuf_queue_is_busy(&fh->vb_vidq)) {
+		em28xx_errdev("%s queue busy\n", __func__);
+		return -EBUSY;
+	}
+
 	dev->norm = *norm;
 
 	/* Adjusts width/height, if needed */
-	f.fmt.pix.width = dev->width;
-	f.fmt.pix.height = dev->height;
+	f.fmt.pix.width = 720;
+	f.fmt.pix.height = (*norm & V4L2_STD_525_60) ? 480 : 576;
 	vidioc_try_fmt_vid_cap(file, priv, &f);
 
 	/* set new image size */
@@ -1034,6 +1047,9 @@ static int vidioc_enum_input(struct file *file, void *priv,
 		i->type = V4L2_INPUT_TYPE_TUNER;
 
 	i->std = dev->vdev->tvnorms;
+	/* webcams do not have the STD API */
+	if (dev->board.is_webcam)
+		i->capabilities = 0;
 
 	return 0;
 }
@@ -2059,7 +2075,6 @@ static const struct video_device em28xx_video_template = {
 	.ioctl_ops 		    = &video_ioctl_ops,
 
 	.tvnorms                    = V4L2_STD_ALL,
-	.current_norm               = V4L2_STD_PAL,
 };
 
 static const struct v4l2_file_operations radio_fops = {
@@ -2109,6 +2124,8 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev,
 	vfd->debug	= video_debug;
 	vfd->lock	= &dev->lock;
 	set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
+	if (dev->board.is_webcam)
+		vfd->tvnorms = 0;
 
 	snprintf(vfd->name, sizeof(vfd->name), "%s %s",
 		 dev->name, type_name);
@@ -2127,7 +2144,7 @@ int em28xx_register_analog_devices(struct em28xx *dev)
 		dev->name, EM28XX_VERSION);
 
 	/* set default norm */
-	dev->norm = em28xx_video_template.current_norm;
+	dev->norm = V4L2_STD_PAL;
 	v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
 	dev->interlaced = EM28XX_INTERLACED_DEFAULT;
 
-- 
1.7.9.5


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

* [PATCH 13/15] em28xx: remove sliced VBI support.
  2013-01-04 20:59 [PATCH 00/15] em28xx VBI2 port and v4l2-compliance fixes Devin Heitmueller
                   ` (11 preceding siblings ...)
  2013-01-04 20:59 ` [PATCH 12/15] em28xx: std fixes: don't implement in webcam mode, and fix std changes Devin Heitmueller
@ 2013-01-04 20:59 ` Devin Heitmueller
  2013-01-04 20:59 ` [PATCH 14/15] em28xx: zero vbi_format reserved array and add try_vbi_fmt Devin Heitmueller
                   ` (2 subsequent siblings)
  15 siblings, 0 replies; 22+ messages in thread
From: Devin Heitmueller @ 2013-01-04 20:59 UTC (permalink / raw)
  To: linux-media; +Cc: Devin Heitmueller, Hans Verkuil

The sliced VBI support in the tvp5150 is completely broken. And there is no
support for the saa7115 sliced VBI implementation in the em28xx driver. So
we remove the sliced VBI support completely.

It should be possible to get it to work with the tvp5150, but that will
require someone to really dig into that driver.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Devin Heitmueller <dheitmueller@kernellabs.com>
---
 drivers/media/usb/em28xx/em28xx-video.c |   49 ++-----------------------------
 1 file changed, 2 insertions(+), 47 deletions(-)

diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index ae713a0..1514b27 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -1438,8 +1438,7 @@ static int vidioc_querycap(struct file *file, void  *priv,
 	else if (vdev->vfl_type == VFL_TYPE_RADIO)
 		cap->device_caps = V4L2_CAP_RADIO;
 	else
-		cap->device_caps = V4L2_CAP_READWRITE |
-			V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE;
+		cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_VBI_CAPTURE;
 
 	if (dev->audio_mode.has_audio)
 		cap->device_caps |= V4L2_CAP_AUDIO;
@@ -1450,8 +1449,7 @@ static int vidioc_querycap(struct file *file, void  *priv,
 	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS |
 		V4L2_CAP_READWRITE | V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
 	if (dev->vbi_dev)
-		cap->capabilities |=
-			V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE;
+		cap->capabilities |= V4L2_CAP_VBI_CAPTURE;
 	if (dev->radio_dev)
 		cap->capabilities |= V4L2_CAP_RADIO;
 	return 0;
@@ -1508,46 +1506,6 @@ static int vidioc_enum_framesizes(struct file *file, void *priv,
 	return 0;
 }
 
-/* Sliced VBI ioctls */
-static int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *priv,
-					struct v4l2_format *f)
-{
-	struct em28xx_fh      *fh  = priv;
-	struct em28xx         *dev = fh->dev;
-	int                   rc;
-
-	rc = check_dev(dev);
-	if (rc < 0)
-		return rc;
-
-	f->fmt.sliced.service_set = 0;
-	v4l2_device_call_all(&dev->v4l2_dev, 0, vbi, g_sliced_fmt, &f->fmt.sliced);
-
-	if (f->fmt.sliced.service_set == 0)
-		rc = -EINVAL;
-
-	return rc;
-}
-
-static int vidioc_try_set_sliced_vbi_cap(struct file *file, void *priv,
-			struct v4l2_format *f)
-{
-	struct em28xx_fh      *fh  = priv;
-	struct em28xx         *dev = fh->dev;
-	int                   rc;
-
-	rc = check_dev(dev);
-	if (rc < 0)
-		return rc;
-
-	v4l2_device_call_all(&dev->v4l2_dev, 0, vbi, g_sliced_fmt, &f->fmt.sliced);
-
-	if (f->fmt.sliced.service_set == 0)
-		return -EINVAL;
-
-	return 0;
-}
-
 /* RAW VBI ioctls */
 
 static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
@@ -2038,9 +1996,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
 	.vidioc_g_audio             = vidioc_g_audio,
 	.vidioc_s_audio             = vidioc_s_audio,
 	.vidioc_cropcap             = vidioc_cropcap,
-	.vidioc_g_fmt_sliced_vbi_cap   = vidioc_g_fmt_sliced_vbi_cap,
-	.vidioc_try_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap,
-	.vidioc_s_fmt_sliced_vbi_cap   = vidioc_try_set_sliced_vbi_cap,
 
 	.vidioc_reqbufs             = vidioc_reqbufs,
 	.vidioc_querybuf            = vidioc_querybuf,
-- 
1.7.9.5


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

* [PATCH 14/15] em28xx: zero vbi_format reserved array and add try_vbi_fmt.
  2013-01-04 20:59 [PATCH 00/15] em28xx VBI2 port and v4l2-compliance fixes Devin Heitmueller
                   ` (12 preceding siblings ...)
  2013-01-04 20:59 ` [PATCH 13/15] em28xx: remove sliced VBI support Devin Heitmueller
@ 2013-01-04 20:59 ` Devin Heitmueller
  2013-01-04 20:59 ` [PATCH 15/15] em28xx: convert to videobuf2 Devin Heitmueller
  2013-01-04 21:04 ` [PATCH 00/15] em28xx VBI2 port and v4l2-compliance fixes Devin Heitmueller
  15 siblings, 0 replies; 22+ messages in thread
From: Devin Heitmueller @ 2013-01-04 20:59 UTC (permalink / raw)
  To: linux-media; +Cc: Devin Heitmueller, Hans Verkuil

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Devin Heitmueller <dheitmueller@kernellabs.com>
---
 drivers/media/usb/em28xx/em28xx-video.c |    3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index 1514b27..3adaa7b 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -1521,6 +1521,7 @@ static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
 	format->fmt.vbi.sampling_rate = 6750000 * 4 / 2;
 	format->fmt.vbi.count[0] = dev->vbi_height;
 	format->fmt.vbi.count[1] = dev->vbi_height;
+	memset(format->fmt.vbi.reserved, 0, sizeof(format->fmt.vbi.reserved));
 
 	/* Varies by video standard (NTSC, PAL, etc.) */
 	if (dev->norm & V4L2_STD_525_60) {
@@ -1549,6 +1550,7 @@ static int vidioc_s_fmt_vbi_cap(struct file *file, void *priv,
 	format->fmt.vbi.sampling_rate = 6750000 * 4 / 2;
 	format->fmt.vbi.count[0] = dev->vbi_height;
 	format->fmt.vbi.count[1] = dev->vbi_height;
+	memset(format->fmt.vbi.reserved, 0, sizeof(format->fmt.vbi.reserved));
 
 	/* Varies by video standard (NTSC, PAL, etc.) */
 	if (dev->norm & V4L2_STD_525_60) {
@@ -1991,6 +1993,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
 	.vidioc_try_fmt_vid_cap     = vidioc_try_fmt_vid_cap,
 	.vidioc_s_fmt_vid_cap       = vidioc_s_fmt_vid_cap,
 	.vidioc_g_fmt_vbi_cap       = vidioc_g_fmt_vbi_cap,
+	.vidioc_try_fmt_vbi_cap     = vidioc_g_fmt_vbi_cap,
 	.vidioc_s_fmt_vbi_cap       = vidioc_s_fmt_vbi_cap,
 	.vidioc_enum_framesizes     = vidioc_enum_framesizes,
 	.vidioc_g_audio             = vidioc_g_audio,
-- 
1.7.9.5


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

* [PATCH 15/15] em28xx: convert to videobuf2
  2013-01-04 20:59 [PATCH 00/15] em28xx VBI2 port and v4l2-compliance fixes Devin Heitmueller
                   ` (13 preceding siblings ...)
  2013-01-04 20:59 ` [PATCH 14/15] em28xx: zero vbi_format reserved array and add try_vbi_fmt Devin Heitmueller
@ 2013-01-04 20:59 ` Devin Heitmueller
  2013-01-08 18:40   ` Frank Schäfer
  2013-01-04 21:04 ` [PATCH 00/15] em28xx VBI2 port and v4l2-compliance fixes Devin Heitmueller
  15 siblings, 1 reply; 22+ messages in thread
From: Devin Heitmueller @ 2013-01-04 20:59 UTC (permalink / raw)
  To: linux-media; +Cc: Devin Heitmueller

This patch converts the em28xx driver over to videobuf2.  It is
likely that em28xx_fh can go away entirely, but that will come in
a separate patch.

[mchehab@redhat.com: fix a non-trivial merge conflict with some VBI
 patches]

Signed-off-by: Devin Heitmueller <dheitmueller@kernellabs.com>
---
 drivers/media/usb/em28xx/Kconfig        |    3 +-
 drivers/media/usb/em28xx/em28xx-cards.c |    7 +-
 drivers/media/usb/em28xx/em28xx-dvb.c   |    4 +-
 drivers/media/usb/em28xx/em28xx-vbi.c   |  123 ++---
 drivers/media/usb/em28xx/em28xx-video.c |  743 +++++++++++--------------------
 drivers/media/usb/em28xx/em28xx.h       |   30 +-
 6 files changed, 327 insertions(+), 583 deletions(-)

diff --git a/drivers/media/usb/em28xx/Kconfig b/drivers/media/usb/em28xx/Kconfig
index 094c4ec..c754a80 100644
--- a/drivers/media/usb/em28xx/Kconfig
+++ b/drivers/media/usb/em28xx/Kconfig
@@ -3,7 +3,7 @@ config VIDEO_EM28XX
 	depends on VIDEO_DEV && I2C
 	select VIDEO_TUNER
 	select VIDEO_TVEEPROM
-	select VIDEOBUF_VMALLOC
+	select VIDEOBUF2_VMALLOC
 	select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT
 	select VIDEO_TVP5150 if MEDIA_SUBDRV_AUTOSELECT
 	select VIDEO_MSP3400 if MEDIA_SUBDRV_AUTOSELECT
@@ -48,7 +48,6 @@ config VIDEO_EM28XX_DVB
 	select DVB_S5H1409 if MEDIA_SUBDRV_AUTOSELECT
 	select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT
 	select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT
-	select VIDEOBUF_DVB
 	---help---
 	  This adds support for DVB cards based on the
 	  Empiatech em28xx chips.
diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index 4117d38..0a4c868 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -57,7 +57,7 @@ module_param(disable_usb_speed_check, int, 0444);
 MODULE_PARM_DESC(disable_usb_speed_check,
 		 "override min bandwidth requirement of 480M bps");
 
-static unsigned int card[]     = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
+static unsigned int card[]     = {[0 ... (EM28XX_MAXBOARDS - 1)] = -1U };
 module_param_array(card,  int, NULL, 0444);
 MODULE_PARM_DESC(card,     "card type");
 
@@ -2965,6 +2965,8 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
 	const char *chip_name = default_chip_name;
 
 	dev->udev = udev;
+	mutex_init(&dev->vb_queue_lock);
+	mutex_init(&dev->vb_vbi_queue_lock);
 	mutex_init(&dev->ctrl_urb_lock);
 	spin_lock_init(&dev->slock);
 
@@ -3411,6 +3413,9 @@ static int em28xx_usb_probe(struct usb_interface *interface,
 	/* save our data pointer in this interface device */
 	usb_set_intfdata(interface, dev);
 
+	/* initialize videobuf2 stuff */
+	em28xx_vb2_setup(dev);
+
 	/* allocate device struct */
 	mutex_init(&dev->lock);
 	mutex_lock(&dev->lock);
diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
index a70b19e..01bb800 100644
--- a/drivers/media/usb/em28xx/em28xx-dvb.c
+++ b/drivers/media/usb/em28xx/em28xx-dvb.c
@@ -27,7 +27,9 @@
 
 #include "em28xx.h"
 #include <media/v4l2-common.h>
-#include <media/videobuf-vmalloc.h>
+#include <dvb_demux.h>
+#include <dvb_net.h>
+#include <dmxdev.h>
 #include <media/tuner.h>
 #include "tuner-simple.h"
 #include <linux/gpio.h>
diff --git a/drivers/media/usb/em28xx/em28xx-vbi.c b/drivers/media/usb/em28xx/em28xx-vbi.c
index d74713b..9fcfc910 100644
--- a/drivers/media/usb/em28xx/em28xx-vbi.c
+++ b/drivers/media/usb/em28xx/em28xx-vbi.c
@@ -41,105 +41,72 @@ MODULE_PARM_DESC(vbi_debug, "enable debug messages [vbi]");
 
 /* ------------------------------------------------------------------ */
 
-static void
-free_buffer(struct videobuf_queue *vq, struct em28xx_buffer *buf)
+static int vbi_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+                           unsigned int *nbuffers, unsigned int *nplanes,
+                           unsigned int sizes[], void *alloc_ctxs[])
 {
-	struct em28xx_fh     *fh  = vq->priv_data;
-	struct em28xx        *dev = fh->dev;
-	unsigned long flags = 0;
-	if (in_interrupt())
-		BUG();
-
-	/* We used to wait for the buffer to finish here, but this didn't work
-	   because, as we were keeping the state as VIDEOBUF_QUEUED,
-	   videobuf_queue_cancel marked it as finished for us.
-	   (Also, it could wedge forever if the hardware was misconfigured.)
-
-	   This should be safe; by the time we get here, the buffer isn't
-	   queued anymore. If we ever start marking the buffers as
-	   VIDEOBUF_ACTIVE, it won't be, though.
-	*/
-	spin_lock_irqsave(&dev->slock, flags);
-	if (dev->usb_ctl.vbi_buf == buf)
-		dev->usb_ctl.vbi_buf = NULL;
-	spin_unlock_irqrestore(&dev->slock, flags);
+	struct em28xx *dev = vb2_get_drv_priv(vq);
+	unsigned long size;
 
-	videobuf_vmalloc_free(&buf->vb);
-	buf->vb.state = VIDEOBUF_NEEDS_INIT;
-}
+	if (fmt)
+		size = fmt->fmt.pix.sizeimage;
+	else
+		size = dev->vbi_width * dev->vbi_height * 2;
 
-static int
-vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
-{
-	struct em28xx_fh     *fh  = q->priv_data;
-	struct em28xx        *dev = fh->dev;
+	if (0 == *nbuffers)
+		*nbuffers = 32;
+	if (*nbuffers < 2)
+		*nbuffers = 2;
+	if (*nbuffers > 32)
+		*nbuffers = 32;
 
-	*size = dev->vbi_width * dev->vbi_height * 2;
+	*nplanes = 1;
+	sizes[0] = size;
 
-	if (0 == *count)
-		*count = vbibufs;
-	if (*count < 2)
-		*count = 2;
-	if (*count > 32)
-		*count = 32;
 	return 0;
 }
 
-static int
-vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
-	    enum v4l2_field field)
+static int vbi_buffer_prepare(struct vb2_buffer *vb)
 {
-	struct em28xx_fh     *fh  = q->priv_data;
-	struct em28xx        *dev = fh->dev;
+	struct em28xx        *dev = vb2_get_drv_priv(vb->vb2_queue);
 	struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
-	int                  rc = 0;
+	unsigned long        size;
 
-	buf->vb.size = dev->vbi_width * dev->vbi_height * 2;
+	size = dev->vbi_width * dev->vbi_height * 2;
 
-	if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
+	if (vb2_plane_size(vb, 0) < size) {
+		printk(KERN_INFO "%s data will not fit into plane (%lu < %lu)\n",
+		       __func__, vb2_plane_size(vb, 0), size);
 		return -EINVAL;
-
-	buf->vb.width  = dev->vbi_width;
-	buf->vb.height = dev->vbi_height;
-	buf->vb.field  = field;
-
-	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
-		rc = videobuf_iolock(q, &buf->vb, NULL);
-		if (rc < 0)
-			goto fail;
 	}
+	vb2_set_plane_payload(&buf->vb, 0, size);
 
-	buf->vb.state = VIDEOBUF_PREPARED;
 	return 0;
-
-fail:
-	free_buffer(q, buf);
-	return rc;
 }
 
 static void
-vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
-	struct em28xx_buffer    *buf     = container_of(vb,
-							struct em28xx_buffer,
-							vb);
-	struct em28xx_fh        *fh      = vq->priv_data;
-	struct em28xx           *dev     = fh->dev;
-	struct em28xx_dmaqueue  *vbiq    = &dev->vbiq;
-
-	buf->vb.state = VIDEOBUF_QUEUED;
-	list_add_tail(&buf->vb.queue, &vbiq->active);
-}
-
-static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+vbi_buffer_queue(struct vb2_buffer *vb)
 {
+	struct em28xx *dev = vb2_get_drv_priv(vb->vb2_queue);
 	struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
-	free_buffer(q, buf);
+	struct em28xx_dmaqueue *vbiq = &dev->vbiq;
+	unsigned long flags = 0;
+
+	buf->mem = vb2_plane_vaddr(vb, 0);
+	buf->length = vb2_plane_size(vb, 0);
+
+	spin_lock_irqsave(&dev->slock, flags);
+	list_add_tail(&buf->list, &vbiq->active);
+	spin_unlock_irqrestore(&dev->slock, flags);
 }
 
-struct videobuf_queue_ops em28xx_vbi_qops = {
-	.buf_setup    = vbi_setup,
-	.buf_prepare  = vbi_prepare,
-	.buf_queue    = vbi_queue,
-	.buf_release  = vbi_release,
+
+struct vb2_ops em28xx_vbi_qops = {
+	.queue_setup    = vbi_queue_setup,
+	.buf_prepare    = vbi_buffer_prepare,
+	.buf_queue      = vbi_buffer_queue,
+	.start_streaming = em28xx_start_analog_streaming,
+	.stop_streaming = em28xx_stop_vbi_streaming,
+	.wait_prepare   = vb2_ops_wait_prepare,
+	.wait_finish    = vb2_ops_wait_finish,
 };
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index 3adaa7b..4dbd7aa 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -76,9 +76,9 @@ MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 MODULE_VERSION(EM28XX_VERSION);
 
-static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
-static unsigned int vbi_nr[]   = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
-static unsigned int radio_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
+static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = -1U };
+static unsigned int vbi_nr[]   = {[0 ... (EM28XX_MAXBOARDS - 1)] = -1U };
+static unsigned int radio_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = -1U };
 
 module_param_array(video_nr, int, NULL, 0444);
 module_param_array(vbi_nr, int, NULL, 0444);
@@ -136,12 +136,13 @@ static struct em28xx_fmt format[] = {
 static inline void finish_buffer(struct em28xx *dev,
 				 struct em28xx_buffer *buf)
 {
-	em28xx_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i);
-	buf->vb.state = VIDEOBUF_DONE;
-	buf->vb.field_count++;
-	v4l2_get_timestamp(&buf->vb.ts);
-	list_del(&buf->vb.queue);
-	wake_up(&buf->vb.done);
+	em28xx_isocdbg("[%p/%d] wakeup\n", buf, buf->top_field);
+
+	buf->vb.v4l2_buf.sequence = dev->field_count++;
+	buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED;
+	v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
+
+	vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
 }
 
 /*
@@ -156,8 +157,8 @@ static void em28xx_copy_video(struct em28xx *dev,
 	int  linesdone, currlinedone, offset, lencopy, remain;
 	int bytesperline = dev->width << 1;
 
-	if (buf->pos + len > buf->vb.size)
-		len = buf->vb.size - buf->pos;
+	if (buf->pos + len > buf->length)
+		len = buf->length - buf->pos;
 
 	startread = usb_buf;
 	remain = len;
@@ -179,11 +180,11 @@ static void em28xx_copy_video(struct em28xx *dev,
 	lencopy = bytesperline - currlinedone;
 	lencopy = lencopy > remain ? remain : lencopy;
 
-	if ((char *)startwrite + lencopy > (char *)buf->vb_buf + buf->vb.size) {
+	if ((char *)startwrite + lencopy > (char *)buf->vb_buf + buf->length) {
 		em28xx_isocdbg("Overflow of %zi bytes past buffer end (1)\n",
 			      ((char *)startwrite + lencopy) -
-			      ((char *)buf->vb_buf + buf->vb.size));
-		remain = (char *)buf->vb_buf + buf->vb.size -
+			      ((char *)buf->vb_buf + buf->length));
+		remain = (char *)buf->vb_buf + buf->length -
 			 (char *)startwrite;
 		lencopy = remain;
 	}
@@ -205,13 +206,13 @@ static void em28xx_copy_video(struct em28xx *dev,
 			lencopy = bytesperline;
 
 		if ((char *)startwrite + lencopy > (char *)buf->vb_buf +
-		    buf->vb.size) {
+		    buf->length) {
 			em28xx_isocdbg("Overflow of %zi bytes past buffer end"
 				       "(2)\n",
 				       ((char *)startwrite + lencopy) -
-				       ((char *)buf->vb_buf + buf->vb.size));
-			lencopy = remain = (char *)buf->vb_buf + buf->vb.size -
-					   (char *)startwrite;
+				       ((char *)buf->vb_buf + buf->length));
+			lencopy = remain = (char *)buf->vb_buf + buf->length -
+				(char *)startwrite;
 		}
 		if (lencopy <= 0)
 			break;
@@ -234,8 +235,8 @@ static void em28xx_copy_vbi(struct em28xx *dev,
 {
 	unsigned int offset;
 
-	if (buf->pos + len > buf->vb.size)
-		len = buf->vb.size - buf->pos;
+	if (buf->pos + len > buf->length)
+		len = buf->length - buf->pos;
 
 	offset = buf->pos;
 	/* Make sure the bottom field populates the second half of the frame */
@@ -292,7 +293,6 @@ static inline struct em28xx_buffer *get_next_buf(struct em28xx *dev,
 						 struct em28xx_dmaqueue *dma_q)
 {
 	struct em28xx_buffer *buf;
-	char *outp;
 
 	if (list_empty(&dma_q->active)) {
 		em28xx_isocdbg("No active queue to serve\n");
@@ -300,12 +300,11 @@ static inline struct em28xx_buffer *get_next_buf(struct em28xx *dev,
 	}
 
 	/* Get the next buffer */
-	buf = list_entry(dma_q->active.next, struct em28xx_buffer, vb.queue);
+	buf = list_entry(dma_q->active.next, struct em28xx_buffer, list);
 	/* Cleans up buffer - Useful for testing for frame/URB loss */
-	outp = videobuf_to_vmalloc(&buf->vb);
-	memset(outp, 0, buf->vb.size);
+	list_del(&buf->list);
 	buf->pos = 0;
-	buf->vb_buf = outp;
+	buf->vb_buf = buf->mem;
 
 	return buf;
 }
@@ -467,92 +466,118 @@ static inline int em28xx_urb_data_copy(struct em28xx *dev, struct urb *urb)
 }
 
 
+static int get_ressource(enum v4l2_buf_type f_type)
+{
+	switch (f_type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		return EM28XX_RESOURCE_VIDEO;
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+		return EM28XX_RESOURCE_VBI;
+	default:
+		BUG();
+		return 0;
+	}
+}
+
+/* Usage lock check functions */
+static int res_get(struct em28xx *dev, enum v4l2_buf_type f_type)
+{
+	int res_type = get_ressource(f_type);
+
+	/* is it free? */
+	if (dev->resources & res_type) {
+		/* no, someone else uses it */
+		return -EBUSY;
+	}
+
+	/* it's free, grab it */
+	dev->resources |= res_type;
+	em28xx_videodbg("res: get %d\n", res_type);
+	return 0;
+}
+
+static void res_free(struct em28xx *dev, enum v4l2_buf_type f_type)
+{
+	int res_type = get_ressource(f_type);
+
+	dev->resources &= ~res_type;
+	em28xx_videodbg("res: put %d\n", res_type);
+}
+
 /* ------------------------------------------------------------------
-	Videobuf operations
+	Videobuf2 operations
    ------------------------------------------------------------------*/
 
-static int
-buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
+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 em28xx_fh *fh = vq->priv_data;
-	struct em28xx        *dev = fh->dev;
-	struct v4l2_frequency f;
-
-	*size = (fh->dev->width * fh->dev->height * dev->format->depth + 7)
-		>> 3;
+	struct em28xx *dev = vb2_get_drv_priv(vq);
+	unsigned long size;
 
-	if (0 == *count)
-		*count = EM28XX_DEF_BUF;
+	if (fmt)
+		size = fmt->fmt.pix.sizeimage;
+	else
+		size = (dev->width * dev->height * dev->format->depth + 7) >> 3;
 
-	if (*count < EM28XX_MIN_BUF)
-		*count = EM28XX_MIN_BUF;
+	if (size == 0)
+		return -EINVAL;
 
-	/* Ask tuner to go to analog or radio mode */
-	memset(&f, 0, sizeof(f));
-	f.frequency = dev->ctl_freq;
-	f.type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+	if (0 == *nbuffers)
+		*nbuffers = 32;
 
-	v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
+	*nplanes = 1;
+	sizes[0] = size;
 
 	return 0;
 }
 
-/* This is called *without* dev->slock held; please keep it that way */
-static void free_buffer(struct videobuf_queue *vq, struct em28xx_buffer *buf)
+static int
+buffer_prepare(struct vb2_buffer *vb)
 {
-	struct em28xx_fh     *fh  = vq->priv_data;
-	struct em28xx        *dev = fh->dev;
-	unsigned long flags = 0;
-	if (in_interrupt())
-		BUG();
+	struct em28xx        *dev = vb2_get_drv_priv(vb->vb2_queue);
+	struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
+	unsigned long size;
 
-	/* We used to wait for the buffer to finish here, but this didn't work
-	   because, as we were keeping the state as VIDEOBUF_QUEUED,
-	   videobuf_queue_cancel marked it as finished for us.
-	   (Also, it could wedge forever if the hardware was misconfigured.)
+	em28xx_videodbg("%s, field=%d\n", __func__, vb->v4l2_buf.field);
 
-	   This should be safe; by the time we get here, the buffer isn't
-	   queued anymore. If we ever start marking the buffers as
-	   VIDEOBUF_ACTIVE, it won't be, though.
-	*/
-	spin_lock_irqsave(&dev->slock, flags);
-	if (dev->usb_ctl.vid_buf == buf)
-		dev->usb_ctl.vid_buf = NULL;
-	spin_unlock_irqrestore(&dev->slock, flags);
+	size = (dev->width * dev->height * dev->format->depth + 7) >> 3;
 
-	videobuf_vmalloc_free(&buf->vb);
-	buf->vb.state = VIDEOBUF_NEEDS_INIT;
+	if (vb2_plane_size(vb, 0) < size) {
+		em28xx_videodbg("%s data will not fit into plane (%lu < %lu)\n",
+				__func__, vb2_plane_size(vb, 0), size);
+		return -EINVAL;
+	}
+	vb2_set_plane_payload(&buf->vb, 0, size);
+
+	return 0;
 }
 
-static int
-buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
-						enum v4l2_field field)
+int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count)
 {
-	struct em28xx_fh     *fh  = vq->priv_data;
-	struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
-	struct em28xx        *dev = fh->dev;
-	int                  rc = 0, urb_init = 0;
+	struct em28xx *dev = vb2_get_drv_priv(vq);
+	struct v4l2_frequency f;
+	int rc = 0;
 
-	buf->vb.size = (fh->dev->width * fh->dev->height * dev->format->depth
-			+ 7) >> 3;
+	em28xx_videodbg("%s\n", __func__);
 
-	if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
-		return -EINVAL;
+	/* Make sure streaming is not already in progress for this type
+	   of filehandle (e.g. video, vbi) */
+	rc = res_get(dev, vq->type);
+	if (rc)
+		return rc;
 
-	buf->vb.width  = dev->width;
-	buf->vb.height = dev->height;
-	buf->vb.field  = field;
+	if (dev->streaming_users++ == 0) {
+		/* First active streaming user, so allocate all the URBs */
 
-	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
-		rc = videobuf_iolock(vq, &buf->vb, NULL);
-		if (rc < 0)
-			goto fail;
-	}
+		/* Allocate the USB bandwidth */
+		em28xx_set_alternate(dev);
 
-	if (!dev->usb_ctl.analog_bufs.num_bufs)
-		urb_init = 1;
+		/* Needed, since GPIO might have disabled power of
+		   some i2c device
+		*/
+		em28xx_wake_i2c(dev);
 
-	if (urb_init) {
 		dev->capture_type = -1;
 		rc = em28xx_init_usb_xfer(dev, EM28XX_ANALOG_MODE,
 					  dev->analog_xfer_bulk,
@@ -562,52 +587,142 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
 					  em28xx_urb_data_copy);
 		if (rc < 0)
 			goto fail;
-	}
 
-	buf->vb.state = VIDEOBUF_PREPARED;
-	return 0;
+		/* djh: it's not clear whether this code is still needed.  I'm
+		   leaving it in here for now entirely out of concern for backward
+		   compatibility (the old code did it) */
+
+		/* Ask tuner to go to analog or radio mode */
+		memset(&f, 0, sizeof(f));
+		f.frequency = dev->ctl_freq;
+		if (vq->owner && vq->owner->vdev->vfl_type == VFL_TYPE_RADIO)
+			f.type = V4L2_TUNER_RADIO;
+		else
+			f.type = V4L2_TUNER_ANALOG_TV;
+		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
+	}
 
 fail:
-	free_buffer(vq, buf);
 	return rc;
 }
 
-static void
-buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+int em28xx_stop_streaming(struct vb2_queue *vq)
 {
-	struct em28xx_buffer    *buf     = container_of(vb,
-							struct em28xx_buffer,
-							vb);
-	struct em28xx_fh        *fh      = vq->priv_data;
-	struct em28xx           *dev     = fh->dev;
-	struct em28xx_dmaqueue  *vidq    = &dev->vidq;
+	struct em28xx *dev = vb2_get_drv_priv(vq);
+	struct em28xx_dmaqueue *vidq = &dev->vidq;
+	unsigned long flags = 0;
+
+	em28xx_videodbg("%s\n", __func__);
+
+	res_free(dev, vq->type);
 
-	buf->vb.state = VIDEOBUF_QUEUED;
-	list_add_tail(&buf->vb.queue, &vidq->active);
+	if (dev->streaming_users-- == 1) {
+		/* Last active user, so shutdown all the URBS */
+		em28xx_uninit_usb_xfer(dev, EM28XX_ANALOG_MODE);
+	}
 
+	spin_lock_irqsave(&dev->slock, flags);
+	while (!list_empty(&vidq->active)) {
+		struct em28xx_buffer *buf;
+		buf = list_entry(vidq->active.next, struct em28xx_buffer, list);
+		list_del(&buf->list);
+		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+	}
+	dev->usb_ctl.vid_buf = NULL;
+	spin_unlock_irqrestore(&dev->slock, flags);
+
+	return 0;
 }
 
-static void buffer_release(struct videobuf_queue *vq,
-				struct videobuf_buffer *vb)
+int em28xx_stop_vbi_streaming(struct vb2_queue *vq)
 {
-	struct em28xx_buffer   *buf  = container_of(vb,
-						    struct em28xx_buffer,
-						    vb);
-	struct em28xx_fh       *fh   = vq->priv_data;
-	struct em28xx          *dev  = (struct em28xx *)fh->dev;
+	struct em28xx *dev = vb2_get_drv_priv(vq);
+	struct em28xx_dmaqueue *vbiq = &dev->vbiq;
+	unsigned long flags = 0;
+
+	em28xx_videodbg("%s\n", __func__);
 
-	em28xx_isocdbg("em28xx: called buffer_release\n");
+	res_free(dev, vq->type);
 
-	free_buffer(vq, buf);
+	if (dev->streaming_users-- == 1) {
+		/* Last active user, so shutdown all the URBS */
+		em28xx_uninit_usb_xfer(dev, EM28XX_ANALOG_MODE);
+	}
+
+	spin_lock_irqsave(&dev->slock, flags);
+	while (!list_empty(&vbiq->active)) {
+		struct em28xx_buffer *buf;
+		buf = list_entry(vbiq->active.next, struct em28xx_buffer, list);
+		list_del(&buf->list);
+		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+	}
+	dev->usb_ctl.vbi_buf = NULL;
+	spin_unlock_irqrestore(&dev->slock, flags);
+
+	return 0;
 }
 
-static struct videobuf_queue_ops em28xx_video_qops = {
-	.buf_setup      = buffer_setup,
+static void
+buffer_queue(struct vb2_buffer *vb)
+{
+	struct em28xx *dev = vb2_get_drv_priv(vb->vb2_queue);
+	struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
+	struct em28xx_dmaqueue *vidq = &dev->vidq;
+	unsigned long flags = 0;
+
+	em28xx_videodbg("%s\n", __func__);
+	buf->mem = vb2_plane_vaddr(vb, 0);
+	buf->length = vb2_plane_size(vb, 0);
+
+	spin_lock_irqsave(&dev->slock, flags);
+	list_add_tail(&buf->list, &vidq->active);
+	spin_unlock_irqrestore(&dev->slock, flags);
+}
+
+static struct vb2_ops em28xx_video_qops = {
+	.queue_setup    = queue_setup,
 	.buf_prepare    = buffer_prepare,
 	.buf_queue      = buffer_queue,
-	.buf_release    = buffer_release,
+	.start_streaming = em28xx_start_analog_streaming,
+	.stop_streaming = em28xx_stop_streaming,
+	.wait_prepare   = vb2_ops_wait_prepare,
+	.wait_finish    = vb2_ops_wait_finish,
 };
 
+int em28xx_vb2_setup(struct em28xx *dev)
+{
+	int rc;
+	struct vb2_queue *q;
+
+	/* Setup Videobuf2 for Video capture */
+	q = &dev->vb_vidq;
+	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	q->io_modes = VB2_READ | VB2_MMAP | VB2_USERPTR;
+	q->drv_priv = dev;
+	q->buf_struct_size = sizeof(struct em28xx_buffer);
+	q->ops = &em28xx_video_qops;
+	q->mem_ops = &vb2_vmalloc_memops;
+
+	rc = vb2_queue_init(q);
+	if (rc < 0)
+		return rc;
+
+	/* Setup Videobuf2 for VBI capture */
+	q = &dev->vb_vbiq;
+	q->type = V4L2_BUF_TYPE_VBI_CAPTURE;
+	q->io_modes = VB2_READ | VB2_MMAP | VB2_USERPTR;
+	q->drv_priv = dev;
+	q->buf_struct_size = sizeof(struct em28xx_buffer);
+	q->ops = &em28xx_vbi_qops;
+	q->mem_ops = &vb2_vmalloc_memops;
+
+	rc = vb2_queue_init(q);
+	if (rc < 0)
+		return rc;
+
+	return 0;
+}
+
 /*********************  v4l2 interface  **************************************/
 
 static void video_mux(struct em28xx *dev, int index)
@@ -640,61 +755,6 @@ static void video_mux(struct em28xx *dev, int index)
 	em28xx_audio_analog_set(dev);
 }
 
-/* Usage lock check functions */
-static int res_get(struct em28xx_fh *fh, unsigned int bit)
-{
-	struct em28xx    *dev = fh->dev;
-
-	if (fh->resources & bit)
-		/* have it already allocated */
-		return 1;
-
-	/* is it free? */
-	if (dev->resources & bit) {
-		/* no, someone else uses it */
-		return 0;
-	}
-	/* it's free, grab it */
-	fh->resources  |= bit;
-	dev->resources |= bit;
-	em28xx_videodbg("res: get %d\n", bit);
-	return 1;
-}
-
-static int res_check(struct em28xx_fh *fh, unsigned int bit)
-{
-	return fh->resources & bit;
-}
-
-static int res_locked(struct em28xx *dev, unsigned int bit)
-{
-	return dev->resources & bit;
-}
-
-static void res_free(struct em28xx_fh *fh, unsigned int bits)
-{
-	struct em28xx    *dev = fh->dev;
-
-	BUG_ON((fh->resources & bits) != bits);
-
-	fh->resources  &= ~bits;
-	dev->resources &= ~bits;
-	em28xx_videodbg("res: put %d\n", bits);
-}
-
-static int get_ressource(struct em28xx_fh *fh)
-{
-	switch (fh->type) {
-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		return EM28XX_RESOURCE_VIDEO;
-	case V4L2_BUF_TYPE_VBI_CAPTURE:
-		return EM28XX_RESOURCE_VBI;
-	default:
-		BUG();
-		return 0;
-	}
-}
-
 void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv)
 {
 	struct em28xx *dev = priv;
@@ -875,7 +935,6 @@ static int em28xx_set_video_format(struct em28xx *dev, unsigned int fourcc,
 	/* set new image size */
 	get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
 
-	em28xx_set_alternate(dev);
 	em28xx_resolution_set(dev);
 
 	return 0;
@@ -884,21 +943,13 @@ static int em28xx_set_video_format(struct em28xx *dev, unsigned int fourcc,
 static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
 			struct v4l2_format *f)
 {
-	struct em28xx_fh      *fh  = priv;
-	struct em28xx         *dev = fh->dev;
-	int                   rc;
+	struct em28xx *dev = video_drvdata(file);
 
-	rc = check_dev(dev);
-	if (rc < 0)
-		return rc;
+	if (dev->streaming_users > 0)
+		return -EBUSY;
 
 	vidioc_try_fmt_vid_cap(file, priv, f);
 
-	if (videobuf_queue_is_busy(&fh->vb_vidq)) {
-		em28xx_errdev("%s queue busy\n", __func__);
-		return -EBUSY;
-	}
-
 	return em28xx_set_video_format(dev, f->fmt.pix.pixelformat,
 				f->fmt.pix.width, f->fmt.pix.height);
 }
@@ -952,10 +1003,8 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
 	if (rc < 0)
 		return rc;
 
-	if (videobuf_queue_is_busy(&fh->vb_vidq)) {
-		em28xx_errdev("%s queue busy\n", __func__);
+	if (dev->streaming_users > 0)
 		return -EBUSY;
-	}
 
 	dev->norm = *norm;
 
@@ -1358,69 +1407,6 @@ static int vidioc_cropcap(struct file *file, void *priv,
 	return 0;
 }
 
-static int vidioc_streamon(struct file *file, void *priv,
-					enum v4l2_buf_type type)
-{
-	struct em28xx_fh      *fh  = priv;
-	struct em28xx         *dev = fh->dev;
-	int                   rc = -EINVAL;
-
-	rc = check_dev(dev);
-	if (rc < 0)
-		return rc;
-
-	if (unlikely(type != fh->type))
-		return -EINVAL;
-
-	em28xx_videodbg("vidioc_streamon fh=%p t=%d fh->res=%d dev->res=%d\n",
-			fh, type, fh->resources, dev->resources);
-
-	if (unlikely(!res_get(fh, get_ressource(fh))))
-		return -EBUSY;
-
-	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		rc = videobuf_streamon(&fh->vb_vidq);
-	else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
-		rc = videobuf_streamon(&fh->vb_vbiq);
-
-	return rc;
-}
-
-static int vidioc_streamoff(struct file *file, void *priv,
-					enum v4l2_buf_type type)
-{
-	struct em28xx_fh      *fh  = priv;
-	struct em28xx         *dev = fh->dev;
-	int                   rc;
-
-	rc = check_dev(dev);
-	if (rc < 0)
-		return rc;
-
-	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
-	    fh->type != V4L2_BUF_TYPE_VBI_CAPTURE)
-		return -EINVAL;
-	if (type != fh->type)
-		return -EINVAL;
-
-	em28xx_videodbg("vidioc_streamoff fh=%p t=%d fh->res=%d dev->res=%d\n",
-			fh, type, fh->resources, dev->resources);
-
-	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-		if (res_check(fh, EM28XX_RESOURCE_VIDEO)) {
-			videobuf_streamoff(&fh->vb_vidq);
-			res_free(fh, EM28XX_RESOURCE_VIDEO);
-		}
-	} else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
-		if (res_check(fh, EM28XX_RESOURCE_VBI)) {
-			videobuf_streamoff(&fh->vb_vbiq);
-			res_free(fh, EM28XX_RESOURCE_VBI);
-		}
-	}
-
-	return 0;
-}
-
 static int vidioc_querycap(struct file *file, void  *priv,
 					struct v4l2_capability *cap)
 {
@@ -1566,83 +1552,6 @@ static int vidioc_s_fmt_vbi_cap(struct file *file, void *priv,
 	return 0;
 }
 
-static int vidioc_reqbufs(struct file *file, void *priv,
-			  struct v4l2_requestbuffers *rb)
-{
-	struct em28xx_fh      *fh  = priv;
-	struct em28xx         *dev = fh->dev;
-	int                   rc;
-
-	rc = check_dev(dev);
-	if (rc < 0)
-		return rc;
-
-	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		return videobuf_reqbufs(&fh->vb_vidq, rb);
-	else
-		return videobuf_reqbufs(&fh->vb_vbiq, rb);
-}
-
-static int vidioc_querybuf(struct file *file, void *priv,
-			   struct v4l2_buffer *b)
-{
-	struct em28xx_fh      *fh  = priv;
-	struct em28xx         *dev = fh->dev;
-	int                   rc;
-
-	rc = check_dev(dev);
-	if (rc < 0)
-		return rc;
-
-	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		return videobuf_querybuf(&fh->vb_vidq, b);
-	else {
-		/* FIXME: I'm not sure yet whether this is a bug in zvbi or
-		   the videobuf framework, but we probably shouldn't be
-		   returning a buffer larger than that which was asked for.
-		   At a minimum, it causes a crash in zvbi since it does
-		   a memcpy based on the source buffer length */
-		int result = videobuf_querybuf(&fh->vb_vbiq, b);
-		b->length = dev->vbi_width * dev->vbi_height * 2;
-
-		return result;
-	}
-}
-
-static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
-{
-	struct em28xx_fh      *fh  = priv;
-	struct em28xx         *dev = fh->dev;
-	int                   rc;
-
-	rc = check_dev(dev);
-	if (rc < 0)
-		return rc;
-
-	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		return videobuf_qbuf(&fh->vb_vidq, b);
-	else
-		return videobuf_qbuf(&fh->vb_vbiq, b);
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
-{
-	struct em28xx_fh      *fh  = priv;
-	struct em28xx         *dev = fh->dev;
-	int                   rc;
-
-	rc = check_dev(dev);
-	if (rc < 0)
-		return rc;
-
-	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags &
-				      O_NONBLOCK);
-	else
-		return videobuf_dqbuf(&fh->vb_vbiq, b, file->f_flags &
-				      O_NONBLOCK);
-}
-
 /* ----------------------------------------------------------- */
 /* RADIO ESPECIFIC IOCTLS                                      */
 /* ----------------------------------------------------------- */
@@ -1682,12 +1591,10 @@ static int radio_s_tuner(struct file *file, void *priv,
  */
 static int em28xx_v4l2_open(struct file *filp)
 {
-	int errCode = 0, radio = 0;
 	struct video_device *vdev = video_devdata(filp);
 	struct em28xx *dev = video_drvdata(filp);
 	enum v4l2_buf_type fh_type = 0;
 	struct em28xx_fh *fh;
-	enum v4l2_field field;
 
 	switch (vdev->vfl_type) {
 	case VFL_TYPE_GRABBER:
@@ -1696,9 +1603,6 @@ static int em28xx_v4l2_open(struct file *filp)
 	case VFL_TYPE_VBI:
 		fh_type = V4L2_BUF_TYPE_VBI_CAPTURE;
 		break;
-	case VFL_TYPE_RADIO:
-		radio = 1;
-		break;
 	}
 
 	em28xx_videodbg("open dev=%s type=%s users=%d\n",
@@ -1716,13 +1620,11 @@ static int em28xx_v4l2_open(struct file *filp)
 	}
 	v4l2_fh_init(&fh->fh, vdev);
 	fh->dev = dev;
-	fh->radio = radio;
 	fh->type = fh_type;
 	filp->private_data = fh;
 
 	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
 		em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
-		em28xx_set_alternate(dev);
 		em28xx_resolution_set(dev);
 
 		/* Needed, since GPIO might have disabled power of
@@ -1731,32 +1633,18 @@ static int em28xx_v4l2_open(struct file *filp)
 		em28xx_wake_i2c(dev);
 
 	}
-	if (fh->radio) {
+
+	if (vdev->vfl_type == VFL_TYPE_RADIO) {
 		em28xx_videodbg("video_open: setting radio device\n");
 		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_radio);
 	}
 
 	dev->users++;
 
-	if (dev->progressive)
-		field = V4L2_FIELD_NONE;
-	else
-		field = V4L2_FIELD_INTERLACED;
-
-	videobuf_queue_vmalloc_init(&fh->vb_vidq, &em28xx_video_qops,
-				    NULL, &dev->slock,
-				    V4L2_BUF_TYPE_VIDEO_CAPTURE, field,
-				    sizeof(struct em28xx_buffer), fh, &dev->lock);
-
-	videobuf_queue_vmalloc_init(&fh->vb_vbiq, &em28xx_vbi_qops,
-				    NULL, &dev->slock,
-				    V4L2_BUF_TYPE_VBI_CAPTURE,
-				    V4L2_FIELD_SEQ_TB,
-				    sizeof(struct em28xx_buffer), fh, &dev->lock);
 	mutex_unlock(&dev->lock);
 	v4l2_fh_add(&fh->fh);
 
-	return errCode;
+	return 0;
 }
 
 /*
@@ -1810,15 +1698,7 @@ static int em28xx_v4l2_close(struct file *filp)
 	em28xx_videodbg("users=%d\n", dev->users);
 
 	mutex_lock(&dev->lock);
-	if (res_check(fh, EM28XX_RESOURCE_VIDEO)) {
-		videobuf_stop(&fh->vb_vidq);
-		res_free(fh, EM28XX_RESOURCE_VIDEO);
-	}
-
-	if (res_check(fh, EM28XX_RESOURCE_VBI)) {
-		videobuf_stop(&fh->vb_vbiq);
-		res_free(fh, EM28XX_RESOURCE_VBI);
-	}
+	vb2_fop_release(filp);
 
 	if (dev->users == 1) {
 		/* the device is already disconnect,
@@ -1828,7 +1708,6 @@ static int em28xx_v4l2_close(struct file *filp)
 			kfree(dev->alt_max_pkt_size_isoc);
 			mutex_unlock(&dev->lock);
 			kfree(dev);
-			kfree(fh);
 			return 0;
 		}
 
@@ -1836,7 +1715,6 @@ static int em28xx_v4l2_close(struct file *filp)
 		v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
 
 		/* do this before setting alternate! */
-		em28xx_uninit_usb_xfer(dev, EM28XX_ANALOG_MODE);
 		em28xx_set_mode(dev, EM28XX_SUSPEND);
 
 		/* set alternate 0 */
@@ -1848,141 +1726,19 @@ static int em28xx_v4l2_close(struct file *filp)
 					"0 (error=%i)\n", errCode);
 		}
 	}
-	v4l2_fh_del(&fh->fh);
-	v4l2_fh_exit(&fh->fh);
 
-	videobuf_mmap_free(&fh->vb_vidq);
-	videobuf_mmap_free(&fh->vb_vbiq);
-	kfree(fh);
 	dev->users--;
 	mutex_unlock(&dev->lock);
 	return 0;
 }
 
-/*
- * em28xx_v4l2_read()
- * will allocate buffers when called for the first time
- */
-static ssize_t
-em28xx_v4l2_read(struct file *filp, char __user *buf, size_t count,
-		 loff_t *pos)
-{
-	struct em28xx_fh *fh = filp->private_data;
-	struct em28xx *dev = fh->dev;
-	int rc;
-
-	rc = check_dev(dev);
-	if (rc < 0)
-		return rc;
-
-	if (mutex_lock_interruptible(&dev->lock))
-		return -ERESTARTSYS;
-	/* FIXME: read() is not prepared to allow changing the video
-	   resolution while streaming. Seems a bug at em28xx_set_fmt
-	 */
-
-	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-		if (res_locked(dev, EM28XX_RESOURCE_VIDEO))
-			rc = -EBUSY;
-		else
-			rc = videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0,
-					filp->f_flags & O_NONBLOCK);
-	} else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
-		if (!res_get(fh, EM28XX_RESOURCE_VBI))
-			rc = -EBUSY;
-		else
-			rc = videobuf_read_stream(&fh->vb_vbiq, buf, count, pos, 0,
-					filp->f_flags & O_NONBLOCK);
-	}
-	mutex_unlock(&dev->lock);
-
-	return rc;
-}
-
-/*
- * em28xx_poll()
- * will allocate buffers when called for the first time
- */
-static unsigned int em28xx_poll(struct file *filp, poll_table *wait)
-{
-	struct em28xx_fh *fh = filp->private_data;
-	unsigned long req_events = poll_requested_events(wait);
-	struct em28xx *dev = fh->dev;
-	unsigned int res = 0;
-	int rc;
-
-	rc = check_dev(dev);
-	if (rc < 0)
-		return DEFAULT_POLLMASK;
-
-	if (v4l2_event_pending(&fh->fh))
-		res = POLLPRI;
-	else if (req_events & POLLPRI)
-		poll_wait(filp, &fh->fh.wait, wait);
-
-	if (req_events & (POLLIN | POLLRDNORM)) {
-		if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-			if (!res_get(fh, EM28XX_RESOURCE_VIDEO))
-				return res | POLLERR;
-			return videobuf_poll_stream(filp, &fh->vb_vidq, wait);
-		}
-		if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
-			if (!res_get(fh, EM28XX_RESOURCE_VBI))
-				return res | POLLERR;
-			return res | videobuf_poll_stream(filp, &fh->vb_vbiq, wait);
-		}
-	}
-	return res;
-}
-
-static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table *wait)
-{
-	struct em28xx_fh *fh = filp->private_data;
-	struct em28xx *dev = fh->dev;
-	unsigned int res;
-
-	mutex_lock(&dev->lock);
-	res = em28xx_poll(filp, wait);
-	mutex_unlock(&dev->lock);
-	return res;
-}
-
-/*
- * em28xx_v4l2_mmap()
- */
-static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
-{
-	struct em28xx_fh *fh    = filp->private_data;
-	struct em28xx	 *dev   = fh->dev;
-	int		 rc;
-
-	rc = check_dev(dev);
-	if (rc < 0)
-		return rc;
-
-	if (mutex_lock_interruptible(&dev->lock))
-		return -ERESTARTSYS;
-	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
-	else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
-		rc = videobuf_mmap_mapper(&fh->vb_vbiq, vma);
-	mutex_unlock(&dev->lock);
-
-	em28xx_videodbg("vma start=0x%08lx, size=%ld, ret=%d\n",
-		(unsigned long)vma->vm_start,
-		(unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
-		rc);
-
-	return rc;
-}
-
 static const struct v4l2_file_operations em28xx_v4l_fops = {
 	.owner         = THIS_MODULE,
 	.open          = em28xx_v4l2_open,
 	.release       = em28xx_v4l2_close,
-	.read          = em28xx_v4l2_read,
-	.poll          = em28xx_v4l2_poll,
-	.mmap          = em28xx_v4l2_mmap,
+	.read          = vb2_fop_read,
+	.poll          = vb2_fop_poll,
+	.mmap          = vb2_fop_mmap,
 	.unlocked_ioctl = video_ioctl2,
 };
 
@@ -2000,10 +1756,13 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
 	.vidioc_s_audio             = vidioc_s_audio,
 	.vidioc_cropcap             = vidioc_cropcap,
 
-	.vidioc_reqbufs             = vidioc_reqbufs,
-	.vidioc_querybuf            = vidioc_querybuf,
-	.vidioc_qbuf                = vidioc_qbuf,
-	.vidioc_dqbuf               = vidioc_dqbuf,
+	.vidioc_reqbufs             = vb2_ioctl_reqbufs,
+	.vidioc_create_bufs         = vb2_ioctl_create_bufs,
+	.vidioc_prepare_buf         = vb2_ioctl_prepare_buf,
+	.vidioc_querybuf            = vb2_ioctl_querybuf,
+	.vidioc_qbuf                = vb2_ioctl_qbuf,
+	.vidioc_dqbuf               = vb2_ioctl_dqbuf,
+
 	.vidioc_g_std               = vidioc_g_std,
 	.vidioc_querystd            = vidioc_querystd,
 	.vidioc_s_std               = vidioc_s_std,
@@ -2012,8 +1771,8 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
 	.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_g_tuner             = vidioc_g_tuner,
 	.vidioc_s_tuner             = vidioc_s_tuner,
 	.vidioc_g_frequency         = vidioc_g_frequency,
@@ -2029,7 +1788,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
 
 static const struct video_device em28xx_video_template = {
 	.fops                       = &em28xx_v4l_fops,
-	.release                    = video_device_release,
+	.release                    = video_device_release_empty,
 	.ioctl_ops 		    = &video_ioctl_ops,
 
 	.tvnorms                    = V4L2_STD_ALL,
@@ -2078,7 +1837,6 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev,
 
 	*vfd		= *template;
 	vfd->v4l2_dev	= &dev->v4l2_dev;
-	vfd->release	= video_device_release;
 	vfd->debug	= video_debug;
 	vfd->lock	= &dev->lock;
 	set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
@@ -2139,6 +1897,8 @@ int em28xx_register_analog_devices(struct em28xx *dev)
 		em28xx_errdev("cannot allocate video_device.\n");
 		return -ENODEV;
 	}
+	dev->vdev->queue = &dev->vb_vidq;
+	dev->vdev->queue->lock = &dev->vb_queue_lock;
 
 	/* register v4l2 video video_device */
 	ret = video_register_device(dev->vdev, VFL_TYPE_GRABBER,
@@ -2154,6 +1914,9 @@ int em28xx_register_analog_devices(struct em28xx *dev)
 		dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template,
 						"vbi");
 
+		dev->vbi_dev->queue = &dev->vb_vbiq;
+		dev->vbi_dev->queue->lock = &dev->vb_vbi_queue_lock;
+
 		/* register v4l2 vbi video_device */
 		ret = video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
 					    vbi_nr[dev->devno]);
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index 7432be4..bf0a790 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -31,15 +31,12 @@
 #include <linux/mutex.h>
 #include <linux/videodev2.h>
 
-#include <media/videobuf-vmalloc.h>
+#include <media/videobuf2-vmalloc.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-fh.h>
 #include <media/ir-kbd-i2c.h>
 #include <media/rc-core.h>
-#if defined(CONFIG_VIDEO_EM28XX_DVB) || defined(CONFIG_VIDEO_EM28XX_DVB_MODULE)
-#include <media/videobuf-dvb.h>
-#endif
 #include "tuner-xc2028.h"
 #include "xc5000.h"
 #include "em28xx-reg.h"
@@ -252,8 +249,11 @@ struct em28xx_fmt {
 /* buffer for one video frame */
 struct em28xx_buffer {
 	/* common v4l buffer stuff -- must be first */
-	struct videobuf_buffer vb;
+	struct vb2_buffer vb;
+	struct list_head list;
 
+	void *mem;
+	unsigned int length;
 	int top_field;
 
 	/* counter to control buffer fill */
@@ -480,11 +480,6 @@ struct em28xx;
 struct em28xx_fh {
 	struct v4l2_fh fh;
 	struct em28xx *dev;
-	int           radio;
-	unsigned int  resources;
-
-	struct videobuf_queue        vb_vidq;
-	struct videobuf_queue        vb_vbiq;
 
 	enum v4l2_buf_type           type;
 };
@@ -545,6 +540,7 @@ struct em28xx {
 	struct i2c_client i2c_client;
 	/* video for linux */
 	int users;		/* user count for exclusive use */
+	int streaming_users;    /* Number of actively streaming users */
 	struct video_device *vdev;	/* video for linux device struct */
 	v4l2_std_id norm;	/* selected tv norm */
 	int ctl_freq;		/* selected frequency */
@@ -587,6 +583,12 @@ struct em28xx {
 	struct video_device *vbi_dev;
 	struct video_device *radio_dev;
 
+	/* Videobuf2 */
+	struct vb2_queue vb_vidq;
+	struct vb2_queue vb_vbiq;
+	struct mutex vb_queue_lock;
+	struct mutex vb_vbi_queue_lock;
+
 	/* resources in use */
 	unsigned int resources;
 
@@ -598,6 +600,9 @@ struct em28xx {
 	struct em28xx_usb_ctl usb_ctl;
 	spinlock_t slock;
 
+	unsigned int field_count;
+	unsigned int vbi_field_count;
+
 	/* usb transfer */
 	struct usb_device *udev;	/* the usb device */
 	u8 analog_ep_isoc;	/* address of isoc endpoint for analog */
@@ -709,9 +714,12 @@ void em28xx_init_extension(struct em28xx *dev);
 void em28xx_close_extension(struct em28xx *dev);
 
 /* Provided by em28xx-video.c */
+int em28xx_vb2_setup(struct em28xx *dev);
 int em28xx_register_analog_devices(struct em28xx *dev);
 void em28xx_release_analog_resources(struct em28xx *dev);
 void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv);
+int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count);
+int em28xx_stop_vbi_streaming(struct vb2_queue *vq);
 extern const struct v4l2_ctrl_ops em28xx_ctrl_ops;
 
 /* Provided by em28xx-cards.c */
@@ -723,7 +731,7 @@ int em28xx_tuner_callback(void *ptr, int component, int command, int arg);
 void em28xx_release_resources(struct em28xx *dev);
 
 /* Provided by em28xx-vbi.c */
-extern struct videobuf_queue_ops em28xx_vbi_qops;
+extern struct vb2_ops em28xx_vbi_qops;
 
 /* printk macros */
 
-- 
1.7.9.5


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

* Re: [PATCH 00/15] em28xx VBI2 port and v4l2-compliance fixes
  2013-01-04 20:59 [PATCH 00/15] em28xx VBI2 port and v4l2-compliance fixes Devin Heitmueller
                   ` (14 preceding siblings ...)
  2013-01-04 20:59 ` [PATCH 15/15] em28xx: convert to videobuf2 Devin Heitmueller
@ 2013-01-04 21:04 ` Devin Heitmueller
  15 siblings, 0 replies; 22+ messages in thread
From: Devin Heitmueller @ 2013-01-04 21:04 UTC (permalink / raw)
  To: linux-media

On Fri, Jan 4, 2013 at 3:59 PM, Devin Heitmueller
<dheitmueller@kernellabs.com> wrote:
> This patch series converts the em28xx driver to videobuf2 and fixes
> a number of issues found with v4l2-compliance on em28xx.

There was a typo on my part.  It's VB2 (videobuf2), not VBI2.

Devin

-- 
Devin J. Heitmueller - Kernel Labs
http://www.kernellabs.com

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

* Re: [PATCH 10/15] em28xx: fix broken TRY_FMT.
  2013-01-04 20:59 ` [PATCH 10/15] em28xx: fix broken TRY_FMT Devin Heitmueller
@ 2013-01-05  2:54   ` Mauro Carvalho Chehab
  2013-01-05 13:34     ` Hans Verkuil
  0 siblings, 1 reply; 22+ messages in thread
From: Mauro Carvalho Chehab @ 2013-01-05  2:54 UTC (permalink / raw)
  To: Devin Heitmueller, Hans Verkuil; +Cc: linux-media

Hans/Devin,

Em Fri,  4 Jan 2013 15:59:40 -0500
Devin Heitmueller <dheitmueller@kernellabs.com> escreveu:

> TRY_FMT should not return an error if a pixelformat is unsupported. Instead just
> pick a common pixelformat.
> 
> Also the bytesperline calculation was incorrect: it used the old width instead of
> the provided with, and it miscalculated the bytesperline value for the depth == 12
> case.
> 
> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
> Signed-off-by: Devin Heitmueller <dheitmueller@kernellabs.com>
> ---
>  drivers/media/usb/em28xx/em28xx-video.c |    4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
> index a91a248..7c09b55 100644
> --- a/drivers/media/usb/em28xx/em28xx-video.c
> +++ b/drivers/media/usb/em28xx/em28xx-video.c
> @@ -821,7 +821,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
>  	if (!fmt) {
>  		em28xx_videodbg("Fourcc format (%08x) invalid.\n",
>  				f->fmt.pix.pixelformat);
> -		return -EINVAL;
> +		fmt = format_by_fourcc(V4L2_PIX_FMT_YUYV);

This change has the potential of causing userspace regressions, so,
for now, I won't apply such change.

We need to discuss it better, before risk breaking things, and likely fix
applications first.

Regards,
Mauro

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

* Re: [PATCH 10/15] em28xx: fix broken TRY_FMT.
  2013-01-05  2:54   ` Mauro Carvalho Chehab
@ 2013-01-05 13:34     ` Hans Verkuil
  2013-01-05 15:36       ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 22+ messages in thread
From: Hans Verkuil @ 2013-01-05 13:34 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Devin Heitmueller, Hans Verkuil, linux-media

On Sat January 5 2013 03:54:44 Mauro Carvalho Chehab wrote:
> Hans/Devin,
> 
> Em Fri,  4 Jan 2013 15:59:40 -0500
> Devin Heitmueller <dheitmueller@kernellabs.com> escreveu:
> 
> > TRY_FMT should not return an error if a pixelformat is unsupported. Instead just
> > pick a common pixelformat.
> > 
> > Also the bytesperline calculation was incorrect: it used the old width instead of
> > the provided with, and it miscalculated the bytesperline value for the depth == 12
> > case.
> > 
> > Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
> > Signed-off-by: Devin Heitmueller <dheitmueller@kernellabs.com>
> > ---
> >  drivers/media/usb/em28xx/em28xx-video.c |    4 ++--
> >  1 file changed, 2 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
> > index a91a248..7c09b55 100644
> > --- a/drivers/media/usb/em28xx/em28xx-video.c
> > +++ b/drivers/media/usb/em28xx/em28xx-video.c
> > @@ -821,7 +821,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
> >  	if (!fmt) {
> >  		em28xx_videodbg("Fourcc format (%08x) invalid.\n",
> >  				f->fmt.pix.pixelformat);
> > -		return -EINVAL;
> > +		fmt = format_by_fourcc(V4L2_PIX_FMT_YUYV);
> 
> This change has the potential of causing userspace regressions, so,
> for now, I won't apply such change.

Good!

> We need to discuss it better, before risk breaking things, and likely fix
> applications first.

Absolutely. I also want to change this test in v4l2-compliance from 'failure'
to 'warning' for the time being.

Regards,

	Hans

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

* Re: [PATCH 10/15] em28xx: fix broken TRY_FMT.
  2013-01-05 13:34     ` Hans Verkuil
@ 2013-01-05 15:36       ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 22+ messages in thread
From: Mauro Carvalho Chehab @ 2013-01-05 15:36 UTC (permalink / raw)
  To: Hans Verkuil; +Cc: Devin Heitmueller, Hans Verkuil, linux-media

Em Sat, 5 Jan 2013 14:34:04 +0100
Hans Verkuil <hverkuil@xs4all.nl> escreveu:

> On Sat January 5 2013 03:54:44 Mauro Carvalho Chehab wrote:
> > Hans/Devin,
> > 
> > Em Fri,  4 Jan 2013 15:59:40 -0500
> > Devin Heitmueller <dheitmueller@kernellabs.com> escreveu:
> > 
> > > TRY_FMT should not return an error if a pixelformat is unsupported. Instead just
> > > pick a common pixelformat.
> > > 
> > > Also the bytesperline calculation was incorrect: it used the old width instead of
> > > the provided with, and it miscalculated the bytesperline value for the depth == 12
> > > case.
> > > 
> > > Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
> > > Signed-off-by: Devin Heitmueller <dheitmueller@kernellabs.com>
> > > ---
> > >  drivers/media/usb/em28xx/em28xx-video.c |    4 ++--
> > >  1 file changed, 2 insertions(+), 2 deletions(-)
> > > 
> > > diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
> > > index a91a248..7c09b55 100644
> > > --- a/drivers/media/usb/em28xx/em28xx-video.c
> > > +++ b/drivers/media/usb/em28xx/em28xx-video.c
> > > @@ -821,7 +821,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
> > >  	if (!fmt) {
> > >  		em28xx_videodbg("Fourcc format (%08x) invalid.\n",
> > >  				f->fmt.pix.pixelformat);
> > > -		return -EINVAL;
> > > +		fmt = format_by_fourcc(V4L2_PIX_FMT_YUYV);
> > 
> > This change has the potential of causing userspace regressions, so,
> > for now, I won't apply such change.
> 
> Good!
> 
> > We need to discuss it better, before risk breaking things, and likely fix
> > applications first.
> 
> Absolutely. I also want to change this test in v4l2-compliance from 'failure'
> to 'warning' for the time being.

Sounds reasonable for me.

Regards,
Mauro

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

* Re: [PATCH 15/15] em28xx: convert to videobuf2
  2013-01-04 20:59 ` [PATCH 15/15] em28xx: convert to videobuf2 Devin Heitmueller
@ 2013-01-08 18:40   ` Frank Schäfer
  2013-01-08 18:59     ` Devin Heitmueller
  0 siblings, 1 reply; 22+ messages in thread
From: Frank Schäfer @ 2013-01-08 18:40 UTC (permalink / raw)
  To: Devin Heitmueller, Mauro Carvalho Chehab, Linux Media Mailing List

Am 04.01.2013 21:59, schrieb Devin Heitmueller:
> This patch converts the em28xx driver over to videobuf2.  It is
> likely that em28xx_fh can go away entirely, but that will come in
> a separate patch.
>
> [mchehab@redhat.com: fix a non-trivial merge conflict with some VBI
>  patches]
>
> Signed-off-by: Devin Heitmueller <dheitmueller@kernellabs.com>
> ---
>  drivers/media/usb/em28xx/Kconfig        |    3 +-
>  drivers/media/usb/em28xx/em28xx-cards.c |    7 +-
>  drivers/media/usb/em28xx/em28xx-dvb.c   |    4 +-
>  drivers/media/usb/em28xx/em28xx-vbi.c   |  123 ++---
>  drivers/media/usb/em28xx/em28xx-video.c |  743 +++++++++++--------------------
>  drivers/media/usb/em28xx/em28xx.h       |   30 +-
>  6 files changed, 327 insertions(+), 583 deletions(-)
>
> diff --git a/drivers/media/usb/em28xx/Kconfig b/drivers/media/usb/em28xx/Kconfig
> index 094c4ec..c754a80 100644
> --- a/drivers/media/usb/em28xx/Kconfig
> +++ b/drivers/media/usb/em28xx/Kconfig
> @@ -3,7 +3,7 @@ config VIDEO_EM28XX
>  	depends on VIDEO_DEV && I2C
>  	select VIDEO_TUNER
>  	select VIDEO_TVEEPROM
> -	select VIDEOBUF_VMALLOC
> +	select VIDEOBUF2_VMALLOC
>  	select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT
>  	select VIDEO_TVP5150 if MEDIA_SUBDRV_AUTOSELECT
>  	select VIDEO_MSP3400 if MEDIA_SUBDRV_AUTOSELECT
> @@ -48,7 +48,6 @@ config VIDEO_EM28XX_DVB
>  	select DVB_S5H1409 if MEDIA_SUBDRV_AUTOSELECT
>  	select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT
>  	select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT
> -	select VIDEOBUF_DVB
>  	---help---
>  	  This adds support for DVB cards based on the
>  	  Empiatech em28xx chips.
> diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
> index 4117d38..0a4c868 100644
> --- a/drivers/media/usb/em28xx/em28xx-cards.c
> +++ b/drivers/media/usb/em28xx/em28xx-cards.c
> @@ -57,7 +57,7 @@ module_param(disable_usb_speed_check, int, 0444);
>  MODULE_PARM_DESC(disable_usb_speed_check,
>  		 "override min bandwidth requirement of 480M bps");
>  
> -static unsigned int card[]     = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
> +static unsigned int card[]     = {[0 ... (EM28XX_MAXBOARDS - 1)] = -1U };
>  module_param_array(card,  int, NULL, 0444);
>  MODULE_PARM_DESC(card,     "card type");
>  
> @@ -2965,6 +2965,8 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
>  	const char *chip_name = default_chip_name;
>  
>  	dev->udev = udev;
> +	mutex_init(&dev->vb_queue_lock);
> +	mutex_init(&dev->vb_vbi_queue_lock);
>  	mutex_init(&dev->ctrl_urb_lock);
>  	spin_lock_init(&dev->slock);
>  
> @@ -3411,6 +3413,9 @@ static int em28xx_usb_probe(struct usb_interface *interface,
>  	/* save our data pointer in this interface device */
>  	usb_set_intfdata(interface, dev);
>  
> +	/* initialize videobuf2 stuff */
> +	em28xx_vb2_setup(dev);
> +
>  	/* allocate device struct */
>  	mutex_init(&dev->lock);
>  	mutex_lock(&dev->lock);
> diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
> index a70b19e..01bb800 100644
> --- a/drivers/media/usb/em28xx/em28xx-dvb.c
> +++ b/drivers/media/usb/em28xx/em28xx-dvb.c
> @@ -27,7 +27,9 @@
>  
>  #include "em28xx.h"
>  #include <media/v4l2-common.h>
> -#include <media/videobuf-vmalloc.h>
> +#include <dvb_demux.h>
> +#include <dvb_net.h>
> +#include <dmxdev.h>
>  #include <media/tuner.h>
>  #include "tuner-simple.h"
>  #include <linux/gpio.h>
> diff --git a/drivers/media/usb/em28xx/em28xx-vbi.c b/drivers/media/usb/em28xx/em28xx-vbi.c
> index d74713b..9fcfc910 100644
> --- a/drivers/media/usb/em28xx/em28xx-vbi.c
> +++ b/drivers/media/usb/em28xx/em28xx-vbi.c
> @@ -41,105 +41,72 @@ MODULE_PARM_DESC(vbi_debug, "enable debug messages [vbi]");
>  
>  /* ------------------------------------------------------------------ */
>  
> -static void
> -free_buffer(struct videobuf_queue *vq, struct em28xx_buffer *buf)
> +static int vbi_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
> +                           unsigned int *nbuffers, unsigned int *nplanes,
> +                           unsigned int sizes[], void *alloc_ctxs[])
>  {
> -	struct em28xx_fh     *fh  = vq->priv_data;
> -	struct em28xx        *dev = fh->dev;
> -	unsigned long flags = 0;
> -	if (in_interrupt())
> -		BUG();
> -
> -	/* We used to wait for the buffer to finish here, but this didn't work
> -	   because, as we were keeping the state as VIDEOBUF_QUEUED,
> -	   videobuf_queue_cancel marked it as finished for us.
> -	   (Also, it could wedge forever if the hardware was misconfigured.)
> -
> -	   This should be safe; by the time we get here, the buffer isn't
> -	   queued anymore. If we ever start marking the buffers as
> -	   VIDEOBUF_ACTIVE, it won't be, though.
> -	*/
> -	spin_lock_irqsave(&dev->slock, flags);
> -	if (dev->usb_ctl.vbi_buf == buf)
> -		dev->usb_ctl.vbi_buf = NULL;
> -	spin_unlock_irqrestore(&dev->slock, flags);
> +	struct em28xx *dev = vb2_get_drv_priv(vq);
> +	unsigned long size;
>  
> -	videobuf_vmalloc_free(&buf->vb);
> -	buf->vb.state = VIDEOBUF_NEEDS_INIT;
> -}
> +	if (fmt)
> +		size = fmt->fmt.pix.sizeimage;
> +	else
> +		size = dev->vbi_width * dev->vbi_height * 2;
>  
> -static int
> -vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
> -{
> -	struct em28xx_fh     *fh  = q->priv_data;
> -	struct em28xx        *dev = fh->dev;
> +	if (0 == *nbuffers)
> +		*nbuffers = 32;
> +	if (*nbuffers < 2)
> +		*nbuffers = 2;
> +	if (*nbuffers > 32)
> +		*nbuffers = 32;
>  
> -	*size = dev->vbi_width * dev->vbi_height * 2;
> +	*nplanes = 1;
> +	sizes[0] = size;
>  
> -	if (0 == *count)
> -		*count = vbibufs;
> -	if (*count < 2)
> -		*count = 2;
> -	if (*count > 32)
> -		*count = 32;
>  	return 0;
>  }
>  
> -static int
> -vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
> -	    enum v4l2_field field)
> +static int vbi_buffer_prepare(struct vb2_buffer *vb)
>  {
> -	struct em28xx_fh     *fh  = q->priv_data;
> -	struct em28xx        *dev = fh->dev;
> +	struct em28xx        *dev = vb2_get_drv_priv(vb->vb2_queue);
>  	struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
> -	int                  rc = 0;
> +	unsigned long        size;
>  
> -	buf->vb.size = dev->vbi_width * dev->vbi_height * 2;
> +	size = dev->vbi_width * dev->vbi_height * 2;
>  
> -	if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
> +	if (vb2_plane_size(vb, 0) < size) {
> +		printk(KERN_INFO "%s data will not fit into plane (%lu < %lu)\n",
> +		       __func__, vb2_plane_size(vb, 0), size);
>  		return -EINVAL;
> -
> -	buf->vb.width  = dev->vbi_width;
> -	buf->vb.height = dev->vbi_height;
> -	buf->vb.field  = field;
> -
> -	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
> -		rc = videobuf_iolock(q, &buf->vb, NULL);
> -		if (rc < 0)
> -			goto fail;
>  	}
> +	vb2_set_plane_payload(&buf->vb, 0, size);
>  
> -	buf->vb.state = VIDEOBUF_PREPARED;
>  	return 0;
> -
> -fail:
> -	free_buffer(q, buf);
> -	return rc;
>  }
>  
>  static void
> -vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
> -{
> -	struct em28xx_buffer    *buf     = container_of(vb,
> -							struct em28xx_buffer,
> -							vb);
> -	struct em28xx_fh        *fh      = vq->priv_data;
> -	struct em28xx           *dev     = fh->dev;
> -	struct em28xx_dmaqueue  *vbiq    = &dev->vbiq;
> -
> -	buf->vb.state = VIDEOBUF_QUEUED;
> -	list_add_tail(&buf->vb.queue, &vbiq->active);
> -}
> -
> -static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
> +vbi_buffer_queue(struct vb2_buffer *vb)
>  {
> +	struct em28xx *dev = vb2_get_drv_priv(vb->vb2_queue);
>  	struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
> -	free_buffer(q, buf);
> +	struct em28xx_dmaqueue *vbiq = &dev->vbiq;
> +	unsigned long flags = 0;
> +
> +	buf->mem = vb2_plane_vaddr(vb, 0);
> +	buf->length = vb2_plane_size(vb, 0);
> +
> +	spin_lock_irqsave(&dev->slock, flags);
> +	list_add_tail(&buf->list, &vbiq->active);
> +	spin_unlock_irqrestore(&dev->slock, flags);
>  }
>  
> -struct videobuf_queue_ops em28xx_vbi_qops = {
> -	.buf_setup    = vbi_setup,
> -	.buf_prepare  = vbi_prepare,
> -	.buf_queue    = vbi_queue,
> -	.buf_release  = vbi_release,
> +
> +struct vb2_ops em28xx_vbi_qops = {
> +	.queue_setup    = vbi_queue_setup,
> +	.buf_prepare    = vbi_buffer_prepare,
> +	.buf_queue      = vbi_buffer_queue,
> +	.start_streaming = em28xx_start_analog_streaming,
> +	.stop_streaming = em28xx_stop_vbi_streaming,
> +	.wait_prepare   = vb2_ops_wait_prepare,
> +	.wait_finish    = vb2_ops_wait_finish,
>  };
> diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
> index 3adaa7b..4dbd7aa 100644
> --- a/drivers/media/usb/em28xx/em28xx-video.c
> +++ b/drivers/media/usb/em28xx/em28xx-video.c
> @@ -76,9 +76,9 @@ MODULE_DESCRIPTION(DRIVER_DESC);
>  MODULE_LICENSE("GPL");
>  MODULE_VERSION(EM28XX_VERSION);
>  
> -static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
> -static unsigned int vbi_nr[]   = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
> -static unsigned int radio_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
> +static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = -1U };
> +static unsigned int vbi_nr[]   = {[0 ... (EM28XX_MAXBOARDS - 1)] = -1U };
> +static unsigned int radio_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = -1U };
>  
>  module_param_array(video_nr, int, NULL, 0444);
>  module_param_array(vbi_nr, int, NULL, 0444);
> @@ -136,12 +136,13 @@ static struct em28xx_fmt format[] = {
>  static inline void finish_buffer(struct em28xx *dev,
>  				 struct em28xx_buffer *buf)
>  {
> -	em28xx_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i);
> -	buf->vb.state = VIDEOBUF_DONE;
> -	buf->vb.field_count++;
> -	v4l2_get_timestamp(&buf->vb.ts);
> -	list_del(&buf->vb.queue);
> -	wake_up(&buf->vb.done);
> +	em28xx_isocdbg("[%p/%d] wakeup\n", buf, buf->top_field);
> +
> +	buf->vb.v4l2_buf.sequence = dev->field_count++;
> +	buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED;
> +	v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
> +
> +	vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
>  }
>  
>  /*
> @@ -156,8 +157,8 @@ static void em28xx_copy_video(struct em28xx *dev,
>  	int  linesdone, currlinedone, offset, lencopy, remain;
>  	int bytesperline = dev->width << 1;
>  
> -	if (buf->pos + len > buf->vb.size)
> -		len = buf->vb.size - buf->pos;
> +	if (buf->pos + len > buf->length)
> +		len = buf->length - buf->pos;
>  
>  	startread = usb_buf;
>  	remain = len;
> @@ -179,11 +180,11 @@ static void em28xx_copy_video(struct em28xx *dev,
>  	lencopy = bytesperline - currlinedone;
>  	lencopy = lencopy > remain ? remain : lencopy;
>  
> -	if ((char *)startwrite + lencopy > (char *)buf->vb_buf + buf->vb.size) {
> +	if ((char *)startwrite + lencopy > (char *)buf->vb_buf + buf->length) {
>  		em28xx_isocdbg("Overflow of %zi bytes past buffer end (1)\n",
>  			      ((char *)startwrite + lencopy) -
> -			      ((char *)buf->vb_buf + buf->vb.size));
> -		remain = (char *)buf->vb_buf + buf->vb.size -
> +			      ((char *)buf->vb_buf + buf->length));
> +		remain = (char *)buf->vb_buf + buf->length -
>  			 (char *)startwrite;
>  		lencopy = remain;
>  	}
> @@ -205,13 +206,13 @@ static void em28xx_copy_video(struct em28xx *dev,
>  			lencopy = bytesperline;
>  
>  		if ((char *)startwrite + lencopy > (char *)buf->vb_buf +
> -		    buf->vb.size) {
> +		    buf->length) {
>  			em28xx_isocdbg("Overflow of %zi bytes past buffer end"
>  				       "(2)\n",
>  				       ((char *)startwrite + lencopy) -
> -				       ((char *)buf->vb_buf + buf->vb.size));
> -			lencopy = remain = (char *)buf->vb_buf + buf->vb.size -
> -					   (char *)startwrite;
> +				       ((char *)buf->vb_buf + buf->length));
> +			lencopy = remain = (char *)buf->vb_buf + buf->length -
> +				(char *)startwrite;
>  		}
>  		if (lencopy <= 0)
>  			break;
> @@ -234,8 +235,8 @@ static void em28xx_copy_vbi(struct em28xx *dev,
>  {
>  	unsigned int offset;
>  
> -	if (buf->pos + len > buf->vb.size)
> -		len = buf->vb.size - buf->pos;
> +	if (buf->pos + len > buf->length)
> +		len = buf->length - buf->pos;
>  
>  	offset = buf->pos;
>  	/* Make sure the bottom field populates the second half of the frame */
> @@ -292,7 +293,6 @@ static inline struct em28xx_buffer *get_next_buf(struct em28xx *dev,
>  						 struct em28xx_dmaqueue *dma_q)
>  {
>  	struct em28xx_buffer *buf;
> -	char *outp;
>  
>  	if (list_empty(&dma_q->active)) {
>  		em28xx_isocdbg("No active queue to serve\n");
> @@ -300,12 +300,11 @@ static inline struct em28xx_buffer *get_next_buf(struct em28xx *dev,
>  	}
>  
>  	/* Get the next buffer */
> -	buf = list_entry(dma_q->active.next, struct em28xx_buffer, vb.queue);
> +	buf = list_entry(dma_q->active.next, struct em28xx_buffer, list);
>  	/* Cleans up buffer - Useful for testing for frame/URB loss */
> -	outp = videobuf_to_vmalloc(&buf->vb);
> -	memset(outp, 0, buf->vb.size);
> +	list_del(&buf->list);
>  	buf->pos = 0;
> -	buf->vb_buf = outp;
> +	buf->vb_buf = buf->mem;
>  
>  	return buf;
>  }
> @@ -467,92 +466,118 @@ static inline int em28xx_urb_data_copy(struct em28xx *dev, struct urb *urb)
>  }
>  
>  
> +static int get_ressource(enum v4l2_buf_type f_type)
> +{
> +	switch (f_type) {
> +	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
> +		return EM28XX_RESOURCE_VIDEO;
> +	case V4L2_BUF_TYPE_VBI_CAPTURE:
> +		return EM28XX_RESOURCE_VBI;
> +	default:
> +		BUG();
> +		return 0;
> +	}
> +}
> +
> +/* Usage lock check functions */
> +static int res_get(struct em28xx *dev, enum v4l2_buf_type f_type)
> +{
> +	int res_type = get_ressource(f_type);
> +
> +	/* is it free? */
> +	if (dev->resources & res_type) {
> +		/* no, someone else uses it */
> +		return -EBUSY;
> +	}
> +
> +	/* it's free, grab it */
> +	dev->resources |= res_type;
> +	em28xx_videodbg("res: get %d\n", res_type);
> +	return 0;
> +}
> +
> +static void res_free(struct em28xx *dev, enum v4l2_buf_type f_type)
> +{
> +	int res_type = get_ressource(f_type);
> +
> +	dev->resources &= ~res_type;
> +	em28xx_videodbg("res: put %d\n", res_type);
> +}
> +
>  /* ------------------------------------------------------------------
> -	Videobuf operations
> +	Videobuf2 operations
>     ------------------------------------------------------------------*/
>  
> -static int
> -buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
> +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 em28xx_fh *fh = vq->priv_data;
> -	struct em28xx        *dev = fh->dev;
> -	struct v4l2_frequency f;
> -
> -	*size = (fh->dev->width * fh->dev->height * dev->format->depth + 7)
> -		>> 3;
> +	struct em28xx *dev = vb2_get_drv_priv(vq);
> +	unsigned long size;
>  
> -	if (0 == *count)
> -		*count = EM28XX_DEF_BUF;
> +	if (fmt)
> +		size = fmt->fmt.pix.sizeimage;
> +	else
> +		size = (dev->width * dev->height * dev->format->depth + 7) >> 3;
>  
> -	if (*count < EM28XX_MIN_BUF)
> -		*count = EM28XX_MIN_BUF;
> +	if (size == 0)
> +		return -EINVAL;
>  
> -	/* Ask tuner to go to analog or radio mode */
> -	memset(&f, 0, sizeof(f));
> -	f.frequency = dev->ctl_freq;
> -	f.type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
> +	if (0 == *nbuffers)
> +		*nbuffers = 32;
>  
> -	v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
> +	*nplanes = 1;
> +	sizes[0] = size;
>  
>  	return 0;
>  }
>  
> -/* This is called *without* dev->slock held; please keep it that way */
> -static void free_buffer(struct videobuf_queue *vq, struct em28xx_buffer *buf)
> +static int
> +buffer_prepare(struct vb2_buffer *vb)
>  {
> -	struct em28xx_fh     *fh  = vq->priv_data;
> -	struct em28xx        *dev = fh->dev;
> -	unsigned long flags = 0;
> -	if (in_interrupt())
> -		BUG();
> +	struct em28xx        *dev = vb2_get_drv_priv(vb->vb2_queue);
> +	struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
> +	unsigned long size;
>  
> -	/* We used to wait for the buffer to finish here, but this didn't work
> -	   because, as we were keeping the state as VIDEOBUF_QUEUED,
> -	   videobuf_queue_cancel marked it as finished for us.
> -	   (Also, it could wedge forever if the hardware was misconfigured.)
> +	em28xx_videodbg("%s, field=%d\n", __func__, vb->v4l2_buf.field);
>  
> -	   This should be safe; by the time we get here, the buffer isn't
> -	   queued anymore. If we ever start marking the buffers as
> -	   VIDEOBUF_ACTIVE, it won't be, though.
> -	*/
> -	spin_lock_irqsave(&dev->slock, flags);
> -	if (dev->usb_ctl.vid_buf == buf)
> -		dev->usb_ctl.vid_buf = NULL;
> -	spin_unlock_irqrestore(&dev->slock, flags);
> +	size = (dev->width * dev->height * dev->format->depth + 7) >> 3;
>  
> -	videobuf_vmalloc_free(&buf->vb);
> -	buf->vb.state = VIDEOBUF_NEEDS_INIT;
> +	if (vb2_plane_size(vb, 0) < size) {
> +		em28xx_videodbg("%s data will not fit into plane (%lu < %lu)\n",
> +				__func__, vb2_plane_size(vb, 0), size);
> +		return -EINVAL;
> +	}
> +	vb2_set_plane_payload(&buf->vb, 0, size);
> +
> +	return 0;
>  }
>  
> -static int
> -buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
> -						enum v4l2_field field)
> +int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count)
>  {
> -	struct em28xx_fh     *fh  = vq->priv_data;
> -	struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
> -	struct em28xx        *dev = fh->dev;
> -	int                  rc = 0, urb_init = 0;
> +	struct em28xx *dev = vb2_get_drv_priv(vq);
> +	struct v4l2_frequency f;
> +	int rc = 0;
>  
> -	buf->vb.size = (fh->dev->width * fh->dev->height * dev->format->depth
> -			+ 7) >> 3;
> +	em28xx_videodbg("%s\n", __func__);
>  
> -	if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
> -		return -EINVAL;
> +	/* Make sure streaming is not already in progress for this type
> +	   of filehandle (e.g. video, vbi) */
> +	rc = res_get(dev, vq->type);
> +	if (rc)
> +		return rc;
>  
> -	buf->vb.width  = dev->width;
> -	buf->vb.height = dev->height;
> -	buf->vb.field  = field;
> +	if (dev->streaming_users++ == 0) {
> +		/* First active streaming user, so allocate all the URBs */
>  
> -	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
> -		rc = videobuf_iolock(vq, &buf->vb, NULL);
> -		if (rc < 0)
> -			goto fail;
> -	}
> +		/* Allocate the USB bandwidth */
> +		em28xx_set_alternate(dev);
>  
> -	if (!dev->usb_ctl.analog_bufs.num_bufs)
> -		urb_init = 1;
> +		/* Needed, since GPIO might have disabled power of
> +		   some i2c device
> +		*/
> +		em28xx_wake_i2c(dev);
>  
> -	if (urb_init) {
>  		dev->capture_type = -1;
>  		rc = em28xx_init_usb_xfer(dev, EM28XX_ANALOG_MODE,
>  					  dev->analog_xfer_bulk,
> @@ -562,52 +587,142 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
>  					  em28xx_urb_data_copy);
>  		if (rc < 0)
>  			goto fail;
> -	}
>  
> -	buf->vb.state = VIDEOBUF_PREPARED;
> -	return 0;
> +		/* djh: it's not clear whether this code is still needed.  I'm
> +		   leaving it in here for now entirely out of concern for backward
> +		   compatibility (the old code did it) */
> +
> +		/* Ask tuner to go to analog or radio mode */
> +		memset(&f, 0, sizeof(f));
> +		f.frequency = dev->ctl_freq;
> +		if (vq->owner && vq->owner->vdev->vfl_type == VFL_TYPE_RADIO)
> +			f.type = V4L2_TUNER_RADIO;
> +		else
> +			f.type = V4L2_TUNER_ANALOG_TV;
> +		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
> +	}
>  
>  fail:
> -	free_buffer(vq, buf);
>  	return rc;
>  }
>  
> -static void
> -buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
> +int em28xx_stop_streaming(struct vb2_queue *vq)
>  {
> -	struct em28xx_buffer    *buf     = container_of(vb,
> -							struct em28xx_buffer,
> -							vb);
> -	struct em28xx_fh        *fh      = vq->priv_data;
> -	struct em28xx           *dev     = fh->dev;
> -	struct em28xx_dmaqueue  *vidq    = &dev->vidq;
> +	struct em28xx *dev = vb2_get_drv_priv(vq);
> +	struct em28xx_dmaqueue *vidq = &dev->vidq;
> +	unsigned long flags = 0;
> +
> +	em28xx_videodbg("%s\n", __func__);
> +
> +	res_free(dev, vq->type);
>  
> -	buf->vb.state = VIDEOBUF_QUEUED;
> -	list_add_tail(&buf->vb.queue, &vidq->active);
> +	if (dev->streaming_users-- == 1) {
> +		/* Last active user, so shutdown all the URBS */
> +		em28xx_uninit_usb_xfer(dev, EM28XX_ANALOG_MODE);
> +	}
>  
> +	spin_lock_irqsave(&dev->slock, flags);
> +	while (!list_empty(&vidq->active)) {
> +		struct em28xx_buffer *buf;
> +		buf = list_entry(vidq->active.next, struct em28xx_buffer, list);
> +		list_del(&buf->list);
> +		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
> +	}
> +	dev->usb_ctl.vid_buf = NULL;
> +	spin_unlock_irqrestore(&dev->slock, flags);
> +
> +	return 0;
>  }
>  
> -static void buffer_release(struct videobuf_queue *vq,
> -				struct videobuf_buffer *vb)
> +int em28xx_stop_vbi_streaming(struct vb2_queue *vq)
>  {
> -	struct em28xx_buffer   *buf  = container_of(vb,
> -						    struct em28xx_buffer,
> -						    vb);
> -	struct em28xx_fh       *fh   = vq->priv_data;
> -	struct em28xx          *dev  = (struct em28xx *)fh->dev;
> +	struct em28xx *dev = vb2_get_drv_priv(vq);
> +	struct em28xx_dmaqueue *vbiq = &dev->vbiq;
> +	unsigned long flags = 0;
> +
> +	em28xx_videodbg("%s\n", __func__);
>  
> -	em28xx_isocdbg("em28xx: called buffer_release\n");
> +	res_free(dev, vq->type);
>  
> -	free_buffer(vq, buf);
> +	if (dev->streaming_users-- == 1) {
> +		/* Last active user, so shutdown all the URBS */
> +		em28xx_uninit_usb_xfer(dev, EM28XX_ANALOG_MODE);
> +	}
> +
> +	spin_lock_irqsave(&dev->slock, flags);
> +	while (!list_empty(&vbiq->active)) {
> +		struct em28xx_buffer *buf;
> +		buf = list_entry(vbiq->active.next, struct em28xx_buffer, list);
> +		list_del(&buf->list);
> +		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
> +	}
> +	dev->usb_ctl.vbi_buf = NULL;
> +	spin_unlock_irqrestore(&dev->slock, flags);
> +
> +	return 0;
>  }
>  
> -static struct videobuf_queue_ops em28xx_video_qops = {
> -	.buf_setup      = buffer_setup,
> +static void
> +buffer_queue(struct vb2_buffer *vb)
> +{
> +	struct em28xx *dev = vb2_get_drv_priv(vb->vb2_queue);
> +	struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
> +	struct em28xx_dmaqueue *vidq = &dev->vidq;
> +	unsigned long flags = 0;
> +
> +	em28xx_videodbg("%s\n", __func__);
> +	buf->mem = vb2_plane_vaddr(vb, 0);
> +	buf->length = vb2_plane_size(vb, 0);
> +
> +	spin_lock_irqsave(&dev->slock, flags);
> +	list_add_tail(&buf->list, &vidq->active);
> +	spin_unlock_irqrestore(&dev->slock, flags);
> +}
> +
> +static struct vb2_ops em28xx_video_qops = {
> +	.queue_setup    = queue_setup,
>  	.buf_prepare    = buffer_prepare,
>  	.buf_queue      = buffer_queue,
> -	.buf_release    = buffer_release,
> +	.start_streaming = em28xx_start_analog_streaming,
> +	.stop_streaming = em28xx_stop_streaming,
> +	.wait_prepare   = vb2_ops_wait_prepare,
> +	.wait_finish    = vb2_ops_wait_finish,
>  };
>  
> +int em28xx_vb2_setup(struct em28xx *dev)
> +{
> +	int rc;
> +	struct vb2_queue *q;
> +
> +	/* Setup Videobuf2 for Video capture */
> +	q = &dev->vb_vidq;
> +	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> +	q->io_modes = VB2_READ | VB2_MMAP | VB2_USERPTR;
> +	q->drv_priv = dev;
> +	q->buf_struct_size = sizeof(struct em28xx_buffer);
> +	q->ops = &em28xx_video_qops;
> +	q->mem_ops = &vb2_vmalloc_memops;
> +
> +	rc = vb2_queue_init(q);
> +	if (rc < 0)
> +		return rc;
> +
> +	/* Setup Videobuf2 for VBI capture */
> +	q = &dev->vb_vbiq;
> +	q->type = V4L2_BUF_TYPE_VBI_CAPTURE;
> +	q->io_modes = VB2_READ | VB2_MMAP | VB2_USERPTR;
> +	q->drv_priv = dev;
> +	q->buf_struct_size = sizeof(struct em28xx_buffer);
> +	q->ops = &em28xx_vbi_qops;
> +	q->mem_ops = &vb2_vmalloc_memops;
> +
> +	rc = vb2_queue_init(q);
> +	if (rc < 0)
> +		return rc;
> +
> +	return 0;
> +}
> +
>  /*********************  v4l2 interface  **************************************/
>  
>  static void video_mux(struct em28xx *dev, int index)
> @@ -640,61 +755,6 @@ static void video_mux(struct em28xx *dev, int index)
>  	em28xx_audio_analog_set(dev);
>  }
>  
> -/* Usage lock check functions */
> -static int res_get(struct em28xx_fh *fh, unsigned int bit)
> -{
> -	struct em28xx    *dev = fh->dev;
> -
> -	if (fh->resources & bit)
> -		/* have it already allocated */
> -		return 1;
> -
> -	/* is it free? */
> -	if (dev->resources & bit) {
> -		/* no, someone else uses it */
> -		return 0;
> -	}
> -	/* it's free, grab it */
> -	fh->resources  |= bit;
> -	dev->resources |= bit;
> -	em28xx_videodbg("res: get %d\n", bit);
> -	return 1;
> -}
> -
> -static int res_check(struct em28xx_fh *fh, unsigned int bit)
> -{
> -	return fh->resources & bit;
> -}
> -
> -static int res_locked(struct em28xx *dev, unsigned int bit)
> -{
> -	return dev->resources & bit;
> -}
> -
> -static void res_free(struct em28xx_fh *fh, unsigned int bits)
> -{
> -	struct em28xx    *dev = fh->dev;
> -
> -	BUG_ON((fh->resources & bits) != bits);
> -
> -	fh->resources  &= ~bits;
> -	dev->resources &= ~bits;
> -	em28xx_videodbg("res: put %d\n", bits);
> -}
> -
> -static int get_ressource(struct em28xx_fh *fh)
> -{
> -	switch (fh->type) {
> -	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
> -		return EM28XX_RESOURCE_VIDEO;
> -	case V4L2_BUF_TYPE_VBI_CAPTURE:
> -		return EM28XX_RESOURCE_VBI;
> -	default:
> -		BUG();
> -		return 0;
> -	}
> -}
> -
>  void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv)
>  {
>  	struct em28xx *dev = priv;
> @@ -875,7 +935,6 @@ static int em28xx_set_video_format(struct em28xx *dev, unsigned int fourcc,
>  	/* set new image size */
>  	get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
>  
> -	em28xx_set_alternate(dev);
>  	em28xx_resolution_set(dev);
>  
>  	return 0;
> @@ -884,21 +943,13 @@ static int em28xx_set_video_format(struct em28xx *dev, unsigned int fourcc,
>  static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
>  			struct v4l2_format *f)
>  {
> -	struct em28xx_fh      *fh  = priv;
> -	struct em28xx         *dev = fh->dev;
> -	int                   rc;
> +	struct em28xx *dev = video_drvdata(file);
>  
> -	rc = check_dev(dev);
> -	if (rc < 0)
> -		return rc;
> +	if (dev->streaming_users > 0)
> +		return -EBUSY;
>  
>  	vidioc_try_fmt_vid_cap(file, priv, f);
>  
> -	if (videobuf_queue_is_busy(&fh->vb_vidq)) {
> -		em28xx_errdev("%s queue busy\n", __func__);
> -		return -EBUSY;
> -	}
> -
>  	return em28xx_set_video_format(dev, f->fmt.pix.pixelformat,
>  				f->fmt.pix.width, f->fmt.pix.height);
>  }
> @@ -952,10 +1003,8 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
>  	if (rc < 0)
>  		return rc;
>  
> -	if (videobuf_queue_is_busy(&fh->vb_vidq)) {
> -		em28xx_errdev("%s queue busy\n", __func__);
> +	if (dev->streaming_users > 0)
>  		return -EBUSY;
> -	}
>  
>  	dev->norm = *norm;
>  
> @@ -1358,69 +1407,6 @@ static int vidioc_cropcap(struct file *file, void *priv,
>  	return 0;
>  }
>  
> -static int vidioc_streamon(struct file *file, void *priv,
> -					enum v4l2_buf_type type)
> -{
> -	struct em28xx_fh      *fh  = priv;
> -	struct em28xx         *dev = fh->dev;
> -	int                   rc = -EINVAL;
> -
> -	rc = check_dev(dev);
> -	if (rc < 0)
> -		return rc;
> -
> -	if (unlikely(type != fh->type))
> -		return -EINVAL;
> -
> -	em28xx_videodbg("vidioc_streamon fh=%p t=%d fh->res=%d dev->res=%d\n",
> -			fh, type, fh->resources, dev->resources);
> -
> -	if (unlikely(!res_get(fh, get_ressource(fh))))
> -		return -EBUSY;
> -
> -	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
> -		rc = videobuf_streamon(&fh->vb_vidq);
> -	else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
> -		rc = videobuf_streamon(&fh->vb_vbiq);
> -
> -	return rc;
> -}
> -
> -static int vidioc_streamoff(struct file *file, void *priv,
> -					enum v4l2_buf_type type)
> -{
> -	struct em28xx_fh      *fh  = priv;
> -	struct em28xx         *dev = fh->dev;
> -	int                   rc;
> -
> -	rc = check_dev(dev);
> -	if (rc < 0)
> -		return rc;
> -
> -	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
> -	    fh->type != V4L2_BUF_TYPE_VBI_CAPTURE)
> -		return -EINVAL;
> -	if (type != fh->type)
> -		return -EINVAL;
> -
> -	em28xx_videodbg("vidioc_streamoff fh=%p t=%d fh->res=%d dev->res=%d\n",
> -			fh, type, fh->resources, dev->resources);
> -
> -	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
> -		if (res_check(fh, EM28XX_RESOURCE_VIDEO)) {
> -			videobuf_streamoff(&fh->vb_vidq);
> -			res_free(fh, EM28XX_RESOURCE_VIDEO);
> -		}
> -	} else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
> -		if (res_check(fh, EM28XX_RESOURCE_VBI)) {
> -			videobuf_streamoff(&fh->vb_vbiq);
> -			res_free(fh, EM28XX_RESOURCE_VBI);
> -		}
> -	}
> -
> -	return 0;
> -}
> -
>  static int vidioc_querycap(struct file *file, void  *priv,
>  					struct v4l2_capability *cap)
>  {
> @@ -1566,83 +1552,6 @@ static int vidioc_s_fmt_vbi_cap(struct file *file, void *priv,
>  	return 0;
>  }
>  
> -static int vidioc_reqbufs(struct file *file, void *priv,
> -			  struct v4l2_requestbuffers *rb)
> -{
> -	struct em28xx_fh      *fh  = priv;
> -	struct em28xx         *dev = fh->dev;
> -	int                   rc;
> -
> -	rc = check_dev(dev);
> -	if (rc < 0)
> -		return rc;
> -
> -	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
> -		return videobuf_reqbufs(&fh->vb_vidq, rb);
> -	else
> -		return videobuf_reqbufs(&fh->vb_vbiq, rb);
> -}
> -
> -static int vidioc_querybuf(struct file *file, void *priv,
> -			   struct v4l2_buffer *b)
> -{
> -	struct em28xx_fh      *fh  = priv;
> -	struct em28xx         *dev = fh->dev;
> -	int                   rc;
> -
> -	rc = check_dev(dev);
> -	if (rc < 0)
> -		return rc;
> -
> -	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
> -		return videobuf_querybuf(&fh->vb_vidq, b);
> -	else {
> -		/* FIXME: I'm not sure yet whether this is a bug in zvbi or
> -		   the videobuf framework, but we probably shouldn't be
> -		   returning a buffer larger than that which was asked for.
> -		   At a minimum, it causes a crash in zvbi since it does
> -		   a memcpy based on the source buffer length */
> -		int result = videobuf_querybuf(&fh->vb_vbiq, b);
> -		b->length = dev->vbi_width * dev->vbi_height * 2;
> -
> -		return result;
> -	}
> -}
> -
> -static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
> -{
> -	struct em28xx_fh      *fh  = priv;
> -	struct em28xx         *dev = fh->dev;
> -	int                   rc;
> -
> -	rc = check_dev(dev);
> -	if (rc < 0)
> -		return rc;
> -
> -	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
> -		return videobuf_qbuf(&fh->vb_vidq, b);
> -	else
> -		return videobuf_qbuf(&fh->vb_vbiq, b);
> -}
> -
> -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
> -{
> -	struct em28xx_fh      *fh  = priv;
> -	struct em28xx         *dev = fh->dev;
> -	int                   rc;
> -
> -	rc = check_dev(dev);
> -	if (rc < 0)
> -		return rc;
> -
> -	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
> -		return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags &
> -				      O_NONBLOCK);
> -	else
> -		return videobuf_dqbuf(&fh->vb_vbiq, b, file->f_flags &
> -				      O_NONBLOCK);
> -}
> -
>  /* ----------------------------------------------------------- */
>  /* RADIO ESPECIFIC IOCTLS                                      */
>  /* ----------------------------------------------------------- */
> @@ -1682,12 +1591,10 @@ static int radio_s_tuner(struct file *file, void *priv,
>   */
>  static int em28xx_v4l2_open(struct file *filp)
>  {
> -	int errCode = 0, radio = 0;
>  	struct video_device *vdev = video_devdata(filp);
>  	struct em28xx *dev = video_drvdata(filp);
>  	enum v4l2_buf_type fh_type = 0;
>  	struct em28xx_fh *fh;
> -	enum v4l2_field field;
>  
>  	switch (vdev->vfl_type) {
>  	case VFL_TYPE_GRABBER:
> @@ -1696,9 +1603,6 @@ static int em28xx_v4l2_open(struct file *filp)
>  	case VFL_TYPE_VBI:
>  		fh_type = V4L2_BUF_TYPE_VBI_CAPTURE;
>  		break;
> -	case VFL_TYPE_RADIO:
> -		radio = 1;
> -		break;
>  	}
>  
>  	em28xx_videodbg("open dev=%s type=%s users=%d\n",
> @@ -1716,13 +1620,11 @@ static int em28xx_v4l2_open(struct file *filp)
>  	}
>  	v4l2_fh_init(&fh->fh, vdev);
>  	fh->dev = dev;
> -	fh->radio = radio;
>  	fh->type = fh_type;
>  	filp->private_data = fh;
>  
>  	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
>  		em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
> -		em28xx_set_alternate(dev);
>  		em28xx_resolution_set(dev);
>  
>  		/* Needed, since GPIO might have disabled power of
> @@ -1731,32 +1633,18 @@ static int em28xx_v4l2_open(struct file *filp)
>  		em28xx_wake_i2c(dev);
>  
>  	}
> -	if (fh->radio) {
> +
> +	if (vdev->vfl_type == VFL_TYPE_RADIO) {
>  		em28xx_videodbg("video_open: setting radio device\n");
>  		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_radio);
>  	}
>  
>  	dev->users++;
>  
> -	if (dev->progressive)
> -		field = V4L2_FIELD_NONE;
> -	else
> -		field = V4L2_FIELD_INTERLACED;
> -
> -	videobuf_queue_vmalloc_init(&fh->vb_vidq, &em28xx_video_qops,
> -				    NULL, &dev->slock,
> -				    V4L2_BUF_TYPE_VIDEO_CAPTURE, field,
> -				    sizeof(struct em28xx_buffer), fh, &dev->lock);
> -
> -	videobuf_queue_vmalloc_init(&fh->vb_vbiq, &em28xx_vbi_qops,
> -				    NULL, &dev->slock,
> -				    V4L2_BUF_TYPE_VBI_CAPTURE,
> -				    V4L2_FIELD_SEQ_TB,
> -				    sizeof(struct em28xx_buffer), fh, &dev->lock);
>  	mutex_unlock(&dev->lock);
>  	v4l2_fh_add(&fh->fh);
>  
> -	return errCode;
> +	return 0;
>  }
>  
>  /*
> @@ -1810,15 +1698,7 @@ static int em28xx_v4l2_close(struct file *filp)
>  	em28xx_videodbg("users=%d\n", dev->users);
>  
>  	mutex_lock(&dev->lock);
> -	if (res_check(fh, EM28XX_RESOURCE_VIDEO)) {
> -		videobuf_stop(&fh->vb_vidq);
> -		res_free(fh, EM28XX_RESOURCE_VIDEO);
> -	}
> -
> -	if (res_check(fh, EM28XX_RESOURCE_VBI)) {
> -		videobuf_stop(&fh->vb_vbiq);
> -		res_free(fh, EM28XX_RESOURCE_VBI);
> -	}
> +	vb2_fop_release(filp);
>  
>  	if (dev->users == 1) {
>  		/* the device is already disconnect,
> @@ -1828,7 +1708,6 @@ static int em28xx_v4l2_close(struct file *filp)
>  			kfree(dev->alt_max_pkt_size_isoc);
>  			mutex_unlock(&dev->lock);
>  			kfree(dev);
> -			kfree(fh);
>  			return 0;
>  		}
>  
> @@ -1836,7 +1715,6 @@ static int em28xx_v4l2_close(struct file *filp)
>  		v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
>  
>  		/* do this before setting alternate! */
> -		em28xx_uninit_usb_xfer(dev, EM28XX_ANALOG_MODE);
>  		em28xx_set_mode(dev, EM28XX_SUSPEND);
>  
>  		/* set alternate 0 */
> @@ -1848,141 +1726,19 @@ static int em28xx_v4l2_close(struct file *filp)
>  					"0 (error=%i)\n", errCode);
>  		}
>  	}
> -	v4l2_fh_del(&fh->fh);
> -	v4l2_fh_exit(&fh->fh);
>  
> -	videobuf_mmap_free(&fh->vb_vidq);
> -	videobuf_mmap_free(&fh->vb_vbiq);
> -	kfree(fh);
>  	dev->users--;
>  	mutex_unlock(&dev->lock);
>  	return 0;
>  }
>  
> -/*
> - * em28xx_v4l2_read()
> - * will allocate buffers when called for the first time
> - */
> -static ssize_t
> -em28xx_v4l2_read(struct file *filp, char __user *buf, size_t count,
> -		 loff_t *pos)
> -{
> -	struct em28xx_fh *fh = filp->private_data;
> -	struct em28xx *dev = fh->dev;
> -	int rc;
> -
> -	rc = check_dev(dev);
> -	if (rc < 0)
> -		return rc;
> -
> -	if (mutex_lock_interruptible(&dev->lock))
> -		return -ERESTARTSYS;
> -	/* FIXME: read() is not prepared to allow changing the video
> -	   resolution while streaming. Seems a bug at em28xx_set_fmt
> -	 */
> -
> -	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
> -		if (res_locked(dev, EM28XX_RESOURCE_VIDEO))
> -			rc = -EBUSY;
> -		else
> -			rc = videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0,
> -					filp->f_flags & O_NONBLOCK);
> -	} else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
> -		if (!res_get(fh, EM28XX_RESOURCE_VBI))
> -			rc = -EBUSY;
> -		else
> -			rc = videobuf_read_stream(&fh->vb_vbiq, buf, count, pos, 0,
> -					filp->f_flags & O_NONBLOCK);
> -	}
> -	mutex_unlock(&dev->lock);
> -
> -	return rc;
> -}
> -
> -/*
> - * em28xx_poll()
> - * will allocate buffers when called for the first time
> - */
> -static unsigned int em28xx_poll(struct file *filp, poll_table *wait)
> -{
> -	struct em28xx_fh *fh = filp->private_data;
> -	unsigned long req_events = poll_requested_events(wait);
> -	struct em28xx *dev = fh->dev;
> -	unsigned int res = 0;
> -	int rc;
> -
> -	rc = check_dev(dev);
> -	if (rc < 0)
> -		return DEFAULT_POLLMASK;
> -
> -	if (v4l2_event_pending(&fh->fh))
> -		res = POLLPRI;
> -	else if (req_events & POLLPRI)
> -		poll_wait(filp, &fh->fh.wait, wait);
> -
> -	if (req_events & (POLLIN | POLLRDNORM)) {
> -		if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
> -			if (!res_get(fh, EM28XX_RESOURCE_VIDEO))
> -				return res | POLLERR;
> -			return videobuf_poll_stream(filp, &fh->vb_vidq, wait);
> -		}
> -		if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
> -			if (!res_get(fh, EM28XX_RESOURCE_VBI))
> -				return res | POLLERR;
> -			return res | videobuf_poll_stream(filp, &fh->vb_vbiq, wait);
> -		}
> -	}
> -	return res;
> -}
> -
> -static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table *wait)
> -{
> -	struct em28xx_fh *fh = filp->private_data;
> -	struct em28xx *dev = fh->dev;
> -	unsigned int res;
> -
> -	mutex_lock(&dev->lock);
> -	res = em28xx_poll(filp, wait);
> -	mutex_unlock(&dev->lock);
> -	return res;
> -}
> -
> -/*
> - * em28xx_v4l2_mmap()
> - */
> -static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
> -{
> -	struct em28xx_fh *fh    = filp->private_data;
> -	struct em28xx	 *dev   = fh->dev;
> -	int		 rc;
> -
> -	rc = check_dev(dev);
> -	if (rc < 0)
> -		return rc;
> -
> -	if (mutex_lock_interruptible(&dev->lock))
> -		return -ERESTARTSYS;
> -	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
> -		rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
> -	else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
> -		rc = videobuf_mmap_mapper(&fh->vb_vbiq, vma);
> -	mutex_unlock(&dev->lock);
> -
> -	em28xx_videodbg("vma start=0x%08lx, size=%ld, ret=%d\n",
> -		(unsigned long)vma->vm_start,
> -		(unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
> -		rc);
> -
> -	return rc;
> -}
> -
>  static const struct v4l2_file_operations em28xx_v4l_fops = {
>  	.owner         = THIS_MODULE,
>  	.open          = em28xx_v4l2_open,
>  	.release       = em28xx_v4l2_close,
> -	.read          = em28xx_v4l2_read,
> -	.poll          = em28xx_v4l2_poll,
> -	.mmap          = em28xx_v4l2_mmap,
> +	.read          = vb2_fop_read,
> +	.poll          = vb2_fop_poll,
> +	.mmap          = vb2_fop_mmap,
>  	.unlocked_ioctl = video_ioctl2,
>  };
>  
> @@ -2000,10 +1756,13 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
>  	.vidioc_s_audio             = vidioc_s_audio,
>  	.vidioc_cropcap             = vidioc_cropcap,
>  
> -	.vidioc_reqbufs             = vidioc_reqbufs,
> -	.vidioc_querybuf            = vidioc_querybuf,
> -	.vidioc_qbuf                = vidioc_qbuf,
> -	.vidioc_dqbuf               = vidioc_dqbuf,
> +	.vidioc_reqbufs             = vb2_ioctl_reqbufs,
> +	.vidioc_create_bufs         = vb2_ioctl_create_bufs,
> +	.vidioc_prepare_buf         = vb2_ioctl_prepare_buf,
> +	.vidioc_querybuf            = vb2_ioctl_querybuf,
> +	.vidioc_qbuf                = vb2_ioctl_qbuf,
> +	.vidioc_dqbuf               = vb2_ioctl_dqbuf,
> +
>  	.vidioc_g_std               = vidioc_g_std,
>  	.vidioc_querystd            = vidioc_querystd,
>  	.vidioc_s_std               = vidioc_s_std,
> @@ -2012,8 +1771,8 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
>  	.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_g_tuner             = vidioc_g_tuner,
>  	.vidioc_s_tuner             = vidioc_s_tuner,
>  	.vidioc_g_frequency         = vidioc_g_frequency,
> @@ -2029,7 +1788,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
>  
>  static const struct video_device em28xx_video_template = {
>  	.fops                       = &em28xx_v4l_fops,
> -	.release                    = video_device_release,
> +	.release                    = video_device_release_empty,
>  	.ioctl_ops 		    = &video_ioctl_ops,
>  
>  	.tvnorms                    = V4L2_STD_ALL,
> @@ -2078,7 +1837,6 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev,
>  
>  	*vfd		= *template;
>  	vfd->v4l2_dev	= &dev->v4l2_dev;
> -	vfd->release	= video_device_release;
>  	vfd->debug	= video_debug;
>  	vfd->lock	= &dev->lock;
>  	set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
> @@ -2139,6 +1897,8 @@ int em28xx_register_analog_devices(struct em28xx *dev)
>  		em28xx_errdev("cannot allocate video_device.\n");
>  		return -ENODEV;
>  	}
> +	dev->vdev->queue = &dev->vb_vidq;
> +	dev->vdev->queue->lock = &dev->vb_queue_lock;
>  
>  	/* register v4l2 video video_device */
>  	ret = video_register_device(dev->vdev, VFL_TYPE_GRABBER,
> @@ -2154,6 +1914,9 @@ int em28xx_register_analog_devices(struct em28xx *dev)
>  		dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template,
>  						"vbi");
>  
> +		dev->vbi_dev->queue = &dev->vb_vbiq;
> +		dev->vbi_dev->queue->lock = &dev->vb_vbi_queue_lock;
> +
>  		/* register v4l2 vbi video_device */
>  		ret = video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
>  					    vbi_nr[dev->devno]);
> diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
> index 7432be4..bf0a790 100644
> --- a/drivers/media/usb/em28xx/em28xx.h
> +++ b/drivers/media/usb/em28xx/em28xx.h
> @@ -31,15 +31,12 @@
>  #include <linux/mutex.h>
>  #include <linux/videodev2.h>
>  
> -#include <media/videobuf-vmalloc.h>
> +#include <media/videobuf2-vmalloc.h>
>  #include <media/v4l2-device.h>
>  #include <media/v4l2-ctrls.h>
>  #include <media/v4l2-fh.h>
>  #include <media/ir-kbd-i2c.h>
>  #include <media/rc-core.h>
> -#if defined(CONFIG_VIDEO_EM28XX_DVB) || defined(CONFIG_VIDEO_EM28XX_DVB_MODULE)
> -#include <media/videobuf-dvb.h>
> -#endif
>  #include "tuner-xc2028.h"
>  #include "xc5000.h"
>  #include "em28xx-reg.h"
> @@ -252,8 +249,11 @@ struct em28xx_fmt {
>  /* buffer for one video frame */
>  struct em28xx_buffer {
>  	/* common v4l buffer stuff -- must be first */
> -	struct videobuf_buffer vb;
> +	struct vb2_buffer vb;
> +	struct list_head list;
>  
> +	void *mem;
> +	unsigned int length;
>  	int top_field;
>  
>  	/* counter to control buffer fill */
> @@ -480,11 +480,6 @@ struct em28xx;
>  struct em28xx_fh {
>  	struct v4l2_fh fh;
>  	struct em28xx *dev;
> -	int           radio;
> -	unsigned int  resources;
> -
> -	struct videobuf_queue        vb_vidq;
> -	struct videobuf_queue        vb_vbiq;
>  
>  	enum v4l2_buf_type           type;
>  };
> @@ -545,6 +540,7 @@ struct em28xx {
>  	struct i2c_client i2c_client;
>  	/* video for linux */
>  	int users;		/* user count for exclusive use */
> +	int streaming_users;    /* Number of actively streaming users */
>  	struct video_device *vdev;	/* video for linux device struct */
>  	v4l2_std_id norm;	/* selected tv norm */
>  	int ctl_freq;		/* selected frequency */
> @@ -587,6 +583,12 @@ struct em28xx {
>  	struct video_device *vbi_dev;
>  	struct video_device *radio_dev;
>  
> +	/* Videobuf2 */
> +	struct vb2_queue vb_vidq;
> +	struct vb2_queue vb_vbiq;
> +	struct mutex vb_queue_lock;
> +	struct mutex vb_vbi_queue_lock;
> +
>  	/* resources in use */
>  	unsigned int resources;
>  
> @@ -598,6 +600,9 @@ struct em28xx {
>  	struct em28xx_usb_ctl usb_ctl;
>  	spinlock_t slock;
>  
> +	unsigned int field_count;
> +	unsigned int vbi_field_count;
> +
>  	/* usb transfer */
>  	struct usb_device *udev;	/* the usb device */
>  	u8 analog_ep_isoc;	/* address of isoc endpoint for analog */
> @@ -709,9 +714,12 @@ void em28xx_init_extension(struct em28xx *dev);
>  void em28xx_close_extension(struct em28xx *dev);
>  
>  /* Provided by em28xx-video.c */
> +int em28xx_vb2_setup(struct em28xx *dev);
>  int em28xx_register_analog_devices(struct em28xx *dev);
>  void em28xx_release_analog_resources(struct em28xx *dev);
>  void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv);
> +int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count);
> +int em28xx_stop_vbi_streaming(struct vb2_queue *vq);
>  extern const struct v4l2_ctrl_ops em28xx_ctrl_ops;
>  
>  /* Provided by em28xx-cards.c */
> @@ -723,7 +731,7 @@ int em28xx_tuner_callback(void *ptr, int component, int command, int arg);
>  void em28xx_release_resources(struct em28xx *dev);
>  
>  /* Provided by em28xx-vbi.c */
> -extern struct videobuf_queue_ops em28xx_vbi_qops;
> +extern struct vb2_ops em28xx_vbi_qops;
>  
>  /* printk macros */
>  

Bad news. :(
The patch seems to break USB bulk transfer mode. The framerate is zero.
I've tested with the Silvercrest webcam and the Cinergy 200. Both
devices work fine when selecting isoc transfers.

With video_debug=1 isoc_debug=1 the log shows

...
[ 207.628187] em2710 #0 print_err_status :URB status -75 [Babble (bad
cable?)].
[ 207.628436] em2710 #0 print_err_status :URB status -75 [Babble (bad
cable?)].
[ 207.628687] em2710 #0 print_err_status :URB status -75 [Babble (bad
cable?)].
[ 207.628937] em2710 #0 print_err_status :URB status -75 [Babble (bad
cable?)].
[ 207.629186] em2710 #0 print_err_status :URB status -75 [Babble (bad
cable?)].
[ 207.629436] em2710 #0 print_err_status :URB status -75 [Babble (bad
cable?)].
[ 207.629686] em2710 #0 print_err_status :URB status -75 [Babble (bad
cable?)].
[ 207.629937] em2710 #0 print_err_status :URB status -75 [Babble (bad
cable?)].
[ 207.630005] video1: poll: 00000000
[ 207.630107] video1: poll: 00000000
[ 207.630185] em2710 #0 print_err_status :URB status -75 [Babble (bad
cable?)].
[ 207.630357] video1: poll: 00000000
[ 207.630436] em2710 #0 print_err_status :URB status -75 [Babble (bad
cable?)].
[ 207.630685] em2710 #0 print_err_status :URB status -75 [Babble (bad
cable?)].
[ 207.630936] em2710 #0 print_err_status :URB status -75 [Babble (bad
cable?)].
[ 207.631085] video1: poll: 00000000
[ 207.631186] em2710 #0 print_err_status :URB status -75 [Babble (bad
cable?)].
[ 207.631436] em2710 #0 print_err_status :URB status -75 [Babble (bad
cable?)].
[ 207.631686] em2710 #0 print_err_status :URB status -75 [Babble (bad
cable?)].
[ 207.631934] em2710 #0 print_err_status :URB status -75 [Babble (bad
cable?)].
...


It seems like all incoming urbs have the error -75 = -EOVERFLOW.

I've double-checked that it is really this commit which brakes it (which
doesn't mean that the problem isn't cause by code changed with previous
commits).

Unfortunately I have to stop for today, but I will have more time
tomorrow evening for further tests/debugging/reviewing.

Regards,
Frank


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

* Re: [PATCH 15/15] em28xx: convert to videobuf2
  2013-01-08 18:40   ` Frank Schäfer
@ 2013-01-08 18:59     ` Devin Heitmueller
  0 siblings, 0 replies; 22+ messages in thread
From: Devin Heitmueller @ 2013-01-08 18:59 UTC (permalink / raw)
  To: Frank Schäfer; +Cc: Mauro Carvalho Chehab, Linux Media Mailing List

On Tue, Jan 8, 2013 at 1:40 PM, Frank Schäfer
<fschaefer.oss@googlemail.com> wrote:
> Bad news. :(
> The patch seems to break USB bulk transfer mode. The framerate is zero.
> I've tested with the Silvercrest webcam and the Cinergy 200. Both
> devices work fine when selecting isoc transfers.

I'll take a look.  I cannot actively debug it since I don't have any
devices which do bulk, but I'll at least see if anything jumps out at
me.

If I had to guess, probably something related to the setting up of the
USB alternate.

Devin

-- 
Devin J. Heitmueller - Kernel Labs
http://www.kernellabs.com

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

end of thread, other threads:[~2013-01-08 18:59 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-01-04 20:59 [PATCH 00/15] em28xx VBI2 port and v4l2-compliance fixes Devin Heitmueller
2013-01-04 20:59 ` [PATCH 01/15] em28xx: fix querycap Devin Heitmueller
2013-01-04 20:59 ` [PATCH 02/15] em28xx: remove bogus input/audio ioctls for the radio device Devin Heitmueller
2013-01-04 20:59 ` [PATCH 03/15] em28xx: fix VIDIOC_DBG_G_CHIP_IDENT compliance errors Devin Heitmueller
2013-01-04 20:59 ` [PATCH 04/15] em28xx: fix tuner/frequency handling Devin Heitmueller
2013-01-04 20:59 ` [PATCH 05/15] v4l2-ctrls: add a notify callback Devin Heitmueller
2013-01-04 20:59 ` [PATCH 06/15] em28xx: convert to the control framework Devin Heitmueller
2013-01-04 20:59 ` [PATCH 07/15] em28xx: convert to v4l2_fh, fix priority handling Devin Heitmueller
2013-01-04 20:59 ` [PATCH 08/15] em28xx: add support for control events Devin Heitmueller
2013-01-04 20:59 ` [PATCH 09/15] em28xx: fill in readbuffers and fix incorrect return code Devin Heitmueller
2013-01-04 20:59 ` [PATCH 10/15] em28xx: fix broken TRY_FMT Devin Heitmueller
2013-01-05  2:54   ` Mauro Carvalho Chehab
2013-01-05 13:34     ` Hans Verkuil
2013-01-05 15:36       ` Mauro Carvalho Chehab
2013-01-04 20:59 ` [PATCH 11/15] tvp5150: remove compat control ops Devin Heitmueller
2013-01-04 20:59 ` [PATCH 12/15] em28xx: std fixes: don't implement in webcam mode, and fix std changes Devin Heitmueller
2013-01-04 20:59 ` [PATCH 13/15] em28xx: remove sliced VBI support Devin Heitmueller
2013-01-04 20:59 ` [PATCH 14/15] em28xx: zero vbi_format reserved array and add try_vbi_fmt Devin Heitmueller
2013-01-04 20:59 ` [PATCH 15/15] em28xx: convert to videobuf2 Devin Heitmueller
2013-01-08 18:40   ` Frank Schäfer
2013-01-08 18:59     ` Devin Heitmueller
2013-01-04 21:04 ` [PATCH 00/15] em28xx VBI2 port and v4l2-compliance fixes Devin Heitmueller

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.