All of lore.kernel.org
 help / color / mirror / Atom feed
* [REVIEW PATCH 00/11] hdpvr cleanup
@ 2013-03-20 18:38 Hans Verkuil
  2013-03-20 18:38 ` [REVIEW PATCH 01/11] videodev2.h: fix incorrect V4L2_DV_FL_HALF_LINE bitmask Hans Verkuil
                   ` (10 more replies)
  0 siblings, 11 replies; 12+ messages in thread
From: Hans Verkuil @ 2013-03-20 18:38 UTC (permalink / raw)
  To: linux-media; +Cc: Janne Grunau

This patch series updates the hdpvr driver to the latest v4l2 frameworks
(except, as usual, vb2).

It has been tested with my hdpvr and a HDTV signal generator and it looks
pretty good. I did discover that you need the latest firmware to have the
hdpvr handle input and format switches correctly. I had major problems with
the old firmware that was on my box when I started testing.

Janne, there is no entry for this driver in the MAINTAINERS file. Are you
still maintainer for this driver? If so, can you make a MAINTAINERS entry
for this driver?

Regards,

	Hans


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

* [REVIEW PATCH 01/11] videodev2.h: fix incorrect V4L2_DV_FL_HALF_LINE bitmask.
  2013-03-20 18:38 [REVIEW PATCH 00/11] hdpvr cleanup Hans Verkuil
@ 2013-03-20 18:38 ` Hans Verkuil
  2013-03-20 18:38 ` [REVIEW PATCH 02/11] v4l2-dv-timings.h: add 480i59.94 and 576i50 CEA-861-E timings Hans Verkuil
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Hans Verkuil @ 2013-03-20 18:38 UTC (permalink / raw)
  To: linux-media; +Cc: Janne Grunau, Hans Verkuil

From: Hans Verkuil <hans.verkuil@cisco.com>

This was set to 1 << 0 which is the same as V4L2_DV_FL_REDUCED_BLANKING.
It should be 1 << 3 instead. Luckily interlaced formats are rarely used,
which is why this bug wasn't seen until now.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 include/uapi/linux/videodev2.h |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index b5f5cdd..7d32501 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -1120,7 +1120,7 @@ struct v4l2_bt_timings {
    longer and field 2 is really one half-line shorter, so each field has
    exactly the same number of half-lines. Whether half-lines can be detected
    or used depends on the hardware. */
-#define V4L2_DV_FL_HALF_LINE			(1 << 0)
+#define V4L2_DV_FL_HALF_LINE			(1 << 3)
 
 
 /** struct v4l2_dv_timings - DV timings
-- 
1.7.10.4


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

* [REVIEW PATCH 02/11] v4l2-dv-timings.h: add 480i59.94 and 576i50 CEA-861-E timings.
  2013-03-20 18:38 [REVIEW PATCH 00/11] hdpvr cleanup Hans Verkuil
  2013-03-20 18:38 ` [REVIEW PATCH 01/11] videodev2.h: fix incorrect V4L2_DV_FL_HALF_LINE bitmask Hans Verkuil
@ 2013-03-20 18:38 ` Hans Verkuil
  2013-03-20 18:38 ` [REVIEW PATCH 03/11] hdpvr: convert to the control framework Hans Verkuil
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Hans Verkuil @ 2013-03-20 18:38 UTC (permalink / raw)
  To: linux-media; +Cc: Janne Grunau, Hans Verkuil

From: Hans Verkuil <hans.verkuil@cisco.com>

These formats are supported by the HDPVR, but they were missing in the list.
Note that these formats are different from the common PAL/NTSC/SECAM formats
since all color channels are transmitted separately and so there is no PAL
or NTSC or SECAM color encoding involved.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 include/uapi/linux/v4l2-dv-timings.h |   18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/include/uapi/linux/v4l2-dv-timings.h b/include/uapi/linux/v4l2-dv-timings.h
index 9ef8172..4e0c58d 100644
--- a/include/uapi/linux/v4l2-dv-timings.h
+++ b/include/uapi/linux/v4l2-dv-timings.h
@@ -42,6 +42,15 @@
 		V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CEA861, 0) \
 }
 
+/* Note: these are the nominal timings, for HDMI links this format is typically
+ * double-clocked to meet the minimum pixelclock requirements.  */
+#define V4L2_DV_BT_CEA_720X480I59_94 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(720, 480, 1, 0, \
+		13500000, 19, 62, 57, 4, 3, 15, 4, 3, 16, \
+		V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_HALF_LINE) \
+}
+
 #define V4L2_DV_BT_CEA_720X480P59_94 { \
 	.type = V4L2_DV_BT_656_1120, \
 	V4L2_INIT_BT_TIMINGS(720, 480, 0, 0, \
@@ -49,6 +58,15 @@
 		V4L2_DV_BT_STD_CEA861, 0) \
 }
 
+/* Note: these are the nominal timings, for HDMI links this format is typically
+ * double-clocked to meet the minimum pixelclock requirements.  */
+#define V4L2_DV_BT_CEA_720X576I50 { \
+	.type = V4L2_DV_BT_656_1120, \
+	V4L2_INIT_BT_TIMINGS(720, 576, 1, 0, \
+		13500000, 12, 63, 69, 2, 3, 19, 2, 3, 20, \
+		V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_HALF_LINE) \
+}
+
 #define V4L2_DV_BT_CEA_720X576P50 { \
 	.type = V4L2_DV_BT_656_1120, \
 	V4L2_INIT_BT_TIMINGS(720, 576, 0, 0, \
-- 
1.7.10.4


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

* [REVIEW PATCH 03/11] hdpvr: convert to the control framework.
  2013-03-20 18:38 [REVIEW PATCH 00/11] hdpvr cleanup Hans Verkuil
  2013-03-20 18:38 ` [REVIEW PATCH 01/11] videodev2.h: fix incorrect V4L2_DV_FL_HALF_LINE bitmask Hans Verkuil
  2013-03-20 18:38 ` [REVIEW PATCH 02/11] v4l2-dv-timings.h: add 480i59.94 and 576i50 CEA-861-E timings Hans Verkuil
@ 2013-03-20 18:38 ` Hans Verkuil
  2013-03-20 18:38 ` [REVIEW PATCH 04/11] hdpvr: remove hdpvr_fh and just use v4l2_fh Hans Verkuil
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Hans Verkuil @ 2013-03-20 18:38 UTC (permalink / raw)
  To: linux-media; +Cc: Janne Grunau, Hans Verkuil

From: Hans Verkuil <hans.verkuil@cisco.com>

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/usb/hdpvr/hdpvr-video.c |  515 +++++++++------------------------
 drivers/media/usb/hdpvr/hdpvr.h       |    8 +
 2 files changed, 145 insertions(+), 378 deletions(-)

diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c
index da6b779..9f03add 100644
--- a/drivers/media/usb/hdpvr/hdpvr-video.c
+++ b/drivers/media/usb/hdpvr/hdpvr-video.c
@@ -709,335 +709,69 @@ static int vidioc_g_audio(struct file *file, void *private_data,
 	return 0;
 }
 
-static const s32 supported_v4l2_ctrls[] = {
-	V4L2_CID_BRIGHTNESS,
-	V4L2_CID_CONTRAST,
-	V4L2_CID_SATURATION,
-	V4L2_CID_HUE,
-	V4L2_CID_SHARPNESS,
-	V4L2_CID_MPEG_AUDIO_ENCODING,
-	V4L2_CID_MPEG_VIDEO_ENCODING,
-	V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
-	V4L2_CID_MPEG_VIDEO_BITRATE,
-	V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
-};
-
-static int fill_queryctrl(struct hdpvr_options *opt, struct v4l2_queryctrl *qc,
-			  int ac3, int fw_ver)
-{
-	int err;
-
-	if (fw_ver > 0x15) {
-		switch (qc->id) {
-		case V4L2_CID_BRIGHTNESS:
-			return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
-		case V4L2_CID_CONTRAST:
-			return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x40);
-		case V4L2_CID_SATURATION:
-			return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x40);
-		case V4L2_CID_HUE:
-			return v4l2_ctrl_query_fill(qc, 0x0, 0x1e, 1, 0xf);
-		case V4L2_CID_SHARPNESS:
-			return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
-		}
-	} else {
-		switch (qc->id) {
-		case V4L2_CID_BRIGHTNESS:
-			return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x86);
-		case V4L2_CID_CONTRAST:
-			return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
-		case V4L2_CID_SATURATION:
-			return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
-		case V4L2_CID_HUE:
-			return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
-		case V4L2_CID_SHARPNESS:
-			return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
-		}
-	}
-
-	switch (qc->id) {
-	case V4L2_CID_MPEG_AUDIO_ENCODING:
-		return v4l2_ctrl_query_fill(
-			qc, V4L2_MPEG_AUDIO_ENCODING_AAC,
-			ac3 ? V4L2_MPEG_AUDIO_ENCODING_AC3
-			: V4L2_MPEG_AUDIO_ENCODING_AAC,
-			1, V4L2_MPEG_AUDIO_ENCODING_AAC);
-	case V4L2_CID_MPEG_VIDEO_ENCODING:
-		return v4l2_ctrl_query_fill(
-			qc, V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC,
-			V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 1,
-			V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC);
-
-/* 	case V4L2_CID_MPEG_VIDEO_? maybe keyframe interval: */
-/* 		return v4l2_ctrl_query_fill(qc, 0, 128, 128, 0); */
-	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
-		return v4l2_ctrl_query_fill(
-			qc, V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
-			V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 1,
-			V4L2_MPEG_VIDEO_BITRATE_MODE_CBR);
-
-	case V4L2_CID_MPEG_VIDEO_BITRATE:
-		return v4l2_ctrl_query_fill(qc, 1000000, 13500000, 100000,
-					    6500000);
-	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
-		err = v4l2_ctrl_query_fill(qc, 1100000, 20200000, 100000,
-					   9000000);
-		if (!err && opt->bitrate_mode == HDPVR_CONSTANT)
-			qc->flags |= V4L2_CTRL_FLAG_INACTIVE;
-		return err;
-	default:
-		return -EINVAL;
-	}
-}
-
-static int vidioc_queryctrl(struct file *file, void *private_data,
-			    struct v4l2_queryctrl *qc)
+static int hdpvr_try_ctrl(struct v4l2_ctrl *ctrl)
 {
-	struct hdpvr_fh *fh = file->private_data;
-	struct hdpvr_device *dev = fh->dev;
-	int i, next;
-	u32 id = qc->id;
-
-	memset(qc, 0, sizeof(*qc));
-
-	next = !!(id &  V4L2_CTRL_FLAG_NEXT_CTRL);
-	qc->id = id & ~V4L2_CTRL_FLAG_NEXT_CTRL;
-
-	for (i = 0; i < ARRAY_SIZE(supported_v4l2_ctrls); i++) {
-		if (next) {
-			if (qc->id < supported_v4l2_ctrls[i])
-				qc->id = supported_v4l2_ctrls[i];
-			else
-				continue;
-		}
-
-		if (qc->id == supported_v4l2_ctrls[i])
-			return fill_queryctrl(&dev->options, qc,
-					      dev->flags & HDPVR_FLAG_AC3_CAP,
-					      dev->fw_ver);
-
-		if (qc->id < supported_v4l2_ctrls[i])
-			break;
-	}
-
-	return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *private_data,
-			 struct v4l2_control *ctrl)
-{
-	struct hdpvr_fh *fh = file->private_data;
-	struct hdpvr_device *dev = fh->dev;
+	struct hdpvr_device *dev =
+		container_of(ctrl->handler, struct hdpvr_device, hdl);
 
 	switch (ctrl->id) {
-	case V4L2_CID_BRIGHTNESS:
-		ctrl->value = dev->options.brightness;
-		break;
-	case V4L2_CID_CONTRAST:
-		ctrl->value = dev->options.contrast;
-		break;
-	case V4L2_CID_SATURATION:
-		ctrl->value = dev->options.saturation;
-		break;
-	case V4L2_CID_HUE:
-		ctrl->value = dev->options.hue;
-		break;
-	case V4L2_CID_SHARPNESS:
-		ctrl->value = dev->options.sharpness;
+	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+		if (ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
+		    dev->video_bitrate->val >= dev->video_bitrate_peak->val)
+			dev->video_bitrate_peak->val =
+					dev->video_bitrate->val + 100000;
 		break;
-	default:
-		return -EINVAL;
 	}
 	return 0;
 }
 
