linux-media.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [REVIEWv4 PATCH 00/34] Add support for compound controls, use in solo/go7007
@ 2014-06-12 11:52 Hans Verkuil
  2014-06-12 11:52 ` [REVIEWv4 PATCH 01/34] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
  0 siblings, 1 reply; 36+ messages in thread
From: Hans Verkuil @ 2014-06-12 11:52 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, s.nawrocki, sakari.ailus

This patch series adds support for compound controls and up to 8-dimensional
arrays to the control framework and uses it in the solo6x10 and go7007
drivers for the motion detection implementation.

This patch series supersedes http://www.spinics.net/lists/linux-media/msg73118.html.

It incorporates all of Mauro's comments of the v3 patch series with two
exceptions:

- The v4l2_ctrl_new() prototype still has too many arguments. I do want
  to clean this up, but when I tried it I quickly discovered that that
  would cause quite a bit of code churn so I much rather do that after
  this patch series is merged.

- The number of maximum dimensions for multi-dimensional arrays is set at
  8. I'm not allowing for more than 8 dimensions as was suggested. Based on
  the feedback Sakari gave me and my own feelings on this topic I did not
  want to replace the dims[V4L2_CTRL_MAX_DIMS] array with a dims pointer.
  If changing to a u32 *dims is the only way to get this in, then I will
  do so but I am not ready to give up on this. We're dealing with video
  hardware, not with 11-dimensional string theory.

I have added support for getting/setting multidimensional arrays to
v4l2-ctl here:

http://git.linuxtv.org/cgit.cgi/hverkuil/v4l-utils.git/log/?h=compound

I've also tested this with the solo and go7007 driver.

This patch series is available in the propapi-part4 branch of my git
repo: git://linuxtv.org/hverkuil/media_tree.git.

Regards,

        Hans


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

* [REVIEWv4 PATCH 01/34] v4l2-ctrls: increase internal min/max/step/def to 64 bit
  2014-06-12 11:52 [REVIEWv4 PATCH 00/34] Add support for compound controls, use in solo/go7007 Hans Verkuil
@ 2014-06-12 11:52 ` Hans Verkuil
  2014-06-12 11:52   ` [REVIEWv4 PATCH 02/34] v4l2-ctrls: use pr_info/cont instead of printk Hans Verkuil
                     ` (32 more replies)
  0 siblings, 33 replies; 36+ messages in thread
From: Hans Verkuil @ 2014-06-12 11:52 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, s.nawrocki, sakari.ailus, Hans Verkuil

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

While VIDIOC_QUERYCTRL is limited to 32 bit min/max/step/def values
for controls, the upcoming VIDIOC_QUERY_EXT_CTRL isn't. So increase
the internal representation to 64 bits in preparation.

Because of these changes the msi3101 driver has been modified slightly
to fix a formatting issue (%d becomes %lld), vivi had to be modified
as well to cope with the new 64-bit min/max values and the PIXEL_RATE
control in a few sensor drivers required proper min/max/def values.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Reviewed-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
---
 drivers/media/i2c/mt9v032.c                      |  2 +-
 drivers/media/i2c/smiapp/smiapp-core.c           |  4 +-
 drivers/media/platform/vivi.c                    |  5 +-
 drivers/media/v4l2-core/v4l2-common.c            |  6 +-
 drivers/media/v4l2-core/v4l2-ctrls.c             | 93 +++++++++++++++---------
 drivers/staging/media/msi3101/msi001.c           |  2 +-
 drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c |  4 +-
 include/media/v4l2-ctrls.h                       | 42 +++++------
 8 files changed, 93 insertions(+), 65 deletions(-)

diff --git a/drivers/media/i2c/mt9v032.c b/drivers/media/i2c/mt9v032.c
index 40172b8..65e6e1a 100644
--- a/drivers/media/i2c/mt9v032.c
+++ b/drivers/media/i2c/mt9v032.c
@@ -931,7 +931,7 @@ static int mt9v032_probe(struct i2c_client *client,
 
 	mt9v032->pixel_rate =
 		v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops,
-				  V4L2_CID_PIXEL_RATE, 0, 0, 1, 0);
+				  V4L2_CID_PIXEL_RATE, 1, INT_MAX, 1, 1);
 
 	if (pdata && pdata->link_freqs) {
 		unsigned int def = 0;
diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c
index 06fb032..0e82756 100644
--- a/drivers/media/i2c/smiapp/smiapp-core.c
+++ b/drivers/media/i2c/smiapp/smiapp-core.c
@@ -533,7 +533,7 @@ static int smiapp_init_controls(struct smiapp_sensor *sensor)
 
 	sensor->pixel_rate_parray = v4l2_ctrl_new_std(
 		&sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
-		V4L2_CID_PIXEL_RATE, 0, 0, 1, 0);
+		V4L2_CID_PIXEL_RATE, 1, INT_MAX, 1, 1);
 
 	if (sensor->pixel_array->ctrl_handler.error) {
 		dev_err(&client->dev,
@@ -562,7 +562,7 @@ static int smiapp_init_controls(struct smiapp_sensor *sensor)
 
 	sensor->pixel_rate_csi = v4l2_ctrl_new_std(
 		&sensor->src->ctrl_handler, &smiapp_ctrl_ops,
-		V4L2_CID_PIXEL_RATE, 0, 0, 1, 0);
+		V4L2_CID_PIXEL_RATE, 1, INT_MAX, 1, 1);
 
 	if (sensor->src->ctrl_handler.error) {
 		dev_err(&client->dev,
diff --git a/drivers/media/platform/vivi.c b/drivers/media/platform/vivi.c
index d00bf3d..2fa05e1 100644
--- a/drivers/media/platform/vivi.c
+++ b/drivers/media/platform/vivi.c
@@ -1236,7 +1236,7 @@ static const struct v4l2_ctrl_config vivi_ctrl_int32 = {
 	.id = VIVI_CID_CUSTOM_BASE + 2,
 	.name = "Integer 32 Bits",
 	.type = V4L2_CTRL_TYPE_INTEGER,
-	.min = 0x80000000,
+	.min = -0x80000000LL,
 	.max = 0x7fffffff,
 	.step = 1,
 };
@@ -1246,6 +1246,9 @@ static const struct v4l2_ctrl_config vivi_ctrl_int64 = {
 	.id = VIVI_CID_CUSTOM_BASE + 3,
 	.name = "Integer 64 Bits",
 	.type = V4L2_CTRL_TYPE_INTEGER64,
+	.min = LLONG_MIN,
+	.max = LLONG_MAX,
+	.step = 1,
 };
 
 static const char * const vivi_ctrl_menu_strings[] = {
diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
index 433d6d7..ccaa38f 100644
--- a/drivers/media/v4l2-core/v4l2-common.c
+++ b/drivers/media/v4l2-core/v4l2-common.c
@@ -111,9 +111,13 @@ int v4l2_ctrl_check(struct v4l2_ext_control *ctrl, struct v4l2_queryctrl *qctrl,
 EXPORT_SYMBOL(v4l2_ctrl_check);
 
 /* Fill in a struct v4l2_queryctrl */
-int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def)
+int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 _min, s32 _max, s32 _step, s32 _def)
 {
 	const char *name;
+	s64 min = _min;
+	s64 max = _max;
+	u64 step = _step;
+	s64 def = _def;
 
 	v4l2_ctrl_fill(qctrl->id, &name, &qctrl->type,
 		       &min, &max, &step, &def, &qctrl->flags);
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 55c6832..e132fa2 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -877,7 +877,7 @@ const char *v4l2_ctrl_get_name(u32 id)
 EXPORT_SYMBOL(v4l2_ctrl_get_name);
 
 void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
-		    s32 *min, s32 *max, s32 *step, s32 *def, u32 *flags)
+		    s64 *min, s64 *max, u64 *step, s64 *def, u32 *flags)
 {
 	*name = v4l2_ctrl_get_name(id);
 	*flags = 0;
@@ -1041,14 +1041,23 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
 		*type = V4L2_CTRL_TYPE_INTEGER;
 		*flags |= V4L2_CTRL_FLAG_READ_ONLY;
 		break;
-	case V4L2_CID_MPEG_VIDEO_DEC_FRAME:
 	case V4L2_CID_MPEG_VIDEO_DEC_PTS:
-		*flags |= V4L2_CTRL_FLAG_VOLATILE;
-		/* Fall through */
+		*type = V4L2_CTRL_TYPE_INTEGER64;
+		*flags |= V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY;
+		*min = *def = 0;
+		*max = 0x1ffffffffLL;
+		*step = 1;
+		break;
+	case V4L2_CID_MPEG_VIDEO_DEC_FRAME:
+		*type = V4L2_CTRL_TYPE_INTEGER64;
+		*flags |= V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY;
+		*min = *def = 0;
+		*max = 0x7fffffffffffffffLL;
+		*step = 1;
+		break;
 	case V4L2_CID_PIXEL_RATE:
 		*type = V4L2_CTRL_TYPE_INTEGER64;
 		*flags |= V4L2_CTRL_FLAG_READ_ONLY;
-		*min = *max = *step = *def = 0;
 		break;
 	default:
 		*type = V4L2_CTRL_TYPE_INTEGER;
@@ -1352,7 +1361,7 @@ static int cluster_changed(struct v4l2_ctrl *master)
 
 /* Control range checking */
 static int check_range(enum v4l2_ctrl_type type,
-		s32 min, s32 max, u32 step, s32 def)
+		s64 min, s64 max, u64 step, s64 def)
 {
 	switch (type) {
 	case V4L2_CTRL_TYPE_BOOLEAN:
@@ -1360,7 +1369,8 @@ static int check_range(enum v4l2_ctrl_type type,
 			return -ERANGE;
 		/* fall through */
 	case V4L2_CTRL_TYPE_INTEGER:
-		if (step <= 0 || min > max || def < min || def > max)
+	case V4L2_CTRL_TYPE_INTEGER64:
+		if (step == 0 || min > max || def < min || def > max)
 			return -ERANGE;
 		return 0;
 	case V4L2_CTRL_TYPE_BITMASK:
@@ -1385,23 +1395,30 @@ static int check_range(enum v4l2_ctrl_type type,
 	}
 }
 
+/* Round towards the closest legal value */
+#define ROUND_TO_RANGE(val, offset_type, ctrl)			\
+({								\
+	offset_type offset;					\
+	val += (ctrl)->step / 2;				\
+	val = clamp_t(typeof(val), val,				\
+		      (ctrl)->minimum, (ctrl)->maximum);	\
+	offset = (val) - (ctrl)->minimum;			\
+	offset = (ctrl)->step * (offset / (ctrl)->step);	\
+	val = (ctrl)->minimum + offset;				\
+	0;							\
+})
+
 /* Validate a new control */
 static int validate_new(const struct v4l2_ctrl *ctrl,
 			struct v4l2_ext_control *c)
 {
 	size_t len;
-	u32 offset;
-	s32 val;
 
 	switch (ctrl->type) {
 	case V4L2_CTRL_TYPE_INTEGER:
-		/* Round towards the closest legal value */
-		val = c->value + ctrl->step / 2;
-		val = clamp(val, ctrl->minimum, ctrl->maximum);
-		offset = val - ctrl->minimum;
-		offset = ctrl->step * (offset / ctrl->step);
-		c->value = ctrl->minimum + offset;
-		return 0;
+		return ROUND_TO_RANGE(*(s32 *)&c->value, u32, ctrl);
+	case V4L2_CTRL_TYPE_INTEGER64:
+		return ROUND_TO_RANGE(*(s64 *)&c->value64, u64, ctrl);
 
 	case V4L2_CTRL_TYPE_BOOLEAN:
 		c->value = !!c->value;
@@ -1427,9 +1444,6 @@ static int validate_new(const struct v4l2_ctrl *ctrl,
 		c->value = 0;
 		return 0;
 
-	case V4L2_CTRL_TYPE_INTEGER64:
-		return 0;
-
 	case V4L2_CTRL_TYPE_STRING:
 		len = strlen(c->string);
 		if (len < ctrl->minimum)
@@ -1653,7 +1667,7 @@ unlock:
 static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 			const struct v4l2_ctrl_ops *ops,
 			u32 id, const char *name, enum v4l2_ctrl_type type,
-			s32 min, s32 max, u32 step, s32 def,
+			s64 min, s64 max, u64 step, s64 def,
 			u32 flags, const char * const *qmenu,
 			const s64 *qmenu_int, void *priv)
 {
@@ -1738,10 +1752,10 @@ struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl,
 	const s64 *qmenu_int = cfg->qmenu_int;
 	enum v4l2_ctrl_type type = cfg->type;
 	u32 flags = cfg->flags;
-	s32 min = cfg->min;
-	s32 max = cfg->max;
-	u32 step = cfg->step;
-	s32 def = cfg->def;
+	s64 min = cfg->min;
+	s64 max = cfg->max;
+	u64 step = cfg->step;
+	s64 def = cfg->def;
 
 	if (name == NULL)
 		v4l2_ctrl_fill(cfg->id, &name, &type, &min, &max, &step,
@@ -1774,7 +1788,7 @@ EXPORT_SYMBOL(v4l2_ctrl_new_custom);
 /* Helper function for standard non-menu controls */
 struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl,
 			const struct v4l2_ctrl_ops *ops,
-			u32 id, s32 min, s32 max, u32 step, s32 def)
+			u32 id, s64 min, s64 max, u64 step, s64 def)
 {
 	const char *name;
 	enum v4l2_ctrl_type type;
@@ -1794,15 +1808,17 @@ EXPORT_SYMBOL(v4l2_ctrl_new_std);
 /* Helper function for standard menu controls */
 struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl,
 			const struct v4l2_ctrl_ops *ops,
-			u32 id, s32 max, s32 mask, s32 def)
+			u32 id, u8 _max, u64 mask, u8 _def)
 {
 	const char * const *qmenu = NULL;
 	const s64 *qmenu_int = NULL;
 	unsigned int qmenu_int_len = 0;
 	const char *name;
 	enum v4l2_ctrl_type type;
-	s32 min;
-	s32 step;
+	s64 min;
+	s64 max = _max;
+	s64 def = _def;
+	u64 step;
 	u32 flags;
 
 	v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
@@ -1823,14 +1839,16 @@ EXPORT_SYMBOL(v4l2_ctrl_new_std_menu);
 
 /* Helper function for standard menu controls with driver defined menu */
 struct v4l2_ctrl *v4l2_ctrl_new_std_menu_items(struct v4l2_ctrl_handler *hdl,
-			const struct v4l2_ctrl_ops *ops, u32 id, s32 max,
-			s32 mask, s32 def, const char * const *qmenu)
+			const struct v4l2_ctrl_ops *ops, u32 id, u8 _max,
+			u64 mask, u8 _def, const char * const *qmenu)
 {
 	enum v4l2_ctrl_type type;
 	const char *name;
 	u32 flags;
-	s32 step;
-	s32 min;
+	u64 step;
+	s64 min;
+	s64 max = _max;
+	s64 def = _def;
 
 	/* v4l2_ctrl_new_std_menu_items() should only be called for
 	 * standard controls without a standard menu.
@@ -1854,12 +1872,14 @@ EXPORT_SYMBOL(v4l2_ctrl_new_std_menu_items);
 /* Helper function for standard integer menu controls */
 struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl,
 			const struct v4l2_ctrl_ops *ops,
-			u32 id, s32 max, s32 def, const s64 *qmenu_int)
+			u32 id, u8 _max, u8 _def, const s64 *qmenu_int)
 {
 	const char *name;
 	enum v4l2_ctrl_type type;
-	s32 min;
-	s32 step;
+	s64 min;
+	u64 step;
+	s64 max = _max;
+	s64 def = _def;
 	u32 flags;
 
 	v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
@@ -2887,13 +2907,14 @@ void v4l2_ctrl_notify(struct v4l2_ctrl *ctrl, v4l2_ctrl_notify_fnc notify, void
 EXPORT_SYMBOL(v4l2_ctrl_notify);
 
 int v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl,
-			s32 min, s32 max, u32 step, s32 def)
+			s64 min, s64 max, u64 step, s64 def)
 {
 	int ret = check_range(ctrl->type, min, max, step, def);
 	struct v4l2_ext_control c;
 
 	switch (ctrl->type) {
 	case V4L2_CTRL_TYPE_INTEGER:
+	case V4L2_CTRL_TYPE_INTEGER64:
 	case V4L2_CTRL_TYPE_BOOLEAN:
 	case V4L2_CTRL_TYPE_MENU:
 	case V4L2_CTRL_TYPE_INTEGER_MENU:
diff --git a/drivers/staging/media/msi3101/msi001.c b/drivers/staging/media/msi3101/msi001.c
index bd0b93c..ee99e37 100644
--- a/drivers/staging/media/msi3101/msi001.c
+++ b/drivers/staging/media/msi3101/msi001.c
@@ -381,7 +381,7 @@ static int msi001_s_ctrl(struct v4l2_ctrl *ctrl)
 
 	int ret;
 	dev_dbg(&s->spi->dev,
-			"%s: id=%d name=%s val=%d min=%d max=%d step=%d\n",
+			"%s: id=%d name=%s val=%d min=%lld max=%lld step=%lld\n",
 			__func__, ctrl->id, ctrl->name, ctrl->val,
 			ctrl->minimum, ctrl->maximum, ctrl->step);
 
diff --git a/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c b/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c
index 093df6b..640d899 100644
--- a/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c
+++ b/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c
@@ -1317,7 +1317,7 @@ static int rtl2832_sdr_s_ctrl(struct v4l2_ctrl *ctrl)
 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 	int ret;
 	dev_dbg(&s->udev->dev,
-			"%s: id=%d name=%s val=%d min=%d max=%d step=%d\n",
+			"%s: id=%d name=%s val=%d min=%lld max=%lld step=%lld\n",
 			__func__, ctrl->id, ctrl->name, ctrl->val,
 			ctrl->minimum, ctrl->maximum, ctrl->step);
 
@@ -1329,7 +1329,7 @@ static int rtl2832_sdr_s_ctrl(struct v4l2_ctrl *ctrl)
 			/* Round towards the closest legal value */
 			s32 val = s->f_adc + s->bandwidth->step / 2;
 			u32 offset;
-			val = clamp(val, s->bandwidth->minimum, s->bandwidth->maximum);
+			val = clamp_t(s32, val, s->bandwidth->minimum, s->bandwidth->maximum);
 			offset = val - s->bandwidth->minimum;
 			offset = s->bandwidth->step * (offset / s->bandwidth->step);
 			s->bandwidth->val = s->bandwidth->minimum + offset;
diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
index 16f7f26..a2e8f03 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -131,10 +131,10 @@ struct v4l2_ctrl {
 	u32 id;
 	const char *name;
 	enum v4l2_ctrl_type type;
-	s32 minimum, maximum, default_value;
+	s64 minimum, maximum, default_value;
 	union {
-		u32 step;
-		u32 menu_skip_mask;
+		u64 step;
+		u64 menu_skip_mask;
 	};
 	union {
 		const char * const *qmenu;
@@ -216,9 +216,9 @@ struct v4l2_ctrl_handler {
   * @menu_skip_mask: The control's skip mask for menu controls. This makes it
   *		easy to skip menu items that are not valid. If bit X is set,
   *		then menu item X is skipped. Of course, this only works for
-  *		menus with <= 32 menu items. There are no menus that come
+  *		menus with <= 64 menu items. There are no menus that come
   *		close to that number, so this is OK. Should we ever need more,
-  *		then this will have to be extended to a u64 or a bit array.
+  *		then this will have to be extended to a bit array.
   * @qmenu:	A const char * array for all menu items. Array entries that are
   *		empty strings ("") correspond to non-existing menu items (this
   *		is in addition to the menu_skip_mask above). The last entry
@@ -231,12 +231,12 @@ struct v4l2_ctrl_config {
 	u32 id;
 	const char *name;
 	enum v4l2_ctrl_type type;
-	s32 min;
-	s32 max;
-	u32 step;
-	s32 def;
+	s64 min;
+	s64 max;
+	u64 step;
+	s64 def;
 	u32 flags;
-	u32 menu_skip_mask;
+	u64 menu_skip_mask;
 	const char * const *qmenu;
 	const s64 *qmenu_int;
 	unsigned int is_private:1;
@@ -257,7 +257,7 @@ struct v4l2_ctrl_config {
   * control framework this function will no longer be exported.
   */
 void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
-		    s32 *min, s32 *max, s32 *step, s32 *def, u32 *flags);
+		    s64 *min, s64 *max, u64 *step, s64 *def, u32 *flags);
 
 
 /** v4l2_ctrl_handler_init_class() - Initialize the control handler.
@@ -362,7 +362,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl,
   */
 struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl,
 			const struct v4l2_ctrl_ops *ops,
-			u32 id, s32 min, s32 max, u32 step, s32 def);
+			u32 id, s64 min, s64 max, u64 step, s64 def);
 
 /** v4l2_ctrl_new_std_menu() - Allocate and initialize a new standard V4L2 menu control.
   * @hdl:	The control handler.
@@ -372,9 +372,9 @@ struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl,
   * @mask: 	The control's skip mask for menu controls. This makes it
   *		easy to skip menu items that are not valid. If bit X is set,
   *		then menu item X is skipped. Of course, this only works for
-  *		menus with <= 32 menu items. There are no menus that come
+  *		menus with <= 64 menu items. There are no menus that come
   *		close to that number, so this is OK. Should we ever need more,
-  *		then this will have to be extended to a u64 or a bit array.
+  *		then this will have to be extended to a bit array.
   * @def: 	The control's default value.
   *
   * Same as v4l2_ctrl_new_std(), but @min is set to 0 and the @mask value
@@ -384,7 +384,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl,
   */
 struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl,
 			const struct v4l2_ctrl_ops *ops,
-			u32 id, s32 max, s32 mask, s32 def);
+			u32 id, u8 max, u64 mask, u8 def);
 
 /** v4l2_ctrl_new_std_menu_items() - Create a new standard V4L2 menu control
   * with driver specific menu.
@@ -395,9 +395,9 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl,
   * @mask:	The control's skip mask for menu controls. This makes it
   *		easy to skip menu items that are not valid. If bit X is set,
   *		then menu item X is skipped. Of course, this only works for
-  *		menus with <= 32 menu items. There are no menus that come
+  *		menus with <= 64 menu items. There are no menus that come
   *		close to that number, so this is OK. Should we ever need more,
-  *		then this will have to be extended to a u64 or a bit array.
+  *		then this will have to be extended to a bit array.
   * @def:	The control's default value.
   * @qmenu:	The new menu.
   *
@@ -406,8 +406,8 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl,
   *
   */
 struct v4l2_ctrl *v4l2_ctrl_new_std_menu_items(struct v4l2_ctrl_handler *hdl,
-			const struct v4l2_ctrl_ops *ops, u32 id, s32 max,
-			s32 mask, s32 def, const char * const *qmenu);
+			const struct v4l2_ctrl_ops *ops, u32 id, u8 max,
+			u64 mask, u8 def, const char * const *qmenu);
 
 /** v4l2_ctrl_new_int_menu() - Create a new standard V4L2 integer menu control.
   * @hdl:	The control handler.
@@ -424,7 +424,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu_items(struct v4l2_ctrl_handler *hdl,
   */
 struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl,
 			const struct v4l2_ctrl_ops *ops,
-			u32 id, s32 max, s32 def, const s64 *qmenu_int);
+			u32 id, u8 max, u8 def, const s64 *qmenu_int);
 
 /** v4l2_ctrl_add_ctrl() - Add a control from another handler to this handler.
   * @hdl:	The control handler.
@@ -560,7 +560,7 @@ void v4l2_ctrl_grab(struct v4l2_ctrl *ctrl, bool grabbed);
   * take the lock itself.
   */
 int v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl,
-			s32 min, s32 max, u32 step, s32 def);
+			s64 min, s64 max, u64 step, s64 def);
 
 /** v4l2_ctrl_lock() - Helper function to lock the handler
   * associated with the control.
-- 
2.0.0.rc0


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

* [REVIEWv4 PATCH 02/34] v4l2-ctrls: use pr_info/cont instead of printk.
  2014-06-12 11:52 ` [REVIEWv4 PATCH 01/34] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
@ 2014-06-12 11:52   ` Hans Verkuil
  2014-06-12 11:52   ` [REVIEWv4 PATCH 03/34] videodev2.h: add initial support for compound controls Hans Verkuil
                     ` (31 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Hans Verkuil @ 2014-06-12 11:52 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, s.nawrocki, sakari.ailus, Hans Verkuil

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

Codingstyle fix.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Reviewed-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
---
 drivers/media/v4l2-core/v4l2-ctrls.c | 26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index e132fa2..365884b 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -2068,45 +2068,45 @@ static void log_ctrl(const struct v4l2_ctrl *ctrl,
 	if (ctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS)
 		return;
 
-	printk(KERN_INFO "%s%s%s: ", prefix, colon, ctrl->name);
+	pr_info("%s%s%s: ", prefix, colon, ctrl->name);
 
 	switch (ctrl->type) {
 	case V4L2_CTRL_TYPE_INTEGER:
-		printk(KERN_CONT "%d", ctrl->cur.val);
+		pr_cont("%d", ctrl->cur.val);
 		break;
 	case V4L2_CTRL_TYPE_BOOLEAN:
-		printk(KERN_CONT "%s", ctrl->cur.val ? "true" : "false");
+		pr_cont("%s", ctrl->cur.val ? "true" : "false");
 		break;
 	case V4L2_CTRL_TYPE_MENU:
-		printk(KERN_CONT "%s", ctrl->qmenu[ctrl->cur.val]);
+		pr_cont("%s", ctrl->qmenu[ctrl->cur.val]);
 		break;
 	case V4L2_CTRL_TYPE_INTEGER_MENU:
-		printk(KERN_CONT "%lld", ctrl->qmenu_int[ctrl->cur.val]);
+		pr_cont("%lld", ctrl->qmenu_int[ctrl->cur.val]);
 		break;
 	case V4L2_CTRL_TYPE_BITMASK:
-		printk(KERN_CONT "0x%08x", ctrl->cur.val);
+		pr_cont("0x%08x", ctrl->cur.val);
 		break;
 	case V4L2_CTRL_TYPE_INTEGER64:
-		printk(KERN_CONT "%lld", ctrl->cur.val64);
+		pr_cont("%lld", ctrl->cur.val64);
 		break;
 	case V4L2_CTRL_TYPE_STRING:
-		printk(KERN_CONT "%s", ctrl->cur.string);
+		pr_cont("%s", ctrl->cur.string);
 		break;
 	default:
-		printk(KERN_CONT "unknown type %d", ctrl->type);
+		pr_cont("unknown type %d", ctrl->type);
 		break;
 	}
 	if (ctrl->flags & (V4L2_CTRL_FLAG_INACTIVE |
 			   V4L2_CTRL_FLAG_GRABBED |
 			   V4L2_CTRL_FLAG_VOLATILE)) {
 		if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
-			printk(KERN_CONT " inactive");
+			pr_cont(" inactive");
 		if (ctrl->flags & V4L2_CTRL_FLAG_GRABBED)
-			printk(KERN_CONT " grabbed");
+			pr_cont(" grabbed");
 		if (ctrl->flags & V4L2_CTRL_FLAG_VOLATILE)
-			printk(KERN_CONT " volatile");
+			pr_cont(" volatile");
 	}
-	printk(KERN_CONT "\n");
+	pr_cont("\n");
 }
 
 /* Log all controls owned by the handler */
-- 
2.0.0.rc0


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

* [REVIEWv4 PATCH 03/34] videodev2.h: add initial support for compound controls.
  2014-06-12 11:52 ` [REVIEWv4 PATCH 01/34] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
  2014-06-12 11:52   ` [REVIEWv4 PATCH 02/34] v4l2-ctrls: use pr_info/cont instead of printk Hans Verkuil
@ 2014-06-12 11:52   ` Hans Verkuil
  2014-06-12 11:52   ` [REVIEWv4 PATCH 04/34] videodev2.h: add struct v4l2_query_ext_ctrl and VIDIOC_QUERY_EXT_CTRL Hans Verkuil
                     ` (30 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Hans Verkuil @ 2014-06-12 11:52 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, s.nawrocki, sakari.ailus, Hans Verkuil

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

Compound controls are controls that can be used for compound and array
types. This allows for more compound data structures to be used with the
control framework.

The existing V4L2_CTRL_FLAG_NEXT_CTRL flag will only enumerate non-compound
controls, so a new V4L2_CTRL_FLAG_NEXT_COMPOUND flag is added to enumerate
compound controls. Set both flags to enumerate any control (compound or not).

Compound control types will start at V4L2_CTRL_COMPOUND_TYPES. In addition, any
control that uses the new 'ptr' field or the existing 'string' field will have
flag V4L2_CTRL_FLAG_HAS_PAYLOAD set.

While not strictly necessary, adding that flag makes life for applications
a lot simpler. If the flag is not set, then the control value is set
through the value or value64 fields of struct v4l2_ext_control, otherwise
a pointer points to the value.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Reviewed-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
---
 include/uapi/linux/videodev2.h | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 168ff50..438c4a6 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -1254,6 +1254,7 @@ struct v4l2_ext_control {
 		__s32 value;
 		__s64 value64;
 		char *string;
+		void *ptr;
 	};
 } __attribute__ ((packed));
 
@@ -1278,7 +1279,10 @@ enum v4l2_ctrl_type {
 	V4L2_CTRL_TYPE_CTRL_CLASS    = 6,
 	V4L2_CTRL_TYPE_STRING        = 7,
 	V4L2_CTRL_TYPE_BITMASK       = 8,
-	V4L2_CTRL_TYPE_INTEGER_MENU = 9,
+	V4L2_CTRL_TYPE_INTEGER_MENU  = 9,
+
+	/* Compound types are >= 0x0100 */
+	V4L2_CTRL_COMPOUND_TYPES     = 0x0100,
 };
 
 /*  Used in the VIDIOC_QUERYCTRL ioctl for querying controls */
@@ -1314,9 +1318,11 @@ struct v4l2_querymenu {
 #define V4L2_CTRL_FLAG_SLIDER 		0x0020
 #define V4L2_CTRL_FLAG_WRITE_ONLY 	0x0040
 #define V4L2_CTRL_FLAG_VOLATILE		0x0080
+#define V4L2_CTRL_FLAG_HAS_PAYLOAD	0x0100
 
-/*  Query flag, to be ORed with the control ID */
+/*  Query flags, to be ORed with the control ID */
 #define V4L2_CTRL_FLAG_NEXT_CTRL	0x80000000
+#define V4L2_CTRL_FLAG_NEXT_COMPOUND	0x40000000
 
 /*  User-class control IDs defined by V4L2 */
 #define V4L2_CID_MAX_CTRLS		1024
-- 
2.0.0.rc0


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

* [REVIEWv4 PATCH 04/34] videodev2.h: add struct v4l2_query_ext_ctrl and VIDIOC_QUERY_EXT_CTRL.
  2014-06-12 11:52 ` [REVIEWv4 PATCH 01/34] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
  2014-06-12 11:52   ` [REVIEWv4 PATCH 02/34] v4l2-ctrls: use pr_info/cont instead of printk Hans Verkuil
  2014-06-12 11:52   ` [REVIEWv4 PATCH 03/34] videodev2.h: add initial support for compound controls Hans Verkuil
@ 2014-06-12 11:52   ` Hans Verkuil
  2014-06-12 12:38     ` Sakari Ailus
  2014-06-12 11:52   ` [REVIEWv4 PATCH 05/34] v4l2-ctrls: add support for compound types Hans Verkuil
                     ` (29 subsequent siblings)
  32 siblings, 1 reply; 36+ messages in thread
From: Hans Verkuil @ 2014-06-12 11:52 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, s.nawrocki, sakari.ailus, Hans Verkuil

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

Add a new struct and ioctl to extend the amount of information you can
get for a control.

The range is now a s64 type, and array dimensions and element size can be
reported through nr_of_dims/dims/elems/elem_size.

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

diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 438c4a6..7d94adc 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -1269,6 +1269,7 @@ struct v4l2_ext_controls {
 #define V4L2_CTRL_ID_MASK      	  (0x0fffffff)
 #define V4L2_CTRL_ID2CLASS(id)    ((id) & 0x0fff0000UL)
 #define V4L2_CTRL_DRIVER_PRIV(id) (((id) & 0xffff) >= 0x1000)
+#define V4L2_CTRL_MAX_DIMS	  (8)
 
 enum v4l2_ctrl_type {
 	V4L2_CTRL_TYPE_INTEGER	     = 1,
@@ -1298,6 +1299,23 @@ struct v4l2_queryctrl {
 	__u32		     reserved[2];
 };
 
+/*  Used in the VIDIOC_QUERY_EXT_CTRL ioctl for querying extended controls */
+struct v4l2_query_ext_ctrl {
+	__u32		     id;
+	__u32		     type;
+	char		     name[32];
+	__s64		     minimum;
+	__s64		     maximum;
+	__u64		     step;
+	__s64		     default_value;
+	__u32                flags;
+	__u32                elem_size;
+	__u32                elems;
+	__u32                nr_of_dims;
+	__u32                dims[V4L2_CTRL_MAX_DIMS];
+	__u32		     reserved[16];
+};
+
 /*  Used in the VIDIOC_QUERYMENU ioctl for querying menu items */
 struct v4l2_querymenu {
 	__u32		id;
@@ -2011,6 +2029,8 @@ struct v4l2_create_buffers {
    Never use these in applications! */
 #define VIDIOC_DBG_G_CHIP_INFO  _IOWR('V', 102, struct v4l2_dbg_chip_info)
 
+#define VIDIOC_QUERY_EXT_CTRL	_IOWR('V', 103, struct v4l2_query_ext_ctrl)
+
 /* Reminder: when adding new ioctls please add support for them to
    drivers/media/video/v4l2-compat-ioctl32.c as well! */
 
-- 
2.0.0.rc0


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

* [REVIEWv4 PATCH 05/34] v4l2-ctrls: add support for compound types.
  2014-06-12 11:52 ` [REVIEWv4 PATCH 01/34] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
                     ` (2 preceding siblings ...)
  2014-06-12 11:52   ` [REVIEWv4 PATCH 04/34] videodev2.h: add struct v4l2_query_ext_ctrl and VIDIOC_QUERY_EXT_CTRL Hans Verkuil
@ 2014-06-12 11:52   ` Hans Verkuil
  2014-06-12 11:52   ` [REVIEWv4 PATCH 06/34] v4l2: integrate support for VIDIOC_QUERY_EXT_CTRL Hans Verkuil
                     ` (28 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Hans Verkuil @ 2014-06-12 11:52 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, s.nawrocki, sakari.ailus, Hans Verkuil

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

This patch implements initial support for compound types.

The changes are fairly obvious: basic support for is_ptr types, the
type_is_int function is replaced by a is_int bitfield, and
v4l2_query_ext_ctrl is added.

Note that this patch does not yet add support for N-dimensional
arrays, that comes later. So v4l2_query_ext_ctrl just sets elems to
1 and nr_of_dims and dims[] are all zero.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/v4l2-core/v4l2-ctrls.c | 224 ++++++++++++++++++++++++++---------
 include/media/v4l2-ctrls.h           |  23 +++-
 2 files changed, 187 insertions(+), 60 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 365884b..d5cd1aa 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1124,20 +1124,6 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
 }
 EXPORT_SYMBOL(v4l2_ctrl_fill);
 
-/* Helper function to determine whether the control type is compatible with
-   VIDIOC_G/S_CTRL. */
-static bool type_is_int(const struct v4l2_ctrl *ctrl)
-{
-	switch (ctrl->type) {
-	case V4L2_CTRL_TYPE_INTEGER64:
-	case V4L2_CTRL_TYPE_STRING:
-		/* Nope, these need v4l2_ext_control */
-		return false;
-	default:
-		return true;
-	}
-}
-
 static void fill_event(struct v4l2_event *ev, struct v4l2_ctrl *ctrl, u32 changes)
 {
 	memset(ev->reserved, 0, sizeof(ev->reserved));
@@ -1146,7 +1132,7 @@ static void fill_event(struct v4l2_event *ev, struct v4l2_ctrl *ctrl, u32 change
 	ev->u.ctrl.changes = changes;
 	ev->u.ctrl.type = ctrl->type;
 	ev->u.ctrl.flags = ctrl->flags;
-	if (ctrl->type == V4L2_CTRL_TYPE_STRING)
+	if (ctrl->is_ptr)
 		ev->u.ctrl.value64 = 0;
 	else
 		ev->u.ctrl.value64 = ctrl->cur.val64;
@@ -1181,6 +1167,9 @@ static int cur_to_user(struct v4l2_ext_control *c,
 {
 	u32 len;
 
+	if (ctrl->is_ptr && !ctrl->is_string)
+		return copy_to_user(c->ptr, ctrl->cur.p, ctrl->elem_size);
+
 	switch (ctrl->type) {
 	case V4L2_CTRL_TYPE_STRING:
 		len = strlen(ctrl->cur.string);
@@ -1208,6 +1197,9 @@ static int user_to_new(struct v4l2_ext_control *c,
 	u32 size;
 
 	ctrl->is_new = 1;
+	if (ctrl->is_ptr && !ctrl->is_string)
+		return copy_from_user(ctrl->p, c->ptr, ctrl->elem_size);
+
 	switch (ctrl->type) {
 	case V4L2_CTRL_TYPE_INTEGER64:
 		ctrl->val64 = c->value64;
@@ -1242,6 +1234,9 @@ static int new_to_user(struct v4l2_ext_control *c,
 {
 	u32 len;
 
+	if (ctrl->is_ptr && !ctrl->is_string)
+		return copy_to_user(c->ptr, ctrl->p, ctrl->elem_size);
+
 	switch (ctrl->type) {
 	case V4L2_CTRL_TYPE_STRING:
 		len = strlen(ctrl->string);
@@ -1268,6 +1263,7 @@ static void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags)
 
 	if (ctrl == NULL)
 		return;
+
 	switch (ctrl->type) {
 	case V4L2_CTRL_TYPE_BUTTON:
 		changed = true;
@@ -1282,8 +1278,13 @@ static void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags)
 		ctrl->cur.val64 = ctrl->val64;
 		break;
 	default:
-		changed = ctrl->val != ctrl->cur.val;
-		ctrl->cur.val = ctrl->val;
+		if (ctrl->is_ptr) {
+			changed = memcmp(ctrl->p, ctrl->cur.p, ctrl->elem_size);
+			memcpy(ctrl->cur.p, ctrl->p, ctrl->elem_size);
+		} else {
+			changed = ctrl->val != ctrl->cur.val;
+			ctrl->cur.val = ctrl->val;
+		}
 		break;
 	}
 	if (ch_flags & V4L2_EVENT_CTRL_CH_FLAGS) {
@@ -1323,7 +1324,10 @@ static void cur_to_new(struct v4l2_ctrl *ctrl)
 		ctrl->val64 = ctrl->cur.val64;
 		break;
 	default:
-		ctrl->val = ctrl->cur.val;
+		if (ctrl->is_ptr)
+			memcpy(ctrl->p, ctrl->cur.p, ctrl->elem_size);
+		else
+			ctrl->val = ctrl->cur.val;
 		break;
 	}
 }
@@ -1536,7 +1540,7 @@ static struct v4l2_ctrl_ref *find_private_ref(
 		   VIDIOC_G/S_CTRL. */
 		if (V4L2_CTRL_ID2CLASS(ref->ctrl->id) == V4L2_CTRL_CLASS_USER &&
 		    V4L2_CTRL_DRIVER_PRIV(ref->ctrl->id)) {
-			if (!type_is_int(ref->ctrl))
+			if (!ref->ctrl->is_int)
 				continue;
 			if (id == 0)
 				return ref;
@@ -1606,8 +1610,12 @@ static int handler_new_ref(struct v4l2_ctrl_handler *hdl,
 	u32 class_ctrl = V4L2_CTRL_ID2CLASS(id) | 1;
 	int bucket = id % hdl->nr_of_buckets;	/* which bucket to use */
 
-	/* Automatically add the control class if it is not yet present. */
-	if (id != class_ctrl && find_ref_lock(hdl, class_ctrl) == NULL)
+	/*
+	 * Automatically add the control class if it is not yet present and
+	 * the new control is not a compound control.
+	 */
+	if (ctrl->type < V4L2_CTRL_COMPOUND_TYPES &&
+	    id != class_ctrl && find_ref_lock(hdl, class_ctrl) == NULL)
 		if (!v4l2_ctrl_new_std(hdl, NULL, class_ctrl, 0, 0, 0, 0))
 			return hdl->error;
 
@@ -1668,18 +1676,28 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 			const struct v4l2_ctrl_ops *ops,
 			u32 id, const char *name, enum v4l2_ctrl_type type,
 			s64 min, s64 max, u64 step, s64 def,
+			u32 elem_size,
 			u32 flags, const char * const *qmenu,
 			const s64 *qmenu_int, void *priv)
 {
 	struct v4l2_ctrl *ctrl;
-	unsigned sz_extra = 0;
+	unsigned sz_extra;
+	void *data;
 	int err;
 
 	if (hdl->error)
 		return NULL;
 
+	if (type == V4L2_CTRL_TYPE_INTEGER64)
+		elem_size = sizeof(s64);
+	else if (type == V4L2_CTRL_TYPE_STRING)
+		elem_size = max + 1;
+	else if (type < V4L2_CTRL_COMPOUND_TYPES)
+		elem_size = sizeof(s32);
+
 	/* Sanity checks */
 	if (id == 0 || name == NULL || id >= V4L2_CID_PRIVATE_BASE ||
+	    elem_size == 0 ||
 	    (type == V4L2_CTRL_TYPE_MENU && qmenu == NULL) ||
 	    (type == V4L2_CTRL_TYPE_INTEGER_MENU && qmenu_int == NULL)) {
 		handler_set_err(hdl, -ERANGE);
@@ -1695,12 +1713,13 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 		return NULL;
 	}
 
+	sz_extra = 0;
 	if (type == V4L2_CTRL_TYPE_BUTTON)
 		flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
 	else if (type == V4L2_CTRL_TYPE_CTRL_CLASS)
 		flags |= V4L2_CTRL_FLAG_READ_ONLY;
-	else if (type == V4L2_CTRL_TYPE_STRING)
-		sz_extra += 2 * (max + 1);
+	else if (type == V4L2_CTRL_TYPE_STRING || type >= V4L2_CTRL_COMPOUND_TYPES)
+		sz_extra += 2 * elem_size;
 
 	ctrl = kzalloc(sizeof(*ctrl) + sz_extra, GFP_KERNEL);
 	if (ctrl == NULL) {
@@ -1719,18 +1738,28 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 	ctrl->minimum = min;
 	ctrl->maximum = max;
 	ctrl->step = step;
+	ctrl->default_value = def;
+	ctrl->is_string = type == V4L2_CTRL_TYPE_STRING;
+	ctrl->is_ptr = type >= V4L2_CTRL_COMPOUND_TYPES || ctrl->is_string;
+	ctrl->is_int = !ctrl->is_ptr && type != V4L2_CTRL_TYPE_INTEGER64;
+	ctrl->elem_size = elem_size;
 	if (type == V4L2_CTRL_TYPE_MENU)
 		ctrl->qmenu = qmenu;
 	else if (type == V4L2_CTRL_TYPE_INTEGER_MENU)
 		ctrl->qmenu_int = qmenu_int;
 	ctrl->priv = priv;
-	ctrl->cur.val = ctrl->val = ctrl->default_value = def;
+	ctrl->cur.val = ctrl->val = def;
+	data = &ctrl->cur + 1;
+
+	if (ctrl->is_string) {
+		ctrl->string = data;
+		ctrl->cur.string = data + elem_size;
 
-	if (ctrl->type == V4L2_CTRL_TYPE_STRING) {
-		ctrl->cur.string = (char *)&ctrl[1] + sz_extra - (max + 1);
-		ctrl->string = (char *)&ctrl[1] + sz_extra - 2 * (max + 1);
 		if (ctrl->minimum)
 			memset(ctrl->cur.string, ' ', ctrl->minimum);
+	} else if (ctrl->is_ptr) {
+		ctrl->p = data;
+		ctrl->cur.p = data + elem_size;
 	}
 	if (handler_new_ref(hdl, ctrl)) {
 		kfree(ctrl);
@@ -1778,7 +1807,8 @@ struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl,
 	ctrl = v4l2_ctrl_new(hdl, cfg->ops, cfg->id, name,
 			type, min, max,
 			is_menu ? cfg->menu_skip_mask : step,
-			def, flags, qmenu, qmenu_int, priv);
+			def, cfg->elem_size,
+			flags, qmenu, qmenu_int, priv);
 	if (ctrl)
 		ctrl->is_private = cfg->is_private;
 	return ctrl;
@@ -1795,13 +1825,15 @@ struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl,
 	u32 flags;
 
 	v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
-	if (type == V4L2_CTRL_TYPE_MENU
-	    || type == V4L2_CTRL_TYPE_INTEGER_MENU) {
+	if (type == V4L2_CTRL_TYPE_MENU ||
+	    type == V4L2_CTRL_TYPE_INTEGER_MENU ||
+	    type >= V4L2_CTRL_COMPOUND_TYPES) {
 		handler_set_err(hdl, -EINVAL);
 		return NULL;
 	}
 	return v4l2_ctrl_new(hdl, ops, id, name, type,
-			     min, max, step, def, flags, NULL, NULL, NULL);
+			     min, max, step, def, 0,
+			     flags, NULL, NULL, NULL);
 }
 EXPORT_SYMBOL(v4l2_ctrl_new_std);
 
@@ -1833,7 +1865,8 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl,
 		return NULL;
 	}
 	return v4l2_ctrl_new(hdl, ops, id, name, type,
-			     0, max, mask, def, flags, qmenu, qmenu_int, NULL);
+			     0, max, mask, def, 0,
+			     flags, qmenu, qmenu_int, NULL);
 }
 EXPORT_SYMBOL(v4l2_ctrl_new_std_menu);
 
@@ -1864,7 +1897,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu_items(struct v4l2_ctrl_handler *hdl,
 		return NULL;
 	}
 	return v4l2_ctrl_new(hdl, ops, id, name, type, 0, max, mask, def,
-			     flags, qmenu, NULL, NULL);
+			     0, flags, qmenu, NULL, NULL);
 
 }
 EXPORT_SYMBOL(v4l2_ctrl_new_std_menu_items);
@@ -1888,7 +1921,8 @@ struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl,
 		return NULL;
 	}
 	return v4l2_ctrl_new(hdl, ops, id, name, type,
-			     0, max, 0, def, flags, NULL, qmenu_int, NULL);
+			     0, max, 0, def, 0,
+			     flags, NULL, qmenu_int, NULL);
 }
 EXPORT_SYMBOL(v4l2_ctrl_new_int_menu);
 
@@ -2177,9 +2211,10 @@ int v4l2_ctrl_handler_setup(struct v4l2_ctrl_handler *hdl)
 }
 EXPORT_SYMBOL(v4l2_ctrl_handler_setup);
 
-/* Implement VIDIOC_QUERYCTRL */
-int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc)
+/* Implement VIDIOC_QUERY_EXT_CTRL */
+int v4l2_query_ext_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_query_ext_ctrl *qc)
 {
+	const unsigned next_flags = V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND;
 	u32 id = qc->id & V4L2_CTRL_ID_MASK;
 	struct v4l2_ctrl_ref *ref;
 	struct v4l2_ctrl *ctrl;
@@ -2192,7 +2227,20 @@ int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc)
 	/* Try to find it */
 	ref = find_ref(hdl, id);
 
-	if ((qc->id & V4L2_CTRL_FLAG_NEXT_CTRL) && !list_empty(&hdl->ctrl_refs)) {
+	if ((qc->id & next_flags) && !list_empty(&hdl->ctrl_refs)) {
+		bool is_compound;
+		/* Match any control that is not hidden */
+		unsigned mask = 1;
+		bool match = false;
+
+		if ((qc->id & next_flags) == V4L2_CTRL_FLAG_NEXT_COMPOUND) {
+			/* Match any hidden control */
+			match = true;
+		} else if ((qc->id & next_flags) == next_flags) {
+			/* Match any control, compound or not */
+			mask = 0;
+		}
+
 		/* Find the next control with ID > qc->id */
 
 		/* Did we reach the end of the control list? */
@@ -2200,19 +2248,34 @@ int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc)
 			ref = NULL; /* Yes, so there is no next control */
 		} else if (ref) {
 			/* We found a control with the given ID, so just get
-			   the next one in the list. */
-			ref = list_entry(ref->node.next, typeof(*ref), node);
+			   the next valid one in the list. */
+			list_for_each_entry_continue(ref, &hdl->ctrl_refs, node) {
+				is_compound =
+					ref->ctrl->type >= V4L2_CTRL_COMPOUND_TYPES;
+				if (id < ref->ctrl->id &&
+				    (is_compound & mask) == match)
+					break;
+			}
+			if (&ref->node == &hdl->ctrl_refs)
+				ref = NULL;
 		} else {
 			/* No control with the given ID exists, so start
 			   searching for the next largest ID. We know there
 			   is one, otherwise the first 'if' above would have
 			   been true. */
-			list_for_each_entry(ref, &hdl->ctrl_refs, node)
-				if (id < ref->ctrl->id)
+			list_for_each_entry(ref, &hdl->ctrl_refs, node) {
+				is_compound =
+					ref->ctrl->type >= V4L2_CTRL_COMPOUND_TYPES;
+				if (id < ref->ctrl->id &&
+				    (is_compound & mask) == match)
 					break;
+			}
+			if (&ref->node == &hdl->ctrl_refs)
+				ref = NULL;
 		}
 	}
 	mutex_unlock(hdl->lock);
+
 	if (!ref)
 		return -EINVAL;
 
@@ -2223,6 +2286,12 @@ int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc)
 	else
 		qc->id = ctrl->id;
 	strlcpy(qc->name, ctrl->name, sizeof(qc->name));
+	qc->flags = ctrl->flags;
+	qc->type = ctrl->type;
+	if (ctrl->is_ptr)
+		qc->flags |= V4L2_CTRL_FLAG_HAS_PAYLOAD;
+	qc->elem_size = ctrl->elem_size;
+	qc->elems = 1;
 	qc->minimum = ctrl->minimum;
 	qc->maximum = ctrl->maximum;
 	qc->default_value = ctrl->default_value;
@@ -2231,15 +2300,50 @@ int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc)
 		qc->step = 1;
 	else
 		qc->step = ctrl->step;
-	qc->flags = ctrl->flags;
-	qc->type = ctrl->type;
+	return 0;
+}
+EXPORT_SYMBOL(v4l2_query_ext_ctrl);
+
+/* Implement VIDIOC_QUERYCTRL */
+int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc)
+{
+	struct v4l2_query_ext_ctrl qec = { qc->id };
+	int rc;
+
+	rc = v4l2_query_ext_ctrl(hdl, &qec);
+	if (rc)
+		return rc;
+
+	qc->id = qec.id;
+	qc->type = qec.type;
+	qc->flags = qec.flags;
+	strlcpy(qc->name, qec.name, sizeof(qc->name));
+	switch (qc->type) {
+	case V4L2_CTRL_TYPE_INTEGER:
+	case V4L2_CTRL_TYPE_BOOLEAN:
+	case V4L2_CTRL_TYPE_MENU:
+	case V4L2_CTRL_TYPE_INTEGER_MENU:
+	case V4L2_CTRL_TYPE_STRING:
+	case V4L2_CTRL_TYPE_BITMASK:
+		qc->minimum = qec.minimum;
+		qc->maximum = qec.maximum;
+		qc->step = qec.step;
+		qc->default_value = qec.default_value;
+		break;
+	default:
+		qc->minimum = 0;
+		qc->maximum = 0;
+		qc->step = 0;
+		qc->default_value = 0;
+		break;
+	}
 	return 0;
 }
 EXPORT_SYMBOL(v4l2_queryctrl);
 
 int v4l2_subdev_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
 {
-	if (qc->id & V4L2_CTRL_FLAG_NEXT_CTRL)
+	if (qc->id & (V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND))
 		return -EINVAL;
 	return v4l2_queryctrl(sd->ctrl_handler, qc);
 }
@@ -2339,7 +2443,8 @@ EXPORT_SYMBOL(v4l2_subdev_querymenu);
    Find the controls in the control array and do some basic checks. */
 static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl,
 			     struct v4l2_ext_controls *cs,
-			     struct v4l2_ctrl_helper *helpers)
+			     struct v4l2_ctrl_helper *helpers,
+			     bool get)
 {
 	struct v4l2_ctrl_helper *h;
 	bool have_clusters = false;
@@ -2371,6 +2476,13 @@ static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl,
 			have_clusters = true;
 		if (ctrl->cluster[0] != ctrl)
 			ref = find_ref_lock(hdl, ctrl->cluster[0]->id);
+		if (ctrl->is_ptr && !ctrl->is_string && c->size < ctrl->elem_size) {
+			if (get) {
+				c->size = ctrl->elem_size;
+				return -ENOSPC;
+			}
+			return -EFAULT;
+		}
 		/* Store the ref to the master control of the cluster */
 		h->mref = ref;
 		h->ctrl = ctrl;
@@ -2451,7 +2563,7 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs
 			return -ENOMEM;
 	}
 
-	ret = prepare_ext_ctrls(hdl, cs, helpers);
+	ret = prepare_ext_ctrls(hdl, cs, helpers, true);
 	cs->error_idx = cs->count;
 
 	for (i = 0; !ret && i < cs->count; i++)
@@ -2513,11 +2625,11 @@ static int get_ctrl(struct v4l2_ctrl *ctrl, struct v4l2_ext_control *c)
 	int ret = 0;
 	int i;
 
-	/* String controls are not supported. The new_to_user() and
+	/* Compound controls are not supported. The new_to_user() and
 	 * cur_to_user() calls below would need to be modified not to access
 	 * userspace memory when called from get_ctrl().
 	 */
-	if (ctrl->type == V4L2_CTRL_TYPE_STRING)
+	if (!ctrl->is_int)
 		return -EINVAL;
 
 	if (ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY)
@@ -2543,7 +2655,7 @@ int v4l2_g_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_control *control)
 	struct v4l2_ext_control c;
 	int ret;
 
-	if (ctrl == NULL || !type_is_int(ctrl))
+	if (ctrl == NULL || !ctrl->is_int)
 		return -EINVAL;
 	ret = get_ctrl(ctrl, &c);
 	control->value = c.value;
@@ -2562,7 +2674,7 @@ s32 v4l2_ctrl_g_ctrl(struct v4l2_ctrl *ctrl)
 	struct v4l2_ext_control c;
 
 	/* It's a driver bug if this happens. */
-	WARN_ON(!type_is_int(ctrl));
+	WARN_ON(!ctrl->is_int);
 	c.value = 0;
 	get_ctrl(ctrl, &c);
 	return c.value;
@@ -2698,7 +2810,7 @@ static int try_set_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
 		if (!helpers)
 			return -ENOMEM;
 	}
-	ret = prepare_ext_ctrls(hdl, cs, helpers);
+	ret = prepare_ext_ctrls(hdl, cs, helpers, false);
 	if (!ret)
 		ret = validate_ctrls(cs, helpers, set);
 	if (ret && set)
@@ -2803,11 +2915,11 @@ static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl,
 	struct v4l2_ctrl *master = ctrl->cluster[0];
 	int i;
 
-	/* String controls are not supported. The user_to_new() and
+	/* Compound controls are not supported. The user_to_new() and
 	 * cur_to_user() calls below would need to be modified not to access
 	 * userspace memory when called from set_ctrl().
 	 */
-	if (ctrl->type == V4L2_CTRL_TYPE_STRING)
+	if (ctrl->is_ptr)
 		return -EINVAL;
 
 	/* Reset the 'is_new' flags of the cluster */
@@ -2849,7 +2961,7 @@ int v4l2_s_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
 	struct v4l2_ext_control c;
 	int ret;
 
-	if (ctrl == NULL || !type_is_int(ctrl))
+	if (ctrl == NULL || !ctrl->is_int)
 		return -EINVAL;
 
 	if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY)
@@ -2873,7 +2985,7 @@ int v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val)
 	struct v4l2_ext_control c;
 
 	/* It's a driver bug if this happens. */
-	WARN_ON(!type_is_int(ctrl));
+	WARN_ON(!ctrl->is_int);
 	c.value = val;
 	return set_ctrl_lock(NULL, ctrl, &c);
 }
diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
index a2e8f03..9024dae 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -73,6 +73,12 @@ typedef void (*v4l2_ctrl_notify_fnc)(struct v4l2_ctrl *ctrl, void *priv);
   *		members are in 'automatic' mode or 'manual' mode. This is
   *		used for autogain/gain type clusters. Drivers should never
   *		set this flag directly.
+  * @is_int:    If set, then this control has a simple integer value (i.e. it
+  *		uses ctrl->val).
+  * @is_string: If set, then this control has type V4L2_CTRL_TYPE_STRING.
+  * @is_ptr:	If set, then this control is an array and/or has type >= V4L2_CTRL_COMPOUND_TYPES
+  *		and/or has type V4L2_CTRL_TYPE_STRING. In other words, struct
+  *		v4l2_ext_control uses field p to point to the data.
   * @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
@@ -90,6 +96,7 @@ typedef void (*v4l2_ctrl_notify_fnc)(struct v4l2_ctrl *ctrl, void *priv);
   * @maximum:	The control's maximum value.
   * @default_value: The control's default value.
   * @step:	The control's step value for non-menu controls.
+  * @elem_size:	The size in bytes of the control.
   * @menu_skip_mask: The control's skip mask for menu controls. This makes it
   *		easy to skip menu items that are not valid. If bit X is set,
   *		then menu item X is skipped. Of course, this only works for
@@ -104,7 +111,6 @@ typedef void (*v4l2_ctrl_notify_fnc)(struct v4l2_ctrl *ctrl, void *priv);
   * @cur:	The control's current value.
   * @val:	The control's new s32 value.
   * @val64:	The control's new s64 value.
-  * @string:	The control's new string value.
   * @priv:	The control's private pointer. For use by the driver. It is
   *		untouched by the control framework. Note that this pointer is
   *		not freed when the control is deleted. Should this be needed
@@ -123,6 +129,9 @@ struct v4l2_ctrl {
 	unsigned int is_new:1;
 	unsigned int is_private:1;
 	unsigned int is_auto:1;
+	unsigned int is_int:1;
+	unsigned int is_string:1;
+	unsigned int is_ptr:1;
 	unsigned int has_volatiles:1;
 	unsigned int call_notify:1;
 	unsigned int manual_mode_value:8;
@@ -132,6 +141,7 @@ struct v4l2_ctrl {
 	const char *name;
 	enum v4l2_ctrl_type type;
 	s64 minimum, maximum, default_value;
+	u32 elem_size;
 	union {
 		u64 step;
 		u64 menu_skip_mask;
@@ -141,17 +151,19 @@ struct v4l2_ctrl {
 		const s64 *qmenu_int;
 	};
 	unsigned long flags;
+	void *priv;
 	union {
 		s32 val;
 		s64 val64;
 		char *string;
-	} cur;
+		void *p;
+	};
 	union {
 		s32 val;
 		s64 val64;
 		char *string;
-	};
-	void *priv;
+		void *p;
+	} cur;
 };
 
 /** struct v4l2_ctrl_ref - The control reference.
@@ -212,6 +224,7 @@ struct v4l2_ctrl_handler {
   * @max:	The control's maximum value.
   * @step:	The control's step value for non-menu controls.
   * @def: 	The control's default value.
+  * @elem_size:	The size in bytes of the control.
   * @flags:	The control's flags.
   * @menu_skip_mask: The control's skip mask for menu controls. This makes it
   *		easy to skip menu items that are not valid. If bit X is set,
@@ -235,6 +248,7 @@ struct v4l2_ctrl_config {
 	s64 max;
 	u64 step;
 	s64 def;
+	u32 elem_size;
 	u32 flags;
 	u64 menu_skip_mask;
 	const char * const *qmenu;
@@ -659,6 +673,7 @@ unsigned int v4l2_ctrl_poll(struct file *file, struct poll_table_struct *wait);
 
 /* Helpers for ioctl_ops. If hdl == NULL then they will all return -EINVAL. */
 int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc);
+int v4l2_query_ext_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_query_ext_ctrl *qc);
 int v4l2_querymenu(struct v4l2_ctrl_handler *hdl, struct v4l2_querymenu *qm);
 int v4l2_g_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_control *ctrl);
 int v4l2_s_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
-- 
2.0.0.rc0


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

* [REVIEWv4 PATCH 06/34] v4l2: integrate support for VIDIOC_QUERY_EXT_CTRL.
  2014-06-12 11:52 ` [REVIEWv4 PATCH 01/34] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
                     ` (3 preceding siblings ...)
  2014-06-12 11:52   ` [REVIEWv4 PATCH 05/34] v4l2-ctrls: add support for compound types Hans Verkuil
@ 2014-06-12 11:52   ` Hans Verkuil
  2014-06-12 11:52   ` [REVIEWv4 PATCH 07/34] v4l2-ctrls: create type_ops Hans Verkuil
                     ` (27 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Hans Verkuil @ 2014-06-12 11:52 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, s.nawrocki, sakari.ailus, Hans Verkuil

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

Add the v4l2 core plumbing for the new VIDIOC_QUERY_EXT_CTRL ioctl.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Reviewed-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
---
 drivers/media/v4l2-core/v4l2-dev.c    |  2 ++
 drivers/media/v4l2-core/v4l2-ioctl.c  | 33 +++++++++++++++++++++++++++++++++
 drivers/media/v4l2-core/v4l2-subdev.c |  3 +++
 include/media/v4l2-ioctl.h            |  2 ++
 4 files changed, 40 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c
index 634d863..aba277c 100644
--- a/drivers/media/v4l2-core/v4l2-dev.c
+++ b/drivers/media/v4l2-core/v4l2-dev.c
@@ -577,6 +577,8 @@ static void determine_valid_ioctls(struct video_device *vdev)
 	   be valid if the filehandle passed the control handler. */
 	if (vdev->ctrl_handler || ops->vidioc_queryctrl)
 		set_bit(_IOC_NR(VIDIOC_QUERYCTRL), valid_ioctls);
+	if (vdev->ctrl_handler || ops->vidioc_query_ext_ctrl)
+		set_bit(_IOC_NR(VIDIOC_QUERY_EXT_CTRL), valid_ioctls);
 	if (vdev->ctrl_handler || ops->vidioc_g_ctrl || ops->vidioc_g_ext_ctrls)
 		set_bit(_IOC_NR(VIDIOC_G_CTRL), valid_ioctls);
 	if (vdev->ctrl_handler || ops->vidioc_s_ctrl || ops->vidioc_s_ext_ctrls)
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 16bffd8..b82ea79 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -525,6 +525,21 @@ static void v4l_print_queryctrl(const void *arg, bool write_only)
 			p->step, p->default_value, p->flags);
 }
 
+static void v4l_print_query_ext_ctrl(const void *arg, bool write_only)
+{
+	const struct v4l2_query_ext_ctrl *p = arg;
+
+	pr_cont("id=0x%x, type=%d, name=%.*s, min/max=%lld/%lld, "
+		"step=%lld, default=%lld, flags=0x%08x, elem_size=%u, elems=%u, "
+		"nr_of_dims=%u, dims=%u,%u,%u,%u,%u,%u,%u,%u\n",
+			p->id, p->type, (int)sizeof(p->name), p->name,
+			p->minimum, p->maximum,
+			p->step, p->default_value, p->flags,
+			p->elem_size, p->elems, p->nr_of_dims,
+			p->dims[0], p->dims[1], p->dims[2], p->dims[3],
+			p->dims[4], p->dims[5], p->dims[6], p->dims[7]);
+}
+
 static void v4l_print_querymenu(const void *arg, bool write_only)
 {
 	const struct v4l2_querymenu *p = arg;
@@ -1561,6 +1576,23 @@ static int v4l_queryctrl(const struct v4l2_ioctl_ops *ops,
 	return -ENOTTY;
 }
 
+static int v4l_query_ext_ctrl(const struct v4l2_ioctl_ops *ops,
+				struct file *file, void *fh, void *arg)
+{
+	struct video_device *vfd = video_devdata(file);
+	struct v4l2_query_ext_ctrl *p = arg;
+	struct v4l2_fh *vfh =
+		test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) ? fh : NULL;
+
+	if (vfh && vfh->ctrl_handler)
+		return v4l2_query_ext_ctrl(vfh->ctrl_handler, p);
+	if (vfd->ctrl_handler)
+		return v4l2_query_ext_ctrl(vfd->ctrl_handler, p);
+	if (ops->vidioc_query_ext_ctrl)
+		return ops->vidioc_query_ext_ctrl(file, fh, p);
+	return -ENOTTY;
+}
+
 static int v4l_querymenu(const struct v4l2_ioctl_ops *ops,
 				struct file *file, void *fh, void *arg)
 {
@@ -2121,6 +2153,7 @@ static struct v4l2_ioctl_info v4l2_ioctls[] = {
 	IOCTL_INFO_STD(VIDIOC_DV_TIMINGS_CAP, vidioc_dv_timings_cap, v4l_print_dv_timings_cap, INFO_FL_CLEAR(v4l2_dv_timings_cap, type)),
 	IOCTL_INFO_FNC(VIDIOC_ENUM_FREQ_BANDS, v4l_enum_freq_bands, v4l_print_freq_band, 0),
 	IOCTL_INFO_FNC(VIDIOC_DBG_G_CHIP_INFO, v4l_dbg_g_chip_info, v4l_print_dbg_chip_info, INFO_FL_CLEAR(v4l2_dbg_chip_info, match)),
+	IOCTL_INFO_FNC(VIDIOC_QUERY_EXT_CTRL, v4l_query_ext_ctrl, v4l_print_query_ext_ctrl, INFO_FL_CTRL | INFO_FL_CLEAR(v4l2_query_ext_ctrl, id)),
 };
 #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
 
diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
index 058c1a6..b984f33 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -139,6 +139,9 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 	case VIDIOC_QUERYCTRL:
 		return v4l2_queryctrl(vfh->ctrl_handler, arg);
 
+	case VIDIOC_QUERY_EXT_CTRL:
+		return v4l2_query_ext_ctrl(vfh->ctrl_handler, arg);
+
 	case VIDIOC_QUERYMENU:
 		return v4l2_querymenu(vfh->ctrl_handler, arg);
 
diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h
index 50cf7c1..53605f0 100644
--- a/include/media/v4l2-ioctl.h
+++ b/include/media/v4l2-ioctl.h
@@ -158,6 +158,8 @@ struct v4l2_ioctl_ops {
 		/* Control handling */
 	int (*vidioc_queryctrl)        (struct file *file, void *fh,
 					struct v4l2_queryctrl *a);
+	int (*vidioc_query_ext_ctrl)   (struct file *file, void *fh,
+					struct v4l2_query_ext_ctrl *a);
 	int (*vidioc_g_ctrl)           (struct file *file, void *fh,
 					struct v4l2_control *a);
 	int (*vidioc_s_ctrl)           (struct file *file, void *fh,
-- 
2.0.0.rc0


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

* [REVIEWv4 PATCH 07/34] v4l2-ctrls: create type_ops.
  2014-06-12 11:52 ` [REVIEWv4 PATCH 01/34] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
                     ` (4 preceding siblings ...)
  2014-06-12 11:52   ` [REVIEWv4 PATCH 06/34] v4l2: integrate support for VIDIOC_QUERY_EXT_CTRL Hans Verkuil
@ 2014-06-12 11:52   ` Hans Verkuil
  2014-06-12 11:52   ` [REVIEWv4 PATCH 08/34] v4l2-ctrls: rewrite copy routines to operate on union v4l2_ctrl_ptr Hans Verkuil
                     ` (26 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Hans Verkuil @ 2014-06-12 11:52 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, s.nawrocki, sakari.ailus, Hans Verkuil

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

Since compound controls can have non-standard types we need to be able to do
type-specific checks etc. In order to make that easy type operations are added.
There are four operations:

- equal: check if two values are equal
- init: initialize a value
- log: log the value
- validate: validate a new value

The v4l2_ctrl struct adds p_new and p_cur unions at the end of the struct.
This union provides a standard way of accessing control types through a pointer,
which greatly simplifies internal control processing.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/v4l2-core/v4l2-ctrls.c | 273 ++++++++++++++++++++++-------------
 include/media/v4l2-ctrls.h           |  37 +++++
 2 files changed, 210 insertions(+), 100 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index d5cd1aa..09e2c3a 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1161,6 +1161,149 @@ static void send_event(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 changes)
 			v4l2_event_queue_fh(sev->fh, &ev);
 }
 
+static bool std_equal(const struct v4l2_ctrl *ctrl,
+		      union v4l2_ctrl_ptr ptr1,
+		      union v4l2_ctrl_ptr ptr2)
+{
+	switch (ctrl->type) {
+	case V4L2_CTRL_TYPE_BUTTON:
+		return false;
+	case V4L2_CTRL_TYPE_STRING:
+		/* strings are always 0-terminated */
+		return !strcmp(ptr1.p_char, ptr2.p_char);
+	case V4L2_CTRL_TYPE_INTEGER64:
+		return *ptr1.p_s64 == *ptr2.p_s64;
+	default:
+		if (ctrl->is_ptr)
+			return !memcmp(ptr1.p, ptr2.p, ctrl->elem_size);
+		return *ptr1.p_s32 == *ptr2.p_s32;
+	}
+}
+
+static void std_init(const struct v4l2_ctrl *ctrl,
+		     union v4l2_ctrl_ptr ptr)
+{
+	switch (ctrl->type) {
+	case V4L2_CTRL_TYPE_STRING:
+		memset(ptr.p_char, ' ', ctrl->minimum);
+		ptr.p_char[ctrl->minimum] = '\0';
+		break;
+	case V4L2_CTRL_TYPE_INTEGER64:
+		*ptr.p_s64 = ctrl->default_value;
+		break;
+	case V4L2_CTRL_TYPE_INTEGER:
+	case V4L2_CTRL_TYPE_INTEGER_MENU:
+	case V4L2_CTRL_TYPE_MENU:
+	case V4L2_CTRL_TYPE_BITMASK:
+	case V4L2_CTRL_TYPE_BOOLEAN:
+		*ptr.p_s32 = ctrl->default_value;
+		break;
+	default:
+		break;
+	}
+}
+
+static void std_log(const struct v4l2_ctrl *ctrl)
+{
+	union v4l2_ctrl_ptr ptr = ctrl->p_cur;
+
+	switch (ctrl->type) {
+	case V4L2_CTRL_TYPE_INTEGER:
+		pr_cont("%d", *ptr.p_s32);
+		break;
+	case V4L2_CTRL_TYPE_BOOLEAN:
+		pr_cont("%s", *ptr.p_s32 ? "true" : "false");
+		break;
+	case V4L2_CTRL_TYPE_MENU:
+		pr_cont("%s", ctrl->qmenu[*ptr.p_s32]);
+		break;
+	case V4L2_CTRL_TYPE_INTEGER_MENU:
+		pr_cont("%lld", ctrl->qmenu_int[*ptr.p_s32]);
+		break;
+	case V4L2_CTRL_TYPE_BITMASK:
+		pr_cont("0x%08x", *ptr.p_s32);
+		break;
+	case V4L2_CTRL_TYPE_INTEGER64:
+		pr_cont("%lld", *ptr.p_s64);
+		break;
+	case V4L2_CTRL_TYPE_STRING:
+		pr_cont("%s", ptr.p_char);
+		break;
+	default:
+		pr_cont("unknown type %d", ctrl->type);
+		break;
+	}
+}
+
+/* Round towards the closest legal value */
+#define ROUND_TO_RANGE(val, offset_type, ctrl)			\
+({								\
+	offset_type offset;					\
+	val += (ctrl)->step / 2;				\
+	val = clamp_t(typeof(val), val,				\
+		      (ctrl)->minimum, (ctrl)->maximum);	\
+	offset = (val) - (ctrl)->minimum;			\
+	offset = (ctrl)->step * (offset / (ctrl)->step);	\
+	val = (ctrl)->minimum + offset;				\
+	0;							\
+})
+
+/* Validate a new control */
+static int std_validate(const struct v4l2_ctrl *ctrl,
+			union v4l2_ctrl_ptr ptr)
+{
+	size_t len;
+
+	switch (ctrl->type) {
+	case V4L2_CTRL_TYPE_INTEGER:
+		return ROUND_TO_RANGE(*ptr.p_s32, u32, ctrl);
+	case V4L2_CTRL_TYPE_INTEGER64:
+		return ROUND_TO_RANGE(*ptr.p_s64, u64, ctrl);
+
+	case V4L2_CTRL_TYPE_BOOLEAN:
+		*ptr.p_s32 = !!*ptr.p_s32;
+		return 0;
+
+	case V4L2_CTRL_TYPE_MENU:
+	case V4L2_CTRL_TYPE_INTEGER_MENU:
+		if (*ptr.p_s32 < ctrl->minimum || *ptr.p_s32 > ctrl->maximum)
+			return -ERANGE;
+		if (ctrl->menu_skip_mask & (1 << *ptr.p_s32))
+			return -EINVAL;
+		if (ctrl->type == V4L2_CTRL_TYPE_MENU &&
+		    ctrl->qmenu[*ptr.p_s32][0] == '\0')
+			return -EINVAL;
+		return 0;
+
+	case V4L2_CTRL_TYPE_BITMASK:
+		*ptr.p_s32 &= ctrl->maximum;
+		return 0;
+
+	case V4L2_CTRL_TYPE_BUTTON:
+	case V4L2_CTRL_TYPE_CTRL_CLASS:
+		*ptr.p_s32 = 0;
+		return 0;
+
+	case V4L2_CTRL_TYPE_STRING:
+		len = strlen(ptr.p_char);
+		if (len < ctrl->minimum)
+			return -ERANGE;
+		if ((len - ctrl->minimum) % ctrl->step)
+			return -ERANGE;
+		return 0;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct v4l2_ctrl_type_ops std_type_ops = {
+	.equal = std_equal,
+	.init = std_init,
+	.log = std_log,
+	.validate = std_validate,
+};
+
 /* Helper function: copy the current control value back to the caller */
 static int cur_to_user(struct v4l2_ext_control *c,
 		       struct v4l2_ctrl *ctrl)
@@ -1344,21 +1487,7 @@ static int cluster_changed(struct v4l2_ctrl *master)
 
 		if (ctrl == NULL)
 			continue;
-		switch (ctrl->type) {
-		case V4L2_CTRL_TYPE_BUTTON:
-			/* Button controls are always 'different' */
-			return 1;
-		case V4L2_CTRL_TYPE_STRING:
-			/* strings are always 0-terminated */
-			diff = strcmp(ctrl->string, ctrl->cur.string);
-			break;
-		case V4L2_CTRL_TYPE_INTEGER64:
-			diff = ctrl->val64 != ctrl->cur.val64;
-			break;
-		default:
-			diff = ctrl->val != ctrl->cur.val;
-			break;
-		}
+		diff = !ctrl->type_ops->equal(ctrl, ctrl->p_cur, ctrl->p_new);
 	}
 	return diff;
 }
@@ -1399,65 +1528,30 @@ static int check_range(enum v4l2_ctrl_type type,
 	}
 }
 
-/* Round towards the closest legal value */
-#define ROUND_TO_RANGE(val, offset_type, ctrl)			\
-({								\
-	offset_type offset;					\
-	val += (ctrl)->step / 2;				\
-	val = clamp_t(typeof(val), val,				\
-		      (ctrl)->minimum, (ctrl)->maximum);	\
-	offset = (val) - (ctrl)->minimum;			\
-	offset = (ctrl)->step * (offset / (ctrl)->step);	\
-	val = (ctrl)->minimum + offset;				\
-	0;							\
-})
-
 /* Validate a new control */
 static int validate_new(const struct v4l2_ctrl *ctrl,
 			struct v4l2_ext_control *c)
 {
-	size_t len;
+	union v4l2_ctrl_ptr ptr;
 
 	switch (ctrl->type) {
 	case V4L2_CTRL_TYPE_INTEGER:
-		return ROUND_TO_RANGE(*(s32 *)&c->value, u32, ctrl);
-	case V4L2_CTRL_TYPE_INTEGER64:
-		return ROUND_TO_RANGE(*(s64 *)&c->value64, u64, ctrl);
-
-	case V4L2_CTRL_TYPE_BOOLEAN:
-		c->value = !!c->value;
-		return 0;
-
-	case V4L2_CTRL_TYPE_MENU:
 	case V4L2_CTRL_TYPE_INTEGER_MENU:
-		if (c->value < ctrl->minimum || c->value > ctrl->maximum)
-			return -ERANGE;
-		if (ctrl->menu_skip_mask & (1 << c->value))
-			return -EINVAL;
-		if (ctrl->type == V4L2_CTRL_TYPE_MENU &&
-		    ctrl->qmenu[c->value][0] == '\0')
-			return -EINVAL;
-		return 0;
-
+	case V4L2_CTRL_TYPE_MENU:
 	case V4L2_CTRL_TYPE_BITMASK:
-		c->value &= ctrl->maximum;
-		return 0;
-
+	case V4L2_CTRL_TYPE_BOOLEAN:
 	case V4L2_CTRL_TYPE_BUTTON:
 	case V4L2_CTRL_TYPE_CTRL_CLASS:
-		c->value = 0;
-		return 0;
+		ptr.p_s32 = &c->value;
+		return ctrl->type_ops->validate(ctrl, ptr);
 
-	case V4L2_CTRL_TYPE_STRING:
-		len = strlen(c->string);
-		if (len < ctrl->minimum)
-			return -ERANGE;
-		if ((len - ctrl->minimum) % ctrl->step)
-			return -ERANGE;
-		return 0;
+	case V4L2_CTRL_TYPE_INTEGER64:
+		ptr.p_s64 = &c->value64;
+		return ctrl->type_ops->validate(ctrl, ptr);
 
 	default:
-		return -EINVAL;
+		ptr.p = c->ptr;
+		return ctrl->type_ops->validate(ctrl, ptr);
 	}
 }
 
@@ -1674,6 +1768,7 @@ unlock:
 /* Add a new control */
 static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 			const struct v4l2_ctrl_ops *ops,
+			const struct v4l2_ctrl_type_ops *type_ops,
 			u32 id, const char *name, enum v4l2_ctrl_type type,
 			s64 min, s64 max, u64 step, s64 def,
 			u32 elem_size,
@@ -1731,6 +1826,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 	INIT_LIST_HEAD(&ctrl->ev_subs);
 	ctrl->handler = hdl;
 	ctrl->ops = ops;
+	ctrl->type_ops = type_ops ? type_ops : &std_type_ops;
 	ctrl->id = id;
 	ctrl->name = name;
 	ctrl->type = type;
@@ -1751,16 +1847,16 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 	ctrl->cur.val = ctrl->val = def;
 	data = &ctrl->cur + 1;
 
-	if (ctrl->is_string) {
-		ctrl->string = data;
-		ctrl->cur.string = data + elem_size;
-
-		if (ctrl->minimum)
-			memset(ctrl->cur.string, ' ', ctrl->minimum);
-	} else if (ctrl->is_ptr) {
-		ctrl->p = data;
-		ctrl->cur.p = data + elem_size;
+	if (ctrl->is_ptr) {
+		ctrl->p = ctrl->p_new.p = data;
+		ctrl->p_cur.p = data + elem_size;
+	} else {
+		ctrl->p_new.p = &ctrl->val;
+		ctrl->p_cur.p = &ctrl->cur.val;
 	}
+	ctrl->type_ops->init(ctrl, ctrl->p_cur);
+	ctrl->type_ops->init(ctrl, ctrl->p_new);
+
 	if (handler_new_ref(hdl, ctrl)) {
 		kfree(ctrl);
 		return NULL;
@@ -1804,7 +1900,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl,
 		return NULL;
 	}
 
-	ctrl = v4l2_ctrl_new(hdl, cfg->ops, cfg->id, name,
+	ctrl = v4l2_ctrl_new(hdl, cfg->ops, cfg->type_ops, cfg->id, name,
 			type, min, max,
 			is_menu ? cfg->menu_skip_mask : step,
 			def, cfg->elem_size,
@@ -1831,7 +1927,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl,
 		handler_set_err(hdl, -EINVAL);
 		return NULL;
 	}
-	return v4l2_ctrl_new(hdl, ops, id, name, type,
+	return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
 			     min, max, step, def, 0,
 			     flags, NULL, NULL, NULL);
 }
@@ -1864,7 +1960,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl,
 		handler_set_err(hdl, -EINVAL);
 		return NULL;
 	}
-	return v4l2_ctrl_new(hdl, ops, id, name, type,
+	return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
 			     0, max, mask, def, 0,
 			     flags, qmenu, qmenu_int, NULL);
 }
@@ -1896,7 +1992,8 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu_items(struct v4l2_ctrl_handler *hdl,
 		handler_set_err(hdl, -EINVAL);
 		return NULL;
 	}
-	return v4l2_ctrl_new(hdl, ops, id, name, type, 0, max, mask, def,
+	return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
+			     0, max, mask, def,
 			     0, flags, qmenu, NULL, NULL);
 
 }