-static int vidioc_s_ctrl(struct file *file, void *private_data,
-			 struct v4l2_control *ctrl)
+static int hdpvr_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-	struct hdpvr_fh *fh = file->private_data;
-	struct hdpvr_device *dev = fh->dev;
-	int retval;
+	struct hdpvr_device *dev =
+		container_of(ctrl->handler, struct hdpvr_device, hdl);
+	struct hdpvr_options *opt = &dev->options;
+	int ret = -EINVAL;
 
 	switch (ctrl->id) {
 	case V4L2_CID_BRIGHTNESS:
-		retval = hdpvr_config_call(dev, CTRL_BRIGHTNESS, ctrl->value);
-		if (!retval)
-			dev->options.brightness = ctrl->value;
-		break;
+		ret = hdpvr_config_call(dev, CTRL_BRIGHTNESS, ctrl->val);
+		if (ret)
+			break;
+		dev->options.brightness = ctrl->val;
+		return 0;
 	case V4L2_CID_CONTRAST:
-		retval = hdpvr_config_call(dev, CTRL_CONTRAST, ctrl->value);
-		if (!retval)
-			dev->options.contrast = ctrl->value;
-		break;
+		ret = hdpvr_config_call(dev, CTRL_CONTRAST, ctrl->val);
+		if (ret)
+			break;
+		dev->options.contrast = ctrl->val;
+		return 0;
 	case V4L2_CID_SATURATION:
-		retval = hdpvr_config_call(dev, CTRL_SATURATION, ctrl->value);
-		if (!retval)
-			dev->options.saturation = ctrl->value;
-		break;
+		ret = hdpvr_config_call(dev, CTRL_SATURATION, ctrl->val);
+		if (ret)
+			break;
+		dev->options.saturation = ctrl->val;
+		return 0;
 	case V4L2_CID_HUE:
-		retval = hdpvr_config_call(dev, CTRL_HUE, ctrl->value);
-		if (!retval)
-			dev->options.hue = ctrl->value;
-		break;
+		ret = hdpvr_config_call(dev, CTRL_HUE, ctrl->val);
+		if (ret)
+			break;
+		dev->options.hue = ctrl->val;
+		return 0;
 	case V4L2_CID_SHARPNESS:
-		retval = hdpvr_config_call(dev, CTRL_SHARPNESS, ctrl->value);
-		if (!retval)
-			dev->options.sharpness = ctrl->value;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return retval;
-}
-
-
-static int hdpvr_get_ctrl(struct hdpvr_options *opt,
-			  struct v4l2_ext_control *ctrl)
-{
-	switch (ctrl->id) {
-	case V4L2_CID_MPEG_AUDIO_ENCODING:
-		ctrl->value = opt->audio_codec;
-		break;
-	case V4L2_CID_MPEG_VIDEO_ENCODING:
-		ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC;
-		break;
-/* 	case V4L2_CID_MPEG_VIDEO_B_FRAMES: */
-/* 		ctrl->value = (opt->gop_mode & 0x2) ? 0 : 128; */
-/* 		break; */
-	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
-		ctrl->value = opt->bitrate_mode == HDPVR_CONSTANT
-			? V4L2_MPEG_VIDEO_BITRATE_MODE_CBR
-			: V4L2_MPEG_VIDEO_BITRATE_MODE_VBR;
-		break;
-	case V4L2_CID_MPEG_VIDEO_BITRATE:
-		ctrl->value = opt->bitrate * 100000;
-		break;
-	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
-		ctrl->value = opt->peak_bitrate * 100000;
-		break;
-	case V4L2_CID_MPEG_STREAM_TYPE:
-		ctrl->value = V4L2_MPEG_STREAM_TYPE_MPEG2_TS;
-		break;
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
-static int vidioc_g_ext_ctrls(struct file *file, void *priv,
-			      struct v4l2_ext_controls *ctrls)
-{
-	struct hdpvr_fh *fh = file->private_data;
-	struct hdpvr_device *dev = fh->dev;
-	int i, err = 0;
-
-	if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
-		for (i = 0; i < ctrls->count; i++) {
-			struct v4l2_ext_control *ctrl = ctrls->controls + i;
-
-			err = hdpvr_get_ctrl(&dev->options, ctrl);
-			if (err) {
-				ctrls->error_idx = i;
-				break;
-			}
-		}
-		return err;
-
-	}
-
-	return -EINVAL;
-}
-
-
-static int hdpvr_try_ctrl(struct v4l2_ext_control *ctrl, int ac3)
-{
-	int ret = -EINVAL;
-
-	switch (ctrl->id) {
-	case V4L2_CID_MPEG_AUDIO_ENCODING:
-		if (ctrl->value == V4L2_MPEG_AUDIO_ENCODING_AAC ||
-		    (ac3 && ctrl->value == V4L2_MPEG_AUDIO_ENCODING_AC3))
-			ret = 0;
-		break;
-	case V4L2_CID_MPEG_VIDEO_ENCODING:
-		if (ctrl->value == V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC)
-			ret = 0;
-		break;
-/* 	case V4L2_CID_MPEG_VIDEO_B_FRAMES: */
-/* 		if (ctrl->value == 0 || ctrl->value == 128) */
-/* 			ret = 0; */
-/* 		break; */
-	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
-		if (ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR ||
-		    ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR)
-			ret = 0;
-		break;
-	case V4L2_CID_MPEG_VIDEO_BITRATE:
-	{
-		uint bitrate = ctrl->value / 100000;
-		if (bitrate >= 10 && bitrate <= 135)
-			ret = 0;
-		break;
-	}
-	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
-	{
-		uint peak_bitrate = ctrl->value / 100000;
-		if (peak_bitrate >= 10 && peak_bitrate <= 202)
-			ret = 0;
-		break;
-	}
-	case V4L2_CID_MPEG_STREAM_TYPE:
-		if (ctrl->value == V4L2_MPEG_STREAM_TYPE_MPEG2_TS)
-			ret = 0;
-		break;
-	default:
-		return -EINVAL;
-	}
-	return ret;
-}
-
-static int vidioc_try_ext_ctrls(struct file *file, void *priv,
-				struct v4l2_ext_controls *ctrls)
-{
-	struct hdpvr_fh *fh = file->private_data;
-	struct hdpvr_device *dev = fh->dev;
-	int i, err = 0;
-
-	if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
-		for (i = 0; i < ctrls->count; i++) {
-			struct v4l2_ext_control *ctrl = ctrls->controls + i;
-
-			err = hdpvr_try_ctrl(ctrl,
-					     dev->flags & HDPVR_FLAG_AC3_CAP);
-			if (err) {
-				ctrls->error_idx = i;
-				break;
-			}
-		}
-		return err;
-	}
-
-	return -EINVAL;
-}
-
-
-static int hdpvr_set_ctrl(struct hdpvr_device *dev,
-			  struct v4l2_ext_control *ctrl)
-{
-	struct hdpvr_options *opt = &dev->options;
-	int ret = 0;
-
-	switch (ctrl->id) {
+		ret = hdpvr_config_call(dev, CTRL_SHARPNESS, ctrl->val);
+		if (ret)
+			break;
+		dev->options.sharpness = ctrl->val;
+		return 0;
 	case V4L2_CID_MPEG_AUDIO_ENCODING:
 		if (dev->flags & HDPVR_FLAG_AC3_CAP) {
-			opt->audio_codec = ctrl->value;
-			ret = hdpvr_set_audio(dev, opt->audio_input,
+			opt->audio_codec = ctrl->val;
+			return hdpvr_set_audio(dev, opt->audio_input,
 					      opt->audio_codec);
 		}
-		break;
+		return 0;
 	case V4L2_CID_MPEG_VIDEO_ENCODING:
-		break;
+		return 0;
 /* 	case V4L2_CID_MPEG_VIDEO_B_FRAMES: */
 /* 		if (ctrl->value == 0 && !(opt->gop_mode & 0x2)) { */
 /* 			opt->gop_mode |= 0x2; */
@@ -1050,81 +784,37 @@ static int hdpvr_set_ctrl(struct hdpvr_device *dev,
 /* 					  opt->gop_mode); */
 /* 		} */
 /* 		break; */
-	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
-		if (ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR &&
-		    opt->bitrate_mode != HDPVR_CONSTANT) {
-			opt->bitrate_mode = HDPVR_CONSTANT;
-			hdpvr_config_call(dev, CTRL_BITRATE_MODE_VALUE,
-					  opt->bitrate_mode);
-		}
-		if (ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
-		    opt->bitrate_mode == HDPVR_CONSTANT) {
-			opt->bitrate_mode = HDPVR_VARIABLE_AVERAGE;
+	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: {
+		uint peak_bitrate = dev->video_bitrate_peak->val / 100000;
+		uint bitrate = dev->video_bitrate->val / 100000;
+
+		if (ctrl->is_new) {
+			if (ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
+				opt->bitrate_mode = HDPVR_CONSTANT;
+			else
+				opt->bitrate_mode = HDPVR_VARIABLE_AVERAGE;
 			hdpvr_config_call(dev, CTRL_BITRATE_MODE_VALUE,
 					  opt->bitrate_mode);
+			v4l2_ctrl_activate(dev->video_bitrate_peak,
+				ctrl->val != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR);
 		}
-		break;
-	case V4L2_CID_MPEG_VIDEO_BITRATE: {
-		uint bitrate = ctrl->value / 100000;
-
-		opt->bitrate = bitrate;
-		if (bitrate >= opt->peak_bitrate)
-			opt->peak_bitrate = bitrate+1;
-
-		hdpvr_set_bitrate(dev);
-		break;
-	}
-	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: {
-		uint peak_bitrate = ctrl->value / 100000;
 
-		if (opt->bitrate_mode == HDPVR_CONSTANT)
-			break;
-
-		if (opt->bitrate < peak_bitrate) {
+		if (dev->video_bitrate_peak->is_new ||
+		    dev->video_bitrate->is_new) {
+			opt->bitrate = bitrate;
 			opt->peak_bitrate = peak_bitrate;
 			hdpvr_set_bitrate(dev);
-		} else
-			ret = -EINVAL;
-		break;
+		}
+		return 0;
 	}
 	case V4L2_CID_MPEG_STREAM_TYPE:
-		break;
+		return 0;
 	default:
-		return -EINVAL;
+		break;
 	}
 	return ret;
 }
 
-static int vidioc_s_ext_ctrls(struct file *file, void *priv,
-			      struct v4l2_ext_controls *ctrls)
-{
-	struct hdpvr_fh *fh = file->private_data;
-	struct hdpvr_device *dev = fh->dev;
-	int i, err = 0;
-
-	if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
-		for (i = 0; i < ctrls->count; i++) {
-			struct v4l2_ext_control *ctrl = ctrls->controls + i;
-
-			err = hdpvr_try_ctrl(ctrl,
-					     dev->flags & HDPVR_FLAG_AC3_CAP);
-			if (err) {
-				ctrls->error_idx = i;
-				break;
-			}
-			err = hdpvr_set_ctrl(dev, ctrl);
-			if (err) {
-				ctrls->error_idx = i;
-				break;
-			}
-		}
-		return err;
-
-	}
-
-	return -EINVAL;
-}
-
 static int vidioc_enum_fmt_vid_cap(struct file *file, void *private_data,
 				    struct v4l2_fmtdesc *f)
 {
@@ -1214,12 +904,6 @@ static const struct v4l2_ioctl_ops hdpvr_ioctl_ops = {
 	.vidioc_enumaudio	= vidioc_enumaudio,
 	.vidioc_g_audio		= vidioc_g_audio,
 	.vidioc_s_audio		= vidioc_s_audio,
-	.vidioc_queryctrl	= vidioc_queryctrl,
-	.vidioc_g_ctrl		= vidioc_g_ctrl,
-	.vidioc_s_ctrl		= vidioc_s_ctrl,
-	.vidioc_g_ext_ctrls	= vidioc_g_ext_ctrls,
-	.vidioc_s_ext_ctrls	= vidioc_s_ext_ctrls,
-	.vidioc_try_ext_ctrls	= vidioc_try_ext_ctrls,
 	.vidioc_enum_fmt_vid_cap	= vidioc_enum_fmt_vid_cap,
 	.vidioc_g_fmt_vid_cap		= vidioc_g_fmt_vid_cap,
 	.vidioc_encoder_cmd	= vidioc_encoder_cmd,
@@ -1236,6 +920,7 @@ static void hdpvr_device_release(struct video_device *vdev)
 	mutex_unlock(&dev->io_mutex);
 
 	v4l2_device_unregister(&dev->v4l2_dev);
+	v4l2_ctrl_handler_free(&dev->hdl);
 
 	/* deregister I2C adapter */
 #if defined(CONFIG_I2C) || (CONFIG_I2C_MODULE)
@@ -1263,13 +948,85 @@ static const struct video_device hdpvr_video_template = {
 		V4L2_STD_PAL_60,
 };
 
+static const struct v4l2_ctrl_ops hdpvr_ctrl_ops = {
+	.try_ctrl = hdpvr_try_ctrl,
+	.s_ctrl = hdpvr_s_ctrl,
+};
+
 int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent,
 			    int devnum)
 {
+	struct v4l2_ctrl_handler *hdl = &dev->hdl;
+	bool ac3 = dev->flags & HDPVR_FLAG_AC3_CAP;
+	int res;
+
+	v4l2_ctrl_handler_init(hdl, 11);
+	if (dev->fw_ver > 0x15) {
+		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
+			V4L2_CID_BRIGHTNESS, 0x0, 0xff, 1, 0x80);
+		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
+			V4L2_CID_CONTRAST, 0x0, 0xff, 1, 0x40);
+		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
+			V4L2_CID_SATURATION, 0x0, 0xff, 1, 0x40);
+		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
+			V4L2_CID_HUE, 0x0, 0x1e, 1, 0xf);
+		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
+			V4L2_CID_SHARPNESS, 0x0, 0xff, 1, 0x80);
+	} else {
+		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
+			V4L2_CID_BRIGHTNESS, 0x0, 0xff, 1, 0x86);
+		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
+			V4L2_CID_CONTRAST, 0x0, 0xff, 1, 0x80);
+		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
+			V4L2_CID_SATURATION, 0x0, 0xff, 1, 0x80);
+		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
+			V4L2_CID_HUE, 0x0, 0xff, 1, 0x80);
+		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
+			V4L2_CID_SHARPNESS, 0x0, 0xff, 1, 0x80);
+	}
+
+	v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops,
+		V4L2_CID_MPEG_STREAM_TYPE,
+		V4L2_MPEG_STREAM_TYPE_MPEG2_TS,
+		0x1, V4L2_MPEG_STREAM_TYPE_MPEG2_TS);
+	v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops,
+		V4L2_CID_MPEG_AUDIO_ENCODING,
+		ac3 ? V4L2_MPEG_AUDIO_ENCODING_AC3 : V4L2_MPEG_AUDIO_ENCODING_AAC,
+		0x7, V4L2_MPEG_AUDIO_ENCODING_AAC);
+	v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops,
+		V4L2_CID_MPEG_VIDEO_ENCODING,
+		V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 0x3,
+		V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC);
+
+	dev->video_mode = v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops,
+		V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+		V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0,
+		V4L2_MPEG_VIDEO_BITRATE_MODE_CBR);
+
+	dev->video_bitrate = v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
+		V4L2_CID_MPEG_VIDEO_BITRATE,
+		1000000, 13500000, 100000, 6500000);
+	dev->video_bitrate_peak = v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
+		V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
+		1100000, 20200000, 100000, 9000000);
+	dev->v4l2_dev.ctrl_handler = hdl;
+	if (hdl->error) {
+		res = hdl->error;
+		v4l2_err(&dev->v4l2_dev, "Could not register controls\n");
+		goto error;
+	}
+	v4l2_ctrl_cluster(3, &dev->video_mode);
+	res = v4l2_ctrl_handler_setup(hdl);
+	if (res < 0) {
+		v4l2_err(&dev->v4l2_dev, "Could not setup controls\n");
+		goto error;
+	}
+
 	/* setup and register video device */
 	dev->video_dev = video_device_alloc();
 	if (!dev->video_dev) {
 		v4l2_err(&dev->v4l2_dev, "video_device_alloc() failed\n");
+		res = -ENOMEM;
 		goto error;
 	}
 
@@ -1278,12 +1035,14 @@ int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent,
 	dev->video_dev->parent = parent;
 	video_set_drvdata(dev->video_dev, dev);
 
-	if (video_register_device(dev->video_dev, VFL_TYPE_GRABBER, devnum)) {
+	res = video_register_device(dev->video_dev, VFL_TYPE_GRABBER, devnum);
+	if (res < 0) {
 		v4l2_err(&dev->v4l2_dev, "video_device registration failed\n");
 		goto error;
 	}
 
 	return 0;
 error:
-	return -ENOMEM;
+	v4l2_ctrl_handler_free(hdl);
+	return res;
 }
diff --git a/drivers/media/usb/hdpvr/hdpvr.h b/drivers/media/usb/hdpvr/hdpvr.h
index fea3c69..2a4deab 100644
--- a/drivers/media/usb/hdpvr/hdpvr.h
+++ b/drivers/media/usb/hdpvr/hdpvr.h
@@ -16,6 +16,7 @@
 #include <linux/videodev2.h>
 
 #include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
 #include <media/ir-kbd-i2c.h>
 
 #define HDPVR_MAX 8
@@ -65,10 +66,17 @@ struct hdpvr_options {
 struct hdpvr_device {
 	/* the v4l device for this device */
 	struct video_device	*video_dev;
+	/* the control handler for this device */
+	struct v4l2_ctrl_handler hdl;
 	/* the usb device for this device */
 	struct usb_device	*udev;
 	/* v4l2-device unused */
 	struct v4l2_device	v4l2_dev;
+	struct { /* video mode/bitrate control cluster */
+		struct v4l2_ctrl *video_mode;
+		struct v4l2_ctrl *video_bitrate;
+		struct v4l2_ctrl *video_bitrate_peak;
+	};
 
 	/* the max packet size of the bulk endpoint */
 	size_t			bulk_in_size;
-- 
1.7.10.4


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

* [REVIEW PATCH 04/11] hdpvr: remove hdpvr_fh and just use v4l2_fh.
  2013-03-20 18:38 [REVIEW PATCH 00/11] hdpvr cleanup Hans Verkuil
                   ` (2 preceding siblings ...)
  2013-03-20 18:38 ` [REVIEW PATCH 03/11] hdpvr: convert to the control framework Hans Verkuil
@ 2013-03-20 18:38 ` Hans Verkuil
  2013-03-20 18:38 ` [REVIEW PATCH 05/11] hdpvr: add prio and control event support Hans Verkuil
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Hans Verkuil @ 2013-03-20 18:38 UTC (permalink / raw)
  To: linux-media; +Cc: Janne Grunau, Hans Verkuil

From: Hans Verkuil <hans.verkuil@cisco.com>

This prepares the driver for priority and control event handling.

This patch also checks for correct streaming ownership and it makes a
small improvement to the encoder_cmd ioctls: always zero 'flags' and
drop the memset of 'raw' as that is already done by the v4l2 core.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/usb/hdpvr/hdpvr-video.c |  116 +++++++++++++--------------------
 drivers/media/usb/hdpvr/hdpvr.h       |    4 +-
 2 files changed, 46 insertions(+), 74 deletions(-)

diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c
index 9f03add..873bb23 100644
--- a/drivers/media/usb/hdpvr/hdpvr-video.c
+++ b/drivers/media/usb/hdpvr/hdpvr-video.c
@@ -34,10 +34,6 @@
 			 list_size(&dev->free_buff_list),		\
 			 list_size(&dev->rec_buff_list)); }
 