@@ -1920,7 +2017,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl,
 		handler_set_err(hdl, -EINVAL);
 		return NULL;
 	}
-	return v4l2_ctrl_new(hdl, ops, id, name, type,
+	return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
 			     0, max, 0, def, 0,
 			     flags, NULL, qmenu_int, NULL);
 }
@@ -2104,32 +2201,8 @@ static void log_ctrl(const struct v4l2_ctrl *ctrl,
 
 	pr_info("%s%s%s: ", prefix, colon, ctrl->name);
 
-	switch (ctrl->type) {
-	case V4L2_CTRL_TYPE_INTEGER:
-		pr_cont("%d", ctrl->cur.val);
-		break;
-	case V4L2_CTRL_TYPE_BOOLEAN:
-		pr_cont("%s", ctrl->cur.val ? "true" : "false");
-		break;
-	case V4L2_CTRL_TYPE_MENU:
-		pr_cont("%s", ctrl->qmenu[ctrl->cur.val]);
-		break;
-	case V4L2_CTRL_TYPE_INTEGER_MENU:
-		pr_cont("%lld", ctrl->qmenu_int[ctrl->cur.val]);
-		break;
-	case V4L2_CTRL_TYPE_BITMASK:
-		pr_cont("0x%08x", ctrl->cur.val);
-		break;
-	case V4L2_CTRL_TYPE_INTEGER64:
-		pr_cont("%lld", ctrl->cur.val64);
-		break;
-	case V4L2_CTRL_TYPE_STRING:
-		pr_cont("%s", ctrl->cur.string);
-		break;
-	default:
-		pr_cont("unknown type %d", ctrl->type);
-		break;
-	}
+	ctrl->type_ops->log(ctrl);
+
 	if (ctrl->flags & (V4L2_CTRL_FLAG_INACTIVE |
 			   V4L2_CTRL_FLAG_GRABBED |
 			   V4L2_CTRL_FLAG_VOLATILE)) {
diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
index 9024dae..ddd9fdf 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -36,6 +36,19 @@ struct v4l2_subscribed_event;
 struct v4l2_fh;
 struct poll_table_struct;
 
+/** union v4l2_ctrl_ptr - A pointer to a control value.
+ * @p_s32:	Pointer to a 32-bit signed value.
+ * @p_s64:	Pointer to a 64-bit signed value.
+ * @p_char:	Pointer to a string.
+ * @p:		Pointer to a compound value.
+ */
+union v4l2_ctrl_ptr {
+	s32 *p_s32;
+	s64 *p_s64;
+	char *p_char;
+	void *p;
+};
+
 /** struct v4l2_ctrl_ops - The control operations that the driver has to provide.
   * @g_volatile_ctrl: Get a new value for this control. Generally only relevant
   *		for volatile (and usually read-only) controls such as a control
@@ -54,6 +67,23 @@ struct v4l2_ctrl_ops {
 	int (*s_ctrl)(struct v4l2_ctrl *ctrl);
 };
 
+/** struct v4l2_ctrl_type_ops - The control type operations that the driver has to provide.
+  * @equal: return true if both values are equal.
+  * @init: initialize the value.
+  * @log: log the value.
+  * @validate: validate the value. Return 0 on success and a negative value otherwise.
+  */
+struct v4l2_ctrl_type_ops {
+	bool (*equal)(const struct v4l2_ctrl *ctrl,
+		      union v4l2_ctrl_ptr ptr1,
+		      union v4l2_ctrl_ptr ptr2);
+	void (*init)(const struct v4l2_ctrl *ctrl,
+		     union v4l2_ctrl_ptr ptr);
+	void (*log)(const struct v4l2_ctrl *ctrl);
+	int (*validate)(const struct v4l2_ctrl *ctrl,
+			union v4l2_ctrl_ptr ptr);
+};
+
 typedef void (*v4l2_ctrl_notify_fnc)(struct v4l2_ctrl *ctrl, void *priv);
 
 /** struct v4l2_ctrl - The control structure.
@@ -89,6 +119,7 @@ typedef void (*v4l2_ctrl_notify_fnc)(struct v4l2_ctrl *ctrl, void *priv);
   *		value, then the whole cluster is in manual mode. Drivers should
   *		never set this flag directly.
   * @ops:	The control ops.
+  * @type_ops:	The control type ops.
   * @id:	The control ID.
   * @name:	The control name.
   * @type:	The control type.
@@ -137,6 +168,7 @@ struct v4l2_ctrl {
 	unsigned int manual_mode_value:8;
 
 	const struct v4l2_ctrl_ops *ops;
+	const struct v4l2_ctrl_type_ops *type_ops;
 	u32 id;
 	const char *name;
 	enum v4l2_ctrl_type type;
@@ -164,6 +196,9 @@ struct v4l2_ctrl {
 		char *string;
 		void *p;
 	} cur;
+
+	union v4l2_ctrl_ptr p_new;
+	union v4l2_ctrl_ptr p_cur;
 };
 
 /** struct v4l2_ctrl_ref - The control reference.
@@ -217,6 +252,7 @@ struct v4l2_ctrl_handler {
 
 /** struct v4l2_ctrl_config - Control configuration structure.
   * @ops:	The control ops.
+  * @type_ops:	The control type ops. Only needed for compound controls.
   * @id:	The control ID.
   * @name:	The control name.
   * @type:	The control type.
@@ -241,6 +277,7 @@ struct v4l2_ctrl_handler {
   */
 struct v4l2_ctrl_config {
 	const struct v4l2_ctrl_ops *ops;
+	const struct v4l2_ctrl_type_ops *type_ops;
 	u32 id;
 	const char *name;
 	enum v4l2_ctrl_type type;
-- 
2.0.0.rc0


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

* [REVIEWv4 PATCH 08/34] v4l2-ctrls: rewrite copy routines to operate on union v4l2_ctrl_ptr.
  2014-06-12 11:52 ` [REVIEWv4 PATCH 01/34] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
                     ` (5 preceding siblings ...)
  2014-06-12 11:52   ` [REVIEWv4 PATCH 07/34] v4l2-ctrls: create type_ops Hans Verkuil
@ 2014-06-12 11:52   ` Hans Verkuil
  2014-06-12 11:52   ` [REVIEWv4 PATCH 09/34] v4l2-ctrls: compare values only once Hans Verkuil
                     ` (25 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Hans Verkuil @ 2014-06-12 11:52 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, s.nawrocki, sakari.ailus, Hans Verkuil

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

In order to implement array support and (for the future) configuration stores
we need to have more generic copy routines that all operate on the v4l2_ctrl_ptr
union. So instead of e.g. using ctrl->cur.string it uses ptr.p_char. This makes
e.g. cur_to_user generic so it can be used to copy any v4l2_ctrl_ptr value to
userspace, not just the (hardcoded) current value.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/v4l2-core/v4l2-ctrls.c | 129 +++++++++++++++--------------------
 1 file changed, 56 insertions(+), 73 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 09e2c3a..e7e0bea 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1304,48 +1304,64 @@ static const struct v4l2_ctrl_type_ops std_type_ops = {
 	.validate = std_validate,
 };
 
-/* Helper function: copy the current control value back to the caller */
-static int cur_to_user(struct v4l2_ext_control *c,
-		       struct v4l2_ctrl *ctrl)
+/* Helper function: copy the given control value back to the caller */
+static int ptr_to_user(struct v4l2_ext_control *c,
+		       struct v4l2_ctrl *ctrl,
+		       union v4l2_ctrl_ptr ptr)
 {
 	u32 len;
 
 	if (ctrl->is_ptr && !ctrl->is_string)
-		return copy_to_user(c->ptr, ctrl->cur.p, ctrl->elem_size);
+		return copy_to_user(c->ptr, ptr.p, ctrl->elem_size);
 
 	switch (ctrl->type) {
 	case V4L2_CTRL_TYPE_STRING:
-		len = strlen(ctrl->cur.string);
+		len = strlen(ptr.p_char);
 		if (c->size < len + 1) {
 			c->size = len + 1;
 			return -ENOSPC;
 		}
-		return copy_to_user(c->string, ctrl->cur.string,
-						len + 1) ? -EFAULT : 0;
+		return copy_to_user(c->string, ptr.p_char, len + 1) ?
+								-EFAULT : 0;
 	case V4L2_CTRL_TYPE_INTEGER64:
-		c->value64 = ctrl->cur.val64;
+		c->value64 = *ptr.p_s64;
 		break;
 	default:
-		c->value = ctrl->cur.val;
+		c->value = *ptr.p_s32;
 		break;
 	}
 	return 0;
 }
 
-/* Helper function: copy the caller-provider value as the new control value */
-static int user_to_new(struct v4l2_ext_control *c,
+/* Helper function: copy the current control value back to the caller */
+static int cur_to_user(struct v4l2_ext_control *c,
 		       struct v4l2_ctrl *ctrl)
 {
+	return ptr_to_user(c, ctrl, ctrl->p_cur);
+}
+
+/* Helper function: copy the new control value back to the caller */
+static int new_to_user(struct v4l2_ext_control *c,
+		       struct v4l2_ctrl *ctrl)
+{
+	return ptr_to_user(c, ctrl, ctrl->p_new);
+}
+
+/* Helper function: copy the caller-provider value to the given control value */
+static int user_to_ptr(struct v4l2_ext_control *c,
+		       struct v4l2_ctrl *ctrl,
+		       union v4l2_ctrl_ptr ptr)
+{
 	int ret;
 	u32 size;
 
 	ctrl->is_new = 1;
 	if (ctrl->is_ptr && !ctrl->is_string)
-		return copy_from_user(ctrl->p, c->ptr, ctrl->elem_size);
+		return copy_from_user(ptr.p, c->ptr, ctrl->elem_size);
 
 	switch (ctrl->type) {
 	case V4L2_CTRL_TYPE_INTEGER64:
-		ctrl->val64 = c->value64;
+		*ptr.p_s64 = c->value64;
 		break;
 	case V4L2_CTRL_TYPE_STRING:
 		size = c->size;
@@ -1353,83 +1369,64 @@ static int user_to_new(struct v4l2_ext_control *c,
 			return -ERANGE;
 		if (size > ctrl->maximum + 1)
 			size = ctrl->maximum + 1;
-		ret = copy_from_user(ctrl->string, c->string, size);
+		ret = copy_from_user(ptr.p_char, c->string, size);
 		if (!ret) {
-			char last = ctrl->string[size - 1];
+			char last = ptr.p_char[size - 1];
 
-			ctrl->string[size - 1] = 0;
+			ptr.p_char[size - 1] = 0;
 			/* If the string was longer than ctrl->maximum,
 			   then return an error. */
-			if (strlen(ctrl->string) == ctrl->maximum && last)
+			if (strlen(ptr.p_char) == ctrl->maximum && last)
 				return -ERANGE;
 		}
 		return ret ? -EFAULT : 0;
 	default:
-		ctrl->val = c->value;
+		*ptr.p_s32 = c->value;
 		break;
 	}
 	return 0;
 }
 
-/* Helper function: copy the new control value back to the caller */
-static int new_to_user(struct v4l2_ext_control *c,
+/* Helper function: copy the caller-provider value as the new control value */
+static int user_to_new(struct v4l2_ext_control *c,
 		       struct v4l2_ctrl *ctrl)
 {
-	u32 len;
-
-	if (ctrl->is_ptr && !ctrl->is_string)
-		return copy_to_user(c->ptr, ctrl->p, ctrl->elem_size);
+	return user_to_ptr(c, ctrl, ctrl->p_new);
+}
 
+/* Copy the one value to another. */
+static void ptr_to_ptr(struct v4l2_ctrl *ctrl,
+		       union v4l2_ctrl_ptr from, union v4l2_ctrl_ptr to)
+{
+	if (ctrl == NULL)
+		return;
 	switch (ctrl->type) {
 	case V4L2_CTRL_TYPE_STRING:
-		len = strlen(ctrl->string);
-		if (c->size < len + 1) {
-			c->size = ctrl->maximum + 1;
-			return -ENOSPC;
-		}
-		return copy_to_user(c->string, ctrl->string,
-						len + 1) ? -EFAULT : 0;
+		/* strings are always 0-terminated */
+		strcpy(to.p_char, from.p_char);
+		break;
 	case V4L2_CTRL_TYPE_INTEGER64:
-		c->value64 = ctrl->val64;
+		*to.p_s64 = *from.p_s64;
 		break;
 	default:
-		c->value = ctrl->val;
+		if (ctrl->is_ptr)
+			memcpy(to.p, from.p, ctrl->elem_size);
+		else
+			*to.p_s32 = *from.p_s32;
 		break;
 	}
-	return 0;
 }
 
 /* Copy the new value to the current value. */
 static void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags)
 {
-	bool changed = false;
+	bool changed;
 
 	if (ctrl == NULL)
 		return;
+	changed = !ctrl->type_ops->equal(ctrl, ctrl->p_cur, ctrl->p_new);
+	ptr_to_ptr(ctrl, ctrl->p_new, ctrl->p_cur);
 
-	switch (ctrl->type) {
-	case V4L2_CTRL_TYPE_BUTTON:
-		changed = true;
-		break;
-	case V4L2_CTRL_TYPE_STRING:
-		/* strings are always 0-terminated */
-		changed = strcmp(ctrl->string, ctrl->cur.string);
-		strcpy(ctrl->cur.string, ctrl->string);
-		break;
-	case V4L2_CTRL_TYPE_INTEGER64:
-		changed = ctrl->val64 != ctrl->cur.val64;
-		ctrl->cur.val64 = ctrl->val64;
-		break;
-	default:
-		if (ctrl->is_ptr) {
-			changed = memcmp(ctrl->p, ctrl->cur.p, ctrl->elem_size);
-			memcpy(ctrl->cur.p, ctrl->p, ctrl->elem_size);
-		} else {
-			changed = ctrl->val != ctrl->cur.val;
-			ctrl->cur.val = ctrl->val;
-		}
-		break;
-	}
 	if (ch_flags & V4L2_EVENT_CTRL_CH_FLAGS) {
 		/* Note: CH_FLAGS is only set for auto clusters. */
 		ctrl->flags &=
@@ -1458,21 +1455,7 @@ static void cur_to_new(struct v4l2_ctrl *ctrl)
 {
 	if (ctrl == NULL)
 		return;
-	switch (ctrl->type) {
-	case V4L2_CTRL_TYPE_STRING:
-		/* strings are always 0-terminated */
-		strcpy(ctrl->string, ctrl->cur.string);
-		break;
-	case V4L2_CTRL_TYPE_INTEGER64:
-		ctrl->val64 = ctrl->cur.val64;
-		break;
-	default:
-		if (ctrl->is_ptr)
-			memcpy(ctrl->p, ctrl->cur.p, ctrl->elem_size);
-		else
-			ctrl->val = ctrl->cur.val;
-		break;
-	}
+	ptr_to_ptr(ctrl, ctrl->p_cur, ctrl->p_new);
 }
 
 /* Return non-zero if one or more of the controls in the cluster has a new
-- 
2.0.0.rc0


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

* [REVIEWv4 PATCH 09/34] v4l2-ctrls: compare values only once.
  2014-06-12 11:52 ` [REVIEWv4 PATCH 01/34] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
                     ` (6 preceding siblings ...)
  2014-06-12 11:52   ` [REVIEWv4 PATCH 08/34] v4l2-ctrls: rewrite copy routines to operate on union v4l2_ctrl_ptr Hans Verkuil
@ 2014-06-12 11:52   ` Hans Verkuil
  2014-06-12 11:52   ` [REVIEWv4 PATCH 10/34] v4l2-ctrls: use ptrs for all but the s32 type Hans Verkuil
                     ` (24 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Hans Verkuil @ 2014-06-12 11:52 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, s.nawrocki, sakari.ailus, Hans Verkuil

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

When setting a control the control's new value is compared to the current
value twice: once by new_to_cur(), once by cluster_changed(). Not a big
deal when dealing with simple values, but it can be a problem when dealing
with compound types or arrays. So fix this: cluster_changed() sets the
has_changed flag, which is used by new_to_cur() instead of having to do
another compare.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Reviewed-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
---
 drivers/media/v4l2-core/v4l2-ctrls.c | 17 +++++++++++------
 include/media/v4l2-ctrls.h           |  3 +++
 2 files changed, 14 insertions(+), 6 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index e7e0bea..1b4d37c 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1424,8 +1424,11 @@ static void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags)
 
 	if (ctrl == NULL)
 		return;
-	changed = !ctrl->type_ops->equal(ctrl, ctrl->p_cur, ctrl->p_new);
-	ptr_to_ptr(ctrl, ctrl->p_new, ctrl->p_cur);
+
+	/* has_changed is set by cluster_changed */
+	changed = ctrl->has_changed;
+	if (changed)
+		ptr_to_ptr(ctrl, ctrl->p_new, ctrl->p_cur);
 
 	if (ch_flags & V4L2_EVENT_CTRL_CH_FLAGS) {
 		/* Note: CH_FLAGS is only set for auto clusters. */
@@ -1462,17 +1465,19 @@ static void cur_to_new(struct v4l2_ctrl *ctrl)
    value that differs from the current value. */
 static int cluster_changed(struct v4l2_ctrl *master)
 {
-	int diff = 0;
+	bool changed = false;
 	int i;
 
-	for (i = 0; !diff && i < master->ncontrols; i++) {
+	for (i = 0; i < master->ncontrols; i++) {
 		struct v4l2_ctrl *ctrl = master->cluster[i];
 
 		if (ctrl == NULL)
 			continue;
-		diff = !ctrl->type_ops->equal(ctrl, ctrl->p_cur, ctrl->p_new);
+		ctrl->has_changed = !ctrl->type_ops->equal(ctrl,
+						ctrl->p_cur, ctrl->p_new);
+		changed |= ctrl->has_changed;
 	}
-	return diff;
+	return changed;
 }
 
 /* Control range checking */
diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
index ddd9fdf..a38bd55 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -96,6 +96,8 @@ typedef void (*v4l2_ctrl_notify_fnc)(struct v4l2_ctrl *ctrl, void *priv);
   * @is_new:	Set when the user specified a new value for this control. It
   *		is also set when called from v4l2_ctrl_handler_setup. Drivers
   *		should never set this flag.
+  * @has_changed: Set when the current value differs from the new value. Drivers
+  *		should never use this flag.
   * @is_private: If set, then this control is private to its handler and it
   *		will not be added to any other handlers. Drivers can set
   *		this flag.
@@ -158,6 +160,7 @@ struct v4l2_ctrl {
 	unsigned int done:1;
 
 	unsigned int is_new:1;
+	unsigned int has_changed:1;
 	unsigned int is_private:1;
 	unsigned int is_auto:1;
 	unsigned int is_int:1;
-- 
2.0.0.rc0


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

* [REVIEWv4 PATCH 10/34] v4l2-ctrls: use ptrs for all but the s32 type.
  2014-06-12 11:52 ` [REVIEWv4 PATCH 01/34] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
                     ` (7 preceding siblings ...)
  2014-06-12 11:52   ` [REVIEWv4 PATCH 09/34] v4l2-ctrls: compare values only once Hans Verkuil
@ 2014-06-12 11:52   ` Hans Verkuil
  2014-06-12 11:52   ` [REVIEWv4 PATCH 11/34] v4l2-ctrls: prepare for array support Hans Verkuil
                     ` (23 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Hans Verkuil @ 2014-06-12 11:52 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, s.nawrocki, sakari.ailus, Hans Verkuil

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

Rather than having two unions for all types just keep 'val' and
'cur.val' and use the p_cur and p_new unions to access all others.

The only reason for keeping 'val' and 'cur.val' is that it is used
all over, so converting this as well would be a huge job.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 Documentation/video4linux/v4l2-controls.txt        |  2 +-
 drivers/media/i2c/mt9v032.c                        |  2 +-
 drivers/media/i2c/smiapp/smiapp-core.c             |  4 ++--
 drivers/media/pci/ivtv/ivtv-controls.c             |  4 ++--
 drivers/media/platform/vivi.c                      |  4 ++--
 drivers/media/radio/si4713/si4713.c                |  4 ++--
 drivers/media/v4l2-core/v4l2-ctrls.c               | 16 +++++++++-------
 drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c |  2 +-
 include/media/v4l2-ctrls.h                         | 12 ++----------
 9 files changed, 22 insertions(+), 28 deletions(-)

diff --git a/Documentation/video4linux/v4l2-controls.txt b/Documentation/video4linux/v4l2-controls.txt
index 06cf3ac..c9ee9a7 100644
--- a/Documentation/video4linux/v4l2-controls.txt
+++ b/Documentation/video4linux/v4l2-controls.txt
@@ -362,7 +362,7 @@ will result in a deadlock since these helpers lock the handler as well.
 You can also take the handler lock yourself:
 
 	mutex_lock(&state->ctrl_handler.lock);
-	printk(KERN_INFO "String value is '%s'\n", ctrl1->cur.string);
+	pr_info("String value is '%s'\n", ctrl1->p_cur.p_char);
 	printk(KERN_INFO "Integer value is '%s'\n", ctrl2->cur.val);
 	mutex_unlock(&state->ctrl_handler.lock);
 
diff --git a/drivers/media/i2c/mt9v032.c b/drivers/media/i2c/mt9v032.c
index 65e6e1a..435e9e6 100644
--- a/drivers/media/i2c/mt9v032.c
+++ b/drivers/media/i2c/mt9v032.c
@@ -667,7 +667,7 @@ static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl)
 			break;
 
 		freq = mt9v032->pdata->link_freqs[mt9v032->link_freq->val];
-		mt9v032->pixel_rate->val64 = freq;
+		*mt9v032->pixel_rate->p_new.p_s64 = freq;
 		mt9v032->sysclk = freq;
 		break;
 
diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c
index 0e82756..83d506e 100644
--- a/drivers/media/i2c/smiapp/smiapp-core.c
+++ b/drivers/media/i2c/smiapp/smiapp-core.c
@@ -297,8 +297,8 @@ static int smiapp_pll_update(struct smiapp_sensor *sensor)
 	if (rval < 0)
 		return rval;
 
-	sensor->pixel_rate_parray->cur.val64 = pll->vt_pix_clk_freq_hz;
-	sensor->pixel_rate_csi->cur.val64 = pll->pixel_rate_csi;
+	*sensor->pixel_rate_parray->p_cur.p_s64 = pll->vt_pix_clk_freq_hz;
+	*sensor->pixel_rate_csi->p_cur.p_s64 = pll->pixel_rate_csi;
 
 	return 0;
 }
diff --git a/drivers/media/pci/ivtv/ivtv-controls.c b/drivers/media/pci/ivtv/ivtv-controls.c
index c604246..2b0ab26 100644
--- a/drivers/media/pci/ivtv/ivtv-controls.c
+++ b/drivers/media/pci/ivtv/ivtv-controls.c
@@ -135,8 +135,8 @@ static int ivtv_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
 	/* V4L2_CID_MPEG_VIDEO_DEC_PTS and V4L2_CID_MPEG_VIDEO_DEC_FRAME
 	   control cluster */
 	case V4L2_CID_MPEG_VIDEO_DEC_PTS:
-		return ivtv_g_pts_frame(itv, &itv->ctrl_pts->val64,
-					     &itv->ctrl_frame->val64);
+		return ivtv_g_pts_frame(itv, itv->ctrl_pts->p_new.p_s64,
+					     itv->ctrl_frame->p_new.p_s64);
 	}
 	return 0;
 }
diff --git a/drivers/media/platform/vivi.c b/drivers/media/platform/vivi.c
index 2fa05e1..69e65e6 100644
--- a/drivers/media/platform/vivi.c
+++ b/drivers/media/platform/vivi.c
@@ -648,13 +648,13 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
 	gen_text(dev, vbuf, line++ * 16, 16, str);
 	snprintf(str, sizeof(str), " int32 %d, int64 %lld, bitmask %08x ",
 			dev->int32->cur.val,
-			dev->int64->cur.val64,
+			*dev->int64->p_cur.p_s64,
 			dev->bitmask->cur.val);
 	gen_text(dev, vbuf, line++ * 16, 16, str);
 	snprintf(str, sizeof(str), " boolean %d, menu %s, string \"%s\" ",
 			dev->boolean->cur.val,
 			dev->menu->qmenu[dev->menu->cur.val],
-			dev->string->cur.string);
+			dev->string->p_cur.p_char);
 	gen_text(dev, vbuf, line++ * 16, 16, str);
 	snprintf(str, sizeof(str), " integer_menu %lld, value %d ",
 			dev->int_menu->qmenu_int[dev->int_menu->cur.val],
diff --git a/drivers/media/radio/si4713/si4713.c b/drivers/media/radio/si4713/si4713.c
index 07d5153..dbe4726 100644
--- a/drivers/media/radio/si4713/si4713.c
+++ b/drivers/media/radio/si4713/si4713.c
@@ -1098,11 +1098,11 @@ static int si4713_s_ctrl(struct v4l2_ctrl *ctrl)
 
 		switch (ctrl->id) {
 		case V4L2_CID_RDS_TX_PS_NAME:
-			ret = si4713_set_rds_ps_name(sdev, ctrl->string);
+			ret = si4713_set_rds_ps_name(sdev, ctrl->p_new.p_char);
 			break;
 
 		case V4L2_CID_RDS_TX_RADIO_TEXT:
-			ret = si4713_set_rds_radio_text(sdev, ctrl->string);
+			ret = si4713_set_rds_radio_text(sdev, ctrl->p_new.p_char);
 			break;
 
 		case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 1b4d37c..4b10571 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1135,7 +1135,7 @@ static void fill_event(struct v4l2_event *ev, struct v4l2_ctrl *ctrl, u32 change
 	if (ctrl->is_ptr)
 		ev->u.ctrl.value64 = 0;
 	else
-		ev->u.ctrl.value64 = ctrl->cur.val64;
+		ev->u.ctrl.value64 = *ctrl->p_cur.p_s64;
 	ev->u.ctrl.minimum = ctrl->minimum;
 	ev->u.ctrl.maximum = ctrl->maximum;
 	if (ctrl->type == V4L2_CTRL_TYPE_MENU
@@ -1801,7 +1801,9 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 		flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
 	else if (type == V4L2_CTRL_TYPE_CTRL_CLASS)
 		flags |= V4L2_CTRL_FLAG_READ_ONLY;
-	else if (type == V4L2_CTRL_TYPE_STRING || type >= V4L2_CTRL_COMPOUND_TYPES)
+	else if (type == V4L2_CTRL_TYPE_INTEGER64 ||
+		 type == V4L2_CTRL_TYPE_STRING ||
+		 type >= V4L2_CTRL_COMPOUND_TYPES)
 		sz_extra += 2 * elem_size;
 
 	ctrl = kzalloc(sizeof(*ctrl) + sz_extra, GFP_KERNEL);
@@ -1833,10 +1835,10 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 		ctrl->qmenu_int = qmenu_int;
 	ctrl->priv = priv;
 	ctrl->cur.val = ctrl->val = def;
-	data = &ctrl->cur + 1;
+	data = &ctrl[1];
 
-	if (ctrl->is_ptr) {
-		ctrl->p = ctrl->p_new.p = data;
+	if (!ctrl->is_int) {
+		ctrl->p_new.p = data;
 		ctrl->p_cur.p = data + elem_size;
 	} else {
 		ctrl->p_new.p = &ctrl->val;
@@ -3103,10 +3105,10 @@ int v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl,
 	ctrl->maximum = max;
 	ctrl->step = step;
 	ctrl->default_value = def;
-	c.value = ctrl->cur.val;
+	c.value = *ctrl->p_cur.p_s32;
 	if (validate_new(ctrl, &c))
 		c.value = def;
-	if (c.value != ctrl->cur.val)
+	if (c.value != *ctrl->p_cur.p_s32)
 		ret = set_ctrl(NULL, ctrl, &c, V4L2_EVENT_CTRL_CH_RANGE);
 	else
 		send_event(NULL, ctrl, V4L2_EVENT_CTRL_CH_RANGE);
diff --git a/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c b/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
index b8ff113..09ce30b 100644
--- a/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
+++ b/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
@@ -1131,7 +1131,7 @@ static int solo_s_ctrl(struct v4l2_ctrl *ctrl)
 		solo_motion_toggle(solo_enc, ctrl->val);
 		return 0;
 	case V4L2_CID_OSD_TEXT:
-		strcpy(solo_enc->osd_text, ctrl->string);
+		strcpy(solo_enc->osd_text, ctrl->p_new.p_char);
 		err = solo_osd_print(solo_enc);
 		return err;
 	default:
diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
index a38bd55..eb69c52 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -187,17 +187,9 @@ struct v4l2_ctrl {
 	};
 	unsigned long flags;
 	void *priv;
-	union {
-		s32 val;
-		s64 val64;
-		char *string;
-		void *p;
-	};
-	union {
+	s32 val;
+	struct {
 		s32 val;
-		s64 val64;
-		char *string;
-		void *p;
 	} cur;
 
 	union v4l2_ctrl_ptr p_new;
-- 
2.0.0.rc0


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

* [REVIEWv4 PATCH 11/34] v4l2-ctrls: prepare for array support
  2014-06-12 11:52 ` [REVIEWv4 PATCH 01/34] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
                     ` (8 preceding siblings ...)
  2014-06-12 11:52   ` [REVIEWv4 PATCH 10/34] v4l2-ctrls: use ptrs for all but the s32 type Hans Verkuil
@ 2014-06-12 11:52   ` Hans Verkuil
  2014-06-12 11:52   ` [REVIEWv4 PATCH 12/34] " Hans Verkuil
                     ` (22 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Hans Verkuil @ 2014-06-12 11:52 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, s.nawrocki, sakari.ailus, Hans Verkuil

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

Add dims, nr_of_dims and elems fields to the core control structures in preparation
for N-dimensional array support.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/v4l2-core/v4l2-ctrls.c | 33 ++++++++++++++++++++++++---------
 include/media/v4l2-ctrls.h           |  8 ++++++++
 2 files changed, 32 insertions(+), 9 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 4b10571..e6c98a7 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1759,18 +1759,27 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 			const struct v4l2_ctrl_type_ops *type_ops,
 			u32 id, const char *name, enum v4l2_ctrl_type type,
 			s64 min, s64 max, u64 step, s64 def,
-			u32 elem_size,
+			const u32 dims[V4L2_CTRL_MAX_DIMS], u32 elem_size,
 			u32 flags, const char * const *qmenu,
 			const s64 *qmenu_int, void *priv)
 {
 	struct v4l2_ctrl *ctrl;
 	unsigned sz_extra;
+	unsigned nr_of_dims = 0;
+	unsigned elems = 1;
 	void *data;
 	int err;
 
 	if (hdl->error)
 		return NULL;
 
+	while (dims && dims[nr_of_dims]) {
+		elems *= dims[nr_of_dims];
+		nr_of_dims++;
+		if (nr_of_dims == V4L2_CTRL_MAX_DIMS)
+			break;
+	}
+
 	if (type == V4L2_CTRL_TYPE_INTEGER64)
 		elem_size = sizeof(s64);
 	else if (type == V4L2_CTRL_TYPE_STRING)
@@ -1828,6 +1837,10 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 	ctrl->is_string = type == V4L2_CTRL_TYPE_STRING;
 	ctrl->is_ptr = type >= V4L2_CTRL_COMPOUND_TYPES || ctrl->is_string;
 	ctrl->is_int = !ctrl->is_ptr && type != V4L2_CTRL_TYPE_INTEGER64;
+	ctrl->elems = elems;
+	ctrl->nr_of_dims = nr_of_dims;
+	if (nr_of_dims)
+		memcpy(ctrl->dims, dims, nr_of_dims * sizeof(dims[0]));
 	ctrl->elem_size = elem_size;
 	if (type == V4L2_CTRL_TYPE_MENU)
 		ctrl->qmenu = qmenu;
@@ -1892,8 +1905,8 @@ struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl,
 
 	ctrl = v4l2_ctrl_new(hdl, cfg->ops, cfg->type_ops, cfg->id, name,
 			type, min, max,
-			is_menu ? cfg->menu_skip_mask : step,
-			def, cfg->elem_size,
+			is_menu ? cfg->menu_skip_mask : step, def,
+			cfg->dims, cfg->elem_size,
 			flags, qmenu, qmenu_int, priv);
 	if (ctrl)
 		ctrl->is_private = cfg->is_private;
@@ -1918,7 +1931,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl,
 		return NULL;
 	}
 	return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
-			     min, max, step, def, 0,
+			     min, max, step, def, NULL, 0,
 			     flags, NULL, NULL, NULL);
 }
 EXPORT_SYMBOL(v4l2_ctrl_new_std);
@@ -1951,7 +1964,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl,
 		return NULL;
 	}
 	return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
-			     0, max, mask, def, 0,
+			     0, max, mask, def, NULL, 0,
 			     flags, qmenu, qmenu_int, NULL);
 }
 EXPORT_SYMBOL(v4l2_ctrl_new_std_menu);
@@ -1983,8 +1996,8 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu_items(struct v4l2_ctrl_handler *hdl,
 		return NULL;
 	}
 	return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
-			     0, max, mask, def,
-			     0, flags, qmenu, NULL, NULL);
+			     0, max, mask, def, NULL, 0,
+			     flags, qmenu, NULL, NULL);
 
 }
 EXPORT_SYMBOL(v4l2_ctrl_new_std_menu_items);
@@ -2008,7 +2021,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl,
 		return NULL;
 	}
 	return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
-			     0, max, 0, def, 0,
+			     0, max, 0, def, NULL, 0,
 			     flags, NULL, qmenu_int, NULL);
 }
 EXPORT_SYMBOL(v4l2_ctrl_new_int_menu);
@@ -2354,7 +2367,9 @@ int v4l2_query_ext_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_query_ext_ctr
 	if (ctrl->is_ptr)
 		qc->flags |= V4L2_CTRL_FLAG_HAS_PAYLOAD;
 	qc->elem_size = ctrl->elem_size;
-	qc->elems = 1;
+	qc->elems = ctrl->elems;
+	qc->nr_of_dims = ctrl->nr_of_dims;
+	memcpy(qc->dims, ctrl->dims, qc->nr_of_dims * sizeof(qc->dims[0]));
 	qc->minimum = ctrl->minimum;
 	qc->maximum = ctrl->maximum;
 	qc->default_value = ctrl->default_value;
diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
index eb69c52..d30da09 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -129,7 +129,10 @@ typedef void (*v4l2_ctrl_notify_fnc)(struct v4l2_ctrl *ctrl, void *priv);
   * @maximum:	The control's maximum value.
   * @default_value: The control's default value.
   * @step:	The control's step value for non-menu controls.
+  * @elems:	The number of elements in the N-dimensional array.
   * @elem_size:	The size in bytes of the control.
+  * @dims:	The size of each dimension.
+  * @nr_of_dims:The number of dimensions in @dims.
   * @menu_skip_mask: The control's skip mask for menu controls. This makes it
   *		easy to skip menu items that are not valid. If bit X is set,
   *		then menu item X is skipped. Of course, this only works for
@@ -176,7 +179,10 @@ struct v4l2_ctrl {
 	const char *name;
 	enum v4l2_ctrl_type type;
 	s64 minimum, maximum, default_value;
+	u32 elems;
 	u32 elem_size;
+	u32 dims[V4L2_CTRL_MAX_DIMS];
+	u32 nr_of_dims;
 	union {
 		u64 step;
 		u64 menu_skip_mask;
@@ -255,6 +261,7 @@ struct v4l2_ctrl_handler {
   * @max:	The control's maximum value.
   * @step:	The control's step value for non-menu controls.
   * @def: 	The control's default value.
+  * @dims:	The size of each dimension.
   * @elem_size:	The size in bytes of the control.
   * @flags:	The control's flags.
   * @menu_skip_mask: The control's skip mask for menu controls. This makes it
@@ -280,6 +287,7 @@ struct v4l2_ctrl_config {
 	s64 max;
 	u64 step;
 	s64 def;
+	u32 dims[V4L2_CTRL_MAX_DIMS];
 	u32 elem_size;
 	u32 flags;
 	u64 menu_skip_mask;
-- 
2.0.0.rc0


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

* [REVIEWv4 PATCH 12/34] v4l2-ctrls: prepare for array support.
  2014-06-12 11:52 ` [REVIEWv4 PATCH 01/34] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
                     ` (9 preceding siblings ...)
  2014-06-12 11:52   ` [REVIEWv4 PATCH 11/34] v4l2-ctrls: prepare for array support Hans Verkuil
@ 2014-06-12 11:52   ` Hans Verkuil
  2014-06-12 11:52   ` [REVIEWv4 PATCH 13/34] v4l2-ctrls: type_ops can handle array elements Hans Verkuil
                     ` (21 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Hans Verkuil @ 2014-06-12 11:52 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, s.nawrocki, sakari.ailus, Hans Verkuil

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

Add core support for N-dimensional arrays.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/v4l2-core/v4l2-ctrls.c | 58 ++++++++++++++++++++++++------------
 include/media/v4l2-ctrls.h           |  8 +++--
 2 files changed, 44 insertions(+), 22 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index e6c98a7..6ed2d56 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1161,7 +1161,7 @@ static void send_event(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 changes)
 			v4l2_event_queue_fh(sev->fh, &ev);
 }
 
-static bool std_equal(const struct v4l2_ctrl *ctrl,
+static bool std_equal(const struct v4l2_ctrl *ctrl, u32 idx,
 		      union v4l2_ctrl_ptr ptr1,
 		      union v4l2_ctrl_ptr ptr2)
 {
@@ -1180,7 +1180,7 @@ static bool std_equal(const struct v4l2_ctrl *ctrl,
 	}
 }
 
-static void std_init(const struct v4l2_ctrl *ctrl,
+static void std_init(const struct v4l2_ctrl *ctrl, u32 idx,
 		     union v4l2_ctrl_ptr ptr)
 {
 	switch (ctrl->type) {
@@ -1207,6 +1207,14 @@ static void std_log(const struct v4l2_ctrl *ctrl)
 {
 	union v4l2_ctrl_ptr ptr = ctrl->p_cur;
 
+	if (ctrl->is_array) {
+		unsigned i;
+
+		for (i = 0; i < ctrl->nr_of_dims; i++)
+			pr_cont("[%u]", ctrl->dims[i]);
+		pr_cont(" ");
+	}
+
 	switch (ctrl->type) {
 	case V4L2_CTRL_TYPE_INTEGER:
 		pr_cont("%d", *ptr.p_s32);
@@ -1249,7 +1257,7 @@ static void std_log(const struct v4l2_ctrl *ctrl)
 })
 
 /* Validate a new control */
-static int std_validate(const struct v4l2_ctrl *ctrl,
+static int std_validate(const struct v4l2_ctrl *ctrl, u32 idx,
 			union v4l2_ctrl_ptr ptr)
 {
 	size_t len;
@@ -1473,8 +1481,8 @@ static int cluster_changed(struct v4l2_ctrl *master)
 
 		if (ctrl == NULL)
 			continue;
-		ctrl->has_changed = !ctrl->type_ops->equal(ctrl,
-						ctrl->p_cur, ctrl->p_new);
+		ctrl->has_changed = !ctrl->type_ops->equal(ctrl, 0,
+				ctrl->p_cur, ctrl->p_new);
 		changed |= ctrl->has_changed;
 	}
 	return changed;
@@ -1531,15 +1539,15 @@ static int validate_new(const struct v4l2_ctrl *ctrl,
 	case V4L2_CTRL_TYPE_BUTTON:
 	case V4L2_CTRL_TYPE_CTRL_CLASS:
 		ptr.p_s32 = &c->value;
-		return ctrl->type_ops->validate(ctrl, ptr);
+		return ctrl->type_ops->validate(ctrl, 0, ptr);
 
 	case V4L2_CTRL_TYPE_INTEGER64:
 		ptr.p_s64 = &c->value64;
-		return ctrl->type_ops->validate(ctrl, ptr);
+		return ctrl->type_ops->validate(ctrl, 0, ptr);
 
 	default:
 		ptr.p = c->ptr;
-		return ctrl->type_ops->validate(ctrl, ptr);
+		return ctrl->type_ops->validate(ctrl, 0, ptr);
 	}
 }
 
@@ -1767,6 +1775,8 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 	unsigned sz_extra;
 	unsigned nr_of_dims = 0;
 	unsigned elems = 1;
+	bool is_array;
+	unsigned tot_ctrl_size;
 	void *data;
 	int err;
 
@@ -1779,6 +1789,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 		if (nr_of_dims == V4L2_CTRL_MAX_DIMS)
 			break;
 	}
+	is_array = nr_of_dims > 0;
 
 	if (type == V4L2_CTRL_TYPE_INTEGER64)
 		elem_size = sizeof(s64);
@@ -1786,10 +1797,11 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 		elem_size = max + 1;
 	else if (type < V4L2_CTRL_COMPOUND_TYPES)
 		elem_size = sizeof(s32);
+	tot_ctrl_size = elem_size * elems;
 
 	/* Sanity checks */
-	if (id == 0 || name == NULL || id >= V4L2_CID_PRIVATE_BASE ||
-	    elem_size == 0 ||
+	if (id == 0 || name == NULL || !elem_size ||
+	    id >= V4L2_CID_PRIVATE_BASE ||
 	    (type == V4L2_CTRL_TYPE_MENU && qmenu == NULL) ||
 	    (type == V4L2_CTRL_TYPE_INTEGER_MENU && qmenu_int == NULL)) {
 		handler_set_err(hdl, -ERANGE);
@@ -1804,6 +1816,12 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 		handler_set_err(hdl, -ERANGE);
 		return NULL;
 	}
+	if (is_array &&
+	    (type == V4L2_CTRL_TYPE_BUTTON ||
+	     type == V4L2_CTRL_TYPE_CTRL_CLASS)) {
+		handler_set_err(hdl, -EINVAL);
+		return NULL;
+	}
 
 	sz_extra = 0;
 	if (type == V4L2_CTRL_TYPE_BUTTON)
@@ -1812,8 +1830,9 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 		flags |= V4L2_CTRL_FLAG_READ_ONLY;
 	else if (type == V4L2_CTRL_TYPE_INTEGER64 ||
 		 type == V4L2_CTRL_TYPE_STRING ||
-		 type >= V4L2_CTRL_COMPOUND_TYPES)
-		sz_extra += 2 * elem_size;
+		 type >= V4L2_CTRL_COMPOUND_TYPES ||
+		 is_array)
+		sz_extra += 2 * tot_ctrl_size;
 
 	ctrl = kzalloc(sizeof(*ctrl) + sz_extra, GFP_KERNEL);
 	if (ctrl == NULL) {
@@ -1834,9 +1853,10 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 	ctrl->maximum = max;
 	ctrl->step = step;
 	ctrl->default_value = def;
-	ctrl->is_string = type == V4L2_CTRL_TYPE_STRING;
-	ctrl->is_ptr = type >= V4L2_CTRL_COMPOUND_TYPES || ctrl->is_string;
+	ctrl->is_string = !is_array && type == V4L2_CTRL_TYPE_STRING;
+	ctrl->is_ptr = is_array || type >= V4L2_CTRL_COMPOUND_TYPES || ctrl->is_string;
 	ctrl->is_int = !ctrl->is_ptr && type != V4L2_CTRL_TYPE_INTEGER64;
+	ctrl->is_array = is_array;
 	ctrl->elems = elems;
 	ctrl->nr_of_dims = nr_of_dims;
 	if (nr_of_dims)
@@ -1852,13 +1872,13 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 
 	if (!ctrl->is_int) {
 		ctrl->p_new.p = data;
-		ctrl->p_cur.p = data + elem_size;
+		ctrl->p_cur.p = data + tot_ctrl_size;
 	} else {
 		ctrl->p_new.p = &ctrl->val;
 		ctrl->p_cur.p = &ctrl->cur.val;
 	}
-	ctrl->type_ops->init(ctrl, ctrl->p_cur);
-	ctrl->type_ops->init(ctrl, ctrl->p_new);
+	ctrl->type_ops->init(ctrl, 0, ctrl->p_cur);
+	ctrl->type_ops->init(ctrl, 0, ctrl->p_new);
 
 	if (handler_new_ref(hdl, ctrl)) {
 		kfree(ctrl);
@@ -2764,7 +2784,7 @@ s64 v4l2_ctrl_g_ctrl_int64(struct v4l2_ctrl *ctrl)
 	struct v4l2_ext_control c;
 
 	/* It's a driver bug if this happens. */
-	WARN_ON(ctrl->type != V4L2_CTRL_TYPE_INTEGER64);
+	WARN_ON(ctrl->is_ptr || ctrl->type != V4L2_CTRL_TYPE_INTEGER64);
 	c.value = 0;
 	get_ctrl(ctrl, &c);
 	return c.value;
@@ -3074,7 +3094,7 @@ int v4l2_ctrl_s_ctrl_int64(struct v4l2_ctrl *ctrl, s64 val)
 	struct v4l2_ext_control c;
 
 	/* It's a driver bug if this happens. */
-	WARN_ON(ctrl->type != V4L2_CTRL_TYPE_INTEGER64);
+	WARN_ON(ctrl->is_ptr || ctrl->type != V4L2_CTRL_TYPE_INTEGER64);
 	c.value64 = val;
 	return set_ctrl_lock(NULL, ctrl, &c);
 }
diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
index d30da09..7915b1125 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -74,13 +74,13 @@ struct v4l2_ctrl_ops {
   * @validate: validate the value. Return 0 on success and a negative value otherwise.
   */
 struct v4l2_ctrl_type_ops {
-	bool (*equal)(const struct v4l2_ctrl *ctrl,
+	bool (*equal)(const struct v4l2_ctrl *ctrl, u32 idx,
 		      union v4l2_ctrl_ptr ptr1,
 		      union v4l2_ctrl_ptr ptr2);
-	void (*init)(const struct v4l2_ctrl *ctrl,
+	void (*init)(const struct v4l2_ctrl *ctrl, u32 idx,
 		     union v4l2_ctrl_ptr ptr);
 	void (*log)(const struct v4l2_ctrl *ctrl);
-	int (*validate)(const struct v4l2_ctrl *ctrl,
+	int (*validate)(const struct v4l2_ctrl *ctrl, u32 idx,
 			union v4l2_ctrl_ptr ptr);
 };
 
@@ -111,6 +111,7 @@ typedef void (*v4l2_ctrl_notify_fnc)(struct v4l2_ctrl *ctrl, void *priv);
   * @is_ptr:	If set, then this control is an array and/or has type >= V4L2_CTRL_COMPOUND_TYPES
   *		and/or has type V4L2_CTRL_TYPE_STRING. In other words, struct
   *		v4l2_ext_control uses field p to point to the data.
+  * @is_array: If set, then this control contains an N-dimensional array.
   * @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
@@ -169,6 +170,7 @@ struct v4l2_ctrl {
 	unsigned int is_int:1;
 	unsigned int is_string:1;
 	unsigned int is_ptr:1;
+	unsigned int is_array:1;
 	unsigned int has_volatiles:1;
 	unsigned int call_notify:1;
 	unsigned int manual_mode_value:8;
-- 
2.0.0.rc0


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

* [REVIEWv4 PATCH 13/34] v4l2-ctrls: type_ops can handle array elements.
  2014-06-12 11:52 ` [REVIEWv4 PATCH 01/34] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
                     ` (10 preceding siblings ...)
  2014-06-12 11:52   ` [REVIEWv4 PATCH 12/34] " Hans Verkuil
@ 2014-06-12 11:52   ` Hans Verkuil
  2014-06-12 11:52   ` [REVIEWv4 PATCH 14/34] v4l2-ctrls: add array support Hans Verkuil
                     ` (20 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Hans Verkuil @ 2014-06-12 11:52 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, s.nawrocki, sakari.ailus, Hans Verkuil

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

Extend the control type operations to handle N-dimensional array elements.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/v4l2-core/v4l2-ctrls.c | 40 ++++++++++++++++++++----------------
 1 file changed, 22 insertions(+), 18 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 6ed2d56..f6ac927 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1169,14 +1169,16 @@ static bool std_equal(const struct v4l2_ctrl *ctrl, u32 idx,
 	case V4L2_CTRL_TYPE_BUTTON:
 		return false;
 	case V4L2_CTRL_TYPE_STRING:
+		idx *= ctrl->elem_size;
 		/* strings are always 0-terminated */
-		return !strcmp(ptr1.p_char, ptr2.p_char);
+		return !strcmp(ptr1.p_char + idx, ptr2.p_char + idx);
 	case V4L2_CTRL_TYPE_INTEGER64:
-		return *ptr1.p_s64 == *ptr2.p_s64;
+		return ptr1.p_s64[idx] == ptr2.p_s64[idx];
 	default:
-		if (ctrl->is_ptr)
-			return !memcmp(ptr1.p, ptr2.p, ctrl->elem_size);
-		return *ptr1.p_s32 == *ptr2.p_s32;
+		if (ctrl->is_int)
+			return ptr1.p_s32[idx] == ptr2.p_s32[idx];
+		idx *= ctrl->elem_size;
+		return !memcmp(ptr1.p + idx, ptr2.p + idx, ctrl->elem_size);
 	}
 }
 
@@ -1185,18 +1187,19 @@ static void std_init(const struct v4l2_ctrl *ctrl, u32 idx,
 {
 	switch (ctrl->type) {
 	case V4L2_CTRL_TYPE_STRING:
-		memset(ptr.p_char, ' ', ctrl->minimum);
-		ptr.p_char[ctrl->minimum] = '\0';
+		idx *= ctrl->elem_size;
+		memset(ptr.p_char + idx, ' ', ctrl->minimum);
+		ptr.p_char[idx + ctrl->minimum] = '\0';
 		break;
 	case V4L2_CTRL_TYPE_INTEGER64:
-		*ptr.p_s64 = ctrl->default_value;
+		ptr.p_s64[idx] = ctrl->default_value;
 		break;
 	case V4L2_CTRL_TYPE_INTEGER:
 	case V4L2_CTRL_TYPE_INTEGER_MENU:
 	case V4L2_CTRL_TYPE_MENU:
 	case V4L2_CTRL_TYPE_BITMASK:
 	case V4L2_CTRL_TYPE_BOOLEAN:
-		*ptr.p_s32 = ctrl->default_value;
+		ptr.p_s32[idx] = ctrl->default_value;
 		break;
 	default:
 		break;
@@ -1264,36 +1267,37 @@ static int std_validate(const struct v4l2_ctrl *ctrl, u32 idx,
 
 	switch (ctrl->type) {
 	case V4L2_CTRL_TYPE_INTEGER:
-		return ROUND_TO_RANGE(*ptr.p_s32, u32, ctrl);
+		return ROUND_TO_RANGE(ptr.p_s32[idx], u32, ctrl);
 	case V4L2_CTRL_TYPE_INTEGER64:
-		return ROUND_TO_RANGE(*ptr.p_s64, u64, ctrl);
+		return ROUND_TO_RANGE(ptr.p_s64[idx], u64, ctrl);
 
 	case V4L2_CTRL_TYPE_BOOLEAN:
-		*ptr.p_s32 = !!*ptr.p_s32;
+		ptr.p_s32[idx] = !!ptr.p_s32[idx];
 		return 0;
 
 	case V4L2_CTRL_TYPE_MENU:
 	case V4L2_CTRL_TYPE_INTEGER_MENU:
-		if (*ptr.p_s32 < ctrl->minimum || *ptr.p_s32 > ctrl->maximum)
+		if (ptr.p_s32[idx] < ctrl->minimum || ptr.p_s32[idx] > ctrl->maximum)
 			return -ERANGE;
-		if (ctrl->menu_skip_mask & (1 << *ptr.p_s32))
+		if (ctrl->menu_skip_mask & (1 << ptr.p_s32[idx]))
 			return -EINVAL;
 		if (ctrl->type == V4L2_CTRL_TYPE_MENU &&
-		    ctrl->qmenu[*ptr.p_s32][0] == '\0')
+		    ctrl->qmenu[ptr.p_s32[idx]][0] == '\0')
 			return -EINVAL;
 		return 0;
 
 	case V4L2_CTRL_TYPE_BITMASK:
-		*ptr.p_s32 &= ctrl->maximum;
+		ptr.p_s32[idx] &= ctrl->maximum;
 		return 0;
 
 	case V4L2_CTRL_TYPE_BUTTON:
 	case V4L2_CTRL_TYPE_CTRL_CLASS:
-		*ptr.p_s32 = 0;
+		ptr.p_s32[idx] = 0;
 		return 0;
 
 	case V4L2_CTRL_TYPE_STRING:
-		len = strlen(ptr.p_char);
+		idx *= ctrl->elem_size;
+		len = strlen(ptr.p_char + idx);
 		if (len < ctrl->minimum)
 			return -ERANGE;
 		if ((len - ctrl->minimum) % ctrl->step)
-- 
2.0.0.rc0


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

* [REVIEWv4 PATCH 14/34] v4l2-ctrls: add array support.
  2014-06-12 11:52 ` [REVIEWv4 PATCH 01/34] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
                     ` (11 preceding siblings ...)
  2014-06-12 11:52   ` [REVIEWv4 PATCH 13/34] v4l2-ctrls: type_ops can handle array elements Hans Verkuil
@ 2014-06-12 11:52   ` Hans Verkuil
  2014-06-12 11:52   ` [REVIEWv4 PATCH 15/34] v4l2-ctrls: return elem_size instead of strlen Hans Verkuil
                     ` (19 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Hans Verkuil @ 2014-06-12 11:52 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, s.nawrocki, sakari.ailus, Hans Verkuil

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

Finish the userspace-facing array support.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/v4l2-core/v4l2-ctrls.c | 109 ++++++++++++++++++++---------------
 1 file changed, 63 insertions(+), 46 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index f6ac927..b3ab8a9 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1202,6 +1202,8 @@ static void std_init(const struct v4l2_ctrl *ctrl, u32 idx,
 		ptr.p_s32[idx] = ctrl->default_value;
 		break;
 	default:
+		idx *= ctrl->elem_size;
+		memset(ptr.p + idx, 0, ctrl->elem_size);
 		break;
 	}
 }
@@ -1324,7 +1326,7 @@ static int ptr_to_user(struct v4l2_ext_control *c,
 	u32 len;
 
 	if (ctrl->is_ptr && !ctrl->is_string)
-		return copy_to_user(c->ptr, ptr.p, ctrl->elem_size);
+		return copy_to_user(c->ptr, ptr.p, c->size);
 
 	switch (ctrl->type) {
 	case V4L2_CTRL_TYPE_STRING:
@@ -1368,8 +1370,16 @@ static int user_to_ptr(struct v4l2_ext_control *c,
 	u32 size;
 
 	ctrl->is_new = 1;
-	if (ctrl->is_ptr && !ctrl->is_string)
-		return copy_from_user(ptr.p, c->ptr, ctrl->elem_size);
+	if (ctrl->is_ptr && !ctrl->is_string) {
+		unsigned idx;
+
+		ret = copy_from_user(ptr.p, c->ptr, c->size);
+		if (ret || !ctrl->is_array)
+			return ret;
+		for (idx = c->size / ctrl->elem_size; idx < ctrl->elems; idx++)
+			ctrl->type_ops->init(ctrl, idx, ptr);
+		return 0;
+	}
 
 	switch (ctrl->type) {
 	case V4L2_CTRL_TYPE_INTEGER64:
@@ -1412,21 +1422,7 @@ static void ptr_to_ptr(struct v4l2_ctrl *ctrl,
 {
 	if (ctrl == NULL)
 		return;
-	switch (ctrl->type) {
-	case V4L2_CTRL_TYPE_STRING:
-		/* strings are always 0-terminated */
-		strcpy(to.p_char, from.p_char);
-		break;
-	case V4L2_CTRL_TYPE_INTEGER64:
-		*to.p_s64 = *from.p_s64;
-		break;
-	default:
-		if (ctrl->is_ptr)
-			memcpy(to.p, from.p, ctrl->elem_size);
-		else
-			*to.p_s32 = *from.p_s32;
-		break;
-	}
+	memcpy(to.p, from.p, ctrl->elems * ctrl->elem_size);
 }
 
 /* Copy the new value to the current value. */
@@ -1478,15 +1474,19 @@ static void cur_to_new(struct v4l2_ctrl *ctrl)
 static int cluster_changed(struct v4l2_ctrl *master)
 {
 	bool changed = false;
+	unsigned idx;
 	int i;
 
 	for (i = 0; i < master->ncontrols; i++) {
 		struct v4l2_ctrl *ctrl = master->cluster[i];
+		bool ctrl_changed = false;
 
 		if (ctrl == NULL)
 			continue;
-		ctrl->has_changed = !ctrl->type_ops->equal(ctrl, 0,
+		for (idx = 0; !ctrl_changed && idx < ctrl->elems; idx++)
+			ctrl_changed = !ctrl->type_ops->equal(ctrl, idx,
 				ctrl->p_cur, ctrl->p_new);
+		ctrl->has_changed = ctrl_changed;
 		changed |= ctrl->has_changed;
 	}
 	return changed;
@@ -1533,26 +1533,32 @@ static int validate_new(const struct v4l2_ctrl *ctrl,
 			struct v4l2_ext_control *c)
 {
 	union v4l2_ctrl_ptr ptr;
-
-	switch (ctrl->type) {
-	case V4L2_CTRL_TYPE_INTEGER:
-	case V4L2_CTRL_TYPE_INTEGER_MENU:
-	case V4L2_CTRL_TYPE_MENU:
-	case V4L2_CTRL_TYPE_BITMASK:
-	case V4L2_CTRL_TYPE_BOOLEAN:
-	case V4L2_CTRL_TYPE_BUTTON:
-	case V4L2_CTRL_TYPE_CTRL_CLASS:
-		ptr.p_s32 = &c->value;
-		return ctrl->type_ops->validate(ctrl, 0, ptr);
-
-	case V4L2_CTRL_TYPE_INTEGER64:
-		ptr.p_s64 = &c->value64;
-		return ctrl->type_ops->validate(ctrl, 0, ptr);
-
-	default:
-		ptr.p = c->ptr;
-		return ctrl->type_ops->validate(ctrl, 0, ptr);
+	unsigned idx;
+	int err = 0;
+
+	if (!ctrl->is_ptr) {
+		switch (ctrl->type) {
+		case V4L2_CTRL_TYPE_INTEGER:
+		case V4L2_CTRL_TYPE_INTEGER_MENU:
+		case V4L2_CTRL_TYPE_MENU:
+		case V4L2_CTRL_TYPE_BITMASK:
+		case V4L2_CTRL_TYPE_BOOLEAN:
+		case V4L2_CTRL_TYPE_BUTTON:
+		case V4L2_CTRL_TYPE_CTRL_CLASS:
+			ptr.p_s32 = &c->value;
+			return ctrl->type_ops->validate(ctrl, 0, ptr);
+
+		case V4L2_CTRL_TYPE_INTEGER64:
+			ptr.p_s64 = &c->value64;
+			return ctrl->type_ops->validate(ctrl, 0, ptr);
+		default:
+			break;
+		}
 	}
+	ptr.p = c->ptr;
+	for (idx = 0; !err && idx < c->size / ctrl->elem_size; idx++)
+		err = ctrl->type_ops->validate(ctrl, idx, ptr);
+	return err;
 }
 
 static inline u32 node2id(struct list_head *node)
@@ -1781,6 +1787,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 	unsigned elems = 1;
 	bool is_array;
 	unsigned tot_ctrl_size;
+	unsigned idx;
 	void *data;
 	int err;
 
@@ -1881,8 +1888,10 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 		ctrl->p_new.p = &ctrl->val;
 		ctrl->p_cur.p = &ctrl->cur.val;
 	}
-	ctrl->type_ops->init(ctrl, 0, ctrl->p_cur);
-	ctrl->type_ops->init(ctrl, 0, ctrl->p_new);
+	for (idx = 0; idx < elems; idx++) {
+		ctrl->type_ops->init(ctrl, idx, ctrl->p_cur);
+		ctrl->type_ops->init(ctrl, idx, ctrl->p_new);
+	}
 
 	if (handler_new_ref(hdl, ctrl)) {
 		kfree(ctrl);
@@ -2578,12 +2587,17 @@ static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl,
 			have_clusters = true;
 		if (ctrl->cluster[0] != ctrl)
 			ref = find_ref_lock(hdl, ctrl->cluster[0]->id);
-		if (ctrl->is_ptr && !ctrl->is_string && c->size < ctrl->elem_size) {
-			if (get) {
-				c->size = ctrl->elem_size;
-				return -ENOSPC;
+		if (ctrl->is_ptr && !ctrl->is_string) {
+			unsigned tot_size = ctrl->elems * ctrl->elem_size;
+
+			if (c->size < tot_size) {
+				if (get) {
+					c->size = tot_size;
+					return -ENOSPC;
+				}
+				return -EFAULT;
 			}
-			return -EFAULT;
+			c->size = tot_size;
 		}
 		/* Store the ref to the master control of the cluster */
 		h->mref = ref;
@@ -3123,7 +3137,7 @@ EXPORT_SYMBOL(v4l2_ctrl_notify);
 int v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl,
 			s64 min, s64 max, u64 step, s64 def)
 {
-	int ret = check_range(ctrl->type, min, max, step, def);
+	int ret;
 	struct v4l2_ext_control c;
 
 	switch (ctrl->type) {
@@ -3133,6 +3147,9 @@ int v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl,
 	case V4L2_CTRL_TYPE_MENU:
 	case V4L2_CTRL_TYPE_INTEGER_MENU:
 	case V4L2_CTRL_TYPE_BITMASK:
+		if (ctrl->is_array)
+			return -EINVAL;
+		ret = check_range(ctrl->type, min, max, step, def);
 		if (ret)
 			return ret;
 		break;
-- 
2.0.0.rc0


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

* [REVIEWv4 PATCH 15/34] v4l2-ctrls: return elem_size instead of strlen
  2014-06-12 11:52 ` [REVIEWv4 PATCH 01/34] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
                     ` (12 preceding siblings ...)
  2014-06-12 11:52   ` [REVIEWv4 PATCH 14/34] v4l2-ctrls: add array support Hans Verkuil
@ 2014-06-12 11:52   ` Hans Verkuil
  2014-06-12 11:52   ` [REVIEWv4 PATCH 16/34] v4l2-ctrl: fix error return of copy_to/from_user Hans Verkuil
                     ` (18 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Hans Verkuil @ 2014-06-12 11:52 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, s.nawrocki, sakari.ailus, Hans Verkuil

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

When getting a string and the size given by the application is too
short return the max length the string can have (elem_size) instead
of the string length + 1. That makes more sense.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Reviewed-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
---
 drivers/media/v4l2-core/v4l2-ctrls.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index b3ab8a9..e6e33b3 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1332,7 +1332,7 @@ static int ptr_to_user(struct v4l2_ext_control *c,
 	case V4L2_CTRL_TYPE_STRING:
 		len = strlen(ptr.p_char);
 		if (c->size < len + 1) {
-			c->size = len + 1;
+			c->size = ctrl->elem_size;
 			return -ENOSPC;
 		}
 		return copy_to_user(c->string, ptr.p_char, len + 1) ?
-- 
2.0.0.rc0


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

* [REVIEWv4 PATCH 16/34] v4l2-ctrl: fix error return of copy_to/from_user.
  2014-06-12 11:52 ` [REVIEWv4 PATCH 01/34] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
                     ` (13 preceding siblings ...)
  2014-06-12 11:52   ` [REVIEWv4 PATCH 15/34] v4l2-ctrls: return elem_size instead of strlen Hans Verkuil
@ 2014-06-12 11:52   ` Hans Verkuil
  2014-06-12 11:52   ` [REVIEWv4 PATCH 17/34] DocBook media: document VIDIOC_QUERY_EXT_CTRL Hans Verkuil
                     ` (17 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Hans Verkuil @ 2014-06-12 11:52 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, s.nawrocki, sakari.ailus, Hans Verkuil

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

copy_to/from_user returns the number of bytes not copied, it does not
return a 'normal' linux error code.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/v4l2-core/v4l2-ctrls.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index e6e33b3..1086ae3 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1326,7 +1326,8 @@ static int ptr_to_user(struct v4l2_ext_control *c,
 	u32 len;
 
 	if (ctrl->is_ptr && !ctrl->is_string)
-		return copy_to_user(c->ptr, ptr.p, c->size);
+		return copy_to_user(c->ptr, ptr.p, c->size) ?
+		       -EFAULT : 0;
 
 	switch (ctrl->type) {
 	case V4L2_CTRL_TYPE_STRING:
@@ -1336,7 +1337,7 @@ static int ptr_to_user(struct v4l2_ext_control *c,
 			return -ENOSPC;
 		}
 		return copy_to_user(c->string, ptr.p_char, len + 1) ?
-								-EFAULT : 0;
+		       -EFAULT : 0;
 	case V4L2_CTRL_TYPE_INTEGER64:
 		c->value64 = *ptr.p_s64;
 		break;
@@ -1373,7 +1374,7 @@ static int user_to_ptr(struct v4l2_ext_control *c,
 	if (ctrl->is_ptr && !ctrl->is_string) {
 		unsigned idx;
 
-		ret = copy_from_user(ptr.p, c->ptr, c->size);
+		ret = copy_from_user(ptr.p, c->ptr, c->size) ? -EFAULT : 0;
 		if (ret || !ctrl->is_array)
 			return ret;
 		for (idx = c->size / ctrl->elem_size; idx < ctrl->elems; idx++)
@@ -1391,7 +1392,7 @@ static int user_to_ptr(struct v4l2_ext_control *c,
 			return -ERANGE;
 		if (size > ctrl->maximum + 1)
 			size = ctrl->maximum + 1;
-		ret = copy_from_user(ptr.p_char, c->string, size);
+		ret = copy_from_user(ptr.p_char, c->string, size) ? -EFAULT : 0;
 		if (!ret) {
 			char last = ptr.p_char[size - 1];
 
@@ -1401,7 +1402,7 @@ static int user_to_ptr(struct v4l2_ext_control *c,
 			if (strlen(ptr.p_char) == ctrl->maximum && last)
 				return -ERANGE;
 		}
-		return ret ? -EFAULT : 0;
+		return ret;
 	default:
 		*ptr.p_s32 = c->value;
 		break;
-- 
2.0.0.rc0


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

* [REVIEWv4 PATCH 17/34] DocBook media: document VIDIOC_QUERY_EXT_CTRL.
  2014-06-12 11:52 ` [REVIEWv4 PATCH 01/34] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
                     ` (14 preceding siblings ...)
  2014-06-12 11:52   ` [REVIEWv4 PATCH 16/34] v4l2-ctrl: fix error return of copy_to/from_user Hans Verkuil
@ 2014-06-12 11:52   ` Hans Verkuil
  2014-06-12 11:52   ` [REVIEWv4 PATCH 18/34] DocBook media: update VIDIOC_G/S/TRY_EXT_CTRLS Hans Verkuil
                     ` (16 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Hans Verkuil @ 2014-06-12 11:52 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, s.nawrocki, sakari.ailus, Hans Verkuil

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

Document the new VIDIOC_QUERY_EXT_CTRL ioctl.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 .../DocBook/media/v4l/vidioc-queryctrl.xml         | 211 +++++++++++++++++----
 1 file changed, 175 insertions(+), 36 deletions(-)

diff --git a/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml b/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml
index e6645b9..30c4e8a 100644
--- a/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml
@@ -1,11 +1,12 @@
 <refentry id="vidioc-queryctrl">
   <refmeta>
-    <refentrytitle>ioctl VIDIOC_QUERYCTRL, VIDIOC_QUERYMENU</refentrytitle>
+    <refentrytitle>ioctl VIDIOC_QUERYCTRL, VIDIOC_QUERY_EXT_CTRL, VIDIOC_QUERYMENU</refentrytitle>
     &manvol;
   </refmeta>
 
   <refnamediv>
     <refname>VIDIOC_QUERYCTRL</refname>
+    <refname>VIDIOC_QUERY_EXT_CTRL</refname>
     <refname>VIDIOC_QUERYMENU</refname>
     <refpurpose>Enumerate controls and menu control items</refpurpose>
   </refnamediv>
@@ -24,6 +25,14 @@
 	<funcdef>int <function>ioctl</function></funcdef>
 	<paramdef>int <parameter>fd</parameter></paramdef>
 	<paramdef>int <parameter>request</parameter></paramdef>
+	<paramdef>struct v4l2_query_ext_ctrl *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+    <funcsynopsis>
+      <funcprototype>
+	<funcdef>int <function>ioctl</function></funcdef>
+	<paramdef>int <parameter>fd</parameter></paramdef>
+	<paramdef>int <parameter>request</parameter></paramdef>
 	<paramdef>struct v4l2_querymenu *<parameter>argp</parameter></paramdef>
       </funcprototype>
     </funcsynopsis>
@@ -42,7 +51,7 @@
       <varlistentry>
 	<term><parameter>request</parameter></term>
 	<listitem>
-	  <para>VIDIOC_QUERYCTRL, VIDIOC_QUERYMENU</para>
+	  <para>VIDIOC_QUERYCTRL, VIDIOC_QUERY_EXT_CTRL, VIDIOC_QUERYMENU</para>
 	</listitem>
       </varlistentry>
       <varlistentry>
@@ -89,9 +98,23 @@ prematurely end the enumeration).</para></footnote></para>
 
     <para>When the application ORs <structfield>id</structfield> with
 <constant>V4L2_CTRL_FLAG_NEXT_CTRL</constant> the driver returns the
-next supported control, or <errorcode>EINVAL</errorcode> if there is
-none. Drivers which do not support this flag yet always return
-<errorcode>EINVAL</errorcode>.</para>
+next supported non-compound control, or <errorcode>EINVAL</errorcode>
+if there is none. In addition, the <constant>V4L2_CTRL_FLAG_NEXT_COMPOUND</constant>
+flag can be specified to enumerate all compound controls (i.e. controls
+with type &ge; <constant>V4L2_CTRL_COMPOUND_TYPES</constant>). Specify both
+<constant>V4L2_CTRL_FLAG_NEXT_CTRL</constant> and
+<constant>V4L2_CTRL_FLAG_NEXT_COMPOUND</constant> in order to enumerate
+all controls, compound or not. Drivers which do not support these flags yet
+always return <errorcode>EINVAL</errorcode>.</para>
+
+    <para>The <constant>VIDIOC_QUERY_EXT_CTRL</constant> ioctl was
+introduced in order to better support controls that can use compound
+types, and to expose additional control information that cannot be
+returned in &v4l2-queryctrl; since that structure is full.</para>
+
+    <para><constant>VIDIOC_QUERY_EXT_CTRL</constant> is used in the
+same way as <constant>VIDIOC_QUERYCTRL</constant>, except that the
+<structfield>reserved</structfield> array must be zeroed as well.</para>
 
     <para>Additional information is required for menu controls: the
 names of the menu items. To query them applications set the
@@ -142,38 +165,23 @@ string. This information is intended for the user.</entry>
 	    <entry>__s32</entry>
 	    <entry><structfield>minimum</structfield></entry>
 	    <entry>Minimum value, inclusive. This field gives a lower
-bound for <constant>V4L2_CTRL_TYPE_INTEGER</constant> controls and the
-lowest valid index for <constant>V4L2_CTRL_TYPE_MENU</constant> controls.
-For <constant>V4L2_CTRL_TYPE_STRING</constant> controls the minimum value
-gives the minimum length of the string. This length <emphasis>does not include the terminating
-zero</emphasis>. It may not be valid for any other type of control, including
-<constant>V4L2_CTRL_TYPE_INTEGER64</constant> controls. Note that this is a
-signed value.</entry>
+bound for the control. See &v4l2-ctrl-type; how the minimum value is to
+be used for each possible control type. Note that this a signed 32-bit value.</entry>
 	  </row>
 	  <row>
 	    <entry>__s32</entry>
 	    <entry><structfield>maximum</structfield></entry>
 	    <entry>Maximum value, inclusive. This field gives an upper
-bound for <constant>V4L2_CTRL_TYPE_INTEGER</constant> controls and the
-highest valid index for <constant>V4L2_CTRL_TYPE_MENU</constant>
-controls. For <constant>V4L2_CTRL_TYPE_BITMASK</constant> controls it is the
-set of usable bits.
-For <constant>V4L2_CTRL_TYPE_STRING</constant> controls the maximum value
-gives the maximum length of the string. This length <emphasis>does not include the terminating
-zero</emphasis>. It may not be valid for any other type of control, including
-<constant>V4L2_CTRL_TYPE_INTEGER64</constant> controls. Note that this is a
-signed value.</entry>
+bound for the control. See &v4l2-ctrl-type; how the maximum value is to
+be used for each possible control type. Note that this a signed 32-bit value.</entry>
 	  </row>
 	  <row>
 	    <entry>__s32</entry>
 	    <entry><structfield>step</structfield></entry>
-	    <entry><para>This field gives a step size for
-<constant>V4L2_CTRL_TYPE_INTEGER</constant> controls. For
-<constant>V4L2_CTRL_TYPE_STRING</constant> controls this field refers to
-the string length that has to be a multiple of this step size.
-It may not be valid for any other type of control, including
-<constant>V4L2_CTRL_TYPE_INTEGER64</constant>
-controls.</para><para>Generally drivers should not scale hardware
+	    <entry><para>This field gives a step size for the control.
+See &v4l2-ctrl-type; how the step value is to be used for each possible
+control type. Note that this an unsigned 32-bit value.
+</para><para>Generally drivers should not scale hardware
 control values. It may be necessary for example when the
 <structfield>name</structfield> or <structfield>id</structfield> imply
 a particular unit and the hardware actually accepts only multiples of
@@ -192,10 +200,11 @@ be always positive.</para></entry>
 	    <entry><structfield>default_value</structfield></entry>
 	    <entry>The default value of a
 <constant>V4L2_CTRL_TYPE_INTEGER</constant>,
-<constant>_BOOLEAN</constant> or <constant>_MENU</constant> control.
-Not valid for other types of controls. Drivers reset controls only
-when the driver is loaded, not later, in particular not when the
-func-open; is called.</entry>
+<constant>_BOOLEAN</constant>, <constant>_BITMASK</constant>,
+<constant>_MENU</constant> or <constant>_INTEGER_MENU</constant> control.
+Not valid for other types of controls.
+Note that drivers reset controls to their default value only when the
+driver is first loaded, never afterwards.</entry>
 	  </row>
 	  <row>
 	    <entry>__u32</entry>
@@ -213,6 +222,125 @@ the array to zero.</entry>
       </tgroup>
     </table>
 
+    <table pgwide="1" frame="none" id="v4l2-query-ext-ctrl">
+      <title>struct <structname>v4l2_query_ext_ctrl</structname></title>
+      <tgroup cols="3">
+	&cs-str;
+	<tbody valign="top">
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>id</structfield></entry>
+	    <entry>Identifies the control, set by the application. See
+<xref linkend="control-id" /> for predefined IDs. When the ID is ORed
+with <constant>V4L2_CTRL_FLAG_NEXT_CTRL</constant> the driver clears the
+flag and returns the first non-compound control with a higher ID. When the
+ID is ORed with <constant>V4L2_CTRL_FLAG_NEXT_COMPOUND</constant> the driver
+clears the flag and returns the first compound control with a higher ID.
+Set both to get the first control (compound or not) with a higher ID.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>type</structfield></entry>
+	    <entry>Type of control, see <xref
+		linkend="v4l2-ctrl-type" />.</entry>
+	  </row>
+	  <row>
+	    <entry>char</entry>
+	    <entry><structfield>name</structfield>[32]</entry>
+	    <entry>Name of the control, a NUL-terminated ASCII
+string. This information is intended for the user.</entry>
+	  </row>
+	  <row>
+	    <entry>__s64</entry>
+	    <entry><structfield>minimum</structfield></entry>
+	    <entry>Minimum value, inclusive. This field gives a lower
+bound for the control. See &v4l2-ctrl-type; how the minimum value is to
+be used for each possible control type. Note that this a signed 64-bit value.</entry>
+	  </row>
+	  <row>
+	    <entry>__s64</entry>
+	    <entry><structfield>maximum</structfield></entry>
+	    <entry>Maximum value, inclusive. This field gives an upper
+bound for the control. See &v4l2-ctrl-type; how the maximum value is to
+be used for each possible control type. Note that this a signed 64-bit value.</entry>
+	  </row>
+	  <row>
+	    <entry>__u64</entry>
+	    <entry><structfield>step</structfield></entry>
+	    <entry><para>This field gives a step size for the control.
+See &v4l2-ctrl-type; how the step value is to be used for each possible
+control type. Note that this an unsigned 64-bit value.
+</para><para>Generally drivers should not scale hardware
+control values. It may be necessary for example when the
+<structfield>name</structfield> or <structfield>id</structfield> imply
+a particular unit and the hardware actually accepts only multiples of
+said unit. If so, drivers must take care values are properly rounded
+when scaling, such that errors will not accumulate on repeated
+read-write cycles.</para><para>This field gives the smallest change of
+an integer control actually affecting hardware. Often the information
+is needed when the user can change controls by keyboard or GUI
+buttons, rather than a slider. When for example a hardware register
+accepts values 0-511 and the driver reports 0-65535, step should be
+128.</para></entry>
+	  </row>
+	  <row>
+	    <entry>__s64</entry>
+	    <entry><structfield>default_value</structfield></entry>
+	    <entry>The default value of a
+<constant>V4L2_CTRL_TYPE_INTEGER</constant>, <constant>_INTEGER64</constant>,
+<constant>_BOOLEAN</constant>, <constant>_BITMASK</constant>,
+<constant>_MENU</constant> or <constant>_INTEGER_MENU</constant> control.
+Not valid for other types of controls.
+Note that drivers reset controls to their default value only when the
+driver is first loaded, never afterwards.
+</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>flags</structfield></entry>
+	    <entry>Control flags, see <xref
+		linkend="control-flags" />.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>elem_size</structfield></entry>
+	    <entry>The size in bytes of a single element of the array.
+Given a char pointer <constant>p</constant> to a 3-dimensional array you can find the
+position of cell <constant>(z, y, x)</constant> as follows:
+<constant>p + ((z * dims[1] + y) * dims[0] + x) * elem_size</constant>. <structfield>elem_size</structfield>
+is always valid, also when the control isn't an array. For string controls
+<structfield>elem_size</structfield> is equal to <structfield>maximum + 1</structfield>.
+</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>elems</structfield></entry>
+	    <entry>The number of elements in the N-dimensional array. If this control
+is not an array, then <structfield>elems</structfield> is 1. The <structfield>elems</structfield>
+field can never be 0.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>nr_of_dims</structfield></entry>
+	    <entry>The number of dimension in the N-dimensional array. If this control
+is not an array, then this field is 0.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>dims[V4L2_CTRL_MAX_DIMS]</structfield></entry>
+	    <entry>The size of each dimension. The first <structfield>nr_of_dims</structfield>
+elements of this array must be non-zero, all remaining elements must be zero.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>reserved</structfield>[18]</entry>
+	    <entry>Reserved for future extensions. Applications and drivers
+must set the array to zero.</entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+
     <table pgwide="1" frame="none" id="v4l2-querymenu">
       <title>struct <structname>v4l2_querymenu</structname></title>
       <tgroup cols="4">
@@ -347,11 +475,14 @@ Drivers must ignore the value passed with
 	  </row>
 	  <row>
 	    <entry><constant>V4L2_CTRL_TYPE_INTEGER64</constant></entry>
-	    <entry>n/a</entry>
-	    <entry>n/a</entry>
-	    <entry>n/a</entry>
+	    <entry>any</entry>
+	    <entry>any</entry>
+	    <entry>any</entry>
 	    <entry>A 64-bit integer valued control. Minimum, maximum
-and step size cannot be queried.</entry>
+and step size cannot be queried using <constant>VIDIOC_QUERYCTRL</constant>.
+Only <constant>VIDIOC_QUERY_EXT_CTRL</constant> can retrieve the 64-bit
+min/max/step values, they should be interpreted as n/a when using
+<constant>VIDIOC_QUERYCTRL</constant>.</entry>
 	  </row>
 	  <row>
 	    <entry><constant>V4L2_CTRL_TYPE_STRING</constant></entry>
@@ -450,6 +581,14 @@ is in auto-gain mode. In such a case the hardware calculates the gain value base
 the lighting conditions which can change over time. Note that setting a new value for
 a volatile control will have no effect. The new value will just be ignored.</entry>
 	  </row>
+	  <row>
+	    <entry><constant>V4L2_CTRL_FLAG_HAS_PAYLOAD</constant></entry>
+	    <entry>0x0100</entry>
+	    <entry>This control has a pointer type, so its value has to be accessed
+using one of the pointer fields of &v4l2-ext-control;. This flag is set for controls
+that are an array, string, or have a compound type. In all cases you have to set a
+pointer to memory containing the payload of the control.</entry>
+	  </row>
 	</tbody>
       </tgroup>
     </table>
-- 
2.0.0.rc0


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

* [REVIEWv4 PATCH 18/34] DocBook media: update VIDIOC_G/S/TRY_EXT_CTRLS.
  2014-06-12 11:52 ` [REVIEWv4 PATCH 01/34] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
                     ` (15 preceding siblings ...)
  2014-06-12 11:52   ` [REVIEWv4 PATCH 17/34] DocBook media: document VIDIOC_QUERY_EXT_CTRL Hans Verkuil
@ 2014-06-12 11:52   ` Hans Verkuil
  2014-06-12 11:52   ` [REVIEWv4 PATCH 19/34] DocBook media: fix coding style in the control example code Hans Verkuil
                     ` (15 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Hans Verkuil @ 2014-06-12 11:52 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, s.nawrocki, sakari.ailus, Hans Verkuil

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

Document the support for the new compound type controls.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 .../DocBook/media/v4l/vidioc-g-ext-ctrls.xml       | 37 +++++++++++++++++-----
 1 file changed, 29 insertions(+), 8 deletions(-)

diff --git a/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml b/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
index e9f6735..2a157b3 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
@@ -72,23 +72,30 @@ initialize the <structfield>id</structfield>,
 <structfield>size</structfield> and <structfield>reserved2</structfield> fields
 of each &v4l2-ext-control; and call the
 <constant>VIDIOC_G_EXT_CTRLS</constant> ioctl. String controls controls
-must also set the <structfield>string</structfield> field.</para>
+must also set the <structfield>string</structfield> field. Controls
+of compound types (<constant>V4L2_CTRL_FLAG_HAS_PAYLOAD</constant> is set)
+must set the <structfield>ptr</structfield> field.</para>
 
     <para>If the <structfield>size</structfield> is too small to
 receive the control result (only relevant for pointer-type controls
 like strings), then the driver will set <structfield>size</structfield>
 to a valid value and return an &ENOSPC;. You should re-allocate the
-string memory to this new size and try again. It is possible that the
-same issue occurs again if the string has grown in the meantime. It is
+memory to this new size and try again. For the string type it is possible that
+the same issue occurs again if the string has grown in the meantime. It is
 recommended to call &VIDIOC-QUERYCTRL; first and use
 <structfield>maximum</structfield>+1 as the new <structfield>size</structfield>
 value. It is guaranteed that that is sufficient memory.
 </para>
 
+    <para>N-dimensional arrays are set and retrieved row-by-row. You cannot set a partial
+array, all elements have to be set or retrieved. The total size is calculated
+as <structfield>elems</structfield> * <structfield>elem_size</structfield>.
+These values can be obtained by calling &VIDIOC-QUERY-EXT-CTRL;.</para>
+
     <para>To change the value of a set of controls applications
 initialize the <structfield>id</structfield>, <structfield>size</structfield>,
 <structfield>reserved2</structfield> and
-<structfield>value/string</structfield> fields of each &v4l2-ext-control; and
+<structfield>value/value64/string/ptr</structfield> fields of each &v4l2-ext-control; and
 call the <constant>VIDIOC_S_EXT_CTRLS</constant> ioctl. The controls
 will only be set if <emphasis>all</emphasis> control values are
 valid.</para>
@@ -96,7 +103,7 @@ valid.</para>
     <para>To check if a set of controls have correct values applications
 initialize the <structfield>id</structfield>, <structfield>size</structfield>,
 <structfield>reserved2</structfield> and
-<structfield>value/string</structfield> fields of each &v4l2-ext-control; and
+<structfield>value/value64/string/ptr</structfield> fields of each &v4l2-ext-control; and
 call the <constant>VIDIOC_TRY_EXT_CTRLS</constant> ioctl. It is up to
 the driver whether wrong values are automatically adjusted to a valid
 value or if an error is returned.</para>
@@ -158,19 +165,33 @@ applications must set the array to zero.</entry>
 	    <entry></entry>
 	    <entry>__s32</entry>
 	    <entry><structfield>value</structfield></entry>
-	    <entry>New value or current value.</entry>
+	    <entry>New value or current value. Valid if this control is not of
+type <constant>V4L2_CTRL_TYPE_INTEGER64</constant> and
+<constant>V4L2_CTRL_FLAG_HAS_PAYLOAD</constant> is not set.</entry>
 	  </row>
 	  <row>
 	    <entry></entry>
 	    <entry>__s64</entry>
 	    <entry><structfield>value64</structfield></entry>
-	    <entry>New value or current value.</entry>
+	    <entry>New value or current value. Valid if this control is of
+type <constant>V4L2_CTRL_TYPE_INTEGER64</constant> and
+<constant>V4L2_CTRL_FLAG_HAS_PAYLOAD</constant> is not set.</entry>
 	  </row>
 	  <row>
 	    <entry></entry>
 	    <entry>char *</entry>
 	    <entry><structfield>string</structfield></entry>
-	    <entry>A pointer to a string.</entry>
+	    <entry>A pointer to a string. Valid if this control is of
+type <constant>V4L2_CTRL_TYPE_STRING</constant>.</entry>
+	  </row>
+	  <row>
+	    <entry></entry>
+	    <entry>void *</entry>
+	    <entry><structfield>ptr</structfield></entry>
+	    <entry>A pointer to a compound type which can be an N-dimensional array and/or a
+compound type (the control's type is >= <constant>V4L2_CTRL_COMPOUND_TYPES</constant>).
+Valid if <constant>V4L2_CTRL_FLAG_HAS_PAYLOAD</constant> is set for this control.
+</entry>
 	  </row>
 	</tbody>
       </tgroup>
-- 
2.0.0.rc0


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

* [REVIEWv4 PATCH 19/34] DocBook media: fix coding style in the control example code
  2014-06-12 11:52 ` [REVIEWv4 PATCH 01/34] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
                     ` (16 preceding siblings ...)
  2014-06-12 11:52   ` [REVIEWv4 PATCH 18/34] DocBook media: update VIDIOC_G/S/TRY_EXT_CTRLS Hans Verkuil
@ 2014-06-12 11:52   ` Hans Verkuil
  2014-06-12 11:52   ` [REVIEWv4 PATCH 20/34] DocBook media: improve control section Hans Verkuil
                     ` (14 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Hans Verkuil @ 2014-06-12 11:52 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, s.nawrocki, sakari.ailus, Hans Verkuil

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

Use the proper kernel coding style in these examples.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 Documentation/DocBook/media/v4l/controls.xml | 81 ++++++++++++++--------------
 1 file changed, 40 insertions(+), 41 deletions(-)

diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml
index 47198ee..00cf0a7 100644
--- a/Documentation/DocBook/media/v4l/controls.xml
+++ b/Documentation/DocBook/media/v4l/controls.xml
@@ -441,61 +441,60 @@ more menu type controls.</para>
 &v4l2-queryctrl; queryctrl;
 &v4l2-querymenu; querymenu;
 
-static void
-enumerate_menu (void)
+static void enumerate_menu(void)
 {
-	printf ("  Menu items:\n");
+	printf("  Menu items:\n");
 
-	memset (&amp;querymenu, 0, sizeof (querymenu));
+	memset(&amp;querymenu, 0, sizeof(querymenu));
 	querymenu.id = queryctrl.id;
 
 	for (querymenu.index = queryctrl.minimum;
 	     querymenu.index &lt;= queryctrl.maximum;
-	      querymenu.index++) {
-		if (0 == ioctl (fd, &VIDIOC-QUERYMENU;, &amp;querymenu)) {
-			printf ("  %s\n", querymenu.name);
+	     querymenu.index++) {
+		if (0 == ioctl(fd, &VIDIOC-QUERYMENU;, &amp;querymenu)) {
+			printf("  %s\n", querymenu.name);
 		}
 	}
 }
 
-memset (&amp;queryctrl, 0, sizeof (queryctrl));
+memset(&amp;queryctrl, 0, sizeof(queryctrl));
 
 for (queryctrl.id = V4L2_CID_BASE;
      queryctrl.id &lt; V4L2_CID_LASTP1;
      queryctrl.id++) {
-	if (0 == ioctl (fd, &VIDIOC-QUERYCTRL;, &amp;queryctrl)) {
+	if (0 == ioctl(fd, &VIDIOC-QUERYCTRL;, &amp;queryctrl)) {
 		if (queryctrl.flags &amp; V4L2_CTRL_FLAG_DISABLED)
 			continue;
 
-		printf ("Control %s\n", queryctrl.name);
+		printf("Control %s\n", queryctrl.name);
 
 		if (queryctrl.type == V4L2_CTRL_TYPE_MENU)
-			enumerate_menu ();
+			enumerate_menu();
 	} else {
 		if (errno == EINVAL)
 			continue;
 
-		perror ("VIDIOC_QUERYCTRL");
-		exit (EXIT_FAILURE);
+		perror("VIDIOC_QUERYCTRL");
+		exit(EXIT_FAILURE);
 	}
 }
 
 for (queryctrl.id = V4L2_CID_PRIVATE_BASE;;
      queryctrl.id++) {
-	if (0 == ioctl (fd, &VIDIOC-QUERYCTRL;, &amp;queryctrl)) {
+	if (0 == ioctl(fd, &VIDIOC-QUERYCTRL;, &amp;queryctrl)) {
 		if (queryctrl.flags &amp; V4L2_CTRL_FLAG_DISABLED)
 			continue;
 
-		printf ("Control %s\n", queryctrl.name);
+		printf("Control %s\n", queryctrl.name);
 
 		if (queryctrl.type == V4L2_CTRL_TYPE_MENU)
-			enumerate_menu ();
+			enumerate_menu();
 	} else {
 		if (errno == EINVAL)
 			break;
 
-		perror ("VIDIOC_QUERYCTRL");
-		exit (EXIT_FAILURE);
+		perror("VIDIOC_QUERYCTRL");
+		exit(EXIT_FAILURE);
 	}
 }
 </programlisting>
@@ -508,53 +507,53 @@ for (queryctrl.id = V4L2_CID_PRIVATE_BASE;;
 &v4l2-queryctrl; queryctrl;
 &v4l2-control; control;
 
-memset (&amp;queryctrl, 0, sizeof (queryctrl));
+memset(&amp;queryctrl, 0, sizeof(queryctrl));
 queryctrl.id = V4L2_CID_BRIGHTNESS;
 
-if (-1 == ioctl (fd, &VIDIOC-QUERYCTRL;, &amp;queryctrl)) {
+if (-1 == ioctl(fd, &VIDIOC-QUERYCTRL;, &amp;queryctrl)) {
 	if (errno != EINVAL) {
-		perror ("VIDIOC_QUERYCTRL");
-		exit (EXIT_FAILURE);
+		perror("VIDIOC_QUERYCTRL");
+		exit(EXIT_FAILURE);
 	} else {
-		printf ("V4L2_CID_BRIGHTNESS is not supported\n");
+		printf("V4L2_CID_BRIGHTNESS is not supported\n");
 	}
 } else if (queryctrl.flags &amp; V4L2_CTRL_FLAG_DISABLED) {
-	printf ("V4L2_CID_BRIGHTNESS is not supported\n");
+	printf("V4L2_CID_BRIGHTNESS is not supported\n");
 } else {
-	memset (&amp;control, 0, sizeof (control));
+	memset(&amp;control, 0, sizeof (control));
 	control.id = V4L2_CID_BRIGHTNESS;
 	control.value = queryctrl.default_value;
 
-	if (-1 == ioctl (fd, &VIDIOC-S-CTRL;, &amp;control)) {
-		perror ("VIDIOC_S_CTRL");
-		exit (EXIT_FAILURE);
+	if (-1 == ioctl(fd, &VIDIOC-S-CTRL;, &amp;control)) {
+		perror("VIDIOC_S_CTRL");
+		exit(EXIT_FAILURE);
 	}
 }
 
-memset (&amp;control, 0, sizeof (control));
+memset(&amp;control, 0, sizeof(control));
 control.id = V4L2_CID_CONTRAST;
 
-if (0 == ioctl (fd, &VIDIOC-G-CTRL;, &amp;control)) {
+if (0 == ioctl(fd, &VIDIOC-G-CTRL;, &amp;control)) {
 	control.value += 1;
 
 	/* The driver may clamp the value or return ERANGE, ignored here */
 
-	if (-1 == ioctl (fd, &VIDIOC-S-CTRL;, &amp;control)
+	if (-1 == ioctl(fd, &VIDIOC-S-CTRL;, &amp;control)
 	    &amp;&amp; errno != ERANGE) {
-		perror ("VIDIOC_S_CTRL");
-		exit (EXIT_FAILURE);
+		perror("VIDIOC_S_CTRL");
+		exit(EXIT_FAILURE);
 	}
 /* Ignore if V4L2_CID_CONTRAST is unsupported */
 } else if (errno != EINVAL) {
-	perror ("VIDIOC_G_CTRL");
-	exit (EXIT_FAILURE);
+	perror("VIDIOC_G_CTRL");
+	exit(EXIT_FAILURE);
 }
 
 control.id = V4L2_CID_AUDIO_MUTE;
-control.value = TRUE; /* silence */
+control.value = 1; /* silence */
 
 /* Errors ignored */
-ioctl (fd, VIDIOC_S_CTRL, &amp;control);
+ioctl(fd, VIDIOC_S_CTRL, &amp;control);
 </programlisting>
     </example>
   </section>
@@ -675,12 +674,12 @@ control class is found:</para>
       <informalexample>
 	<programlisting>
 qctrl.id = V4L2_CTRL_CLASS_MPEG | V4L2_CTRL_FLAG_NEXT_CTRL;
-while (0 == ioctl (fd, &VIDIOC-QUERYCTRL;, &amp;qctrl)) {
-	if (V4L2_CTRL_ID2CLASS (qctrl.id) != V4L2_CTRL_CLASS_MPEG)
+while (0 == ioctl(fd, &VIDIOC-QUERYCTRL;, &amp;qctrl)) {
+	if (V4L2_CTRL_ID2CLASS(qctrl.id) != V4L2_CTRL_CLASS_MPEG)
 		break;
 		/* ... */
-		qctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
-	}
+	qctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
+}
 </programlisting>
       </informalexample>
 
-- 
2.0.0.rc0


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

* [REVIEWv4 PATCH 20/34] DocBook media: improve control section.
  2014-06-12 11:52 ` [REVIEWv4 PATCH 01/34] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
                     ` (17 preceding siblings ...)
  2014-06-12 11:52   ` [REVIEWv4 PATCH 19/34] DocBook media: fix coding style in the control example code Hans Verkuil
@ 2014-06-12 11:52   ` Hans Verkuil
  2014-06-12 11:52   ` [REVIEWv4 PATCH 21/34] DocBook media: update " Hans Verkuil
                     ` (13 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Hans Verkuil @ 2014-06-12 11:52 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, s.nawrocki, sakari.ailus, Hans Verkuil

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

Improve the control section:

- Clarify the handling of private controls
- Explain the V4L2_CTRL_FLAG_INACTIVE flag
- Remove obsolete text regarding missing control event (we have them
  today) and the incorrect V4L2_CTRL_FLAG_DISABLED reference.
- Add a code example on how to enumerate over user controls.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Reviewed-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
---
 Documentation/DocBook/media/v4l/controls.xml | 74 +++++++++++++++++++++-------
 1 file changed, 55 insertions(+), 19 deletions(-)

diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml
index 00cf0a7..73bae13 100644
--- a/Documentation/DocBook/media/v4l/controls.xml
+++ b/Documentation/DocBook/media/v4l/controls.xml
@@ -13,6 +13,19 @@ correctly with any device.</para>
     <para>All controls are accessed using an ID value. V4L2 defines
 several IDs for specific purposes. Drivers can also implement their
 own custom controls using <constant>V4L2_CID_PRIVATE_BASE</constant>
+<footnote><para>The use of <constant>V4L2_CID_PRIVATE_BASE</constant>
+is problematic because different drivers may use the same
+<constant>V4L2_CID_PRIVATE_BASE</constant> ID for different controls.
+This makes it hard to programatically set such controls since the meaning
+of the control with that ID is driver dependent. In order to resolve this
+drivers use unique IDs and the <constant>V4L2_CID_PRIVATE_BASE</constant>
+IDs are mapped to those unique IDs by the kernel. Consider these
+<constant>V4L2_CID_PRIVATE_BASE</constant> IDs as aliases to the real
+IDs.</para>
+<para>Many applications today still use the <constant>V4L2_CID_PRIVATE_BASE</constant>
+IDs instead of using &VIDIOC-QUERYCTRL; with the <constant>V4L2_CTRL_FLAG_NEXT_CTRL</constant>
+flag to enumerate all IDs, so support for <constant>V4L2_CID_PRIVATE_BASE</constant>
+is still around.</para></footnote>
 and higher values. The pre-defined control IDs have the prefix
 <constant>V4L2_CID_</constant>, and are listed in <xref
 linkend="control-id" />. The ID is used when querying the attributes of
@@ -31,25 +44,22 @@ the current video input or output, tuner or modulator, or audio input
 or output. Different in the sense of other bounds, another default and
 current value, step size or other menu items. A control with a certain
 <emphasis>custom</emphasis> ID can also change name and
-type.<footnote>
-	<para>It will be more convenient for applications if drivers
-make use of the <constant>V4L2_CTRL_FLAG_DISABLED</constant> flag, but
-that was never required.</para>
-      </footnote> Control values are stored globally, they do not
+type.</para>
+
+    <para>If a control is not applicable to the current configuration
+of the device (for example, it doesn't apply to the current video input)
+drivers set the <constant>V4L2_CTRL_FLAG_INACTIVE</constant> flag.</para>
+
+    <para>Control values are stored globally, they do not
 change when switching except to stay within the reported bounds. They
 also do not change &eg; when the device is opened or closed, when the
 tuner radio frequency is changed or generally never without
-application request. Since V4L2 specifies no event mechanism, panel
-applications intended to cooperate with other panel applications (be
-they built into a larger application, as a TV viewer) may need to
-regularly poll control values to update their user
-interface.<footnote>
-	<para>Applications could call an ioctl to request events.
-After another process called &VIDIOC-S-CTRL; or another ioctl changing
-shared properties the &func-select; function would indicate
-readability until any ioctl (querying the properties) is
-called.</para>
-      </footnote></para>
+application request.</para>
+
+    <para>V4L2 specifies an event mechanism to notify applications
+when controls change value (see &VIDIOC-SUBSCRIBE-EVENT;, event
+<constant>V4L2_EVENT_CTRL</constant>), panel applications might want to make
+use of that in order to always reflect the correct control value.</para>
 
     <para>
       All controls use machine endianness.
@@ -434,8 +444,8 @@ Drivers must implement <constant>VIDIOC_QUERYCTRL</constant>,
 controls, <constant>VIDIOC_QUERYMENU</constant> when it has one or
 more menu type controls.</para>
 
-    <example>
-      <title>Enumerating all controls</title>
+    <example id="enum_all_controls">
+      <title>Enumerating all user controls</title>
 
       <programlisting>
 &v4l2-queryctrl; queryctrl;
@@ -501,6 +511,32 @@ for (queryctrl.id = V4L2_CID_PRIVATE_BASE;;
     </example>
 
     <example>
+      <title>Enumerating all user controls (alternative)</title>
+	<programlisting>
+memset(&amp;queryctrl, 0, sizeof(queryctrl));
+
+queryctrl.id = V4L2_CTRL_CLASS_USER | V4L2_CTRL_FLAG_NEXT_CTRL;
+while (0 == ioctl(fd, &VIDIOC-QUERYCTRL;, &amp;queryctrl)) {
+	if (V4L2_CTRL_ID2CLASS(queryctrl.id) != V4L2_CTRL_CLASS_USER)
+		break;
+	if (queryctrl.flags &amp; V4L2_CTRL_FLAG_DISABLED)
+		continue;
+
+	printf("Control %s\n", queryctrl.name);
+
+	if (queryctrl.type == V4L2_CTRL_TYPE_MENU)
+		enumerate_menu();
+
+	queryctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
+}
+if (errno != EINVAL) {
+	perror("VIDIOC_QUERYCTRL");
+	exit(EXIT_FAILURE);
+}
+</programlisting>
+    </example>
+
+    <example>
       <title>Changing controls</title>
 
       <programlisting>
@@ -699,7 +735,7 @@ ID based on a control ID.</para>
 <constant>VIDIOC_QUERYCTRL</constant> will fail when used in
 combination with <constant>V4L2_CTRL_FLAG_NEXT_CTRL</constant>. In
 that case the old method of enumerating control should be used (see
-1.8). But if it is supported, then it is guaranteed to enumerate over
+<xref linkend="enum_all_controls" />). But if it is supported, then it is guaranteed to enumerate over
 all controls, including driver-private controls.</para>
     </section>
 
-- 
2.0.0.rc0


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

* [REVIEWv4 PATCH 21/34] DocBook media: update control section.
  2014-06-12 11:52 ` [REVIEWv4 PATCH 01/34] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
                     ` (18 preceding siblings ...)
  2014-06-12 11:52   ` [REVIEWv4 PATCH 20/34] DocBook media: improve control section Hans Verkuil
@ 2014-06-12 11:52   ` Hans Verkuil
  2014-06-12 11:52   ` [REVIEWv4 PATCH 22/34] v4l2-controls.txt: update to the new way of accessing controls Hans Verkuil
                     ` (12 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Hans Verkuil @ 2014-06-12 11:52 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, s.nawrocki, sakari.ailus, Hans Verkuil

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

Document the support for compound types in controls.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Reviewed-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
---
 Documentation/DocBook/media/v4l/controls.xml | 27 ++++++++++++++++++++-------
 1 file changed, 20 insertions(+), 7 deletions(-)

diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml
index 73bae13..e7b8b72 100644
--- a/Documentation/DocBook/media/v4l/controls.xml
+++ b/Documentation/DocBook/media/v4l/controls.xml
@@ -660,16 +660,29 @@ supported.</para>
 &v4l2-control;, except for the fact that it also allows for 64-bit
 values and pointers to be passed.</para>
 
+      <para>Since the &v4l2-ext-control; supports pointers it is now
+also possible to have controls with compound types such as N-dimensional arrays
+and/or structures. You need to specify the <constant>V4L2_CTRL_FLAG_NEXT_COMPOUND</constant>
+when enumerating controls to actually be able to see such compound controls.
+In other words, these controls with compound types should only be used
+programmatically.</para>
+
+      <para>Since such compound controls need to expose more information
+about themselves than is possible with &VIDIOC-QUERYCTRL; the
+&VIDIOC-QUERY-EXT-CTRL; ioctl was added. In particular, this ioctl gives
+the dimensions of the N-dimensional array if this control consists of more than
+one element.</para>
+
       <para>It is important to realize that due to the flexibility of
 controls it is necessary to check whether the control you want to set
 actually is supported in the driver and what the valid range of values
-is. So use the &VIDIOC-QUERYCTRL; and &VIDIOC-QUERYMENU; ioctls to
-check this. Also note that it is possible that some of the menu
-indices in a control of type <constant>V4L2_CTRL_TYPE_MENU</constant>
-may not be supported (<constant>VIDIOC_QUERYMENU</constant> will
-return an error). A good example is the list of supported MPEG audio
-bitrates. Some drivers only support one or two bitrates, others
-support a wider range.</para>
+is. So use the &VIDIOC-QUERYCTRL; (or &VIDIOC-QUERY-EXT-CTRL;) and
+&VIDIOC-QUERYMENU; ioctls to check this. Also note that it is possible
+that some of the menu indices in a control of type
+<constant>V4L2_CTRL_TYPE_MENU</constant> may not be supported
+(<constant>VIDIOC_QUERYMENU</constant> will return an error). A good
+example is the list of supported MPEG audio bitrates. Some drivers only
+support one or two bitrates, others support a wider range.</para>
 
       <para>
 	All controls use machine endianness.
-- 
2.0.0.rc0


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

* [REVIEWv4 PATCH 22/34] v4l2-controls.txt: update to the new way of accessing controls.
  2014-06-12 11:52 ` [REVIEWv4 PATCH 01/34] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
                     ` (19 preceding siblings ...)
  2014-06-12 11:52   ` [REVIEWv4 PATCH 21/34] DocBook media: update " Hans Verkuil
@ 2014-06-12 11:52   ` Hans Verkuil
  2014-06-12 11:52   ` [REVIEWv4 PATCH 23/34] v4l2-ctrls/videodev2.h: add u8 and u16 types Hans Verkuil
                     ` (11 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Hans Verkuil @ 2014-06-12 11:52 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, s.nawrocki, sakari.ailus, Hans Verkuil

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

The way current and new values are accessed has changed. Update the
document to bring it up to date with the code.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Reviewed-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
---
 Documentation/video4linux/v4l2-controls.txt | 61 ++++++++++++++++++-----------
 1 file changed, 38 insertions(+), 23 deletions(-)

diff --git a/Documentation/video4linux/v4l2-controls.txt b/Documentation/video4linux/v4l2-controls.txt
index c9ee9a7..0f84ce8 100644
--- a/Documentation/video4linux/v4l2-controls.txt
+++ b/Documentation/video4linux/v4l2-controls.txt
@@ -77,9 +77,9 @@ Basic usage for V4L2 and sub-device drivers
 
   Where foo->v4l2_dev is of type struct v4l2_device.
 
-  Finally, remove all control functions from your v4l2_ioctl_ops:
-  vidioc_queryctrl, vidioc_querymenu, vidioc_g_ctrl, vidioc_s_ctrl,
-  vidioc_g_ext_ctrls, vidioc_try_ext_ctrls and vidioc_s_ext_ctrls.
+  Finally, remove all control functions from your v4l2_ioctl_ops (if any):
+  vidioc_queryctrl, vidioc_query_ext_ctrl, vidioc_querymenu, vidioc_g_ctrl,
+  vidioc_s_ctrl, vidioc_g_ext_ctrls, vidioc_try_ext_ctrls and vidioc_s_ext_ctrls.
   Those are now no longer needed.
 
 1.3.2) For sub-device drivers do this:
@@ -258,8 +258,8 @@ The new control value has already been validated, so all you need to do is
 to actually update the hardware registers.
 
 You're done! And this is sufficient for most of the drivers we have. No need
-to do any validation of control values, or implement QUERYCTRL/QUERYMENU. And
-G/S_CTRL as well as G/TRY/S_EXT_CTRLS are automatically supported.
+to do any validation of control values, or implement QUERYCTRL, QUERY_EXT_CTRL
+and QUERYMENU. And G/S_CTRL as well as G/TRY/S_EXT_CTRLS are automatically supported.
 
 
 ==============================================================================
@@ -288,30 +288,45 @@ of v4l2_device.
 Accessing Control Values
 ========================
 
-The v4l2_ctrl struct contains these two unions:
+The following union is used inside the control framework to access control
+values:
 
-	/* The current control value. */
-	union {
+union v4l2_ctrl_ptr {
+	s32 *p_s32;
+	s64 *p_s64;
+	char *p_char;
+	void *p;
+};
+
+The v4l2_ctrl struct contains these fields that can be used to access both
+current and new values:
+
+	s32 val;
+	struct {
 		s32 val;
-		s64 val64;
-		char *string;
 	} cur;
 
-	/* The new control value. */
-	union {
-		s32 val;
-		s64 val64;
-		char *string;
-	};
 
-Within the control ops you can freely use these. The val and val64 speak for
-themselves. The string pointers point to character buffers of length
+	union v4l2_ctrl_ptr p_new;
+	union v4l2_ctrl_ptr p_cur;
+
+If the control has a simple s32 type type, then:
+
+	&ctrl->val == ctrl->p_new.p_s32
+	&ctrl->cur.val == ctrl->p_cur.p_s32
+
+For all other types use ctrl->p_cur.p<something>. Basically the val
+and cur.val fields can be considered an alias since these are used so often.
+
+Within the control ops you can freely use these. The val and cur.val speak for
+themselves. The p_char pointers point to character buffers of length
 ctrl->maximum + 1, and are always 0-terminated.
 
-In most cases 'cur' contains the current cached control value. When you create
-a new control this value is made identical to the default value. After calling
-v4l2_ctrl_handler_setup() this value is passed to the hardware. It is generally
-a good idea to call this function.
+Unless the control is marked volatile the p_cur field points to the the
+current cached control value. When you create a new control this value is made
+identical to the default value. After calling v4l2_ctrl_handler_setup() this
+value is passed to the hardware. It is generally a good idea to call this
+function.
 
 Whenever a new value is set that new value is automatically cached. This means
 that most drivers do not need to implement the g_volatile_ctrl() op. The
@@ -363,7 +378,7 @@ You can also take the handler lock yourself:
 
 	mutex_lock(&state->ctrl_handler.lock);
 	pr_info("String value is '%s'\n", ctrl1->p_cur.p_char);
-	printk(KERN_INFO "Integer value is '%s'\n", ctrl2->cur.val);
+	pr_info("Integer value is '%s'\n", ctrl2->cur.val);
 	mutex_unlock(&state->ctrl_handler.lock);
 
 
-- 
2.0.0.rc0


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

* [REVIEWv4 PATCH 23/34] v4l2-ctrls/videodev2.h: add u8 and u16 types.
  2014-06-12 11:52 ` [REVIEWv4 PATCH 01/34] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
                     ` (20 preceding siblings ...)
  2014-06-12 11:52   ` [REVIEWv4 PATCH 22/34] v4l2-controls.txt: update to the new way of accessing controls Hans Verkuil
@ 2014-06-12 11:52   ` Hans Verkuil
  2014-06-12 11:52   ` [REVIEWv4 PATCH 24/34] DocBook media: document new u8 and u16 control types Hans Verkuil
                     ` (10 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Hans Verkuil @ 2014-06-12 11:52 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, s.nawrocki, sakari.ailus, Hans Verkuil

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

These are needed by the upcoming patches for the motion detection
matrices.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/v4l2-core/v4l2-ctrls.c | 45 ++++++++++++++++++++++++++++++++----
 include/media/v4l2-ctrls.h           |  4 ++++
 include/uapi/linux/videodev2.h       |  4 ++++
 3 files changed, 49 insertions(+), 4 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 1086ae3..adf5485 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1174,6 +1174,10 @@ static bool std_equal(const struct v4l2_ctrl *ctrl, u32 idx,
 		return !strcmp(ptr1.p_char + idx, ptr2.p_char + idx);
 	case V4L2_CTRL_TYPE_INTEGER64:
 		return ptr1.p_s64[idx] == ptr2.p_s64[idx];
+	case V4L2_CTRL_TYPE_U8:
+		return ptr1.p_u8[idx] == ptr2.p_u8[idx];
+	case V4L2_CTRL_TYPE_U16:
+		return ptr1.p_u16[idx] == ptr2.p_u16[idx];
 	default:
 		if (ctrl->is_int)
 			return ptr1.p_s32[idx] == ptr2.p_s32[idx];
@@ -1201,6 +1205,12 @@ static void std_init(const struct v4l2_ctrl *ctrl, u32 idx,
 	case V4L2_CTRL_TYPE_BOOLEAN:
 		ptr.p_s32[idx] = ctrl->default_value;
 		break;
+	case V4L2_CTRL_TYPE_U8:
+		ptr.p_u8[idx] = ctrl->default_value;
+		break;
+	case V4L2_CTRL_TYPE_U16:
+		ptr.p_u16[idx] = ctrl->default_value;
+		break;
 	default:
 		idx *= ctrl->elem_size;
 		memset(ptr.p + idx, 0, ctrl->elem_size);
@@ -1242,6 +1252,12 @@ static void std_log(const struct v4l2_ctrl *ctrl)
 	case V4L2_CTRL_TYPE_STRING:
 		pr_cont("%s", ptr.p_char);
 		break;
+	case V4L2_CTRL_TYPE_U8:
+		pr_cont("%u", (unsigned)*ptr.p_u8);
+		break;
+	case V4L2_CTRL_TYPE_U16:
+		pr_cont("%u", (unsigned)*ptr.p_u16);
+		break;
 	default:
 		pr_cont("unknown type %d", ctrl->type);
 		break;
@@ -1272,6 +1288,10 @@ static int std_validate(const struct v4l2_ctrl *ctrl, u32 idx,
 		return ROUND_TO_RANGE(ptr.p_s32[idx], u32, ctrl);
 	case V4L2_CTRL_TYPE_INTEGER64:
 		return ROUND_TO_RANGE(ptr.p_s64[idx], u64, ctrl);
+	case V4L2_CTRL_TYPE_U8:
+		return ROUND_TO_RANGE(ptr.p_u8[idx], u8, ctrl);
+	case V4L2_CTRL_TYPE_U16:
+		return ROUND_TO_RANGE(ptr.p_u16[idx], u16, ctrl);
 
 	case V4L2_CTRL_TYPE_BOOLEAN:
 		ptr.p_s32[idx] = !!ptr.p_s32[idx];
@@ -1502,6 +1522,8 @@ static int check_range(enum v4l2_ctrl_type type,
 		if (step != 1 || max > 1 || min < 0)
 			return -ERANGE;
 		/* fall through */
+	case V4L2_CTRL_TYPE_U8:
+	case V4L2_CTRL_TYPE_U16:
 	case V4L2_CTRL_TYPE_INTEGER:
 	case V4L2_CTRL_TYPE_INTEGER64:
 		if (step == 0 || min > max || def < min || def > max)
@@ -1803,12 +1825,25 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 	}
 	is_array = nr_of_dims > 0;
 
-	if (type == V4L2_CTRL_TYPE_INTEGER64)
+	/* Prefill elem_size for all types handled by std_type_ops */
+	switch (type) {
+	case V4L2_CTRL_TYPE_INTEGER64:
 		elem_size = sizeof(s64);
-	else if (type == V4L2_CTRL_TYPE_STRING)
+		break;
+	case V4L2_CTRL_TYPE_STRING:
 		elem_size = max + 1;
-	else if (type < V4L2_CTRL_COMPOUND_TYPES)
-		elem_size = sizeof(s32);
+		break;
+	case V4L2_CTRL_TYPE_U8:
+		elem_size = sizeof(u8);
+		break;
+	case V4L2_CTRL_TYPE_U16:
+		elem_size = sizeof(u16);
+		break;
+	default:
+		if (type < V4L2_CTRL_COMPOUND_TYPES)
+			elem_size = sizeof(s32);
+		break;
+	}
 	tot_ctrl_size = elem_size * elems;
 
 	/* Sanity checks */
@@ -3148,6 +3183,8 @@ int v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl,
 	case V4L2_CTRL_TYPE_MENU:
 	case V4L2_CTRL_TYPE_INTEGER_MENU:
 	case V4L2_CTRL_TYPE_BITMASK:
+	case V4L2_CTRL_TYPE_U8:
+	case V4L2_CTRL_TYPE_U16:
 		if (ctrl->is_array)
 			return -EINVAL;
 		ret = check_range(ctrl->type, min, max, step, def);
diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
index 7915b1125..c630345 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -39,12 +39,16 @@ struct poll_table_struct;
 /** union v4l2_ctrl_ptr - A pointer to a control value.
  * @p_s32:	Pointer to a 32-bit signed value.
  * @p_s64:	Pointer to a 64-bit signed value.
+ * @p_u8:	Pointer to a 8-bit unsigned value.
+ * @p_u16:	Pointer to a 16-bit unsigned value.
  * @p_char:	Pointer to a string.
  * @p:		Pointer to a compound value.
  */
 union v4l2_ctrl_ptr {
 	s32 *p_s32;
 	s64 *p_s64;
+	u8 *p_u8;
+	u16 *p_u16;
 	char *p_char;
 	void *p;
 };
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 7d94adc..93ae827 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -1254,6 +1254,8 @@ struct v4l2_ext_control {
 		__s32 value;
 		__s64 value64;
 		char *string;
+		__u8 *p_u8;
+		__u16 *p_u16;
 		void *ptr;
 	};
 } __attribute__ ((packed));
@@ -1284,6 +1286,8 @@ enum v4l2_ctrl_type {
 
 	/* Compound types are >= 0x0100 */
 	V4L2_CTRL_COMPOUND_TYPES     = 0x0100,
+	V4L2_CTRL_TYPE_U8	     = 0x0100,
+	V4L2_CTRL_TYPE_U16	     = 0x0101,
 };
 
 /*  Used in the VIDIOC_QUERYCTRL ioctl for querying controls */
-- 
2.0.0.rc0


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

* [REVIEWv4 PATCH 24/34] DocBook media: document new u8 and u16 control types.
  2014-06-12 11:52 ` [REVIEWv4 PATCH 01/34] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
                     ` (21 preceding siblings ...)
  2014-06-12 11:52   ` [REVIEWv4 PATCH 23/34] v4l2-ctrls/videodev2.h: add u8 and u16 types Hans Verkuil
@ 2014-06-12 11:52   ` Hans Verkuil
  2014-06-12 11:52   ` [REVIEWv4 PATCH 25/34] v4l2-ctrls: fix comments Hans Verkuil
                     ` (9 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Hans Verkuil @ 2014-06-12 11:52 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, s.nawrocki, sakari.ailus, Hans Verkuil

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

These types are needed for the upcoming Motion Detection matrix
controls, so document them.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 .../DocBook/media/v4l/vidioc-g-ext-ctrls.xml       | 14 +++++++++++++
 .../DocBook/media/v4l/vidioc-queryctrl.xml         | 23 +++++++++++++++++++++-
 2 files changed, 36 insertions(+), 1 deletion(-)

diff --git a/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml b/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
index 2a157b3..c5bdbfc 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
@@ -186,6 +186,20 @@ type <constant>V4L2_CTRL_TYPE_STRING</constant>.</entry>
 	  </row>
 	  <row>
 	    <entry></entry>
+	    <entry>__u8 *</entry>
+	    <entry><structfield>p_u8</structfield></entry>
+	    <entry>A pointer to a matrix control of unsigned 8-bit values.
+Valid if this control is of type <constant>V4L2_CTRL_TYPE_U8</constant>.</entry>
+	  </row>
+	  <row>
+	    <entry></entry>
+	    <entry>__u16 *</entry>
+	    <entry><structfield>p_u16</structfield></entry>
+	    <entry>A pointer to a matrix control of unsigned 16-bit values.
+Valid if this control is of type <constant>V4L2_CTRL_TYPE_U16</constant>.</entry>
+	  </row>
+	  <row>
+	    <entry></entry>
 	    <entry>void *</entry>
 	    <entry><structfield>ptr</structfield></entry>
 	    <entry>A pointer to a compound type which can be an N-dimensional array and/or a
diff --git a/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml b/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml
index 30c4e8a..0dcb0af 100644
--- a/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml
@@ -289,7 +289,8 @@ accepts values 0-511 and the driver reports 0-65535, step should be
 	    <entry>The default value of a
 <constant>V4L2_CTRL_TYPE_INTEGER</constant>, <constant>_INTEGER64</constant>,
 <constant>_BOOLEAN</constant>, <constant>_BITMASK</constant>,
-<constant>_MENU</constant> or <constant>_INTEGER_MENU</constant> control.
+<constant>_MENU</constant>, <constant>_INTEGER_MENU</constant>,
+<constant>_U8</constant> or <constant>_U16</constant> control.
 Not valid for other types of controls.
 Note that drivers reset controls to their default value only when the
 driver is first loaded, never afterwards.
@@ -510,6 +511,26 @@ ioctl returns the name of the control class and this control type.
 Older drivers which do not support this feature return an
 &EINVAL;.</entry>
 	  </row>
+	  <row>
+	    <entry><constant>V4L2_CTRL_TYPE_U8</constant></entry>
+	    <entry>any</entry>
+	    <entry>any</entry>
+	    <entry>any</entry>
+	    <entry>An unsigned 8-bit valued control ranging from minimum to
+maximum inclusive. The step value indicates the increment between
+values which are actually different on the hardware. This type is only used
+in array controls.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CTRL_TYPE_U16</constant></entry>
+	    <entry>any</entry>
+	    <entry>any</entry>
+	    <entry>any</entry>
+	    <entry>An unsigned 16-bit valued control ranging from minimum to
+maximum inclusive. The step value indicates the increment between
+values which are actually different on the hardware. This type is only used
+in array controls.</entry>
+	  </row>
 	</tbody>
       </tgroup>
     </table>
-- 
2.0.0.rc0


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

* [REVIEWv4 PATCH 25/34] v4l2-ctrls: fix comments
  2014-06-12 11:52 ` [REVIEWv4 PATCH 01/34] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
                     ` (22 preceding siblings ...)
  2014-06-12 11:52   ` [REVIEWv4 PATCH 24/34] DocBook media: document new u8 and u16 control types Hans Verkuil
@ 2014-06-12 11:52   ` Hans Verkuil
  2014-06-12 11:52   ` [REVIEWv4 PATCH 26/34] v4l2-ctrls/v4l2-controls.h: add MD controls Hans Verkuil
                     ` (8 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Hans Verkuil @ 2014-06-12 11:52 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, s.nawrocki, sakari.ailus, Hans Verkuil

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

Various comments referred to videodev2.h, but the control definitions have
been moved to v4l2-controls.h.

Also add the same reminder message to each class of controls.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/v4l2-core/v4l2-ctrls.c | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index adf5485..5aaf15e 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -592,7 +592,7 @@ const char *v4l2_ctrl_get_name(u32 id)
 {
 	switch (id) {
 	/* USER controls */
-	/* Keep the order of the 'case's the same as in videodev2.h! */
+	/* Keep the order of the 'case's the same as in v4l2-controls.h! */
 	case V4L2_CID_USER_CLASS:		return "User Controls";
 	case V4L2_CID_BRIGHTNESS:		return "Brightness";
 	case V4L2_CID_CONTRAST:			return "Contrast";
@@ -754,7 +754,7 @@ const char *v4l2_ctrl_get_name(u32 id)
 	case V4L2_CID_MPEG_VIDEO_VPX_PROFILE:			return "VPX Profile";
 
 	/* CAMERA controls */
-	/* Keep the order of the 'case's the same as in videodev2.h! */
+	/* Keep the order of the 'case's the same as in v4l2-controls.h! */
 	case V4L2_CID_CAMERA_CLASS:		return "Camera Controls";
 	case V4L2_CID_EXPOSURE_AUTO:		return "Auto Exposure";
 	case V4L2_CID_EXPOSURE_ABSOLUTE:	return "Exposure Time, Absolute";
@@ -788,8 +788,8 @@ const char *v4l2_ctrl_get_name(u32 id)
 	case V4L2_CID_AUTO_FOCUS_STATUS:	return "Auto Focus, Status";
 	case V4L2_CID_AUTO_FOCUS_RANGE:		return "Auto Focus, Range";
 
-	/* FM Radio Modulator control */
-	/* Keep the order of the 'case's the same as in videodev2.h! */
+	/* FM Radio Modulator controls */
+	/* Keep the order of the 'case's the same as in v4l2-controls.h! */
 	case V4L2_CID_FM_TX_CLASS:		return "FM Radio Modulator Controls";
 	case V4L2_CID_RDS_TX_DEVIATION:		return "RDS Signal Deviation";
 	case V4L2_CID_RDS_TX_PI:		return "RDS Program ID";
@@ -812,6 +812,7 @@ const char *v4l2_ctrl_get_name(u32 id)
 	case V4L2_CID_TUNE_ANTENNA_CAPACITOR:	return "Tune Antenna Capacitor";
 
 	/* Flash controls */
+	/* Keep the order of the 'case's the same as in v4l2-controls.h! */
 	case V4L2_CID_FLASH_CLASS:		return "Flash Controls";
 	case V4L2_CID_FLASH_LED_MODE:		return "LED Mode";
 	case V4L2_CID_FLASH_STROBE_SOURCE:	return "Strobe Source";
@@ -827,7 +828,7 @@ const char *v4l2_ctrl_get_name(u32 id)
 	case V4L2_CID_FLASH_READY:		return "Ready to Strobe";
 
 	/* JPEG encoder controls */
-	/* Keep the order of the 'case's the same as in videodev2.h! */
+	/* Keep the order of the 'case's the same as in v4l2-controls.h! */
 	case V4L2_CID_JPEG_CLASS:		return "JPEG Compression Controls";
 	case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:	return "Chroma Subsampling";
 	case V4L2_CID_JPEG_RESTART_INTERVAL:	return "Restart Interval";
@@ -835,18 +836,21 @@ const char *v4l2_ctrl_get_name(u32 id)
 	case V4L2_CID_JPEG_ACTIVE_MARKER:	return "Active Markers";
 
 	/* Image source controls */
+	/* Keep the order of the 'case's the same as in v4l2-controls.h! */
 	case V4L2_CID_IMAGE_SOURCE_CLASS:	return "Image Source Controls";
 	case V4L2_CID_VBLANK:			return "Vertical Blanking";
 	case V4L2_CID_HBLANK:			return "Horizontal Blanking";
 	case V4L2_CID_ANALOGUE_GAIN:		return "Analogue Gain";
 
 	/* Image processing controls */
+	/* Keep the order of the 'case's the same as in v4l2-controls.h! */
 	case V4L2_CID_IMAGE_PROC_CLASS:		return "Image Processing Controls";
 	case V4L2_CID_LINK_FREQ:		return "Link Frequency";
 	case V4L2_CID_PIXEL_RATE:		return "Pixel Rate";
 	case V4L2_CID_TEST_PATTERN:		return "Test Pattern";
 
 	/* DV controls */
+	/* Keep the order of the 'case's the same as in v4l2-controls.h! */
 	case V4L2_CID_DV_CLASS:			return "Digital Video Controls";
 	case V4L2_CID_DV_TX_HOTPLUG:		return "Hotplug Present";
 	case V4L2_CID_DV_TX_RXSENSE:		return "RxSense Present";
-- 
2.0.0.rc0


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

* [REVIEWv4 PATCH 26/34] v4l2-ctrls/v4l2-controls.h: add MD controls
  2014-06-12 11:52 ` [REVIEWv4 PATCH 01/34] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
                     ` (23 preceding siblings ...)
  2014-06-12 11:52   ` [REVIEWv4 PATCH 25/34] v4l2-ctrls: fix comments Hans Verkuil
@ 2014-06-12 11:52   ` Hans Verkuil
  2014-06-12 11:52   ` [REVIEWv4 PATCH 27/34] DocBook media: document new motion detection controls Hans Verkuil
                     ` (7 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Hans Verkuil @ 2014-06-12 11:52 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, s.nawrocki, sakari.ailus, Hans Verkuil

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

Add the 'Detect' control class and the new motion detection controls.
Those controls will be used by the solo6x10 and go7007 drivers.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/v4l2-core/v4l2-ctrls.c | 27 +++++++++++++++++++++++++++
 include/uapi/linux/v4l2-controls.h   | 17 +++++++++++++++++
 2 files changed, 44 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 5aaf15e..5c3b8de 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -462,6 +462,13 @@ const char * const *v4l2_ctrl_get_menu(u32 id)
 		"RGB full range (0-255)",
 		NULL,
 	};
+	static const char * const detect_md_mode[] = {
+		"Disabled",
+		"Global",
+		"Threshold Grid",
+		"Region Grid",
+		NULL,
+	};
 
 
 	switch (id) {
@@ -553,6 +560,8 @@ const char * const *v4l2_ctrl_get_menu(u32 id)
 	case V4L2_CID_DV_TX_RGB_RANGE:
 	case V4L2_CID_DV_RX_RGB_RANGE:
 		return dv_rgb_range;
+	case V4L2_CID_DETECT_MD_MODE:
+		return detect_md_mode;
 
 	default:
 		return NULL;
@@ -874,6 +883,15 @@ const char *v4l2_ctrl_get_name(u32 id)
 	case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO:	return "Bandwidth, Auto";
 	case V4L2_CID_RF_TUNER_BANDWIDTH:	return "Bandwidth";
 	case V4L2_CID_RF_TUNER_PLL_LOCK:	return "PLL Lock";
+
+	/* Detection controls */
+	/* Keep the order of the 'case's the same as in v4l2-controls.h! */
+	case V4L2_CID_DETECT_CLASS:		return "Detection Controls";
+	case V4L2_CID_DETECT_MD_MODE:		return "Motion Detection Mode";
+	case V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD: return "MD Global Threshold";
+	case V4L2_CID_DETECT_MD_THRESHOLD_GRID:	return "MD Threshold Grid";
+	case V4L2_CID_DETECT_MD_REGION_GRID:	return "MD Region Grid";
+
 	default:
 		return NULL;
 	}
@@ -992,6 +1010,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
 	case V4L2_CID_TEST_PATTERN:
 	case V4L2_CID_TUNE_DEEMPHASIS:
 	case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL:
+	case V4L2_CID_DETECT_MD_MODE:
 		*type = V4L2_CTRL_TYPE_MENU;
 		break;
 	case V4L2_CID_LINK_FREQ:
@@ -1018,6 +1037,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
 	case V4L2_CID_DV_CLASS:
 	case V4L2_CID_FM_RX_CLASS:
 	case V4L2_CID_RF_TUNER_CLASS:
+	case V4L2_CID_DETECT_CLASS:
 		*type = V4L2_CTRL_TYPE_CTRL_CLASS;
 		/* You can neither read not write these */
 		*flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY;
@@ -1063,6 +1083,12 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
 		*type = V4L2_CTRL_TYPE_INTEGER64;
 		*flags |= V4L2_CTRL_FLAG_READ_ONLY;
 		break;
+	case V4L2_CID_DETECT_MD_REGION_GRID:
+		*type = V4L2_CTRL_TYPE_U8;
+		break;
+	case V4L2_CID_DETECT_MD_THRESHOLD_GRID:
+		*type = V4L2_CTRL_TYPE_U16;
+		break;
 	default:
 		*type = V4L2_CTRL_TYPE_INTEGER;
 		break;
@@ -1103,6 +1129,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
 	case V4L2_CID_RF_TUNER_MIXER_GAIN:
 	case V4L2_CID_RF_TUNER_IF_GAIN:
 	case V4L2_CID_RF_TUNER_BANDWIDTH:
+	case V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD:
 		*flags |= V4L2_CTRL_FLAG_SLIDER;
 		break;
 	case V4L2_CID_PAN_RELATIVE:
diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
index 2ac5597..db526d1 100644
--- a/include/uapi/linux/v4l2-controls.h
+++ b/include/uapi/linux/v4l2-controls.h
@@ -61,6 +61,7 @@
 #define V4L2_CTRL_CLASS_DV		0x00a00000	/* Digital Video controls */
 #define V4L2_CTRL_CLASS_FM_RX		0x00a10000	/* FM Receiver controls */
 #define V4L2_CTRL_CLASS_RF_TUNER	0x00a20000	/* RF tuner controls */
+#define V4L2_CTRL_CLASS_DETECT		0x00a30000	/* Detection controls */
 
 /* User-class control IDs */
 
@@ -914,4 +915,20 @@ enum v4l2_deemphasis {
 #define V4L2_CID_RF_TUNER_IF_GAIN		(V4L2_CID_RF_TUNER_CLASS_BASE + 62)
 #define V4L2_CID_RF_TUNER_PLL_LOCK			(V4L2_CID_RF_TUNER_CLASS_BASE + 91)
 
+
+/*  Detection-class control IDs defined by V4L2 */
+#define V4L2_CID_DETECT_CLASS_BASE		(V4L2_CTRL_CLASS_DETECT | 0x900)
+#define V4L2_CID_DETECT_CLASS			(V4L2_CTRL_CLASS_DETECT | 1)
+
+#define V4L2_CID_DETECT_MD_MODE			(V4L2_CID_DETECT_CLASS_BASE + 1)
+enum v4l2_detect_md_mode {
+	V4L2_DETECT_MD_MODE_DISABLED		= 0,
+	V4L2_DETECT_MD_MODE_GLOBAL		= 1,
+	V4L2_DETECT_MD_MODE_THRESHOLD_GRID	= 2,
+	V4L2_DETECT_MD_MODE_REGION_GRID		= 3,
+};
+#define V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD	(V4L2_CID_DETECT_CLASS_BASE + 2)
+#define V4L2_CID_DETECT_MD_THRESHOLD_GRID	(V4L2_CID_DETECT_CLASS_BASE + 3)
+#define V4L2_CID_DETECT_MD_REGION_GRID		(V4L2_CID_DETECT_CLASS_BASE + 4)
+
 #endif
-- 
2.0.0.rc0


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

* [REVIEWv4 PATCH 27/34] DocBook media: document new motion detection controls.
  2014-06-12 11:52 ` [REVIEWv4 PATCH 01/34] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
                     ` (24 preceding siblings ...)
  2014-06-12 11:52   ` [REVIEWv4 PATCH 26/34] v4l2-ctrls/v4l2-controls.h: add MD controls Hans Verkuil
@ 2014-06-12 11:52   ` Hans Verkuil
  2014-06-12 11:53   ` [REVIEWv4 PATCH 28/34] v4l2: add a motion detection event Hans Verkuil
                     ` (6 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Hans Verkuil @ 2014-06-12 11:52 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, s.nawrocki, sakari.ailus, Hans Verkuil

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

Document the 'Detect' control class and the new Motion Detection controls.
Those controls will be used by the solo6x10 and go7007 drivers.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 Documentation/DocBook/media/v4l/controls.xml | 96 ++++++++++++++++++++++++++++
 1 file changed, 96 insertions(+)

diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml
index e7b8b72..cc0087e 100644
--- a/Documentation/DocBook/media/v4l/controls.xml
+++ b/Documentation/DocBook/media/v4l/controls.xml
@@ -5055,6 +5055,102 @@ defines possible values for de-emphasis. Here they are:</entry>
         </tbody>
       </tgroup>
       </table>
+    </section>
+
+    <section id="detect-controls">
+      <title>Detect Control Reference</title>
+
+      <para>The Detect class includes controls for common features of
+      various motion or object detection capable devices.</para>
+
+      <table pgwide="1" frame="none" id="detect-control-id">
+      <title>Detect Control IDs</title>
+
+      <tgroup cols="4">
+        <colspec colname="c1" colwidth="1*" />
+        <colspec colname="c2" colwidth="6*" />
+        <colspec colname="c3" colwidth="2*" />
+        <colspec colname="c4" colwidth="6*" />
+        <spanspec namest="c1" nameend="c2" spanname="id" />
+        <spanspec namest="c2" nameend="c4" spanname="descr" />
+        <thead>
+          <row>
+            <entry spanname="id" align="left">ID</entry>
+            <entry align="left">Type</entry>
+          </row><row rowsep="1"><entry spanname="descr" align="left">Description</entry>
+          </row>
+        </thead>
+        <tbody valign="top">
+          <row><entry></entry></row>
+          <row>
+            <entry spanname="id"><constant>V4L2_CID_DETECT_CLASS</constant>&nbsp;</entry>
+            <entry>class</entry>
+          </row><row><entry spanname="descr">The Detect class
+descriptor. Calling &VIDIOC-QUERYCTRL; for this control will return a
+description of this control class.</entry>
+          </row>
+          <row>
+            <entry spanname="id"><constant>V4L2_CID_DETECT_MD_MODE</constant>&nbsp;</entry>
+            <entry>menu</entry>
+          </row><row><entry spanname="descr">Sets the motion detection mode.</entry>
+          </row>
+	  <row>
+	    <entrytbl spanname="descr" cols="2">
+	      <tbody valign="top">
+		<row>
+		  <entry><constant>V4L2_DETECT_MD_MODE_DISABLED</constant>
+		  </entry><entry>Disable motion detection.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_DETECT_MD_MODE_GLOBAL</constant>
+		  </entry><entry>Use a single motion detection threshold.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_DETECT_MD_MODE_THRESHOLD_GRID</constant>
+		  </entry><entry>The image is divided into a grid, each cell with its own
+		  motion detection threshold. These thresholds are set through the
+		  <constant>V4L2_CID_DETECT_MD_THRESHOLD_GRID</constant> matrix control.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_DETECT_MD_MODE_REGION_GRID</constant>
+		  </entry><entry>The image is divided into a grid, each cell with its own
+		  region value that specifies which per-region motion detection thresholds
+		  should be used. Each region has its own thresholds. How these per-region
+		  thresholds are set up is driver-specific. The region values for the grid are set
+		  through the <constant>V4L2_CID_DETECT_MD_REGION_GRID</constant> matrix
+		  control.</entry>
+		</row>
+	      </tbody>
+	    </entrytbl>
+	  </row>
+          <row>
+	    <entry spanname="id"><constant>V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD</constant>&nbsp;</entry>
+	    <entry>integer</entry>
+	  </row>
+	  <row><entry spanname="descr">Sets the global motion detection threshold to be
+	  used with the <constant>V4L2_DETECT_MD_MODE_GLOBAL</constant> motion detection mode.</entry>
+          </row>
+          <row>
+	    <entry spanname="id"><constant>V4L2_CID_DETECT_MD_THRESHOLD_GRID</constant>&nbsp;</entry>
+	    <entry>__u16 matrix</entry>
+	  </row>
+	  <row><entry spanname="descr">Sets the motion detection thresholds for each cell in the grid.
+	  To be used with the <constant>V4L2_DETECT_MD_MODE_THRESHOLD_GRID</constant>
+	  motion detection mode. Matrix element (0, 0) represents the cell at the top-left of the
+	  grid.</entry>
+          </row>
+          <row>
+	    <entry spanname="id"><constant>V4L2_CID_DETECT_MD_REGION_GRID</constant>&nbsp;</entry>
+	    <entry>__u8 matrix</entry>
+	  </row>
+	  <row><entry spanname="descr">Sets the motion detection region value for each cell in the grid.
+	  To be used with the <constant>V4L2_DETECT_MD_MODE_REGION_GRID</constant>
+	  motion detection mode. Matrix element (0, 0) represents the cell at the top-left of the
+	  grid.</entry>
+          </row>
+        </tbody>
+      </tgroup>
+      </table>
 
       </section>
 
-- 
2.0.0.rc0


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

* [REVIEWv4 PATCH 28/34] v4l2: add a motion detection event.
  2014-06-12 11:52 ` [REVIEWv4 PATCH 01/34] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
                     ` (25 preceding siblings ...)
  2014-06-12 11:52   ` [REVIEWv4 PATCH 27/34] DocBook media: document new motion detection controls Hans Verkuil
@ 2014-06-12 11:53   ` Hans Verkuil
  2014-06-12 11:53   ` [REVIEWv4 PATCH 29/34] DocBook: document new v4l " Hans Verkuil
                     ` (5 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Hans Verkuil @ 2014-06-12 11:53 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, s.nawrocki, sakari.ailus, Hans Verkuil

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

Add a new MOTION_DET event to signal when motion is detected.

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

diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 93ae827..f7defeb 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -1799,6 +1799,7 @@ struct v4l2_streamparm {
 #define V4L2_EVENT_CTRL				3
 #define V4L2_EVENT_FRAME_SYNC			4
 #define V4L2_EVENT_SOURCE_CHANGE		5
+#define V4L2_EVENT_MOTION_DET			6
 #define V4L2_EVENT_PRIVATE_START		0x08000000
 
 /* Payload for V4L2_EVENT_VSYNC */
@@ -1836,6 +1837,21 @@ struct v4l2_event_src_change {
 	__u32 changes;
 };
 
+#define V4L2_EVENT_MD_FL_HAVE_FRAME_SEQ	(1 << 0)
+
+/**
+ * struct v4l2_event_motion_det - motion detection event
+ * @flags:             if V4L2_EVENT_MD_FL_HAVE_FRAME_SEQ is set, then the
+ *                     frame_sequence field is valid.
+ * @frame_sequence:    the frame sequence number associated with this event.
+ * @region_mask:       which regions detected motion.
+ */
+struct v4l2_event_motion_det {
+	__u32 flags;
+	__u32 frame_sequence;
+	__u32 region_mask;
+};
+
 struct v4l2_event {
 	__u32				type;
 	union {
@@ -1843,6 +1859,7 @@ struct v4l2_event {
 		struct v4l2_event_ctrl		ctrl;
 		struct v4l2_event_frame_sync	frame_sync;
 		struct v4l2_event_src_change	src_change;
+		struct v4l2_event_motion_det	motion_det;
 		__u8				data[64];
 	} u;
 	__u32				pending;
-- 
2.0.0.rc0


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

* [REVIEWv4 PATCH 29/34] DocBook: document new v4l motion detection event.
  2014-06-12 11:52 ` [REVIEWv4 PATCH 01/34] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
                     ` (26 preceding siblings ...)
  2014-06-12 11:53   ` [REVIEWv4 PATCH 28/34] v4l2: add a motion detection event Hans Verkuil
@ 2014-06-12 11:53   ` Hans Verkuil
  2014-06-12 11:53   ` [REVIEWv4 PATCH 30/34] solo6x10: implement the new motion detection controls Hans Verkuil
                     ` (4 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Hans Verkuil @ 2014-06-12 11:53 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, s.nawrocki, sakari.ailus, Hans Verkuil

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

Document the new motion detection event.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 Documentation/DocBook/media/v4l/vidioc-dqevent.xml | 44 ++++++++++++++++++++++
 .../DocBook/media/v4l/vidioc-subscribe-event.xml   |  8 ++++
 2 files changed, 52 insertions(+)

diff --git a/Documentation/DocBook/media/v4l/vidioc-dqevent.xml b/Documentation/DocBook/media/v4l/vidioc-dqevent.xml
index 820f86e..f3767fb 100644
--- a/Documentation/DocBook/media/v4l/vidioc-dqevent.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-dqevent.xml
@@ -94,6 +94,12 @@
 	  </row>
 	  <row>
 	    <entry></entry>
+	    <entry>&v4l2-event-motion-det;</entry>
+            <entry><structfield>motion_det</structfield></entry>
+	    <entry>Event data for event V4L2_EVENT_MOTION_DET.</entry>
+	  </row>
+	  <row>
+	    <entry></entry>
 	    <entry>__u8</entry>
             <entry><structfield>data</structfield>[64]</entry>
 	    <entry>Event data. Defined by the event type. The union
@@ -258,6 +264,44 @@
       </tgroup>
     </table>
 
+    <table frame="none" pgwide="1" id="v4l2-event-motion-det">
+      <title>struct <structname>v4l2_event_motion_det</structname></title>
+      <tgroup cols="3">
+	&cs-str;
+	<tbody valign="top">
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>flags</structfield></entry>
+	    <entry>
+	      Currently only one flag is available: if <constant>V4L2_EVENT_MD_FL_HAVE_FRAME_SEQ</constant>
+	      is set, then the <structfield>frame_sequence</structfield> field is valid,
+	      otherwise that field should be ignored.
+	    </entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>frame_sequence</structfield></entry>
+	    <entry>
+	      The sequence number of the frame being received. Only valid if the
+	      <constant>V4L2_EVENT_MD_FL_HAVE_FRAME_SEQ</constant> flag was set.
+	    </entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>region_mask</structfield></entry>
+	    <entry>
+	      The bitmask of the regions that reported motion. There is at least one
+	      region. If this field is 0, then no motion was detected at all.
+	      If there is no <constant>V4L2_CID_DETECT_MD_REGION_GRID</constant> control
+	      (see <xref linkend="detect-controls" />) to assign a different region
+	      to each cell in the motion detection grid, then that all cells
+	      are automatically assigned to the default region 0.
+	    </entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+
     <table pgwide="1" frame="none" id="changes-flags">
       <title>Changes</title>
       <tgroup cols="3">
diff --git a/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml b/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml
index 17efa87..9f60956 100644
--- a/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml
@@ -175,6 +175,14 @@
 	    </entry>
 	  </row>
 	  <row>
+	    <entry><constant>V4L2_EVENT_MOTION_DET</constant></entry>
+	    <entry>5</entry>
+	    <entry>
+	      <para>Triggered whenever the motion detection state for one or more of the regions
+	      changes. This event has a &v4l2-event-motion-det; associated with it.</para>
+	    </entry>
+	  </row>
+	  <row>
 	    <entry><constant>V4L2_EVENT_PRIVATE_START</constant></entry>
 	    <entry>0x08000000</entry>
 	    <entry>Base event number for driver-private events.</entry>
-- 
2.0.0.rc0


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

* [REVIEWv4 PATCH 30/34] solo6x10: implement the new motion detection controls.
  2014-06-12 11:52 ` [REVIEWv4 PATCH 01/34] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
                     ` (27 preceding siblings ...)
  2014-06-12 11:53   ` [REVIEWv4 PATCH 29/34] DocBook: document new v4l " Hans Verkuil
@ 2014-06-12 11:53   ` Hans Verkuil
  2014-06-12 11:53   ` [REVIEWv4 PATCH 31/34] solo6x10: implement the motion detection event Hans Verkuil
                     ` (3 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Hans Verkuil @ 2014-06-12 11:53 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, s.nawrocki, sakari.ailus, Hans Verkuil

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

Replace the custom ioctls to set motion detection thresholds by standard
matrix controls.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/staging/media/solo6x10/solo6x10-disp.c     |   4 +-
 drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c | 103 +++++++--------------
 drivers/staging/media/solo6x10/solo6x10.h          |  19 +---
 3 files changed, 39 insertions(+), 87 deletions(-)

diff --git a/drivers/staging/media/solo6x10/solo6x10-disp.c b/drivers/staging/media/solo6x10/solo6x10-disp.c
index 145295a..44d98b8 100644
--- a/drivers/staging/media/solo6x10/solo6x10-disp.c
+++ b/drivers/staging/media/solo6x10/solo6x10-disp.c
@@ -211,7 +211,7 @@ int solo_set_motion_threshold(struct solo_dev *solo_dev, u8 ch, u16 val)
 }
 
 int solo_set_motion_block(struct solo_dev *solo_dev, u8 ch,
-		const struct solo_motion_thresholds *thresholds)
+		const u16 *thresholds)
 {
 	u32 off = SOLO_MOT_FLAG_AREA + ch * SOLO_MOT_THRESH_SIZE * 2;
 	u16 buf[64];
@@ -221,7 +221,7 @@ int solo_set_motion_block(struct solo_dev *solo_dev, u8 ch,
 	memset(buf, 0, sizeof(buf));
 	for (y = 0; y < SOLO_MOTION_SZ; y++) {
 		for (x = 0; x < SOLO_MOTION_SZ; x++)
-			buf[x] = cpu_to_le16(thresholds->thresholds[y][x]);
+			buf[x] = cpu_to_le16(thresholds[y * SOLO_MOTION_SZ + x]);
 		ret |= solo_p2m_dma(solo_dev, 1, buf,
 			SOLO_MOTION_EXT_ADDR(solo_dev) + off + y * sizeof(buf),
 			sizeof(buf), 0, 0);
diff --git a/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c b/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
index 09ce30b..67b40a4 100644
--- a/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
+++ b/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
@@ -1068,31 +1068,6 @@ static int solo_s_parm(struct file *file, void *priv,
 	return solo_g_parm(file, priv, sp);
 }
 
-static long solo_enc_default(struct file *file, void *fh,
-			bool valid_prio, unsigned int cmd, void *arg)
-{
-	struct solo_enc_dev *solo_enc = video_drvdata(file);
-	struct solo_dev *solo_dev = solo_enc->solo_dev;
-	struct solo_motion_thresholds *thresholds = arg;
-
-	switch (cmd) {
-	case SOLO_IOC_G_MOTION_THRESHOLDS:
-		*thresholds = solo_enc->motion_thresholds;
-		return 0;
-
-	case SOLO_IOC_S_MOTION_THRESHOLDS:
-		if (!valid_prio)
-			return -EBUSY;
-		solo_enc->motion_thresholds = *thresholds;
-		if (solo_enc->motion_enabled && !solo_enc->motion_global)
-			return solo_set_motion_block(solo_dev, solo_enc->ch,
-						&solo_enc->motion_thresholds);
-		return 0;
-	default:
-		return -ENOTTY;
-	}
-}
-
 static int solo_s_ctrl(struct v4l2_ctrl *ctrl)
 {
 	struct solo_enc_dev *solo_enc =
@@ -1111,25 +1086,30 @@ static int solo_s_ctrl(struct v4l2_ctrl *ctrl)
 	case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
 		solo_enc->gop = ctrl->val;
 		return 0;
-	case V4L2_CID_MOTION_THRESHOLD:
-		solo_enc->motion_thresh = ctrl->val;
+	case V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD:
+		solo_enc->motion_thresh = ctrl->val << 8;
 		if (!solo_enc->motion_global || !solo_enc->motion_enabled)
 			return 0;
 		return solo_set_motion_threshold(solo_dev, solo_enc->ch,
-			ctrl->val);
-	case V4L2_CID_MOTION_MODE:
-		solo_enc->motion_global = ctrl->val == 1;
-		solo_enc->motion_enabled = ctrl->val > 0;
+				solo_enc->motion_thresh);
+	case V4L2_CID_DETECT_MD_MODE:
+		solo_enc->motion_global = ctrl->val == V4L2_DETECT_MD_MODE_GLOBAL;
+		solo_enc->motion_enabled = ctrl->val > V4L2_DETECT_MD_MODE_DISABLED;
 		if (ctrl->val) {
 			if (solo_enc->motion_global)
-				solo_set_motion_threshold(solo_dev,
-					solo_enc->ch, solo_enc->motion_thresh);
+				solo_set_motion_threshold(solo_dev, solo_enc->ch,
+					solo_enc->motion_thresh);
 			else
 				solo_set_motion_block(solo_dev, solo_enc->ch,
-						&solo_enc->motion_thresholds);
+					solo_enc->md_thresholds->p_cur.p_u16);
 		}
 		solo_motion_toggle(solo_enc, ctrl->val);
 		return 0;
+	case V4L2_CID_DETECT_MD_THRESHOLD_GRID:
+		if (solo_enc->motion_enabled && !solo_enc->motion_global)
+			return solo_set_motion_block(solo_dev, solo_enc->ch,
+					solo_enc->md_thresholds->p_new.p_u16);
+		break;
 	case V4L2_CID_OSD_TEXT:
 		strcpy(solo_enc->osd_text, ctrl->p_new.p_char);
 		err = solo_osd_print(solo_enc);
@@ -1181,7 +1161,6 @@ static const struct v4l2_ioctl_ops solo_enc_ioctl_ops = {
 	.vidioc_log_status		= v4l2_ctrl_log_status,
 	.vidioc_subscribe_event		= v4l2_ctrl_subscribe_event,
 	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
-	.vidioc_default			= solo_enc_default,
 };
 
 static const struct video_device solo_enc_template = {
@@ -1197,33 +1176,6 @@ static const struct v4l2_ctrl_ops solo_ctrl_ops = {
 	.s_ctrl = solo_s_ctrl,
 };
 
-static const struct v4l2_ctrl_config solo_motion_threshold_ctrl = {
-	.ops = &solo_ctrl_ops,
-	.id = V4L2_CID_MOTION_THRESHOLD,
-	.name = "Motion Detection Threshold",
-	.type = V4L2_CTRL_TYPE_INTEGER,
-	.max = 0xffff,
-	.def = SOLO_DEF_MOT_THRESH,
-	.step = 1,
-	.flags = V4L2_CTRL_FLAG_SLIDER,
-};
-
-static const char * const solo_motion_mode_menu[] = {
-	"Disabled",
-	"Global Threshold",
-	"Regional Threshold",
-	NULL
-};
-
-static const struct v4l2_ctrl_config solo_motion_enable_ctrl = {
-	.ops = &solo_ctrl_ops,
-	.id = V4L2_CID_MOTION_MODE,
-	.name = "Motion Detection Mode",
-	.type = V4L2_CTRL_TYPE_MENU,
-	.qmenu = solo_motion_mode_menu,
-	.max = 2,
-};
-
 static const struct v4l2_ctrl_config solo_osd_text_ctrl = {
 	.ops = &solo_ctrl_ops,
 	.id = V4L2_CID_OSD_TEXT,
@@ -1233,13 +1185,22 @@ static const struct v4l2_ctrl_config solo_osd_text_ctrl = {
 	.step = 1,
 };
 
+/* Motion Detection Threshold matrix */
+static const struct v4l2_ctrl_config solo_md_thresholds = {
+	.ops = &solo_ctrl_ops,
+	.id = V4L2_CID_DETECT_MD_THRESHOLD_GRID,
+	.dims = { SOLO_MOTION_SZ, SOLO_MOTION_SZ },
+	.def = SOLO_DEF_MOT_THRESH,
+	.max = 65535,
+	.step = 1,
+};
+
 static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev,
 					   u8 ch, unsigned nr)
 {
 	struct solo_enc_dev *solo_enc;
 	struct v4l2_ctrl_handler *hdl;
 	int ret;
-	int x, y;
 
 	solo_enc = kzalloc(sizeof(*solo_enc), GFP_KERNEL);
 	if (!solo_enc)
@@ -1260,9 +1221,16 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev,
 			V4L2_CID_SHARPNESS, 0, 15, 1, 0);
 	v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
 			V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1, 255, 1, solo_dev->fps);
-	v4l2_ctrl_new_custom(hdl, &solo_motion_threshold_ctrl, NULL);
-	v4l2_ctrl_new_custom(hdl, &solo_motion_enable_ctrl, NULL);
+	v4l2_ctrl_new_std_menu(hdl, &solo_ctrl_ops,
+			V4L2_CID_DETECT_MD_MODE,
+			V4L2_DETECT_MD_MODE_THRESHOLD_GRID, 0,
+			V4L2_DETECT_MD_MODE_DISABLED);
+	v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
+			V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD, 0, 0xff, 1,
+			SOLO_DEF_MOT_THRESH >> 8);
 	v4l2_ctrl_new_custom(hdl, &solo_osd_text_ctrl, NULL);
+	solo_enc->md_thresholds =
+		v4l2_ctrl_new_custom(hdl, &solo_md_thresholds, NULL);
 	if (hdl->error) {
 		ret = hdl->error;
 		goto hdl_free;
@@ -1283,11 +1251,6 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev,
 	solo_enc->mode = SOLO_ENC_MODE_CIF;
 	solo_enc->motion_global = true;
 	solo_enc->motion_thresh = SOLO_DEF_MOT_THRESH;
-	for (y = 0; y < SOLO_MOTION_SZ; y++)
-		for (x = 0; x < SOLO_MOTION_SZ; x++)
-			solo_enc->motion_thresholds.thresholds[y][x] =
-							SOLO_DEF_MOT_THRESH;
-
 	solo_enc->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 	solo_enc->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
 	solo_enc->vidq.ops = &solo_enc_video_qops;
diff --git a/drivers/staging/media/solo6x10/solo6x10.h b/drivers/staging/media/solo6x10/solo6x10.h
index 8964f8b..19cb56b 100644
--- a/drivers/staging/media/solo6x10/solo6x10.h
+++ b/drivers/staging/media/solo6x10/solo6x10.h
@@ -102,8 +102,6 @@
 #endif
 
 #define SOLO_CID_CUSTOM_BASE		(V4L2_CID_USER_BASE | 0xf000)
-#define V4L2_CID_MOTION_MODE		(SOLO_CID_CUSTOM_BASE+0)
-#define V4L2_CID_MOTION_THRESHOLD	(SOLO_CID_CUSTOM_BASE+1)
 #define V4L2_CID_MOTION_TRACE		(SOLO_CID_CUSTOM_BASE+2)
 #define V4L2_CID_OSD_TEXT		(SOLO_CID_CUSTOM_BASE+3)
 
@@ -113,19 +111,10 @@
  * effect, 44x30 samples are used for NTSC, and 44x36 for PAL.
  * The 5th sample on the 10th row is (10*64)+5 = 645.
  *
- * Using a 64x64 array will result in a problem on some architectures like
- * the powerpc where the size of the argument is limited to 13 bits.
- * Since both PAL and NTSC do not use the full table anyway I've chosen
- * to limit the array to 45x45 (45*16 = 720, which is the maximum PAL/NTSC
- * width).
+ * Internally it is stored as a 45x45 array (45*16 = 720, which is the
+ * maximum PAL/NTSC width).
  */
 #define SOLO_MOTION_SZ (45)
-struct solo_motion_thresholds {
-	__u16	thresholds[SOLO_MOTION_SZ][SOLO_MOTION_SZ];
-};
-
-#define SOLO_IOC_G_MOTION_THRESHOLDS	_IOR('V', BASE_VIDIOC_PRIVATE+0, struct solo_motion_thresholds)
-#define SOLO_IOC_S_MOTION_THRESHOLDS	_IOW('V', BASE_VIDIOC_PRIVATE+1, struct solo_motion_thresholds)
 
 enum SOLO_I2C_STATE {
 	IIC_STATE_IDLE,
@@ -168,6 +157,7 @@ struct solo_enc_dev {
 	struct solo_dev	*solo_dev;
 	/* V4L2 Items */
 	struct v4l2_ctrl_handler hdl;
+	struct v4l2_ctrl *md_thresholds;
 	struct video_device	*vfd;
 	/* General accounting */
 	struct mutex		lock;
@@ -176,7 +166,6 @@ struct solo_enc_dev {
 	u8			mode, gop, qp, interlaced, interval;
 	u8			bw_weight;
 	u16			motion_thresh;
-	struct solo_motion_thresholds motion_thresholds;
 	bool			motion_global;
 	bool			motion_enabled;
 	u16			width;
@@ -404,7 +393,7 @@ void solo_update_mode(struct solo_enc_dev *solo_enc);
 /* Set the threshold for motion detection */
 int solo_set_motion_threshold(struct solo_dev *solo_dev, u8 ch, u16 val);
 int solo_set_motion_block(struct solo_dev *solo_dev, u8 ch,
-		const struct solo_motion_thresholds *thresholds);
+		const u16 *thresholds);
 #define SOLO_DEF_MOT_THRESH		0x0300
 
 /* Write text on OSD */
-- 
2.0.0.rc0


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

* [REVIEWv4 PATCH 31/34] solo6x10: implement the motion detection event.
  2014-06-12 11:52 ` [REVIEWv4 PATCH 01/34] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
                     ` (28 preceding siblings ...)
  2014-06-12 11:53   ` [REVIEWv4 PATCH 30/34] solo6x10: implement the new motion detection controls Hans Verkuil
@ 2014-06-12 11:53   ` Hans Verkuil
  2014-06-12 11:53   ` [REVIEWv4 PATCH 32/34] solo6x10: fix 'dma from stack' warning Hans Verkuil
                     ` (2 subsequent siblings)
  32 siblings, 0 replies; 36+ messages in thread
From: Hans Verkuil @ 2014-06-12 11:53 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, s.nawrocki, sakari.ailus, Hans Verkuil

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

Use the new motion detection event.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c | 68 ++++++++++++++++++----
 drivers/staging/media/solo6x10/solo6x10.h          |  7 +--
 2 files changed, 60 insertions(+), 15 deletions(-)

diff --git a/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c b/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
index 67b40a4..ab0b1a6 100644
--- a/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
+++ b/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
@@ -243,6 +243,8 @@ static int solo_enc_on(struct solo_enc_dev *solo_enc)
 	if (solo_enc->bw_weight > solo_dev->enc_bw_remain)
 		return -EBUSY;
 	solo_enc->sequence = 0;
+	solo_enc->motion_last_state = false;
+	solo_enc->frames_since_last_motion = 0;
 	solo_dev->enc_bw_remain -= solo_enc->bw_weight;
 
 	if (solo_enc->type == SOLO_ENC_TYPE_EXT)
@@ -544,15 +546,6 @@ static int solo_enc_fillbuf(struct solo_enc_dev *solo_enc,
 	const vop_header *vh = enc_buf->vh;
 	int ret;
 
-	/* Check for motion flags */
-	vb->v4l2_buf.flags &= ~(V4L2_BUF_FLAG_MOTION_ON |
-				V4L2_BUF_FLAG_MOTION_DETECTED);
-	if (solo_is_motion_on(solo_enc)) {
-		vb->v4l2_buf.flags |= V4L2_BUF_FLAG_MOTION_ON;
-		if (enc_buf->motion)
-			vb->v4l2_buf.flags |= V4L2_BUF_FLAG_MOTION_DETECTED;
-	}
-
 	switch (solo_enc->fmt) {
 	case V4L2_PIX_FMT_MPEG4:
 	case V4L2_PIX_FMT_H264:
@@ -564,9 +557,49 @@ static int solo_enc_fillbuf(struct solo_enc_dev *solo_enc,
 	}
 
 	if (!ret) {
+		bool send_event = false;
+
 		vb->v4l2_buf.sequence = solo_enc->sequence++;
 		vb->v4l2_buf.timestamp.tv_sec = vop_sec(vh);
 		vb->v4l2_buf.timestamp.tv_usec = vop_usec(vh);
+
+		/* Check for motion flags */
+		if (solo_is_motion_on(solo_enc)) {
+			/* It takes a few frames for the hardware to detect
+			 * motion. Once it does it clears the motion detection
+			 * register and it takes again a few frames before
+			 * motion is seen. This means in practice that when the
+			 * motion field is 1, it will go back to 0 for the next
+			 * frame. This leads to motion detection event being
+			 * sent all the time, which is not what we want.
+			 * Instead wait a few frames before deciding that the
+			 * motion has halted. After some experimentation it
+			 * turns out that waiting for 5 frames works well.
+			 */
+			if (enc_buf->motion == 0 &&
+			    solo_enc->motion_last_state &&
+			    solo_enc->frames_since_last_motion++ > 5)
+				send_event = true;
+			else if (enc_buf->motion) {
+				solo_enc->frames_since_last_motion = 0;
+				send_event = !solo_enc->motion_last_state;
+			}
+		}
+
+		if (send_event) {
+			struct v4l2_event ev = {
+				.type = V4L2_EVENT_MOTION_DET,
+				.u.motion_det = {
+					.flags = V4L2_EVENT_MD_FL_HAVE_FRAME_SEQ,
+					.frame_sequence = vb->v4l2_buf.sequence,
+					.region_mask = enc_buf->motion ? 1 : 0,
+				},
+			};
+
+			solo_enc->motion_last_state = enc_buf->motion;
+			solo_enc->frames_since_last_motion = 0;
+			v4l2_event_queue(solo_enc->vfd, &ev);
+		}
 	}
 
 	vb2_buffer_done(vb, ret ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
@@ -1121,6 +1154,21 @@ static int solo_s_ctrl(struct v4l2_ctrl *ctrl)
 	return 0;
 }
 
+static int solo_subscribe_event(struct v4l2_fh *fh,
+				const struct v4l2_event_subscription *sub)
+{
+
+	switch (sub->type) {
+	case V4L2_EVENT_CTRL:
+		return v4l2_ctrl_subscribe_event(fh, sub);
+	case V4L2_EVENT_MOTION_DET:
+		/* Allow for up to 30 events (1 second for NTSC) to be
+		 * stored. */
+		return v4l2_event_subscribe(fh, sub, 30, NULL);
+	}
+	return -EINVAL;
+}
+
 static const struct v4l2_file_operations solo_enc_fops = {
 	.owner			= THIS_MODULE,
 	.open			= v4l2_fh_open,
@@ -1159,7 +1207,7 @@ static const struct v4l2_ioctl_ops solo_enc_ioctl_ops = {
 	.vidioc_g_parm			= solo_g_parm,
 	/* Logging and events */
 	.vidioc_log_status		= v4l2_ctrl_log_status,
-	.vidioc_subscribe_event		= v4l2_ctrl_subscribe_event,
+	.vidioc_subscribe_event		= solo_subscribe_event,
 	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
 };
 
diff --git a/drivers/staging/media/solo6x10/solo6x10.h b/drivers/staging/media/solo6x10/solo6x10.h
index 19cb56b..35f9486 100644
--- a/drivers/staging/media/solo6x10/solo6x10.h
+++ b/drivers/staging/media/solo6x10/solo6x10.h
@@ -96,11 +96,6 @@
 
 #define SOLO_DEFAULT_QP			3
 
-#ifndef V4L2_BUF_FLAG_MOTION_ON
-#define V4L2_BUF_FLAG_MOTION_ON		0x10000
-#define V4L2_BUF_FLAG_MOTION_DETECTED	0x20000
-#endif
-
 #define SOLO_CID_CUSTOM_BASE		(V4L2_CID_USER_BASE | 0xf000)
 #define V4L2_CID_MOTION_TRACE		(SOLO_CID_CUSTOM_BASE+2)
 #define V4L2_CID_OSD_TEXT		(SOLO_CID_CUSTOM_BASE+3)
@@ -168,6 +163,8 @@ struct solo_enc_dev {
 	u16			motion_thresh;
 	bool			motion_global;
 	bool			motion_enabled;
+	bool			motion_last_state;
+	u8			frames_since_last_motion;
 	u16			width;
 	u16			height;
 
-- 
2.0.0.rc0


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

* [REVIEWv4 PATCH 32/34] solo6x10: fix 'dma from stack' warning.
  2014-06-12 11:52 ` [REVIEWv4 PATCH 01/34] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
                     ` (29 preceding siblings ...)
  2014-06-12 11:53   ` [REVIEWv4 PATCH 31/34] solo6x10: implement the motion detection event Hans Verkuil
@ 2014-06-12 11:53   ` Hans Verkuil
  2014-06-12 11:53   ` [REVIEWv4 PATCH 33/34] solo6x10: check dma_map_sg() return value Hans Verkuil
  2014-06-12 11:53   ` [REVIEWv4 PATCH 34/34] go7007: add motion detection support Hans Verkuil
  32 siblings, 0 replies; 36+ messages in thread
From: Hans Verkuil @ 2014-06-12 11:53 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, s.nawrocki, sakari.ailus, Hans Verkuil

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

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/staging/media/solo6x10/solo6x10-disp.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/staging/media/solo6x10/solo6x10-disp.c b/drivers/staging/media/solo6x10/solo6x10-disp.c
index 44d98b8..b529a96 100644
--- a/drivers/staging/media/solo6x10/solo6x10-disp.c
+++ b/drivers/staging/media/solo6x10/solo6x10-disp.c
@@ -213,19 +213,21 @@ int solo_set_motion_threshold(struct solo_dev *solo_dev, u8 ch, u16 val)
 int solo_set_motion_block(struct solo_dev *solo_dev, u8 ch,
 		const u16 *thresholds)
 {
+	const unsigned size = sizeof(u16) * 64;
 	u32 off = SOLO_MOT_FLAG_AREA + ch * SOLO_MOT_THRESH_SIZE * 2;
-	u16 buf[64];
+	u16 *buf;
 	int x, y;
 	int ret = 0;
 
-	memset(buf, 0, sizeof(buf));
+	buf = kzalloc(size, GFP_KERNEL);
 	for (y = 0; y < SOLO_MOTION_SZ; y++) {
 		for (x = 0; x < SOLO_MOTION_SZ; x++)
 			buf[x] = cpu_to_le16(thresholds[y * SOLO_MOTION_SZ + x]);
 		ret |= solo_p2m_dma(solo_dev, 1, buf,
-			SOLO_MOTION_EXT_ADDR(solo_dev) + off + y * sizeof(buf),
-			sizeof(buf), 0, 0);
+			SOLO_MOTION_EXT_ADDR(solo_dev) + off + y * size,
+			size, 0, 0);
 	}
+	kfree(buf);
 	return ret;
 }
 
-- 
2.0.0.rc0


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

* [REVIEWv4 PATCH 33/34] solo6x10: check dma_map_sg() return value
  2014-06-12 11:52 ` [REVIEWv4 PATCH 01/34] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
                     ` (30 preceding siblings ...)
  2014-06-12 11:53   ` [REVIEWv4 PATCH 32/34] solo6x10: fix 'dma from stack' warning Hans Verkuil
@ 2014-06-12 11:53   ` Hans Verkuil
  2014-06-12 11:53   ` [REVIEWv4 PATCH 34/34] go7007: add motion detection support Hans Verkuil
  32 siblings, 0 replies; 36+ messages in thread
From: Hans Verkuil @ 2014-06-12 11:53 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, s.nawrocki, sakari.ailus, Hans Verkuil

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

The dma_map_sg() function can fail, so check for the return value.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c b/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
index ab0b1a6..d9d0941 100644
--- a/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
+++ b/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
@@ -478,8 +478,9 @@ static int solo_fill_jpeg(struct solo_enc_dev *solo_enc,
 	vb2_set_plane_payload(vb, 0, vop_jpeg_size(vh) + solo_enc->jpeg_len);
 
 	/* may discard all previous data in vbuf->sgl */
-	dma_map_sg(&solo_dev->pdev->dev, vbuf->sgl, vbuf->nents,
-			DMA_FROM_DEVICE);
+	if (!dma_map_sg(&solo_dev->pdev->dev, vbuf->sgl, vbuf->nents,
+			DMA_FROM_DEVICE))
+		return -ENOMEM;
 	ret = solo_send_desc(solo_enc, solo_enc->jpeg_len, vbuf,
 			     vop_jpeg_offset(vh) - SOLO_JPEG_EXT_ADDR(solo_dev),
 			     frame_size, SOLO_JPEG_EXT_ADDR(solo_dev),
@@ -525,8 +526,9 @@ static int solo_fill_mpeg(struct solo_enc_dev *solo_enc,
 	frame_size = ALIGN(vop_mpeg_size(vh) + skip, DMA_ALIGN);
 
 	/* may discard all previous data in vbuf->sgl */
-	dma_map_sg(&solo_dev->pdev->dev, vbuf->sgl, vbuf->nents,
-			DMA_FROM_DEVICE);
+	if (!dma_map_sg(&solo_dev->pdev->dev, vbuf->sgl, vbuf->nents,
+			DMA_FROM_DEVICE))
+		return -ENOMEM;
 	ret = solo_send_desc(solo_enc, skip, vbuf, frame_off, frame_size,
 			SOLO_MP4E_EXT_ADDR(solo_dev),
 			SOLO_MP4E_EXT_SIZE(solo_dev));
-- 
2.0.0.rc0


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

* [REVIEWv4 PATCH 34/34] go7007: add motion detection support.
  2014-06-12 11:52 ` [REVIEWv4 PATCH 01/34] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
                     ` (31 preceding siblings ...)
  2014-06-12 11:53   ` [REVIEWv4 PATCH 33/34] solo6x10: check dma_map_sg() return value Hans Verkuil
@ 2014-06-12 11:53   ` Hans Verkuil
  32 siblings, 0 replies; 36+ messages in thread
From: Hans Verkuil @ 2014-06-12 11:53 UTC (permalink / raw)
  To: linux-media; +Cc: laurent.pinchart, s.nawrocki, sakari.ailus, Hans Verkuil

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

This patch adds motion detection support to the go7007 driver using the new
motion detection controls, events.

The global motion detection works fine, but the regional motion detection
support probably needs more work. There seems to be some interaction between
regions that makes setting correct thresholds difficult. The exact meaning of
the thresholds isn't entirely clear either.

I do not have any documentation, the only information I have is the custom code
in the driver and a modet.c application.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/staging/media/go7007/go7007-driver.c  | 127 ++++++++---
 drivers/staging/media/go7007/go7007-fw.c      |  28 ++-
 drivers/staging/media/go7007/go7007-priv.h    |  16 ++
 drivers/staging/media/go7007/go7007-v4l2.c    | 317 ++++++++++++++++++--------
 drivers/staging/media/go7007/go7007.h         |  40 ----
 drivers/staging/media/go7007/saa7134-go7007.c |   1 -
 6 files changed, 345 insertions(+), 184 deletions(-)
 delete mode 100644 drivers/staging/media/go7007/go7007.h

diff --git a/drivers/staging/media/go7007/go7007-driver.c b/drivers/staging/media/go7007/go7007-driver.c
index 6f1beca..c200601 100644
--- a/drivers/staging/media/go7007/go7007-driver.c
+++ b/drivers/staging/media/go7007/go7007-driver.c
@@ -32,6 +32,7 @@
 #include <linux/videodev2.h>
 #include <media/tuner.h>
 #include <media/v4l2-common.h>
+#include <media/v4l2-event.h>
 
 #include "go7007-priv.h"
 
@@ -332,20 +333,33 @@ EXPORT_SYMBOL(go7007_register_encoder);
 int go7007_start_encoder(struct go7007 *go)
 {
 	u8 *fw;
-	int fw_len, rv = 0, i;
+	int fw_len, rv = 0, i, x, y;
 	u16 intr_val, intr_data;
 
 	go->modet_enable = 0;
-	if (!go->dvd_mode)
-		for (i = 0; i < 4; ++i) {
-			if (go->modet[i].enable) {
-				go->modet_enable = 1;
-				continue;
+	for (i = 0; i < 4; i++)
+		go->modet[i].enable = 0;
+
+	switch (v4l2_ctrl_g_ctrl(go->modet_mode)) {
+	case V4L2_DETECT_MD_MODE_GLOBAL:
+		memset(go->modet_map, 0, sizeof(go->modet_map));
+		go->modet[0].enable = 1;
+		go->modet_enable = 1;
+		break;
+	case V4L2_DETECT_MD_MODE_REGION_GRID:
+		for (y = 0; y < go->height / 16; y++) {
+			for (x = 0; x < go->width / 16; x++) {
+				int idx = y * go->width / 16 + x;
+
+				go->modet[go->modet_map[idx]].enable = 1;
 			}
-			go->modet[i].pixel_threshold = 32767;
-			go->modet[i].motion_threshold = 32767;
-			go->modet[i].mb_threshold = 32767;
 		}
+		go->modet_enable = 1;
+		break;
+	}
+
+	if (go->dvd_mode)
+		go->modet_enable = 0;
 
 	if (go7007_construct_fw_image(go, &fw, &fw_len) < 0)
 		return -1;
@@ -383,44 +397,89 @@ static inline void store_byte(struct go7007_buffer *vb, u8 byte)
 	}
 }
 
+static void go7007_set_motion_regions(struct go7007 *go, struct go7007_buffer *vb,
+		u32 motion_regions)
+{
+	if (motion_regions != go->modet_event_status) {
+		struct v4l2_event ev = {
+			.type = V4L2_EVENT_MOTION_DET,
+			.u.motion_det = {
+				.flags = V4L2_EVENT_MD_FL_HAVE_FRAME_SEQ,
+				.frame_sequence = vb->vb.v4l2_buf.sequence,
+				.region_mask = motion_regions,
+			},
+		};
+
+		v4l2_event_queue(&go->vdev, &ev);
+		go->modet_event_status = motion_regions;
+	}
+}
+
 /*
- * Deliver the last video buffer and get a new one to start writing to.
+ * Determine regions with motion and send a motion detection event
+ * in case of changes.
  */
-static struct go7007_buffer *frame_boundary(struct go7007 *go, struct go7007_buffer *vb)
+static void go7007_motion_regions(struct go7007 *go, struct go7007_buffer *vb)
 {
-	struct go7007_buffer *vb_tmp = NULL;
 	u32 *bytesused = &vb->vb.v4l2_planes[0].bytesused;
+	unsigned motion[4] = { 0, 0, 0, 0 };
+	u32 motion_regions = 0;
+	unsigned stride = (go->width + 7) >> 3;
+	unsigned x, y;
 	int i;
 
-	if (vb) {
-		if (vb->modet_active) {
-			if (*bytesused + 216 < GO7007_BUF_SIZE) {
-				for (i = 0; i < 216; ++i)
-					store_byte(vb, go->active_map[i]);
-				*bytesused -= 216;
-			} else
-				vb->modet_active = 0;
+	for (i = 0; i < 216; ++i)
+		store_byte(vb, go->active_map[i]);
+	for (y = 0; y < go->height / 16; y++) {
+		for (x = 0; x < go->width / 16; x++) {
+			if (!(go->active_map[y * stride + (x >> 3)] & (1 << (x & 7))))
+				continue;
+			motion[go->modet_map[y * (go->width / 16) + x]]++;
 		}
-		vb->vb.v4l2_buf.sequence = go->next_seq++;
-		v4l2_get_timestamp(&vb->vb.v4l2_buf.timestamp);
-		vb_tmp = vb;
+	}
+	motion_regions = ((motion[0] > 0) << 0) |
+			 ((motion[1] > 0) << 1) |
+			 ((motion[2] > 0) << 2) |
+			 ((motion[3] > 0) << 3);
+	*bytesused -= 216;
+	go7007_set_motion_regions(go, vb, motion_regions);
+}
+
+/*
+ * Deliver the last video buffer and get a new one to start writing to.
+ */
+static struct go7007_buffer *frame_boundary(struct go7007 *go, struct go7007_buffer *vb)
+{
+	u32 *bytesused = &vb->vb.v4l2_planes[0].bytesused;
+	struct go7007_buffer *vb_tmp = NULL;
+
+	if (vb == NULL) {
 		spin_lock(&go->spinlock);
-		list_del(&vb->list);
-		if (list_empty(&go->vidq_active))
-			vb = NULL;
-		else
-			vb = list_first_entry(&go->vidq_active, struct go7007_buffer, list);
-		go->active_buf = vb;
+		if (!list_empty(&go->vidq_active))
+			vb = go->active_buf =
+				list_first_entry(&go->vidq_active, struct go7007_buffer, list);
 		spin_unlock(&go->spinlock);
-		vb2_buffer_done(&vb_tmp->vb, VB2_BUF_STATE_DONE);
+		go->next_seq++;
 		return vb;
 	}
+
+	vb->vb.v4l2_buf.sequence = go->next_seq++;
+	if (vb->modet_active && *bytesused + 216 < GO7007_BUF_SIZE)
+		go7007_motion_regions(go, vb);
+	else
+		go7007_set_motion_regions(go, vb, 0);
+
+	v4l2_get_timestamp(&vb->vb.v4l2_buf.timestamp);
+	vb_tmp = vb;
 	spin_lock(&go->spinlock);
-	if (!list_empty(&go->vidq_active))
-		vb = go->active_buf =
-			list_first_entry(&go->vidq_active, struct go7007_buffer, list);
+	list_del(&vb->list);
+	if (list_empty(&go->vidq_active))
+		vb = NULL;
+	else
+		vb = list_first_entry(&go->vidq_active, struct go7007_buffer, list);
+	go->active_buf = vb;
 	spin_unlock(&go->spinlock);
-	go->next_seq++;
+	vb2_buffer_done(&vb_tmp->vb, VB2_BUF_STATE_DONE);
 	return vb;
 }
 
diff --git a/drivers/staging/media/go7007/go7007-fw.c b/drivers/staging/media/go7007/go7007-fw.c
index 814ce08..f60640b 100644
--- a/drivers/staging/media/go7007/go7007-fw.c
+++ b/drivers/staging/media/go7007/go7007-fw.c
@@ -1432,22 +1432,26 @@ static int audio_to_package(struct go7007 *go, __le16 *code, int space)
 
 static int modet_to_package(struct go7007 *go, __le16 *code, int space)
 {
+	bool has_modet0 = go->modet[0].enable;
+	bool has_modet1 = go->modet[1].enable;
+	bool has_modet2 = go->modet[2].enable;
+	bool has_modet3 = go->modet[3].enable;
 	int ret, mb, i, addr, cnt = 0;
 	u16 pack[32];
 	u16 thresholds[] = {
 		0x200e,		0,
-		0xbf82,		go->modet[0].pixel_threshold,
-		0xbf83,		go->modet[1].pixel_threshold,
-		0xbf84,		go->modet[2].pixel_threshold,
-		0xbf85,		go->modet[3].pixel_threshold,
-		0xbf86,		go->modet[0].motion_threshold,
-		0xbf87,		go->modet[1].motion_threshold,
-		0xbf88,		go->modet[2].motion_threshold,
-		0xbf89,		go->modet[3].motion_threshold,
-		0xbf8a,		go->modet[0].mb_threshold,
-		0xbf8b,		go->modet[1].mb_threshold,
-		0xbf8c,		go->modet[2].mb_threshold,
-		0xbf8d,		go->modet[3].mb_threshold,
+		0xbf82,		has_modet0 ? go->modet[0].pixel_threshold : 32767,
+		0xbf83,		has_modet1 ? go->modet[1].pixel_threshold : 32767,
+		0xbf84,		has_modet2 ? go->modet[2].pixel_threshold : 32767,
+		0xbf85,		has_modet3 ? go->modet[3].pixel_threshold : 32767,
+		0xbf86,		has_modet0 ? go->modet[0].motion_threshold : 32767,
+		0xbf87,		has_modet1 ? go->modet[1].motion_threshold : 32767,
+		0xbf88,		has_modet2 ? go->modet[2].motion_threshold : 32767,
+		0xbf89,		has_modet3 ? go->modet[3].motion_threshold : 32767,
+		0xbf8a,		has_modet0 ? go->modet[0].mb_threshold : 32767,
+		0xbf8b,		has_modet1 ? go->modet[1].mb_threshold : 32767,
+		0xbf8c,		has_modet2 ? go->modet[2].mb_threshold : 32767,
+		0xbf8d,		has_modet3 ? go->modet[3].mb_threshold : 32767,
 		0xbf8e,		0,
 		0xbf8f,		0,
 		0,		0,
diff --git a/drivers/staging/media/go7007/go7007-priv.h b/drivers/staging/media/go7007/go7007-priv.h
index 6e16af7..a8aefed 100644
--- a/drivers/staging/media/go7007/go7007-priv.h
+++ b/drivers/staging/media/go7007/go7007-priv.h
@@ -75,6 +75,20 @@ struct go7007;
 #define GO7007_AUDIO_I2S_MASTER		(1<<16)
 #define GO7007_AUDIO_OKI_MODE		(1<<17)
 
+#define GO7007_CID_CUSTOM_BASE		(V4L2_CID_DETECT_CLASS_BASE + 0x1000)
+#define V4L2_CID_PIXEL_THRESHOLD0	(GO7007_CID_CUSTOM_BASE+1)
+#define V4L2_CID_MOTION_THRESHOLD0	(GO7007_CID_CUSTOM_BASE+2)
+#define V4L2_CID_MB_THRESHOLD0		(GO7007_CID_CUSTOM_BASE+3)
+#define V4L2_CID_PIXEL_THRESHOLD1	(GO7007_CID_CUSTOM_BASE+4)
+#define V4L2_CID_MOTION_THRESHOLD1	(GO7007_CID_CUSTOM_BASE+5)
+#define V4L2_CID_MB_THRESHOLD1		(GO7007_CID_CUSTOM_BASE+6)
+#define V4L2_CID_PIXEL_THRESHOLD2	(GO7007_CID_CUSTOM_BASE+7)
+#define V4L2_CID_MOTION_THRESHOLD2	(GO7007_CID_CUSTOM_BASE+8)
+#define V4L2_CID_MB_THRESHOLD2		(GO7007_CID_CUSTOM_BASE+9)
+#define V4L2_CID_PIXEL_THRESHOLD3	(GO7007_CID_CUSTOM_BASE+10)
+#define V4L2_CID_MOTION_THRESHOLD3	(GO7007_CID_CUSTOM_BASE+11)
+#define V4L2_CID_MB_THRESHOLD3		(GO7007_CID_CUSTOM_BASE+12)
+
 struct go7007_board_info {
 	unsigned int flags;
 	int hpi_buffer_cap;
@@ -168,6 +182,7 @@ struct go7007 {
 	struct v4l2_ctrl *mpeg_video_aspect_ratio;
 	struct v4l2_ctrl *mpeg_video_b_frames;
 	struct v4l2_ctrl *mpeg_video_rep_seqheader;
+	struct v4l2_ctrl *modet_mode;
 	enum { STATUS_INIT, STATUS_ONLINE, STATUS_SHUTDOWN } status;
 	spinlock_t spinlock;
 	struct mutex hw_lock;
@@ -216,6 +231,7 @@ struct go7007 {
 	} modet[4];
 	unsigned char modet_map[1624];
 	unsigned char active_map[216];
+	u32 modet_event_status;
 
 	/* Video streaming */
 	struct mutex queue_lock;
diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c
index da7b549..2dcb61c 100644
--- a/drivers/staging/media/go7007/go7007-v4l2.c
+++ b/drivers/staging/media/go7007/go7007-v4l2.c
@@ -36,7 +36,6 @@
 #include <media/videobuf2-vmalloc.h>
 #include <media/saa7115.h>
 
-#include "go7007.h"
 #include "go7007-priv.h"
 
 #define call_all(dev, o, f, args...) \
@@ -189,7 +188,7 @@ static void set_formatting(struct go7007 *go)
 static int set_capture_size(struct go7007 *go, struct v4l2_format *fmt, int try)
 {
 	int sensor_height = 0, sensor_width = 0;
-	int width, height, i;
+	int width, height;
 
 	if (fmt != NULL && !valid_pixelformat(fmt->fmt.pix.pixelformat))
 		return -EINVAL;
@@ -253,10 +252,6 @@ static int set_capture_size(struct go7007 *go, struct v4l2_format *fmt, int try)
 	go->height = height;
 	go->encoder_h_offset = go->board_info->sensor_h_offset;
 	go->encoder_v_offset = go->board_info->sensor_v_offset;
-	for (i = 0; i < 4; ++i)
-		go->modet[i].enable = 0;
-	for (i = 0; i < 1624; ++i)
-		go->modet_map[i] = 0;
 
 	if (go->board_info->sensor_flags & GO7007_SENSOR_SCALING) {
 		struct v4l2_mbus_framefmt mbus_fmt;
@@ -286,64 +281,6 @@ static int set_capture_size(struct go7007 *go, struct v4l2_format *fmt, int try)
 	return 0;
 }
 
-#if 0
-static int clip_to_modet_map(struct go7007 *go, int region,
-		struct v4l2_clip *clip_list)
-{
-	struct v4l2_clip clip, *clip_ptr;
-	int x, y, mbnum;
-
-	/* Check if coordinates are OK and if any macroblocks are already
-	 * used by other regions (besides 0) */
-	clip_ptr = clip_list;
-	while (clip_ptr) {
-		if (copy_from_user(&clip, clip_ptr, sizeof(clip)))
-			return -EFAULT;
-		if (clip.c.left < 0 || (clip.c.left & 0xF) ||
-				clip.c.width <= 0 || (clip.c.width & 0xF))
-			return -EINVAL;
-		if (clip.c.left + clip.c.width > go->width)
-			return -EINVAL;
-		if (clip.c.top < 0 || (clip.c.top & 0xF) ||
-				clip.c.height <= 0 || (clip.c.height & 0xF))
-			return -EINVAL;
-		if (clip.c.top + clip.c.height > go->height)
-			return -EINVAL;
-		for (y = 0; y < clip.c.height; y += 16)
-			for (x = 0; x < clip.c.width; x += 16) {
-				mbnum = (go->width >> 4) *
-						((clip.c.top + y) >> 4) +
-					((clip.c.left + x) >> 4);
-				if (go->modet_map[mbnum] != 0 &&
-						go->modet_map[mbnum] != region)
-					return -EBUSY;
-			}
-		clip_ptr = clip.next;
-	}
-
-	/* Clear old region macroblocks */
-	for (mbnum = 0; mbnum < 1624; ++mbnum)
-		if (go->modet_map[mbnum] == region)
-			go->modet_map[mbnum] = 0;
-
-	/* Claim macroblocks in this list */
-	clip_ptr = clip_list;
-	while (clip_ptr) {
-		if (copy_from_user(&clip, clip_ptr, sizeof(clip)))
-			return -EFAULT;
-		for (y = 0; y < clip.c.height; y += 16)
-			for (x = 0; x < clip.c.width; x += 16) {
-				mbnum = (go->width >> 4) *
-						((clip.c.top + y) >> 4) +
-					((clip.c.left + x) >> 4);
-				go->modet_map[mbnum] = region;
-			}
-		clip_ptr = clip.next;
-	}
-	return 0;
-}
-#endif
-
 static int vidioc_querycap(struct file *file, void  *priv,
 					struct v4l2_capability *cap)
 {
@@ -495,6 +432,7 @@ static int go7007_start_streaming(struct vb2_queue *q, unsigned int count)
 	mutex_lock(&go->hw_lock);
 	go->next_seq = 0;
 	go->active_buf = NULL;
+	go->modet_event_status = 0;
 	q->streaming = 1;
 	if (go7007_start_encoder(go) < 0)
 		ret = -EIO;
@@ -850,41 +788,76 @@ static int vidioc_log_status(struct file *file, void *priv)
 	return call_all(&go->v4l2_dev, core, log_status);
 }
 
-/* FIXME:
-	Those ioctls are private, and not needed, since several standard
-	extended controls already provide streaming control.
-	So, those ioctls should be converted into vidioc_g_ext_ctrls()
-	and vidioc_s_ext_ctrls()
- */
-
-#if 0
-	case GO7007IOC_S_MD_PARAMS:
-	{
-		struct go7007_md_params *mdp = arg;
+static int vidioc_subscribe_event(struct v4l2_fh *fh,
+				const struct v4l2_event_subscription *sub)
+{
 
-		if (mdp->region > 3)
-			return -EINVAL;
-		if (mdp->trigger > 0) {
-			go->modet[mdp->region].pixel_threshold =
-					mdp->pixel_threshold >> 1;
-			go->modet[mdp->region].motion_threshold =
-					mdp->motion_threshold >> 1;
-			go->modet[mdp->region].mb_threshold =
-					mdp->trigger >> 1;
-			go->modet[mdp->region].enable = 1;
-		} else
-			go->modet[mdp->region].enable = 0;
-		/* fall-through */
+	switch (sub->type) {
+	case V4L2_EVENT_CTRL:
+		return v4l2_ctrl_subscribe_event(fh, sub);
+	case V4L2_EVENT_MOTION_DET:
+		/* Allow for up to 30 events (1 second for NTSC) to be
+		 * stored. */
+		return v4l2_event_subscribe(fh, sub, 30, NULL);
 	}
-	case GO7007IOC_S_MD_REGION:
-	{
-		struct go7007_md_region *region = arg;
+	return -EINVAL;
+}
 
-		if (region->region < 1 || region->region > 3)
-			return -EINVAL;
-		return clip_to_modet_map(go, region->region, region->clips);
+
+static int go7007_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct go7007 *go =
+		container_of(ctrl->handler, struct go7007, hdl);
+	unsigned y;
+	u8 *mt;
+
+	switch (ctrl->id) {
+	case V4L2_CID_PIXEL_THRESHOLD0:
+		go->modet[0].pixel_threshold = ctrl->val;
+		break;
+	case V4L2_CID_MOTION_THRESHOLD0:
+		go->modet[0].motion_threshold = ctrl->val;
+		break;
+	case V4L2_CID_MB_THRESHOLD0:
+		go->modet[0].mb_threshold = ctrl->val;
+		break;
+	case V4L2_CID_PIXEL_THRESHOLD1:
+		go->modet[1].pixel_threshold = ctrl->val;
+		break;
+	case V4L2_CID_MOTION_THRESHOLD1:
+		go->modet[1].motion_threshold = ctrl->val;
+		break;
+	case V4L2_CID_MB_THRESHOLD1:
+		go->modet[1].mb_threshold = ctrl->val;
+		break;
+	case V4L2_CID_PIXEL_THRESHOLD2:
+		go->modet[2].pixel_threshold = ctrl->val;
+		break;
+	case V4L2_CID_MOTION_THRESHOLD2:
+		go->modet[2].motion_threshold = ctrl->val;
+		break;
+	case V4L2_CID_MB_THRESHOLD2:
+		go->modet[2].mb_threshold = ctrl->val;
+		break;
+	case V4L2_CID_PIXEL_THRESHOLD3:
+		go->modet[3].pixel_threshold = ctrl->val;
+		break;
+	case V4L2_CID_MOTION_THRESHOLD3:
+		go->modet[3].motion_threshold = ctrl->val;
+		break;
+	case V4L2_CID_MB_THRESHOLD3:
+		go->modet[3].mb_threshold = ctrl->val;
+		break;
+	case V4L2_CID_DETECT_MD_REGION_GRID:
+		mt = go->modet_map;
+		for (y = 0; y < go->height / 16; y++, mt += go->width / 16)
+			memcpy(mt, ctrl->p_new.p_u8 + y * (720 / 16), go->width / 16);
+		break;
+	default:
+		return -EINVAL;
 	}
-#endif
+	return 0;
+}
 
 static struct v4l2_file_operations go7007_fops = {
 	.owner		= THIS_MODULE,
@@ -926,7 +899,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
 	.vidioc_enum_framesizes   = vidioc_enum_framesizes,
 	.vidioc_enum_frameintervals = vidioc_enum_frameintervals,
 	.vidioc_log_status        = vidioc_log_status,
-	.vidioc_subscribe_event   = v4l2_ctrl_subscribe_event,
+	.vidioc_subscribe_event   = vidioc_subscribe_event,
 	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 };
 
@@ -938,12 +911,144 @@ static struct video_device go7007_template = {
 	.tvnorms	= V4L2_STD_ALL,
 };
 
+static const struct v4l2_ctrl_ops go7007_ctrl_ops = {
+	.s_ctrl = go7007_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config go7007_pixel_threshold0_ctrl = {
+	.ops = &go7007_ctrl_ops,
+	.id = V4L2_CID_PIXEL_THRESHOLD0,
+	.name = "Pixel Threshold Region 0",
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.def = 20,
+	.max = 32767,
+	.step = 1,
+};
+
+static const struct v4l2_ctrl_config go7007_motion_threshold0_ctrl = {
+	.ops = &go7007_ctrl_ops,
+	.id = V4L2_CID_MOTION_THRESHOLD0,
+	.name = "Motion Threshold Region 0",
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.def = 80,
+	.max = 32767,
+	.step = 1,
+};
+
+static const struct v4l2_ctrl_config go7007_mb_threshold0_ctrl = {
+	.ops = &go7007_ctrl_ops,
+	.id = V4L2_CID_MB_THRESHOLD0,
+	.name = "MB Threshold Region 0",
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.def = 200,
+	.max = 32767,
+	.step = 1,
+};
+
+static const struct v4l2_ctrl_config go7007_pixel_threshold1_ctrl = {
+	.ops = &go7007_ctrl_ops,
+	.id = V4L2_CID_PIXEL_THRESHOLD1,
+	.name = "Pixel Threshold Region 1",
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.def = 20,
+	.max = 32767,
+	.step = 1,
+};
+
+static const struct v4l2_ctrl_config go7007_motion_threshold1_ctrl = {
+	.ops = &go7007_ctrl_ops,
+	.id = V4L2_CID_MOTION_THRESHOLD1,
+	.name = "Motion Threshold Region 1",
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.def = 80,
+	.max = 32767,
+	.step = 1,
+};
+
+static const struct v4l2_ctrl_config go7007_mb_threshold1_ctrl = {
+	.ops = &go7007_ctrl_ops,
+	.id = V4L2_CID_MB_THRESHOLD1,
+	.name = "MB Threshold Region 1",
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.def = 200,
+	.max = 32767,
+	.step = 1,
+};
+
+static const struct v4l2_ctrl_config go7007_pixel_threshold2_ctrl = {
+	.ops = &go7007_ctrl_ops,
+	.id = V4L2_CID_PIXEL_THRESHOLD2,
+	.name = "Pixel Threshold Region 2",
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.def = 20,
+	.max = 32767,
+	.step = 1,
+};
+
+static const struct v4l2_ctrl_config go7007_motion_threshold2_ctrl = {
+	.ops = &go7007_ctrl_ops,
+	.id = V4L2_CID_MOTION_THRESHOLD2,
+	.name = "Motion Threshold Region 2",
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.def = 80,
+	.max = 32767,
+	.step = 1,
+};
+
+static const struct v4l2_ctrl_config go7007_mb_threshold2_ctrl = {
+	.ops = &go7007_ctrl_ops,
+	.id = V4L2_CID_MB_THRESHOLD2,
+	.name = "MB Threshold Region 2",
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.def = 200,
+	.max = 32767,
+	.step = 1,
+};
+
+static const struct v4l2_ctrl_config go7007_pixel_threshold3_ctrl = {
+	.ops = &go7007_ctrl_ops,
+	.id = V4L2_CID_PIXEL_THRESHOLD3,
+	.name = "Pixel Threshold Region 3",
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.def = 20,
+	.max = 32767,
+	.step = 1,
+};
+
+static const struct v4l2_ctrl_config go7007_motion_threshold3_ctrl = {
+	.ops = &go7007_ctrl_ops,
+	.id = V4L2_CID_MOTION_THRESHOLD3,
+	.name = "Motion Threshold Region 3",
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.def = 80,
+	.max = 32767,
+	.step = 1,
+};
+
+static const struct v4l2_ctrl_config go7007_mb_threshold3_ctrl = {
+	.ops = &go7007_ctrl_ops,
+	.id = V4L2_CID_MB_THRESHOLD3,
+	.name = "MB Threshold Region 3",
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.def = 200,
+	.max = 32767,
+	.step = 1,
+};
+
+static const struct v4l2_ctrl_config go7007_mb_regions_ctrl = {
+	.ops = &go7007_ctrl_ops,
+	.id = V4L2_CID_DETECT_MD_REGION_GRID,
+	.dims = { 576 / 16, 720 / 16 },
+	.max = 3,
+	.step = 1,
+};
+
 int go7007_v4l2_ctrl_init(struct go7007 *go)
 {
 	struct v4l2_ctrl_handler *hdl = &go->hdl;
 	struct v4l2_ctrl *ctrl;
 
-	v4l2_ctrl_handler_init(hdl, 13);
+	v4l2_ctrl_handler_init(hdl, 22);
 	go->mpeg_video_gop_size = v4l2_ctrl_new_std(hdl, NULL,
 			V4L2_CID_MPEG_VIDEO_GOP_SIZE, 0, 34, 1, 15);
 	go->mpeg_video_gop_closure = v4l2_ctrl_new_std(hdl, NULL,
@@ -968,6 +1073,24 @@ int go7007_v4l2_ctrl_init(struct go7007 *go)
 			V4L2_JPEG_ACTIVE_MARKER_DHT);
 	if (ctrl)
 		ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+	v4l2_ctrl_new_custom(hdl, &go7007_pixel_threshold0_ctrl, NULL);
+	v4l2_ctrl_new_custom(hdl, &go7007_motion_threshold0_ctrl, NULL);
+	v4l2_ctrl_new_custom(hdl, &go7007_mb_threshold0_ctrl, NULL);
+	v4l2_ctrl_new_custom(hdl, &go7007_pixel_threshold1_ctrl, NULL);
+	v4l2_ctrl_new_custom(hdl, &go7007_motion_threshold1_ctrl, NULL);
+	v4l2_ctrl_new_custom(hdl, &go7007_mb_threshold1_ctrl, NULL);
+	v4l2_ctrl_new_custom(hdl, &go7007_pixel_threshold2_ctrl, NULL);
+	v4l2_ctrl_new_custom(hdl, &go7007_motion_threshold2_ctrl, NULL);
+	v4l2_ctrl_new_custom(hdl, &go7007_mb_threshold2_ctrl, NULL);
+	v4l2_ctrl_new_custom(hdl, &go7007_pixel_threshold3_ctrl, NULL);
+	v4l2_ctrl_new_custom(hdl, &go7007_motion_threshold3_ctrl, NULL);
+	v4l2_ctrl_new_custom(hdl, &go7007_mb_threshold3_ctrl, NULL);
+	v4l2_ctrl_new_custom(hdl, &go7007_mb_regions_ctrl, NULL);
+	go->modet_mode = v4l2_ctrl_new_std_menu(hdl, NULL,
+			V4L2_CID_DETECT_MD_MODE,
+			V4L2_DETECT_MD_MODE_REGION_GRID,
+			1 << V4L2_DETECT_MD_MODE_THRESHOLD_GRID,
+			V4L2_DETECT_MD_MODE_DISABLED);
 	if (hdl->error) {
 		int rv = hdl->error;
 
diff --git a/drivers/staging/media/go7007/go7007.h b/drivers/staging/media/go7007/go7007.h
deleted file mode 100644
index 54b9897..0000000
--- a/drivers/staging/media/go7007/go7007.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2005-2006 Micronas USA Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and the associated README documentation file (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
- * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-struct go7007_md_params {
-	__u16 region;
-	__u16 trigger;
-	__u16 pixel_threshold;
-	__u16 motion_threshold;
-	__u32 reserved[8];
-};
-
-struct go7007_md_region {
-	__u16 region;
-	__u16 flags;
-	struct v4l2_clip *clips;
-	__u32 reserved[8];
-};
-
-#define	GO7007IOC_S_MD_PARAMS	_IOWR('V', BASE_VIDIOC_PRIVATE + 6, \
-					struct go7007_md_params)
-#define	GO7007IOC_G_MD_PARAMS	_IOR('V', BASE_VIDIOC_PRIVATE + 7, \
-					struct go7007_md_params)
-#define	GO7007IOC_S_MD_REGION	_IOW('V', BASE_VIDIOC_PRIVATE + 8, \
-					struct go7007_md_region)
diff --git a/drivers/staging/media/go7007/saa7134-go7007.c b/drivers/staging/media/go7007/saa7134-go7007.c
index e40f7fb..df5cb1c 100644
--- a/drivers/staging/media/go7007/saa7134-go7007.c
+++ b/drivers/staging/media/go7007/saa7134-go7007.c
@@ -33,7 +33,6 @@
 
 #include "saa7134.h"
 #include "saa7134-reg.h"
-#include "go7007.h"
 #include "go7007-priv.h"
 
 /*#define GO7007_HPI_DEBUG*/
-- 
2.0.0.rc0


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

* Re: [REVIEWv4 PATCH 04/34] videodev2.h: add struct v4l2_query_ext_ctrl and VIDIOC_QUERY_EXT_CTRL.
  2014-06-12 11:52   ` [REVIEWv4 PATCH 04/34] videodev2.h: add struct v4l2_query_ext_ctrl and VIDIOC_QUERY_EXT_CTRL Hans Verkuil
@ 2014-06-12 12:38     ` Sakari Ailus
  0 siblings, 0 replies; 36+ messages in thread
From: Sakari Ailus @ 2014-06-12 12:38 UTC (permalink / raw)
  To: Hans Verkuil; +Cc: linux-media, laurent.pinchart, s.nawrocki, Hans Verkuil

Hi Hans,

On Thu, Jun 12, 2014 at 01:52:36PM +0200, Hans Verkuil wrote:
> From: Hans Verkuil <hans.verkuil@cisco.com>
> 
> Add a new struct and ioctl to extend the amount of information you can
> get for a control.
> 
> The range is now a s64 type, and array dimensions and element size can be
> reported through nr_of_dims/dims/elems/elem_size.
> 
> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
> ---
>  include/uapi/linux/videodev2.h | 20 ++++++++++++++++++++
>  1 file changed, 20 insertions(+)
> 
> diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
> index 438c4a6..7d94adc 100644
> --- a/include/uapi/linux/videodev2.h
> +++ b/include/uapi/linux/videodev2.h
> @@ -1269,6 +1269,7 @@ struct v4l2_ext_controls {
>  #define V4L2_CTRL_ID_MASK      	  (0x0fffffff)
>  #define V4L2_CTRL_ID2CLASS(id)    ((id) & 0x0fff0000UL)
>  #define V4L2_CTRL_DRIVER_PRIV(id) (((id) & 0xffff) >= 0x1000)
> +#define V4L2_CTRL_MAX_DIMS	  (8)
>  
>  enum v4l2_ctrl_type {
>  	V4L2_CTRL_TYPE_INTEGER	     = 1,
> @@ -1298,6 +1299,23 @@ struct v4l2_queryctrl {
>  	__u32		     reserved[2];
>  };
>  
> +/*  Used in the VIDIOC_QUERY_EXT_CTRL ioctl for querying extended controls */
> +struct v4l2_query_ext_ctrl {
> +	__u32		     id;
> +	__u32		     type;
> +	char		     name[32];
> +	__s64		     minimum;
> +	__s64		     maximum;
> +	__u64		     step;
> +	__s64		     default_value;
> +	__u32                flags;
> +	__u32                elem_size;
> +	__u32                elems;
> +	__u32                nr_of_dims;
> +	__u32                dims[V4L2_CTRL_MAX_DIMS];
> +	__u32		     reserved[16];

Considering that units are going to be added (probably 16 or even 32 bytes),
I might add even more. Something to be discussed is fractional parts which
is a related topic.

As you have already 34 patches in your set, perhaps it'd be good to postpone
these.

> +};
> +
>  /*  Used in the VIDIOC_QUERYMENU ioctl for querying menu items */
>  struct v4l2_querymenu {
>  	__u32		id;
> @@ -2011,6 +2029,8 @@ struct v4l2_create_buffers {
>     Never use these in applications! */
>  #define VIDIOC_DBG_G_CHIP_INFO  _IOWR('V', 102, struct v4l2_dbg_chip_info)
>  
> +#define VIDIOC_QUERY_EXT_CTRL	_IOWR('V', 103, struct v4l2_query_ext_ctrl)
> +
>  /* Reminder: when adding new ioctls please add support for them to
>     drivers/media/video/v4l2-compat-ioctl32.c as well! */
>  

-- 
Regards,

Sakari Ailus
e-mail: sakari.ailus@iki.fi	XMPP: sailus@retiisi.org.uk

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

end of thread, other threads:[~2014-06-12 12:39 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-06-12 11:52 [REVIEWv4 PATCH 00/34] Add support for compound controls, use in solo/go7007 Hans Verkuil
2014-06-12 11:52 ` [REVIEWv4 PATCH 01/34] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
2014-06-12 11:52   ` [REVIEWv4 PATCH 02/34] v4l2-ctrls: use pr_info/cont instead of printk Hans Verkuil
2014-06-12 11:52   ` [REVIEWv4 PATCH 03/34] videodev2.h: add initial support for compound controls Hans Verkuil
2014-06-12 11:52   ` [REVIEWv4 PATCH 04/34] videodev2.h: add struct v4l2_query_ext_ctrl and VIDIOC_QUERY_EXT_CTRL Hans Verkuil
2014-06-12 12:38     ` Sakari Ailus
2014-06-12 11:52   ` [REVIEWv4 PATCH 05/34] v4l2-ctrls: add support for compound types Hans Verkuil
2014-06-12 11:52   ` [REVIEWv4 PATCH 06/34] v4l2: integrate support for VIDIOC_QUERY_EXT_CTRL Hans Verkuil
2014-06-12 11:52   ` [REVIEWv4 PATCH 07/34] v4l2-ctrls: create type_ops Hans Verkuil
2014-06-12 11:52   ` [REVIEWv4 PATCH 08/34] v4l2-ctrls: rewrite copy routines to operate on union v4l2_ctrl_ptr Hans Verkuil
2014-06-12 11:52   ` [REVIEWv4 PATCH 09/34] v4l2-ctrls: compare values only once Hans Verkuil
2014-06-12 11:52   ` [REVIEWv4 PATCH 10/34] v4l2-ctrls: use ptrs for all but the s32 type Hans Verkuil
2014-06-12 11:52   ` [REVIEWv4 PATCH 11/34] v4l2-ctrls: prepare for array support Hans Verkuil
2014-06-12 11:52   ` [REVIEWv4 PATCH 12/34] " Hans Verkuil
2014-06-12 11:52   ` [REVIEWv4 PATCH 13/34] v4l2-ctrls: type_ops can handle array elements Hans Verkuil
2014-06-12 11:52   ` [REVIEWv4 PATCH 14/34] v4l2-ctrls: add array support Hans Verkuil
2014-06-12 11:52   ` [REVIEWv4 PATCH 15/34] v4l2-ctrls: return elem_size instead of strlen Hans Verkuil
2014-06-12 11:52   ` [REVIEWv4 PATCH 16/34] v4l2-ctrl: fix error return of copy_to/from_user Hans Verkuil
2014-06-12 11:52   ` [REVIEWv4 PATCH 17/34] DocBook media: document VIDIOC_QUERY_EXT_CTRL Hans Verkuil
2014-06-12 11:52   ` [REVIEWv4 PATCH 18/34] DocBook media: update VIDIOC_G/S/TRY_EXT_CTRLS Hans Verkuil
2014-06-12 11:52   ` [REVIEWv4 PATCH 19/34] DocBook media: fix coding style in the control example code Hans Verkuil
2014-06-12 11:52   ` [REVIEWv4 PATCH 20/34] DocBook media: improve control section Hans Verkuil
2014-06-12 11:52   ` [REVIEWv4 PATCH 21/34] DocBook media: update " Hans Verkuil
2014-06-12 11:52   ` [REVIEWv4 PATCH 22/34] v4l2-controls.txt: update to the new way of accessing controls Hans Verkuil
2014-06-12 11:52   ` [REVIEWv4 PATCH 23/34] v4l2-ctrls/videodev2.h: add u8 and u16 types Hans Verkuil
2014-06-12 11:52   ` [REVIEWv4 PATCH 24/34] DocBook media: document new u8 and u16 control types Hans Verkuil
2014-06-12 11:52   ` [REVIEWv4 PATCH 25/34] v4l2-ctrls: fix comments Hans Verkuil
2014-06-12 11:52   ` [REVIEWv4 PATCH 26/34] v4l2-ctrls/v4l2-controls.h: add MD controls Hans Verkuil
2014-06-12 11:52   ` [REVIEWv4 PATCH 27/34] DocBook media: document new motion detection controls Hans Verkuil
2014-06-12 11:53   ` [REVIEWv4 PATCH 28/34] v4l2: add a motion detection event Hans Verkuil
2014-06-12 11:53   ` [REVIEWv4 PATCH 29/34] DocBook: document new v4l " Hans Verkuil
2014-06-12 11:53   ` [REVIEWv4 PATCH 30/34] solo6x10: implement the new motion detection controls Hans Verkuil
2014-06-12 11:53   ` [REVIEWv4 PATCH 31/34] solo6x10: implement the motion detection event Hans Verkuil
2014-06-12 11:53   ` [REVIEWv4 PATCH 32/34] solo6x10: fix 'dma from stack' warning Hans Verkuil
2014-06-12 11:53   ` [REVIEWv4 PATCH 33/34] solo6x10: check dma_map_sg() return value Hans Verkuil
2014-06-12 11:53   ` [REVIEWv4 PATCH 34/34] go7007: add motion detection support Hans Verkuil

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).