-struct hdpvr_fh {
-	struct hdpvr_device	*dev;
-};
-
 static uint list_size(struct list_head *list)
 {
 	struct list_head *tmp;
@@ -357,55 +353,21 @@ static int hdpvr_stop_streaming(struct hdpvr_device *dev)
  * video 4 linux 2 file operations
  */
 
-static int hdpvr_open(struct file *file)
-{
-	struct hdpvr_device *dev;
-	struct hdpvr_fh *fh;
-	int retval = -ENOMEM;
-
-	dev = (struct hdpvr_device *)video_get_drvdata(video_devdata(file));
-	if (!dev) {
-		pr_err("open failing with with ENODEV\n");
-		retval = -ENODEV;
-		goto err;
-	}
-
-	fh = kzalloc(sizeof(struct hdpvr_fh), GFP_KERNEL);
-	if (!fh) {
-		v4l2_err(&dev->v4l2_dev, "Out of memory\n");
-		goto err;
-	}
-	/* lock the device to allow correctly handling errors
-	 * in resumption */
-	mutex_lock(&dev->io_mutex);
-	dev->open_count++;
-	mutex_unlock(&dev->io_mutex);
-
-	fh->dev = dev;
-
-	/* save our object in the file's private structure */
-	file->private_data = fh;
-
-	retval = 0;
-err:
-	return retval;
-}
-
 static int hdpvr_release(struct file *file)
 {
-	struct hdpvr_fh		*fh  = file->private_data;
-	struct hdpvr_device	*dev = fh->dev;
+	struct hdpvr_device *dev = video_drvdata(file);
 
 	if (!dev)
 		return -ENODEV;
 
 	mutex_lock(&dev->io_mutex);
-	if (!(--dev->open_count) && dev->status == STATUS_STREAMING)
+	if (file->private_data == dev->owner) {
 		hdpvr_stop_streaming(dev);
-
+		dev->owner = NULL;
+	}
 	mutex_unlock(&dev->io_mutex);
 
-	return 0;
+	return v4l2_fh_release(file);
 }
 
 /*
@@ -415,8 +377,7 @@ static int hdpvr_release(struct file *file)
 static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count,
 			  loff_t *pos)
 {
-	struct hdpvr_fh *fh = file->private_data;
-	struct hdpvr_device *dev = fh->dev;
+	struct hdpvr_device *dev = video_drvdata(file);
 	struct hdpvr_buffer *buf = NULL;
 	struct urb *urb;
 	unsigned int ret = 0;
@@ -439,6 +400,7 @@ static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count,
 			mutex_unlock(&dev->io_mutex);
 			goto err;
 		}
+		dev->owner = file->private_data;
 		print_buffer_status();
 	}
 	mutex_unlock(&dev->io_mutex);
@@ -517,8 +479,7 @@ err:
 static unsigned int hdpvr_poll(struct file *filp, poll_table *wait)
 {
 	struct hdpvr_buffer *buf = NULL;
-	struct hdpvr_fh *fh = filp->private_data;
-	struct hdpvr_device *dev = fh->dev;
+	struct hdpvr_device *dev = video_drvdata(filp);
 	unsigned int mask = 0;
 
 	mutex_lock(&dev->io_mutex);
@@ -533,6 +494,8 @@ static unsigned int hdpvr_poll(struct file *filp, poll_table *wait)
 			v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
 				 "start_streaming failed\n");
 			dev->status = STATUS_IDLE;
+		} else {
+			dev->owner = filp->private_data;
 		}
 
 		print_buffer_status();
@@ -554,7 +517,7 @@ static unsigned int hdpvr_poll(struct file *filp, poll_table *wait)
 
 static const struct v4l2_file_operations hdpvr_fops = {
 	.owner		= THIS_MODULE,
-	.open		= hdpvr_open,
+	.open		= v4l2_fh_open,
 	.release	= hdpvr_release,
 	.read		= hdpvr_read,
 	.poll		= hdpvr_poll,
@@ -583,8 +546,7 @@ static int vidioc_querycap(struct file *file, void  *priv,
 static int vidioc_s_std(struct file *file, void *private_data,
 			v4l2_std_id *std)
 {
-	struct hdpvr_fh *fh = file->private_data;
-	struct hdpvr_device *dev = fh->dev;
+	struct hdpvr_device *dev = video_drvdata(file);
 	u8 std_type = 1;
 
 	if (*std & (V4L2_STD_NTSC | V4L2_STD_PAL_60))
@@ -602,8 +564,7 @@ static const char *iname[] = {
 static int vidioc_enum_input(struct file *file, void *priv,
 				struct v4l2_input *i)
 {
-	struct hdpvr_fh *fh = file->private_data;
-	struct hdpvr_device *dev = fh->dev;
+	struct hdpvr_device *dev = video_drvdata(file);
 	unsigned int n;
 
 	n = i->index;
@@ -625,8 +586,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
 static int vidioc_s_input(struct file *file, void *private_data,
 			  unsigned int index)
 {
-	struct hdpvr_fh *fh = file->private_data;
-	struct hdpvr_device *dev = fh->dev;
+	struct hdpvr_device *dev = video_drvdata(file);
 	int retval;
 
 	if (index >= HDPVR_VIDEO_INPUTS)
@@ -645,8 +605,7 @@ static int vidioc_s_input(struct file *file, void *private_data,
 static int vidioc_g_input(struct file *file, void *private_data,
 			  unsigned int *index)
 {
-	struct hdpvr_fh *fh = file->private_data;
-	struct hdpvr_device *dev = fh->dev;
+	struct hdpvr_device *dev = video_drvdata(file);
 
 	*index = dev->options.video_input;
 	return 0;
@@ -679,8 +638,7 @@ static int vidioc_enumaudio(struct file *file, void *priv,
 static int vidioc_s_audio(struct file *file, void *private_data,
 			  const struct v4l2_audio *audio)
 {
-	struct hdpvr_fh *fh = file->private_data;
-	struct hdpvr_device *dev = fh->dev;
+	struct hdpvr_device *dev = video_drvdata(file);
 	int retval;
 
 	if (audio->index >= HDPVR_AUDIO_INPUTS)
@@ -699,8 +657,7 @@ static int vidioc_s_audio(struct file *file, void *private_data,
 static int vidioc_g_audio(struct file *file, void *private_data,
 			  struct v4l2_audio *audio)
 {
-	struct hdpvr_fh *fh = file->private_data;
-	struct hdpvr_device *dev = fh->dev;
+	struct hdpvr_device *dev = video_drvdata(file);
 
 	audio->index = dev->options.audio_input;
 	audio->capability = V4L2_AUDCAP_STEREO;
@@ -832,8 +789,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *private_data,
 static int vidioc_g_fmt_vid_cap(struct file *file, void *private_data,
 				struct v4l2_format *f)
 {
-	struct hdpvr_fh *fh = file->private_data;
-	struct hdpvr_device *dev = fh->dev;
+	struct hdpvr_device *dev = video_drvdata(file);
 	struct hdpvr_video_info *vid_info;
 
 	if (!dev)
@@ -859,26 +815,43 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *private_data,
 static int vidioc_encoder_cmd(struct file *filp, void *priv,
 			       struct v4l2_encoder_cmd *a)
 {
-	struct hdpvr_fh *fh = filp->private_data;
-	struct hdpvr_device *dev = fh->dev;
-	int res;
+	struct hdpvr_device *dev = video_drvdata(filp);
+	int res = 0;
 
 	mutex_lock(&dev->io_mutex);
+	a->flags = 0;
 
-	memset(&a->raw, 0, sizeof(a->raw));
 	switch (a->cmd) {
-	case V4L2_ENC_CMD_START:
-		a->flags = 0;
+		if (dev->owner && filp->private_data != dev->owner) {
+			res = -EBUSY;
+			break;
+		}
+		if (dev->status == STATUS_STREAMING)
+			break;
 		res = hdpvr_start_streaming(dev);
+		if (!res)
+			dev->owner = filp->private_data;
+		else
+			dev->status = STATUS_IDLE;
 		break;
 	case V4L2_ENC_CMD_STOP:
+		if (dev->owner && filp->private_data != dev->owner) {
+			res = -EBUSY;
+			break;
+		}
+		if (dev->status == STATUS_IDLE)
+			break;
 		res = hdpvr_stop_streaming(dev);
+		if (!res)
+			dev->owner = NULL;
 		break;
 	default:
 		v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
 			 "Unsupported encoder cmd %d\n", a->cmd);
 		res = -EINVAL;
+		break;
 	}
+
 	mutex_unlock(&dev->io_mutex);
 	return res;
 }
@@ -886,6 +859,7 @@ static int vidioc_encoder_cmd(struct file *filp, void *priv,
 static int vidioc_try_encoder_cmd(struct file *filp, void *priv,
 					struct v4l2_encoder_cmd *a)
 {
+	a->flags = 0;
 	switch (a->cmd) {
 	case V4L2_ENC_CMD_START:
 	case V4L2_ENC_CMD_STOP:
@@ -934,8 +908,6 @@ static void hdpvr_device_release(struct video_device *vdev)
 }
 
 static const struct video_device hdpvr_video_template = {
-/* 	.type			= VFL_TYPE_GRABBER, */
-/* 	.type2			= VID_TYPE_CAPTURE | VID_TYPE_MPEG_ENCODER, */
 	.fops			= &hdpvr_fops,
 	.release		= hdpvr_device_release,
 	.ioctl_ops 		= &hdpvr_ioctl_ops,
@@ -1030,9 +1002,9 @@ int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent,
 		goto error;
 	}
 
-	*(dev->video_dev) = hdpvr_video_template;
+	*dev->video_dev = hdpvr_video_template;
 	strcpy(dev->video_dev->name, "Hauppauge HD PVR");
-	dev->video_dev->parent = parent;
+	dev->video_dev->v4l2_dev = &dev->v4l2_dev;
 	video_set_drvdata(dev->video_dev, dev);
 
 	res = video_register_device(dev->video_dev, VFL_TYPE_GRABBER, devnum);
diff --git a/drivers/media/usb/hdpvr/hdpvr.h b/drivers/media/usb/hdpvr/hdpvr.h
index 2a4deab..9450093 100644
--- a/drivers/media/usb/hdpvr/hdpvr.h
+++ b/drivers/media/usb/hdpvr/hdpvr.h
@@ -85,8 +85,6 @@ struct hdpvr_device {
 
 	/* holds the current device status */
 	__u8			status;
-	/* count the number of openers */
-	uint			open_count;
 
 	/* holds the cureent set options */
 	struct hdpvr_options	options;
@@ -107,6 +105,8 @@ struct hdpvr_device {
 	struct workqueue_struct	*workqueue;
 	/**/
 	struct work_struct	worker;
+	/* current stream owner */
+	struct v4l2_fh		*owner;
 
 	/* I2C adapter */
 	struct i2c_adapter	i2c_adapter;
-- 
1.7.10.4


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

* [REVIEW PATCH 05/11] hdpvr: add prio and control event support.
  2013-03-20 18:38 [REVIEW PATCH 00/11] hdpvr cleanup Hans Verkuil
                   ` (3 preceding siblings ...)
  2013-03-20 18:38 ` [REVIEW PATCH 04/11] hdpvr: remove hdpvr_fh and just use v4l2_fh Hans Verkuil
@ 2013-03-20 18:38 ` Hans Verkuil
  2013-03-20 18:38 ` [REVIEW PATCH 06/11] hdpvr: support device_caps in querycap Hans Verkuil
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Hans Verkuil @ 2013-03-20 18:38 UTC (permalink / raw)
  To: linux-media; +Cc: Janne Grunau, Hans Verkuil

From: Hans Verkuil <hans.verkuil@cisco.com>

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/usb/hdpvr/hdpvr-video.c |   20 ++++++++++++--------
 1 file changed, 12 insertions(+), 8 deletions(-)

diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c
index 873bb23..789d808 100644
--- a/drivers/media/usb/hdpvr/hdpvr-video.c
+++ b/drivers/media/usb/hdpvr/hdpvr-video.c
@@ -23,6 +23,7 @@
 #include <media/v4l2-dev.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
 #include "hdpvr.h"
 
 #define BULK_URB_TIMEOUT   90 /* 0.09 seconds */
@@ -478,16 +479,15 @@ err:
 
 static unsigned int hdpvr_poll(struct file *filp, poll_table *wait)
 {
+	unsigned long req_events = poll_requested_events(wait);
 	struct hdpvr_buffer *buf = NULL;
 	struct hdpvr_device *dev = video_drvdata(filp);
-	unsigned int mask = 0;
+	unsigned int mask = v4l2_ctrl_poll(filp, wait);
 
-	mutex_lock(&dev->io_mutex);
+	if (!(req_events & (POLLIN | POLLRDNORM)))
+		return mask;
 
-	if (!video_is_registered(dev->video_dev)) {
-		mutex_unlock(&dev->io_mutex);
-		return -EIO;
-	}
+	mutex_lock(&dev->io_mutex);
 
 	if (dev->status == STATUS_IDLE) {
 		if (hdpvr_start_streaming(dev)) {
@@ -878,10 +878,13 @@ static const struct v4l2_ioctl_ops hdpvr_ioctl_ops = {
 	.vidioc_enumaudio	= vidioc_enumaudio,
 	.vidioc_g_audio		= vidioc_g_audio,
 	.vidioc_s_audio		= vidioc_s_audio,
-	.vidioc_enum_fmt_vid_cap	= vidioc_enum_fmt_vid_cap,
-	.vidioc_g_fmt_vid_cap		= vidioc_g_fmt_vid_cap,
+	.vidioc_enum_fmt_vid_cap= vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap	= vidioc_g_fmt_vid_cap,
 	.vidioc_encoder_cmd	= vidioc_encoder_cmd,
 	.vidioc_try_encoder_cmd	= vidioc_try_encoder_cmd,
+	.vidioc_log_status	= v4l2_ctrl_log_status,
+	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 };
 
 static void hdpvr_device_release(struct video_device *vdev)
@@ -1006,6 +1009,7 @@ int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent,
 	strcpy(dev->video_dev->name, "Hauppauge HD PVR");
 	dev->video_dev->v4l2_dev = &dev->v4l2_dev;
 	video_set_drvdata(dev->video_dev, dev);
+	set_bit(V4L2_FL_USE_FH_PRIO, &dev->video_dev->flags);
 
 	res = video_register_device(dev->video_dev, VFL_TYPE_GRABBER, devnum);
 	if (res < 0) {
-- 
1.7.10.4


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

* [REVIEW PATCH 06/11] hdpvr: support device_caps in querycap.
  2013-03-20 18:38 [REVIEW PATCH 00/11] hdpvr cleanup Hans Verkuil
                   ` (4 preceding siblings ...)
  2013-03-20 18:38 ` [REVIEW PATCH 05/11] hdpvr: add prio and control event support Hans Verkuil
@ 2013-03-20 18:38 ` Hans Verkuil
  2013-03-20 18:38 ` [REVIEW PATCH 07/11] hdpvr: small fixes Hans Verkuil
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Hans Verkuil @ 2013-03-20 18:38 UTC (permalink / raw)
  To: linux-media; +Cc: Janne Grunau, Hans Verkuil

From: Hans Verkuil <hans.verkuil@cisco.com>

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/usb/hdpvr/hdpvr-video.c |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c
index 789d808..51f05d9 100644
--- a/drivers/media/usb/hdpvr/hdpvr-video.c
+++ b/drivers/media/usb/hdpvr/hdpvr-video.c
@@ -537,9 +537,9 @@ static int vidioc_querycap(struct file *file, void  *priv,
 	strcpy(cap->driver, "hdpvr");
 	strcpy(cap->card, "Hauppauge HD PVR");
 	usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
-	cap->capabilities =     V4L2_CAP_VIDEO_CAPTURE |
-				V4L2_CAP_AUDIO         |
-				V4L2_CAP_READWRITE;
+	cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_AUDIO |
+			    V4L2_CAP_READWRITE;
+	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
 	return 0;
 }
 
-- 
1.7.10.4


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

* [REVIEW PATCH 07/11] hdpvr: small fixes
  2013-03-20 18:38 [REVIEW PATCH 00/11] hdpvr cleanup Hans Verkuil
                   ` (5 preceding siblings ...)
  2013-03-20 18:38 ` [REVIEW PATCH 06/11] hdpvr: support device_caps in querycap Hans Verkuil
@ 2013-03-20 18:38 ` Hans Verkuil
  2013-03-20 18:38 ` [REVIEW PATCH 08/11] hdpvr: register the video node at the end of probe Hans Verkuil
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Hans Verkuil @ 2013-03-20 18:38 UTC (permalink / raw)
  To: linux-media; +Cc: Janne Grunau, Hans Verkuil

From: Hans Verkuil <hans.verkuil@cisco.com>

- return EBUSY instead of EAGAIN.
- add missing break.
- remove unnecessary buf type check (done by the core).

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/usb/hdpvr/hdpvr-video.c |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c
index 51f05d9..558dbe7 100644
--- a/drivers/media/usb/hdpvr/hdpvr-video.c
+++ b/drivers/media/usb/hdpvr/hdpvr-video.c
@@ -593,7 +593,7 @@ static int vidioc_s_input(struct file *file, void *private_data,
 		return -EINVAL;
 
 	if (dev->status != STATUS_IDLE)
-		return -EAGAIN;
+		return -EBUSY;
 
 	retval = hdpvr_config_call(dev, CTRL_VIDEO_INPUT_VALUE, index+1);
 	if (!retval)
@@ -645,7 +645,7 @@ static int vidioc_s_audio(struct file *file, void *private_data,
 		return -EINVAL;
 
 	if (dev->status != STATUS_IDLE)
-		return -EAGAIN;
+		return -EBUSY;
 
 	retval = hdpvr_set_audio(dev, audio->index+1, dev->options.audio_codec);
 	if (!retval)
@@ -776,7 +776,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *private_data,
 				    struct v4l2_fmtdesc *f)
 {
 
-	if (f->index != 0 || f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+	if (f->index != 0)
 		return -EINVAL;
 
 	f->flags = V4L2_FMT_FLAG_COMPRESSED;
-- 
1.7.10.4


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

* [REVIEW PATCH 08/11] hdpvr: register the video node at the end of probe.
  2013-03-20 18:38 [REVIEW PATCH 00/11] hdpvr cleanup Hans Verkuil
                   ` (6 preceding siblings ...)
  2013-03-20 18:38 ` [REVIEW PATCH 07/11] hdpvr: small fixes Hans Verkuil
@ 2013-03-20 18:38 ` Hans Verkuil
  2013-03-20 18:39 ` [REVIEW PATCH 09/11] hdpvr: recognize firmware version 0x1e Hans Verkuil
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Hans Verkuil @ 2013-03-20 18:38 UTC (permalink / raw)
  To: linux-media; +Cc: Janne Grunau, Hans Verkuil

From: Hans Verkuil <hans.verkuil@cisco.com>

Video nodes can be used at once after registration, so make sure the full
initialization is done before registering them.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/usb/hdpvr/hdpvr-core.c |   13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/drivers/media/usb/hdpvr/hdpvr-core.c b/drivers/media/usb/hdpvr/hdpvr-core.c
index 73195fe..248835b 100644
--- a/drivers/media/usb/hdpvr/hdpvr-core.c
+++ b/drivers/media/usb/hdpvr/hdpvr-core.c
@@ -386,12 +386,6 @@ static int hdpvr_probe(struct usb_interface *interface,
 	}
 	mutex_unlock(&dev->io_mutex);
 
-	if (hdpvr_register_videodev(dev, &interface->dev,
-				    video_nr[atomic_inc_return(&dev_nr)])) {
-		v4l2_err(&dev->v4l2_dev, "registering videodev failed\n");
-		goto error;
-	}
-
 #if IS_ENABLED(CONFIG_I2C)
 	retval = hdpvr_register_i2c_adapter(dev);
 	if (retval < 0) {
@@ -414,6 +408,13 @@ static int hdpvr_probe(struct usb_interface *interface,
 	}
 #endif
 
+	retval = hdpvr_register_videodev(dev, &interface->dev,
+				    video_nr[atomic_inc_return(&dev_nr)]);
+	if (retval < 0) {
+		v4l2_err(&dev->v4l2_dev, "registering videodev failed\n");
+		goto error;
+	}
+
 	/* let the user know what node this device is now attached to */
 	v4l2_info(&dev->v4l2_dev, "device now attached to %s\n",
 		  video_device_node_name(dev->video_dev));
-- 
1.7.10.4


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

* [REVIEW PATCH 09/11] hdpvr: recognize firmware version 0x1e.
  2013-03-20 18:38 [REVIEW PATCH 00/11] hdpvr cleanup Hans Verkuil
                   ` (7 preceding siblings ...)
  2013-03-20 18:38 ` [REVIEW PATCH 08/11] hdpvr: register the video node at the end of probe Hans Verkuil
@ 2013-03-20 18:39 ` Hans Verkuil
  2013-03-20 18:39 ` [REVIEW PATCH 10/11] hdpvr: add g/querystd, remove deprecated current_norm Hans Verkuil
  2013-03-20 18:39 ` [REVIEW PATCH 11/11] hdpvr: add dv_timings support Hans Verkuil
  10 siblings, 0 replies; 12+ messages in thread
From: Hans Verkuil @ 2013-03-20 18:39 UTC (permalink / raw)
  To: linux-media; +Cc: Janne Grunau, Hans Verkuil

From: Hans Verkuil <hans.verkuil@cisco.com>

This is the latest firmware version and - it seems - the most reliable.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/usb/hdpvr/hdpvr-core.c |    1 +
 drivers/media/usb/hdpvr/hdpvr.h      |    1 +
 2 files changed, 2 insertions(+)

diff --git a/drivers/media/usb/hdpvr/hdpvr-core.c b/drivers/media/usb/hdpvr/hdpvr-core.c
index 248835b..8247c19 100644
--- a/drivers/media/usb/hdpvr/hdpvr-core.c
+++ b/drivers/media/usb/hdpvr/hdpvr-core.c
@@ -174,6 +174,7 @@ static int device_authorization(struct hdpvr_device *dev)
 	case HDPVR_FIRMWARE_VERSION_AC3:
 	case HDPVR_FIRMWARE_VERSION_0X12:
 	case HDPVR_FIRMWARE_VERSION_0X15:
+	case HDPVR_FIRMWARE_VERSION_0X1E:
 		dev->flags |= HDPVR_FLAG_AC3_CAP;
 		break;
 	default:
diff --git a/drivers/media/usb/hdpvr/hdpvr.h b/drivers/media/usb/hdpvr/hdpvr.h
index 9450093..1c12981 100644
--- a/drivers/media/usb/hdpvr/hdpvr.h
+++ b/drivers/media/usb/hdpvr/hdpvr.h
@@ -38,6 +38,7 @@
 #define HDPVR_FIRMWARE_VERSION_AC3	0x0d
 #define HDPVR_FIRMWARE_VERSION_0X12	0x12
 #define HDPVR_FIRMWARE_VERSION_0X15	0x15
+#define HDPVR_FIRMWARE_VERSION_0X1E	0x1e
 
 /* #define HDPVR_DEBUG */
 
-- 
1.7.10.4


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

* [REVIEW PATCH 10/11] hdpvr: add g/querystd, remove deprecated current_norm.
  2013-03-20 18:38 [REVIEW PATCH 00/11] hdpvr cleanup Hans Verkuil
                   ` (8 preceding siblings ...)
  2013-03-20 18:39 ` [REVIEW PATCH 09/11] hdpvr: recognize firmware version 0x1e Hans Verkuil
@ 2013-03-20 18:39 ` Hans Verkuil
  2013-03-20 18:39 ` [REVIEW PATCH 11/11] hdpvr: add dv_timings support Hans Verkuil
  10 siblings, 0 replies; 12+ messages in thread
From: Hans Verkuil @ 2013-03-20 18:39 UTC (permalink / raw)
  To: linux-media; +Cc: Janne Grunau, Hans Verkuil

From: Hans Verkuil <hans.verkuil@cisco.com>

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/usb/hdpvr/hdpvr-video.c |   62 ++++++++++++++++++++++++++-------
 drivers/media/usb/hdpvr/hdpvr.h       |    5 ++-
 2 files changed, 54 insertions(+), 13 deletions(-)

diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c
index 558dbe7..491732b 100644
--- a/drivers/media/usb/hdpvr/hdpvr-video.c
+++ b/drivers/media/usb/hdpvr/hdpvr-video.c
@@ -549,12 +549,50 @@ static int vidioc_s_std(struct file *file, void *private_data,
 	struct hdpvr_device *dev = video_drvdata(file);
 	u8 std_type = 1;
 
-	if (*std & (V4L2_STD_NTSC | V4L2_STD_PAL_60))
+	if (dev->options.video_input == HDPVR_COMPONENT)
+		return -ENODATA;
+	if (dev->status != STATUS_IDLE)
+		return -EBUSY;
+	if (*std & V4L2_STD_525_60)
 		std_type = 0;
+	dev->cur_std = *std;
+	dev->width = 720;
+	dev->height = std_type ? 576 : 480;
 
 	return hdpvr_config_call(dev, CTRL_VIDEO_STD_TYPE, std_type);
 }
 
+static int vidioc_g_std(struct file *file, void *private_data,
+			v4l2_std_id *std)
+{
+	struct hdpvr_device *dev = video_drvdata(file);
+
+	if (dev->options.video_input == HDPVR_COMPONENT)
+		return -ENODATA;
+	*std = dev->cur_std;
+	return 0;
+}
+
+static int vidioc_querystd(struct file *file, void *fh, v4l2_std_id *a)
+{
+	struct hdpvr_device *dev = video_drvdata(file);
+	struct hdpvr_video_info *vid_info;
+
+	if (dev->options.video_input == HDPVR_COMPONENT)
+		return -ENODATA;
+	*a = V4L2_STD_ALL;
+	vid_info = get_video_info(dev);
+	if (vid_info == NULL)
+		return 0;
+	if (vid_info->width == 720 &&
+	    (vid_info->height == 480 || vid_info->height == 576)) {
+		*a = (vid_info->height == 480) ?
+			V4L2_STD_525_60 : V4L2_STD_625_50;
+	}
+	kfree(vid_info);
+	return 0;
+}
+
 static const char *iname[] = {
 	[HDPVR_COMPONENT] = "Component",
 	[HDPVR_SVIDEO]    = "S-Video",
@@ -564,7 +602,6 @@ static const char *iname[] = {
 static int vidioc_enum_input(struct file *file, void *priv,
 				struct v4l2_input *i)
 {
-	struct hdpvr_device *dev = video_drvdata(file);
 	unsigned int n;
 
 	n = i->index;
@@ -578,7 +615,8 @@ static int vidioc_enum_input(struct file *file, void *priv,
 
 	i->audioset = 1<<HDPVR_RCA_FRONT | 1<<HDPVR_RCA_BACK | 1<<HDPVR_SPDIF;
 
-	i->std = dev->video_dev->tvnorms;
+	i->capabilities = n ? V4L2_IN_CAP_STD : V4L2_IN_CAP_DV_TIMINGS;
+	i->std = n ? V4L2_STD_ALL : 0;
 
 	return 0;
 }
@@ -596,8 +634,11 @@ static int vidioc_s_input(struct file *file, void *private_data,
 		return -EBUSY;
 
 	retval = hdpvr_config_call(dev, CTRL_VIDEO_INPUT_VALUE, index+1);
-	if (!retval)
+	if (!retval) {
 		dev->options.video_input = index;
+		dev->video_dev->tvnorms =
+			index != HDPVR_COMPONENT ? V4L2_STD_ALL : 0;
+	}
 
 	return retval;
 }
@@ -775,7 +816,6 @@ static int hdpvr_s_ctrl(struct v4l2_ctrl *ctrl)
 static int vidioc_enum_fmt_vid_cap(struct file *file, void *private_data,
 				    struct v4l2_fmtdesc *f)
 {
-
 	if (f->index != 0)
 		return -EINVAL;
 
@@ -872,6 +912,8 @@ static int vidioc_try_encoder_cmd(struct file *filp, void *priv,
 static const struct v4l2_ioctl_ops hdpvr_ioctl_ops = {
 	.vidioc_querycap	= vidioc_querycap,
 	.vidioc_s_std		= vidioc_s_std,
+	.vidioc_g_std		= vidioc_g_std,
+	.vidioc_querystd	= vidioc_querystd,
 	.vidioc_enum_input	= vidioc_enum_input,
 	.vidioc_g_input		= vidioc_g_input,
 	.vidioc_s_input		= vidioc_s_input,
@@ -914,13 +956,6 @@ static const struct video_device hdpvr_video_template = {
 	.fops			= &hdpvr_fops,
 	.release		= hdpvr_device_release,
 	.ioctl_ops 		= &hdpvr_ioctl_ops,
-	.tvnorms 		=
-		V4L2_STD_NTSC  | V4L2_STD_SECAM | V4L2_STD_PAL_B |
-		V4L2_STD_PAL_G | V4L2_STD_PAL_H | V4L2_STD_PAL_I |
-		V4L2_STD_PAL_D | V4L2_STD_PAL_M | V4L2_STD_PAL_N |
-		V4L2_STD_PAL_60,
-	.current_norm 		= V4L2_STD_NTSC | V4L2_STD_PAL_M |
-		V4L2_STD_PAL_60,
 };
 
 static const struct v4l2_ctrl_ops hdpvr_ctrl_ops = {
@@ -935,6 +970,9 @@ int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent,
 	bool ac3 = dev->flags & HDPVR_FLAG_AC3_CAP;
 	int res;
 
+	dev->cur_std = V4L2_STD_525_60;
+	dev->width = 720;
+	dev->height = 480;
 	v4l2_ctrl_handler_init(hdl, 11);
 	if (dev->fw_ver > 0x15) {
 		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
diff --git a/drivers/media/usb/hdpvr/hdpvr.h b/drivers/media/usb/hdpvr/hdpvr.h
index 1c12981..050c6b9 100644
--- a/drivers/media/usb/hdpvr/hdpvr.h
+++ b/drivers/media/usb/hdpvr/hdpvr.h
@@ -78,6 +78,8 @@ struct hdpvr_device {
 		struct v4l2_ctrl *video_bitrate;
 		struct v4l2_ctrl *video_bitrate_peak;
 	};
+	/* v4l2 format */
+	uint width, height;
 
 	/* the max packet size of the bulk endpoint */
 	size_t			bulk_in_size;
@@ -87,8 +89,9 @@ struct hdpvr_device {
 	/* holds the current device status */
 	__u8			status;
 
-	/* holds the cureent set options */
+	/* holds the current set options */
 	struct hdpvr_options	options;
+	v4l2_std_id		cur_std;
 
 	uint			flags;
 
-- 
1.7.10.4


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

* [REVIEW PATCH 11/11] hdpvr: add dv_timings support.
  2013-03-20 18:38 [REVIEW PATCH 00/11] hdpvr cleanup Hans Verkuil
                   ` (9 preceding siblings ...)
  2013-03-20 18:39 ` [REVIEW PATCH 10/11] hdpvr: add g/querystd, remove deprecated current_norm Hans Verkuil
@ 2013-03-20 18:39 ` Hans Verkuil
  10 siblings, 0 replies; 12+ messages in thread
From: Hans Verkuil @ 2013-03-20 18:39 UTC (permalink / raw)
  To: linux-media; +Cc: Janne Grunau, Hans Verkuil

From: Hans Verkuil <hans.verkuil@cisco.com>

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/usb/hdpvr/hdpvr-video.c |  217 +++++++++++++++++++++++++++++----
 drivers/media/usb/hdpvr/hdpvr.h       |    1 +
 2 files changed, 194 insertions(+), 24 deletions(-)

diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c
index 491732b..e0381a7 100644
--- a/drivers/media/usb/hdpvr/hdpvr-video.c
+++ b/drivers/media/usb/hdpvr/hdpvr-video.c
@@ -20,6 +20,7 @@
 #include <linux/workqueue.h>
 
 #include <linux/videodev2.h>
+#include <linux/v4l2-dv-timings.h>
 #include <media/v4l2-dev.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
@@ -35,6 +36,25 @@
 			 list_size(&dev->free_buff_list),		\
 			 list_size(&dev->rec_buff_list)); }
 
+static const struct v4l2_dv_timings hdpvr_dv_timings[] = {
+	V4L2_DV_BT_CEA_720X480I59_94,
+	V4L2_DV_BT_CEA_720X576I50,
+	V4L2_DV_BT_CEA_720X480P59_94,
+	V4L2_DV_BT_CEA_720X576P50,
+	V4L2_DV_BT_CEA_1280X720P50,
+	V4L2_DV_BT_CEA_1280X720P60,
+	V4L2_DV_BT_CEA_1920X1080I50,
+	V4L2_DV_BT_CEA_1920X1080I60,
+};
+
+/* Use 480i59 as the default timings */
+#define HDPVR_DEF_DV_TIMINGS_IDX (0)
+
+struct hdpvr_fh {
+	struct v4l2_fh fh;
+	bool legacy_mode;
+};
+
 static uint list_size(struct list_head *list)
 {
 	struct list_head *tmp;
@@ -354,13 +374,23 @@ static int hdpvr_stop_streaming(struct hdpvr_device *dev)
  * video 4 linux 2 file operations
  */
 
+static int hdpvr_open(struct file *file)
+{
+	struct hdpvr_fh *fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+
+	if (fh == NULL)
+		return -ENOMEM;
+	fh->legacy_mode = true;
+	v4l2_fh_init(&fh->fh, video_devdata(file));
+	v4l2_fh_add(&fh->fh);
+	file->private_data = fh;
+	return 0;
+}
+
 static int hdpvr_release(struct file *file)
 {
 	struct hdpvr_device *dev = video_drvdata(file);
 
-	if (!dev)
-		return -ENODEV;
-
 	mutex_lock(&dev->io_mutex);
 	if (file->private_data == dev->owner) {
 		hdpvr_stop_streaming(dev);
@@ -387,9 +417,6 @@ static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count,
 	if (*pos)
 		return -ESPIPE;
 
-	if (!dev)
-		return -ENODEV;
-
 	mutex_lock(&dev->io_mutex);
 	if (dev->status == STATUS_IDLE) {
 		if (hdpvr_start_streaming(dev)) {
@@ -517,7 +544,7 @@ static unsigned int hdpvr_poll(struct file *filp, poll_table *wait)
 
 static const struct v4l2_file_operations hdpvr_fops = {
 	.owner		= THIS_MODULE,
-	.open		= v4l2_fh_open,
+	.open		= hdpvr_open,
 	.release	= hdpvr_release,
 	.read		= hdpvr_read,
 	.poll		= hdpvr_poll,
@@ -593,6 +620,121 @@ static int vidioc_querystd(struct file *file, void *fh, v4l2_std_id *a)
 	return 0;
 }
 
+static int vidioc_s_dv_timings(struct file *file, void *_fh,
+				    struct v4l2_dv_timings *timings)
+{
+	struct hdpvr_device *dev = video_drvdata(file);
+	struct hdpvr_fh *fh = _fh;
+	int i;
+
+	fh->legacy_mode = false;
+	if (dev->options.video_input)
+		return -ENODATA;
+	if (dev->status != STATUS_IDLE)
+		return -EBUSY;
+	for (i = 0; i < ARRAY_SIZE(hdpvr_dv_timings); i++)
+		if (v4l_match_dv_timings(timings, hdpvr_dv_timings + i, 0))
+			break;
+	if (i == ARRAY_SIZE(hdpvr_dv_timings))
+		return -EINVAL;
+	dev->cur_dv_timings = hdpvr_dv_timings[i];
+	dev->width = hdpvr_dv_timings[i].bt.width;
+	dev->height = hdpvr_dv_timings[i].bt.height;
+	return 0;
+}
+
+static int vidioc_g_dv_timings(struct file *file, void *_fh,
+				    struct v4l2_dv_timings *timings)
+{
+	struct hdpvr_device *dev = video_drvdata(file);
+	struct hdpvr_fh *fh = _fh;
+
+	fh->legacy_mode = false;
+	if (dev->options.video_input)
+		return -ENODATA;
+	*timings = dev->cur_dv_timings;
+	return 0;
+}
+
+static int vidioc_query_dv_timings(struct file *file, void *_fh,
+				    struct v4l2_dv_timings *timings)
+{
+	struct hdpvr_device *dev = video_drvdata(file);
+	struct hdpvr_fh *fh = _fh;
+	struct hdpvr_video_info *vid_info;
+	bool interlaced;
+	int ret = 0;
+	int i;
+
+	fh->legacy_mode = false;
+	if (dev->options.video_input)
+		return -ENODATA;
+	vid_info = get_video_info(dev);
+	if (vid_info == NULL)
+		return -ENOLCK;
+	interlaced = vid_info->fps <= 30;
+	for (i = 0; i < ARRAY_SIZE(hdpvr_dv_timings); i++) {
+		const struct v4l2_bt_timings *bt = &hdpvr_dv_timings[i].bt;
+		unsigned hsize;
+		unsigned vsize;
+		unsigned fps;
+
+		hsize = bt->hfrontporch + bt->hsync + bt->hbackporch + bt->width;
+		vsize = bt->vfrontporch + bt->vsync + bt->vbackporch +
+			bt->il_vfrontporch + bt->il_vsync + bt->il_vbackporch +
+			bt->height;
+		fps = (unsigned)bt->pixelclock / (hsize * vsize);
+		if (bt->width != vid_info->width ||
+		    bt->height != vid_info->height ||
+		    bt->interlaced != interlaced ||
+		    (fps != vid_info->fps && fps + 1 != vid_info->fps))
+			continue;
+		*timings = hdpvr_dv_timings[i];
+		break;
+	}
+	if (i == ARRAY_SIZE(hdpvr_dv_timings))
+		ret = -ERANGE;
+	kfree(vid_info);
+	return ret;
+}
+
+static int vidioc_enum_dv_timings(struct file *file, void *_fh,
+				    struct v4l2_enum_dv_timings *timings)
+{
+	struct hdpvr_device *dev = video_drvdata(file);
+	struct hdpvr_fh *fh = _fh;
+
+	fh->legacy_mode = false;
+	memset(timings->reserved, 0, sizeof(timings->reserved));
+	if (dev->options.video_input)
+		return -ENODATA;
+	if (timings->index >= ARRAY_SIZE(hdpvr_dv_timings))
+		return -EINVAL;
+	timings->timings = hdpvr_dv_timings[timings->index];
+	return 0;
+}
+
+static int vidioc_dv_timings_cap(struct file *file, void *_fh,
+				    struct v4l2_dv_timings_cap *cap)
+{
+	struct hdpvr_device *dev = video_drvdata(file);
+	struct hdpvr_fh *fh = _fh;
+
+	fh->legacy_mode = false;
+	if (dev->options.video_input)
+		return -ENODATA;
+	cap->type = V4L2_DV_BT_656_1120;
+	cap->bt.min_width = 720;
+	cap->bt.max_width = 1920;
+	cap->bt.min_height = 480;
+	cap->bt.max_height = 1080;
+	cap->bt.min_pixelclock = 27000000;
+	cap->bt.max_pixelclock = 74250000;
+	cap->bt.standards = V4L2_DV_BT_STD_CEA861;
+	cap->bt.capabilities = V4L2_DV_BT_CAP_INTERLACED | V4L2_DV_BT_CAP_PROGRESSIVE;
+	return 0;
+}
+
 static const char *iname[] = {
 	[HDPVR_COMPONENT] = "Component",
 	[HDPVR_SVIDEO]    = "S-Video",
@@ -826,29 +968,48 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *private_data,
 	return 0;
 }
 
-static int vidioc_g_fmt_vid_cap(struct file *file, void *private_data,
+static int vidioc_g_fmt_vid_cap(struct file *file, void *_fh,
 				struct v4l2_format *f)
 {
 	struct hdpvr_device *dev = video_drvdata(file);
-	struct hdpvr_video_info *vid_info;
-
-	if (!dev)
-		return -ENODEV;
-
-	vid_info = get_video_info(dev);
-	if (!vid_info)
-		return -EFAULT;
-
-	f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	struct hdpvr_fh *fh = _fh;
+
+	/*
+	 * The original driver would always returns the current detected
+	 * resolution as the format (and EFAULT if it couldn't be detected).
+	 * With the introduction of VIDIOC_QUERY_DV_TIMINGS there is now a
+	 * better way of doing this, but to stay compatible with existing
+	 * applications we assume legacy mode every time an application opens
+	 * the device. Only if one of the new DV_TIMINGS ioctls is called
+	 * will the filehandle go into 'normal' mode where g_fmt returns the
+	 * last set format.
+	 */
+	if (fh->legacy_mode) {
+		struct hdpvr_video_info *vid_info;
+
+		vid_info = get_video_info(dev);
+		if (!vid_info)
+			return -EFAULT;
+		f->fmt.pix.width = vid_info->width;
+		f->fmt.pix.height = vid_info->height;
+		kfree(vid_info);
+	} else {
+		f->fmt.pix.width = dev->width;
+		f->fmt.pix.height = dev->height;
+	}
 	f->fmt.pix.pixelformat	= V4L2_PIX_FMT_MPEG;
-	f->fmt.pix.width	= vid_info->width;
-	f->fmt.pix.height	= vid_info->height;
 	f->fmt.pix.sizeimage	= dev->bulk_in_size;
-	f->fmt.pix.colorspace	= 0;
 	f->fmt.pix.bytesperline	= 0;
-	f->fmt.pix.field	= V4L2_FIELD_ANY;
-
-	kfree(vid_info);
+	f->fmt.pix.priv		= 0;
+	if (f->fmt.pix.width == 720) {
+		/* SDTV formats */
+		f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+		f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+	} else {
+		/* HDTV formats */
+		f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE240M;
+		f->fmt.pix.field = V4L2_FIELD_NONE;
+	}
 	return 0;
 }
 
@@ -914,6 +1075,11 @@ static const struct v4l2_ioctl_ops hdpvr_ioctl_ops = {
 	.vidioc_s_std		= vidioc_s_std,
 	.vidioc_g_std		= vidioc_g_std,
 	.vidioc_querystd	= vidioc_querystd,
+	.vidioc_s_dv_timings	= vidioc_s_dv_timings,
+	.vidioc_g_dv_timings	= vidioc_g_dv_timings,
+	.vidioc_query_dv_timings= vidioc_query_dv_timings,
+	.vidioc_enum_dv_timings	= vidioc_enum_dv_timings,
+	.vidioc_dv_timings_cap	= vidioc_dv_timings_cap,
 	.vidioc_enum_input	= vidioc_enum_input,
 	.vidioc_g_input		= vidioc_g_input,
 	.vidioc_s_input		= vidioc_s_input,
@@ -922,6 +1088,8 @@ static const struct v4l2_ioctl_ops hdpvr_ioctl_ops = {
 	.vidioc_s_audio		= vidioc_s_audio,
 	.vidioc_enum_fmt_vid_cap= vidioc_enum_fmt_vid_cap,
 	.vidioc_g_fmt_vid_cap	= vidioc_g_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap	= vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap	= vidioc_g_fmt_vid_cap,
 	.vidioc_encoder_cmd	= vidioc_encoder_cmd,
 	.vidioc_try_encoder_cmd	= vidioc_try_encoder_cmd,
 	.vidioc_log_status	= v4l2_ctrl_log_status,
@@ -973,6 +1141,7 @@ int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent,
 	dev->cur_std = V4L2_STD_525_60;
 	dev->width = 720;
 	dev->height = 480;
+	dev->cur_dv_timings = hdpvr_dv_timings[HDPVR_DEF_DV_TIMINGS_IDX];
 	v4l2_ctrl_handler_init(hdl, 11);
 	if (dev->fw_ver > 0x15) {
 		v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
diff --git a/drivers/media/usb/hdpvr/hdpvr.h b/drivers/media/usb/hdpvr/hdpvr.h
index 050c6b9..1478f3d 100644
--- a/drivers/media/usb/hdpvr/hdpvr.h
+++ b/drivers/media/usb/hdpvr/hdpvr.h
@@ -92,6 +92,7 @@ struct hdpvr_device {
 	/* holds the current set options */
 	struct hdpvr_options	options;
 	v4l2_std_id		cur_std;
+	struct v4l2_dv_timings	cur_dv_timings;
 
 	uint			flags;
 
-- 
1.7.10.4


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

end of thread, other threads:[~2013-03-20 18:39 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-03-20 18:38 [REVIEW PATCH 00/11] hdpvr cleanup Hans Verkuil
2013-03-20 18:38 ` [REVIEW PATCH 01/11] videodev2.h: fix incorrect V4L2_DV_FL_HALF_LINE bitmask Hans Verkuil
2013-03-20 18:38 ` [REVIEW PATCH 02/11] v4l2-dv-timings.h: add 480i59.94 and 576i50 CEA-861-E timings Hans Verkuil
2013-03-20 18:38 ` [REVIEW PATCH 03/11] hdpvr: convert to the control framework Hans Verkuil
2013-03-20 18:38 ` [REVIEW PATCH 04/11] hdpvr: remove hdpvr_fh and just use v4l2_fh Hans Verkuil
2013-03-20 18:38 ` [REVIEW PATCH 05/11] hdpvr: add prio and control event support Hans Verkuil
2013-03-20 18:38 ` [REVIEW PATCH 06/11] hdpvr: support device_caps in querycap Hans Verkuil
2013-03-20 18:38 ` [REVIEW PATCH 07/11] hdpvr: small fixes Hans Verkuil
2013-03-20 18:38 ` [REVIEW PATCH 08/11] hdpvr: register the video node at the end of probe Hans Verkuil
2013-03-20 18:39 ` [REVIEW PATCH 09/11] hdpvr: recognize firmware version 0x1e Hans Verkuil
2013-03-20 18:39 ` [REVIEW PATCH 10/11] hdpvr: add g/querystd, remove deprecated current_norm Hans Verkuil
2013-03-20 18:39 ` [REVIEW PATCH 11/11] hdpvr: add dv_timings support Hans Verkuil

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