linux-media.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [REVIEWv3 PATCH 00/35] Add support for complex controls, use in solo/go7007
@ 2014-02-17  9:57 Hans Verkuil
  2014-02-17  9:57 ` [REVIEWv3 PATCH 01/35] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
                   ` (35 more replies)
  0 siblings, 36 replies; 66+ messages in thread
From: Hans Verkuil @ 2014-02-17  9:57 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	sakari.ailus

This patch series adds support for complex controls (aka 'Properties') to
the control framework and uses them in the go7007 and solo6x10 drivers.
It is the first part of a larger patch series that adds support for configuration
stores and support for 'Multiple Selections'.

This patch series is identical to the REVIEWv2 series:

http://www.spinics.net/lists/linux-media/msg72748.html

except that patches 35-40 have been folded into the main series (except for patch
40 which is added as a new patch since it is a standalone bug fix).

If there are no more objections, then I am going to make a pull request for this
in one week time.

I will post a pull request based on this series today as well.

Regards,

	Hans


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

* [REVIEWv3 PATCH 01/35] v4l2-ctrls: increase internal min/max/step/def to 64 bit
  2014-02-17  9:57 [REVIEWv3 PATCH 00/35] Add support for complex controls, use in solo/go7007 Hans Verkuil
@ 2014-02-17  9:57 ` Hans Verkuil
  2014-02-17  9:57 ` [REVIEWv3 PATCH 02/35] v4l2-ctrls: add unit string Hans Verkuil
                   ` (34 subsequent siblings)
  35 siblings, 0 replies; 66+ messages in thread
From: Hans Verkuil @ 2014-02-17  9:57 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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 added by mt9v032.c 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/platform/vivi.c               |  5 +-
 drivers/media/v4l2-core/v4l2-common.c       |  6 +-
 drivers/media/v4l2-core/v4l2-ctrls.c        | 93 ++++++++++++++++++-----------
 drivers/staging/media/msi3101/sdr-msi3101.c |  2 +-
 include/media/v4l2-ctrls.h                  | 38 ++++++------
 6 files changed, 87 insertions(+), 59 deletions(-)

diff --git a/drivers/media/i2c/mt9v032.c b/drivers/media/i2c/mt9v032.c
index 36c504b..4559fee 100644
--- a/drivers/media/i2c/mt9v032.c
+++ b/drivers/media/i2c/mt9v032.c
@@ -925,7 +925,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/platform/vivi.c b/drivers/media/platform/vivi.c
index 2d4e73b..3c92ce3 100644
--- a/drivers/media/platform/vivi.c
+++ b/drivers/media/platform/vivi.c
@@ -1233,7 +1233,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,
 };
@@ -1243,6 +1243,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 6ff002b..cac2713 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -864,7 +864,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;
@@ -1018,14 +1018,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;
@@ -1322,7 +1331,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:
@@ -1330,7 +1339,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:
@@ -1355,23 +1365,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;
@@ -1397,9 +1414,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)
@@ -1623,7 +1637,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)
 {
@@ -1708,10 +1722,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,
@@ -1744,7 +1758,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;
@@ -1764,15 +1778,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);
@@ -1793,14 +1809,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.
@@ -1824,12 +1842,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);
@@ -2856,13 +2876,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/sdr-msi3101.c b/drivers/staging/media/msi3101/sdr-msi3101.c
index 4c3bf77..1152ca3 100644
--- a/drivers/staging/media/msi3101/sdr-msi3101.c
+++ b/drivers/staging/media/msi3101/sdr-msi3101.c
@@ -1713,7 +1713,7 @@ static int msi3101_s_ctrl(struct v4l2_ctrl *ctrl)
 					ctrl_handler);
 	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=%llu\n",
 			__func__, ctrl->id, ctrl->name, ctrl->val,
 			ctrl->minimum, ctrl->maximum, ctrl->step);
 
diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
index 16f7f26..0b347e8 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;
@@ -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.
-- 
1.8.4.rc3


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

* [REVIEWv3 PATCH 02/35] v4l2-ctrls: add unit string.
  2014-02-17  9:57 [REVIEWv3 PATCH 00/35] Add support for complex controls, use in solo/go7007 Hans Verkuil
  2014-02-17  9:57 ` [REVIEWv3 PATCH 01/35] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
@ 2014-02-17  9:57 ` Hans Verkuil
  2014-02-17  9:57 ` [REVIEWv3 PATCH 03/35] v4l2-ctrls: use pr_info/cont instead of printk Hans Verkuil
                   ` (33 subsequent siblings)
  35 siblings, 0 replies; 66+ messages in thread
From: Hans Verkuil @ 2014-02-17  9:57 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	sakari.ailus, Hans Verkuil

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

The upcoming VIDIOC_QUERY_EXT_CTRL adds support for a unit string. This
allows userspace to show the unit belonging to a particular control.

This patch adds support for the unit string to the control framework.

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

diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
index ccaa38f..ee8ea66 100644
--- a/drivers/media/v4l2-core/v4l2-common.c
+++ b/drivers/media/v4l2-core/v4l2-common.c
@@ -114,12 +114,13 @@ EXPORT_SYMBOL(v4l2_ctrl_check);
 int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 _min, s32 _max, s32 _step, s32 _def)
 {
 	const char *name;
+	const char *unit = NULL;
 	s64 min = _min;
 	s64 max = _max;
 	u64 step = _step;
 	s64 def = _def;
 
-	v4l2_ctrl_fill(qctrl->id, &name, &qctrl->type,
+	v4l2_ctrl_fill(qctrl->id, &name, &unit, &qctrl->type,
 		       &min, &max, &step, &def, &qctrl->flags);
 
 	if (name == NULL)
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index cac2713..72ffe76 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -863,8 +863,9 @@ 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,
-		    s64 *min, s64 *max, u64 *step, s64 *def, u32 *flags)
+void v4l2_ctrl_fill(u32 id, const char **name, const char **unit,
+		    enum v4l2_ctrl_type *type, s64 *min, s64 *max,
+		    u64 *step, s64 *def, u32 *flags)
 {
 	*name = v4l2_ctrl_get_name(id);
 	*flags = 0;
@@ -1636,7 +1637,8 @@ unlock:
 /* Add a new control */
 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,
+			u32 id, const char *name, const char *unit,
+			enum v4l2_ctrl_type type,
 			s64 min, s64 max, u64 step, s64 def,
 			u32 flags, const char * const *qmenu,
 			const s64 *qmenu_int, void *priv)
@@ -1684,6 +1686,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 	ctrl->ops = ops;
 	ctrl->id = id;
 	ctrl->name = name;
+	ctrl->unit = unit;
 	ctrl->type = type;
 	ctrl->flags = flags;
 	ctrl->minimum = min;
@@ -1718,6 +1721,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl,
 	bool is_menu;
 	struct v4l2_ctrl *ctrl;
 	const char *name = cfg->name;
+	const char *unit = cfg->unit;
 	const char * const *qmenu = cfg->qmenu;
 	const s64 *qmenu_int = cfg->qmenu_int;
 	enum v4l2_ctrl_type type = cfg->type;
@@ -1728,8 +1732,8 @@ struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl,
 	s64 def = cfg->def;
 
 	if (name == NULL)
-		v4l2_ctrl_fill(cfg->id, &name, &type, &min, &max, &step,
-								&def, &flags);
+		v4l2_ctrl_fill(cfg->id, &name, &unit, &type,
+			       &min, &max, &step, &def, &flags);
 
 	is_menu = (cfg->type == V4L2_CTRL_TYPE_MENU ||
 		   cfg->type == V4L2_CTRL_TYPE_INTEGER_MENU);
@@ -1745,7 +1749,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->id, name, unit,
 			type, min, max,
 			is_menu ? cfg->menu_skip_mask : step,
 			def, flags, qmenu, qmenu_int, priv);
@@ -1761,16 +1765,17 @@ struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl,
 			u32 id, s64 min, s64 max, u64 step, s64 def)
 {
 	const char *name;
+	const char *unit = NULL;
 	enum v4l2_ctrl_type type;
 	u32 flags;
 
-	v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
+	v4l2_ctrl_fill(id, &name, &unit, &type, &min, &max, &step, &def, &flags);
 	if (type == V4L2_CTRL_TYPE_MENU
 	    || type == V4L2_CTRL_TYPE_INTEGER_MENU) {
 		handler_set_err(hdl, -EINVAL);
 		return NULL;
 	}
-	return v4l2_ctrl_new(hdl, ops, id, name, type,
+	return v4l2_ctrl_new(hdl, ops, id, name, unit, type,
 			     min, max, step, def, flags, NULL, NULL, NULL);
 }
 EXPORT_SYMBOL(v4l2_ctrl_new_std);
@@ -1784,6 +1789,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl,
 	const s64 *qmenu_int = NULL;
 	unsigned int qmenu_int_len = 0;
 	const char *name;
+	const char *unit = NULL;
 	enum v4l2_ctrl_type type;
 	s64 min;
 	s64 max = _max;
@@ -1791,7 +1797,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl,
 	u64 step;
 	u32 flags;
 
-	v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
+	v4l2_ctrl_fill(id, &name, &unit, &type, &min, &max, &step, &def, &flags);
 
 	if (type == V4L2_CTRL_TYPE_MENU)
 		qmenu = v4l2_ctrl_get_menu(id);
@@ -1802,7 +1808,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, id, name, unit, type,
 			     0, max, mask, def, flags, qmenu, qmenu_int, NULL);
 }
 EXPORT_SYMBOL(v4l2_ctrl_new_std_menu);
@@ -1814,6 +1820,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu_items(struct v4l2_ctrl_handler *hdl,
 {
 	enum v4l2_ctrl_type type;
 	const char *name;
+	const char *unit = NULL;
 	u32 flags;
 	u64 step;
 	s64 min;
@@ -1828,12 +1835,12 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu_items(struct v4l2_ctrl_handler *hdl,
 		return NULL;
 	}
 
-	v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
+	v4l2_ctrl_fill(id, &name, &unit, &type, &min, &max, &step, &def, &flags);
 	if (type != V4L2_CTRL_TYPE_MENU || qmenu == NULL) {
 		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, id, name, unit, type, 0, max, mask, def,
 			     flags, qmenu, NULL, NULL);
 
 }
@@ -1845,6 +1852,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl,
 			u32 id, u8 _max, u8 _def, const s64 *qmenu_int)
 {
 	const char *name;
+	const char *unit = NULL;
 	enum v4l2_ctrl_type type;
 	s64 min;
 	u64 step;
@@ -1852,12 +1860,12 @@ struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl,
 	s64 def = _def;
 	u32 flags;
 
-	v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
+	v4l2_ctrl_fill(id, &name, &unit, &type, &min, &max, &step, &def, &flags);
 	if (type != V4L2_CTRL_TYPE_INTEGER_MENU) {
 		handler_set_err(hdl, -EINVAL);
 		return NULL;
 	}
-	return v4l2_ctrl_new(hdl, ops, id, name, type,
+	return v4l2_ctrl_new(hdl, ops, id, name, unit, type,
 			     0, max, 0, def, flags, NULL, qmenu_int, NULL);
 }
 EXPORT_SYMBOL(v4l2_ctrl_new_int_menu);
diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
index 0b347e8..3998049 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -85,6 +85,7 @@ typedef void (*v4l2_ctrl_notify_fnc)(struct v4l2_ctrl *ctrl, void *priv);
   * @ops:	The control ops.
   * @id:	The control ID.
   * @name:	The control name.
+  * @unit:	The control's unit. May be NULL.
   * @type:	The control type.
   * @minimum:	The control's minimum value.
   * @maximum:	The control's maximum value.
@@ -130,6 +131,7 @@ struct v4l2_ctrl {
 	const struct v4l2_ctrl_ops *ops;
 	u32 id;
 	const char *name;
+	const char *unit;
 	enum v4l2_ctrl_type type;
 	s64 minimum, maximum, default_value;
 	union {
@@ -207,6 +209,7 @@ struct v4l2_ctrl_handler {
   * @ops:	The control ops.
   * @id:	The control ID.
   * @name:	The control name.
+  * @unit:	The control's unit.
   * @type:	The control type.
   * @min:	The control's minimum value.
   * @max:	The control's maximum value.
@@ -230,6 +233,7 @@ struct v4l2_ctrl_config {
 	const struct v4l2_ctrl_ops *ops;
 	u32 id;
 	const char *name;
+	const char *unit;
 	enum v4l2_ctrl_type type;
 	s64 min;
 	s64 max;
@@ -249,15 +253,16 @@ struct v4l2_ctrl_config {
   * and @name will be NULL.
   *
   * This function will overwrite the contents of @name, @type and @flags.
-  * The contents of @min, @max, @step and @def may be modified depending on
-  * the type.
+  * The contents of @unit, @min, @max, @step and @def may be modified depending
+  * on the type.
   *
   * Do not use in drivers! It is used internally for backwards compatibility
   * control handling only. Once all drivers are converted to use the new
   * control framework this function will no longer be exported.
   */
-void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
-		    s64 *min, s64 *max, u64 *step, s64 *def, u32 *flags);
+void v4l2_ctrl_fill(u32 id, const char **name, const char **unit,
+		    enum v4l2_ctrl_type *type, s64 *min, s64 *max,
+		    u64 *step, s64 *def, u32 *flags);
 
 
 /** v4l2_ctrl_handler_init_class() - Initialize the control handler.
-- 
1.8.4.rc3


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

* [REVIEWv3 PATCH 03/35] v4l2-ctrls: use pr_info/cont instead of printk.
  2014-02-17  9:57 [REVIEWv3 PATCH 00/35] Add support for complex controls, use in solo/go7007 Hans Verkuil
  2014-02-17  9:57 ` [REVIEWv3 PATCH 01/35] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
  2014-02-17  9:57 ` [REVIEWv3 PATCH 02/35] v4l2-ctrls: add unit string Hans Verkuil
@ 2014-02-17  9:57 ` Hans Verkuil
  2014-02-17  9:57 ` [REVIEWv3 PATCH 04/35] videodev2.h: add initial support for complex controls Hans Verkuil
                   ` (32 subsequent siblings)
  35 siblings, 0 replies; 66+ messages in thread
From: Hans Verkuil @ 2014-02-17  9:57 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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 72ffe76..df8ed0a 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -2045,45 +2045,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 */
-- 
1.8.4.rc3


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

* [REVIEWv3 PATCH 04/35] videodev2.h: add initial support for complex controls.
  2014-02-17  9:57 [REVIEWv3 PATCH 00/35] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (2 preceding siblings ...)
  2014-02-17  9:57 ` [REVIEWv3 PATCH 03/35] v4l2-ctrls: use pr_info/cont instead of printk Hans Verkuil
@ 2014-02-17  9:57 ` Hans Verkuil
  2014-03-11 19:34   ` Mauro Carvalho Chehab
  2014-02-17  9:57 ` [REVIEWv3 PATCH 05/35] videodev2.h: add struct v4l2_query_ext_ctrl and VIDIOC_QUERY_EXT_CTRL Hans Verkuil
                   ` (31 subsequent siblings)
  35 siblings, 1 reply; 66+ messages in thread
From: Hans Verkuil @ 2014-02-17  9:57 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	sakari.ailus, Hans Verkuil

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

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

Such controls always have the V4L2_CTRL_FLAG_HIDDEN flag set. Note that
'simple' controls can also set that flag.

The existing V4L2_CTRL_FLAG_NEXT_CTRL flag will only enumerate controls
that do not have the HIDDEN flag, so a new V4L2_CTRL_FLAG_NEXT_HIDDEN flag
is added to enumerate hidden controls. Set both flags to enumerate any
controls (hidden or not).

Complex control types will start at V4L2_CTRL_COMPLEX_TYPES. In addition, any
control that uses the new 'p' field or the existing 'string' field will have
flag V4L2_CTRL_FLAG_IS_PTR 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 | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 6ae7bbe..4d7782a 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -1228,6 +1228,7 @@ struct v4l2_ext_control {
 		__s32 value;
 		__s64 value64;
 		char *string;
+		void *p;
 	};
 } __attribute__ ((packed));
 
@@ -1252,7 +1253,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,
+
+	/* Complex types are >= 0x0100 */
+	V4L2_CTRL_COMPLEX_TYPES	     = 0x0100,
 };
 
 /*  Used in the VIDIOC_QUERYCTRL ioctl for querying controls */
@@ -1288,9 +1292,12 @@ 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_HIDDEN		0x0100
+#define V4L2_CTRL_FLAG_IS_PTR		0x0200
 
-/*  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_HIDDEN	0x40000000
 
 /*  User-class control IDs defined by V4L2 */
 #define V4L2_CID_MAX_CTRLS		1024
-- 
1.8.4.rc3


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

* [REVIEWv3 PATCH 05/35] videodev2.h: add struct v4l2_query_ext_ctrl and VIDIOC_QUERY_EXT_CTRL.
  2014-02-17  9:57 [REVIEWv3 PATCH 00/35] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (3 preceding siblings ...)
  2014-02-17  9:57 ` [REVIEWv3 PATCH 04/35] videodev2.h: add initial support for complex controls Hans Verkuil
@ 2014-02-17  9:57 ` Hans Verkuil
  2014-03-11 19:42   ` Mauro Carvalho Chehab
  2014-02-17  9:57 ` [REVIEWv3 PATCH 06/35] v4l2-ctrls: add support for complex types Hans Verkuil
                   ` (30 subsequent siblings)
  35 siblings, 1 reply; 66+ messages in thread
From: Hans Verkuil @ 2014-02-17  9:57 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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.

It gives back a unit string, the range is now a s64 type, and the matrix
and element size can be reported through cols/rows/elem_size.

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

diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 4d7782a..858a6f3 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -1272,6 +1272,35 @@ 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];
+	char		     unit[32];
+	union {
+		__s64 val;
+		__u32 reserved[4];
+	} min;
+	union {
+		__s64 val;
+		__u32 reserved[4];
+	} max;
+	union {
+		__u64 val;
+		__u32 reserved[4];
+	} step;
+	union {
+		__s64 val;
+		__u32 reserved[4];
+	} def;
+	__u32                flags;
+	__u32                cols;
+	__u32                rows;
+	__u32                elem_size;
+	__u32		     reserved[17];
+};
+
 /*  Used in the VIDIOC_QUERYMENU ioctl for querying menu items */
 struct v4l2_querymenu {
 	__u32		id;
@@ -1965,6 +1994,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! */
 
-- 
1.8.4.rc3


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

* [REVIEWv3 PATCH 06/35] v4l2-ctrls: add support for complex types.
  2014-02-17  9:57 [REVIEWv3 PATCH 00/35] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (4 preceding siblings ...)
  2014-02-17  9:57 ` [REVIEWv3 PATCH 05/35] videodev2.h: add struct v4l2_query_ext_ctrl and VIDIOC_QUERY_EXT_CTRL Hans Verkuil
@ 2014-02-17  9:57 ` Hans Verkuil
  2014-03-11 20:14   ` Mauro Carvalho Chehab
  2014-02-17  9:57 ` [REVIEWv3 PATCH 07/35] v4l2: integrate support for VIDIOC_QUERY_EXT_CTRL Hans Verkuil
                   ` (29 subsequent siblings)
  35 siblings, 1 reply; 66+ messages in thread
From: Hans Verkuil @ 2014-02-17  9:57 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	sakari.ailus, Hans Verkuil

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

This patch implements initial support for complex types.

For the most part 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), but one change needs more explanation:

The v4l2_ctrl struct adds a 'new' field and a 'stores' array at the end
of the struct. This is in preparation for future patches where each control
can have multiple configuration stores. The idea is that stores[0] is the current
control value, stores[1] etc. are the control values for each configuration store
and the 'new' value can be accessed through 'stores[-1]', i.e. the 'new' field.
However, for now only stores[-1] and stores[0] is used.

Drivers are not expected to use the stores array (at least not while support
for configuration stores is not yet fully added), but the stores array will
be used inside the control framework.

These new fields use the v4l2_ctrl_ptr union, which is a pointer to a control
value.

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

diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index df8ed0a..5d1eeea 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1095,20 +1095,6 @@ void v4l2_ctrl_fill(u32 id, const char **name, const char **unit,
 }
 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));
@@ -1117,7 +1103,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;
@@ -1152,6 +1138,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->p, ctrl->cur.p, ctrl->elem_size);
+
 	switch (ctrl->type) {
 	case V4L2_CTRL_TYPE_STRING:
 		len = strlen(ctrl->cur.string);
@@ -1179,6 +1168,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->p, ctrl->elem_size);
+
 	switch (ctrl->type) {
 	case V4L2_CTRL_TYPE_INTEGER64:
 		ctrl->val64 = c->value64;
@@ -1213,6 +1205,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->p, ctrl->p, ctrl->elem_size);
+
 	switch (ctrl->type) {
 	case V4L2_CTRL_TYPE_STRING:
 		len = strlen(ctrl->string);
@@ -1239,6 +1234,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;
@@ -1253,8 +1249,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) {
@@ -1294,7 +1295,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;
 	}
 }
@@ -1507,7 +1511,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;
@@ -1577,8 +1581,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 hidden.
+	 */
+	if (!(ctrl->flags & V4L2_CTRL_FLAG_HIDDEN) &&
+	    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;
 
@@ -1640,23 +1648,36 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 			u32 id, const char *name, const char *unit,
 			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_COMPLEX_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);
 		return NULL;
 	}
+	/* Complex controls are always hidden */
+	if (type >= V4L2_CTRL_COMPLEX_TYPES)
+		flags |= V4L2_CTRL_FLAG_HIDDEN;
 	err = check_range(type, min, max, step, def);
 	if (err) {
 		handler_set_err(hdl, err);
@@ -1667,12 +1688,13 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 		return NULL;
 	}
 
+	sz_extra = sizeof(union v4l2_ctrl_ptr);
 	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_COMPLEX_TYPES)
+		sz_extra += 2 * elem_size;
 
 	ctrl = kzalloc(sizeof(*ctrl) + sz_extra, GFP_KERNEL);
 	if (ctrl == NULL) {
@@ -1692,18 +1714,31 @@ 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_COMPLEX_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->stores[1];
+
+	if (ctrl->is_string) {
+		ctrl->string = ctrl->new.p_char = data;
+		ctrl->stores[0].p_char = 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 = ctrl->new.p = data;
+		ctrl->stores[0].p = data + elem_size;
+	} else {
+		ctrl->new.p = &ctrl->val;
+		ctrl->stores[0].p = &ctrl->cur.val;
 	}
 	if (handler_new_ref(hdl, ctrl)) {
 		kfree(ctrl);
@@ -1752,7 +1787,8 @@ struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl,
 	ctrl = v4l2_ctrl_new(hdl, cfg->ops, cfg->id, name, unit,
 			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;
@@ -1770,13 +1806,15 @@ struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl,
 	u32 flags;
 
 	v4l2_ctrl_fill(id, &name, &unit, &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_COMPLEX_TYPES) {
 		handler_set_err(hdl, -EINVAL);
 		return NULL;
 	}
 	return v4l2_ctrl_new(hdl, ops, id, name, unit, type,
-			     min, max, step, def, flags, NULL, NULL, NULL);
+			     min, max, step, def, 0,
+			     flags, NULL, NULL, NULL);
 }
 EXPORT_SYMBOL(v4l2_ctrl_new_std);
 
@@ -1809,7 +1847,8 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl,
 		return NULL;
 	}
 	return v4l2_ctrl_new(hdl, ops, id, name, unit, 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);
 
@@ -1841,7 +1880,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, unit, type, 0, max, mask, def,
-			     flags, qmenu, NULL, NULL);
+			     0, flags, qmenu, NULL, NULL);
 
 }
 EXPORT_SYMBOL(v4l2_ctrl_new_std_menu_items);
@@ -1866,7 +1905,8 @@ struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl,
 		return NULL;
 	}
 	return v4l2_ctrl_new(hdl, ops, id, name, unit, 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);
 
@@ -2154,9 +2194,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_HIDDEN;
 	u32 id = qc->id & V4L2_CTRL_ID_MASK;
 	struct v4l2_ctrl_ref *ref;
 	struct v4l2_ctrl *ctrl;
@@ -2169,7 +2210,22 @@ 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)) {
+		unsigned mask;
+		unsigned match;
+
+		if ((qc->id & next_flags) == V4L2_CTRL_FLAG_NEXT_HIDDEN) {
+			/* Match any hidden control */
+			mask = match = V4L2_CTRL_FLAG_HIDDEN;
+		} else if ((qc->id & next_flags) == next_flags) {
+			/* Match any control, hidden or not */
+			mask = match = 0;
+		} else {
+			/* Match any control that is not hidden */
+			mask = V4L2_CTRL_FLAG_HIDDEN;
+			match = 0;
+		}
+
 		/* Find the next control with ID > qc->id */
 
 		/* Did we reach the end of the control list? */
@@ -2177,19 +2233,28 @@ 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)
+				if (id < ref->ctrl->id &&
+				    (ref->ctrl->flags & 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)
+				if (id < ref->ctrl->id &&
+				    (ref->ctrl->flags & mask) == match)
 					break;
+			if (&ref->node == &hdl->ctrl_refs)
+				ref = NULL;
 		}
 	}
 	mutex_unlock(hdl->lock);
+
 	if (!ref)
 		return -EINVAL;
 
@@ -2200,23 +2265,66 @@ 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->minimum = ctrl->minimum;
-	qc->maximum = ctrl->maximum;
-	qc->default_value = ctrl->default_value;
+	qc->flags = ctrl->flags;
+	qc->type = ctrl->type;
+	if (ctrl->is_ptr)
+		qc->flags |= V4L2_CTRL_FLAG_IS_PTR;
+	if (ctrl->unit)
+		strlcpy(qc->unit, ctrl->unit, sizeof(qc->unit));
+	qc->elem_size = ctrl->elem_size;
+	qc->min.val = ctrl->minimum;
+	qc->max.val = ctrl->maximum;
+	qc->def.val = ctrl->default_value;
+	qc->cols = qc->rows = 1;
 	if (ctrl->type == V4L2_CTRL_TYPE_MENU
 	    || ctrl->type == V4L2_CTRL_TYPE_INTEGER_MENU)
-		qc->step = 1;
+		qc->step.val = 1;
 	else
-		qc->step = ctrl->step;
-	qc->flags = ctrl->flags;
-	qc->type = ctrl->type;
+		qc->step.val = ctrl->step;
+	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;
+
+	/* VIDIOC_QUERYCTRL cannot be used to enumerate hidden controls */
+	if (qc->id & V4L2_CTRL_FLAG_NEXT_HIDDEN)
+		return -EINVAL;
+	rc = v4l2_query_ext_ctrl(hdl, &qec);
+	if (rc)
+		return rc;
+
+	/* VIDIOC_QUERYCTRL is not allowed to see hidden controls */
+	if (qc->flags & V4L2_CTRL_FLAG_HIDDEN)
+		return -EINVAL;
+	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.min.val;
+		qc->maximum = qec.max.val;
+		qc->step = qec.step.val;
+		qc->default_value = qec.def.val;
+		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_HIDDEN))
 		return -EINVAL;
 	return v4l2_queryctrl(sd->ctrl_handler, qc);
 }
@@ -2316,7 +2424,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;
@@ -2348,6 +2457,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;
@@ -2428,7 +2544,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++)
@@ -2490,11 +2606,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
+	/* Complex 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)
@@ -2520,7 +2636,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;
@@ -2539,7 +2655,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;
@@ -2675,7 +2791,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)
@@ -2780,11 +2896,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
+	/* Complex 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_int)
 		return -EINVAL;
 
 	/* Reset the 'is_new' flags of the cluster */
@@ -2826,7 +2942,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)
@@ -2850,7 +2966,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 3998049..515c1ba 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 complex 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
@@ -73,6 +86,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 a matrix and/or has type >= V4L2_CTRL_COMPLEX_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
@@ -91,6 +110,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
@@ -105,7 +125,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
@@ -124,6 +143,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;
@@ -134,6 +156,7 @@ struct v4l2_ctrl {
 	const char *unit;
 	enum v4l2_ctrl_type type;
 	s64 minimum, maximum, default_value;
+	u32 elem_size;
 	union {
 		u64 step;
 		u64 menu_skip_mask;
@@ -143,17 +166,21 @@ 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;
+	union v4l2_ctrl_ptr new;
+	union v4l2_ctrl_ptr stores[];
 };
 
 /** struct v4l2_ctrl_ref - The control reference.
@@ -215,6 +242,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,
@@ -239,6 +267,7 @@ struct v4l2_ctrl_config {
 	s64 max;
 	u64 step;
 	s64 def;
+	u32 elem_size;
 	u32 flags;
 	u64 menu_skip_mask;
 	const char * const *qmenu;
@@ -664,6 +693,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,
-- 
1.8.4.rc3


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

* [REVIEWv3 PATCH 07/35] v4l2: integrate support for VIDIOC_QUERY_EXT_CTRL.
  2014-02-17  9:57 [REVIEWv3 PATCH 00/35] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (5 preceding siblings ...)
  2014-02-17  9:57 ` [REVIEWv3 PATCH 06/35] v4l2-ctrls: add support for complex types Hans Verkuil
@ 2014-02-17  9:57 ` Hans Verkuil
  2014-02-17  9:57 ` [REVIEWv3 PATCH 08/35] v4l2-ctrls: create type_ops Hans Verkuil
                   ` (28 subsequent siblings)
  35 siblings, 0 replies; 66+ messages in thread
From: Hans Verkuil @ 2014-02-17  9:57 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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-compat-ioctl32.c |  1 +
 drivers/media/v4l2-core/v4l2-dev.c            |  2 ++
 drivers/media/v4l2-core/v4l2-ioctl.c          | 31 +++++++++++++++++++++++++++
 drivers/media/v4l2-core/v4l2-subdev.c         |  3 +++
 include/media/v4l2-ioctl.h                    |  2 ++
 5 files changed, 39 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
index 8f7a6a4..0d9b97e 100644
--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
@@ -1089,6 +1089,7 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
 	case VIDIOC_ENUM_FREQ_BANDS:
 	case VIDIOC_SUBDEV_G_EDID32:
 	case VIDIOC_SUBDEV_S_EDID32:
+	case VIDIOC_QUERY_EXT_CTRL:
 		ret = do_video_ioctl(file, cmd, arg);
 		break;
 
diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c
index 0a30dbf..f5bc5ab 100644
--- a/drivers/media/v4l2-core/v4l2-dev.c
+++ b/drivers/media/v4l2-core/v4l2-dev.c
@@ -576,6 +576,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 707aef7..16c2652 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -515,6 +515,19 @@ 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, unit=%.*s, min/max=%lld/%lld, "
+		"step=%lld, default=%lld, flags=0x%08x, cols=%u, rows=%u\n",
+			p->id, p->type, (int)sizeof(p->name), p->name,
+			(int)sizeof(p->unit), p->unit,
+			p->min.val, p->max.val,
+			p->step.val, p->def.val, p->flags,
+			p->cols, p->rows);
+}
+
 static void v4l_print_querymenu(const void *arg, bool write_only)
 {
 	const struct v4l2_querymenu *p = arg;
@@ -1505,6 +1518,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)
 {
@@ -2058,6 +2088,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 996c248..9242daa 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 e0b74a4..ac2b8b9 100644
--- a/include/media/v4l2-ioctl.h
+++ b/include/media/v4l2-ioctl.h
@@ -150,6 +150,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,
-- 
1.8.4.rc3


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

* [REVIEWv3 PATCH 08/35] v4l2-ctrls: create type_ops.
  2014-02-17  9:57 [REVIEWv3 PATCH 00/35] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (6 preceding siblings ...)
  2014-02-17  9:57 ` [REVIEWv3 PATCH 07/35] v4l2: integrate support for VIDIOC_QUERY_EXT_CTRL Hans Verkuil
@ 2014-02-17  9:57 ` Hans Verkuil
  2014-03-11 20:22   ` Mauro Carvalho Chehab
  2014-02-17  9:57 ` [REVIEWv3 PATCH 09/35] v4l2-ctrls: rewrite copy routines to operate on union v4l2_ctrl_ptr Hans Verkuil
                   ` (27 subsequent siblings)
  35 siblings, 1 reply; 66+ messages in thread
From: Hans Verkuil @ 2014-02-17  9:57 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	sakari.ailus, Hans Verkuil

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

Since complex 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

This patch uses the v4l2_ctrl_ptr union for the first time.

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

diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 5d1eeea..fa737a5 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1132,6 +1132,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->stores[0];
+
+	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)
@@ -1315,21 +1458,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->stores[0], ctrl->new);
 	}
 	return diff;
 }
@@ -1370,65 +1499,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->p;
+		return ctrl->type_ops->validate(ctrl, ptr);
 	}
 }
 
@@ -1645,6 +1739,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, const char *unit,
 			enum v4l2_ctrl_type type,
 			s64 min, s64 max, u64 step, s64 def,
@@ -1656,6 +1751,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 	unsigned sz_extra;
 	void *data;
 	int err;
+	int s;
 
 	if (hdl->error)
 		return NULL;
@@ -1706,6 +1802,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->unit = unit;
@@ -1727,19 +1824,16 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 	ctrl->cur.val = ctrl->val = def;
 	data = &ctrl->stores[1];
 
-	if (ctrl->is_string) {
-		ctrl->string = ctrl->new.p_char = data;
-		ctrl->stores[0].p_char = data + elem_size;
-
-		if (ctrl->minimum)
-			memset(ctrl->cur.string, ' ', ctrl->minimum);
-	} else if (ctrl->is_ptr) {
+	if (ctrl->is_ptr) {
 		ctrl->p = ctrl->new.p = data;
 		ctrl->stores[0].p = data + elem_size;
 	} else {
 		ctrl->new.p = &ctrl->val;
 		ctrl->stores[0].p = &ctrl->cur.val;
 	}
+	for (s = -1; s <= 0; s++)
+		ctrl->type_ops->init(ctrl, ctrl->stores[s]);
+
 	if (handler_new_ref(hdl, ctrl)) {
 		kfree(ctrl);
 		return NULL;
@@ -1784,7 +1878,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, unit,
+	ctrl = v4l2_ctrl_new(hdl, cfg->ops, cfg->type_ops, cfg->id, name, unit,
 			type, min, max,
 			is_menu ? cfg->menu_skip_mask : step,
 			def, cfg->elem_size,
@@ -1812,7 +1906,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, unit, type,
+	return v4l2_ctrl_new(hdl, ops, NULL, id, name, unit, type,
 			     min, max, step, def, 0,
 			     flags, NULL, NULL, NULL);
 }
@@ -1846,7 +1940,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, unit, type,
+	return v4l2_ctrl_new(hdl, ops, NULL, id, name, unit, type,
 			     0, max, mask, def, 0,
 			     flags, qmenu, qmenu_int, NULL);
 }
@@ -1879,7 +1973,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, unit, type, 0, max, mask, def,
+	return v4l2_ctrl_new(hdl, ops, NULL, id, name, unit, type,
+			     0, max, mask, def,
 			     0, flags, qmenu, NULL, NULL);
 
 }
@@ -1904,7 +1999,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, unit, type,
+	return v4l2_ctrl_new(hdl, ops, NULL, id, name, unit, type,
 			     0, max, 0, def, 0,
 			     flags, NULL, qmenu_int, NULL);
 }
@@ -2087,32 +2182,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 515c1ba..aaf7333 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -67,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.
@@ -102,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.
   * @unit:	The control's unit. May be NULL.
@@ -151,6 +169,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;
 	const char *unit;
@@ -234,6 +253,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 complex controls.
   * @id:	The control ID.
   * @name:	The control name.
   * @unit:	The control's unit.
@@ -259,6 +279,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;
 	const char *unit;
-- 
1.8.4.rc3


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

* [REVIEWv3 PATCH 09/35] v4l2-ctrls: rewrite copy routines to operate on union v4l2_ctrl_ptr.
  2014-02-17  9:57 [REVIEWv3 PATCH 00/35] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (7 preceding siblings ...)
  2014-02-17  9:57 ` [REVIEWv3 PATCH 08/35] v4l2-ctrls: create type_ops Hans Verkuil
@ 2014-02-17  9:57 ` Hans Verkuil
  2014-02-17  9:57 ` [REVIEWv3 PATCH 10/35] v4l2-ctrls: compare values only once Hans Verkuil
                   ` (26 subsequent siblings)
  35 siblings, 0 replies; 66+ messages in thread
From: Hans Verkuil @ 2014-02-17  9:57 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	sakari.ailus, Hans Verkuil

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

In order to implement matrix support and (for the future) configuration stores
we need to have more generic copy routines. The v4l2_ctrl_ptr union was designed
for this.

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 fa737a5..4fc2a92 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1275,48 +1275,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->p, ctrl->cur.p, ctrl->elem_size);
+		return copy_to_user(c->p, 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->stores[0]);
+}
+
+/* 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->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->p, ctrl->elem_size);
+		return copy_from_user(ptr.p, c->p, 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;
@@ -1324,83 +1340,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->p, ctrl->p, ctrl->elem_size);
+	return user_to_ptr(c, ctrl, ctrl->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->stores[0], ctrl->new);
+	ptr_to_ptr(ctrl, ctrl->new, ctrl->stores[0]);
 
-	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 &=
@@ -1429,21 +1426,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->stores[0], ctrl->new);
 }
 
 /* Return non-zero if one or more of the controls in the cluster has a new
-- 
1.8.4.rc3


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

* [REVIEWv3 PATCH 10/35] v4l2-ctrls: compare values only once.
  2014-02-17  9:57 [REVIEWv3 PATCH 00/35] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (8 preceding siblings ...)
  2014-02-17  9:57 ` [REVIEWv3 PATCH 09/35] v4l2-ctrls: rewrite copy routines to operate on union v4l2_ctrl_ptr Hans Verkuil
@ 2014-02-17  9:57 ` Hans Verkuil
  2014-02-17  9:57 ` [REVIEWv3 PATCH 11/35] v4l2-ctrls: prepare for matrix support: add cols & rows fields Hans Verkuil
                   ` (25 subsequent siblings)
  35 siblings, 0 replies; 66+ messages in thread
From: Hans Verkuil @ 2014-02-17  9:57 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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 matrices. 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 4fc2a92..ad8e5e4 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1395,8 +1395,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->stores[0], ctrl->new);
-	ptr_to_ptr(ctrl, ctrl->new, ctrl->stores[0]);
+
+	/* has_changed is set by cluster_changed */
+	changed = ctrl->has_changed;
+	if (changed)
+		ptr_to_ptr(ctrl, ctrl->new, ctrl->stores[0]);
 
 	if (ch_flags & V4L2_EVENT_CTRL_CH_FLAGS) {
 		/* Note: CH_FLAGS is only set for auto clusters. */
@@ -1433,17 +1436,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->stores[0], ctrl->new);
+		ctrl->has_changed = !ctrl->type_ops->equal(ctrl,
+						ctrl->stores[0], ctrl->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 aaf7333..5a39877 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.
@@ -159,6 +161,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;
-- 
1.8.4.rc3


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

* [REVIEWv3 PATCH 11/35] v4l2-ctrls: prepare for matrix support: add cols & rows fields.
  2014-02-17  9:57 [REVIEWv3 PATCH 00/35] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (9 preceding siblings ...)
  2014-02-17  9:57 ` [REVIEWv3 PATCH 10/35] v4l2-ctrls: compare values only once Hans Verkuil
@ 2014-02-17  9:57 ` Hans Verkuil
  2014-03-12 10:34   ` Mauro Carvalho Chehab
  2014-02-17  9:57 ` [REVIEWv3 PATCH 12/35] v4l2-ctrls: replace cur by a union v4l2_ctrl_ptr Hans Verkuil
                   ` (24 subsequent siblings)
  35 siblings, 1 reply; 66+ messages in thread
From: Hans Verkuil @ 2014-02-17  9:57 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	sakari.ailus, Hans Verkuil

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

Add cols and rows fields to the core control structures in preparation
for matrix support.

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 +++++++++++++++++---------
 include/media/v4l2-ctrls.h           |  6 ++++++
 2 files changed, 23 insertions(+), 9 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index ad8e5e4..a136cdc 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1731,7 +1731,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 			u32 id, const char *name, const char *unit,
 			enum v4l2_ctrl_type type,
 			s64 min, s64 max, u64 step, s64 def,
-			u32 elem_size,
+			u32 cols, u32 rows, u32 elem_size,
 			u32 flags, const char * const *qmenu,
 			const s64 *qmenu_int, void *priv)
 {
@@ -1744,6 +1744,11 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 	if (hdl->error)
 		return NULL;
 
+	if (cols == 0)
+		cols = 1;
+	if (rows == 0)
+		rows = 1;
+
 	if (type == V4L2_CTRL_TYPE_INTEGER64)
 		elem_size = sizeof(s64);
 	else if (type == V4L2_CTRL_TYPE_STRING)
@@ -1803,6 +1808,8 @@ 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_COMPLEX_TYPES || ctrl->is_string;
 	ctrl->is_int = !ctrl->is_ptr && type != V4L2_CTRL_TYPE_INTEGER64;
+	ctrl->cols = cols;
+	ctrl->rows = rows;
 	ctrl->elem_size = elem_size;
 	if (type == V4L2_CTRL_TYPE_MENU)
 		ctrl->qmenu = qmenu;
@@ -1868,8 +1875,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, unit,
 			type, min, max,
-			is_menu ? cfg->menu_skip_mask : step,
-			def, cfg->elem_size,
+			is_menu ? cfg->menu_skip_mask : step, def,
+			cfg->cols, cfg->rows, cfg->elem_size,
 			flags, qmenu, qmenu_int, priv);
 	if (ctrl)
 		ctrl->is_private = cfg->is_private;
@@ -1895,7 +1902,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl,
 		return NULL;
 	}
 	return v4l2_ctrl_new(hdl, ops, NULL, id, name, unit, type,
-			     min, max, step, def, 0,
+			     min, max, step, def, 0, 0, 0,
 			     flags, NULL, NULL, NULL);
 }
 EXPORT_SYMBOL(v4l2_ctrl_new_std);
@@ -1929,7 +1936,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, unit, type,
-			     0, max, mask, def, 0,
+			     0, max, mask, def, 0, 0, 0,
 			     flags, qmenu, qmenu_int, NULL);
 }
 EXPORT_SYMBOL(v4l2_ctrl_new_std_menu);
@@ -1962,8 +1969,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, unit, type,
-			     0, max, mask, def,
-			     0, flags, qmenu, NULL, NULL);
+			     0, max, mask, def, 0, 0, 0,
+			     flags, qmenu, NULL, NULL);
 
 }
 EXPORT_SYMBOL(v4l2_ctrl_new_std_menu_items);
@@ -1988,7 +1995,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, unit, type,
-			     0, max, 0, def, 0,
+			     0, max, 0, def, 0, 0, 0,
 			     flags, NULL, qmenu_int, NULL);
 }
 EXPORT_SYMBOL(v4l2_ctrl_new_int_menu);
@@ -2334,7 +2341,8 @@ int v4l2_query_ext_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_query_ext_ctr
 	qc->min.val = ctrl->minimum;
 	qc->max.val = ctrl->maximum;
 	qc->def.val = ctrl->default_value;
-	qc->cols = qc->rows = 1;
+	qc->cols = ctrl->cols;
+	qc->rows = ctrl->rows;
 	if (ctrl->type == V4L2_CTRL_TYPE_MENU
 	    || ctrl->type == V4L2_CTRL_TYPE_INTEGER_MENU)
 		qc->step.val = 1;
diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
index 5a39877..9eeb9d9 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -129,6 +129,8 @@ typedef void (*v4l2_ctrl_notify_fnc)(struct v4l2_ctrl *ctrl, void *priv);
   * @minimum:	The control's minimum value.
   * @maximum:	The control's maximum value.
   * @default_value: The control's default value.
+  * @rows:	The number of rows in the matrix.
+  * @cols:	The number of columns in the matrix.
   * @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
@@ -178,6 +180,7 @@ struct v4l2_ctrl {
 	const char *unit;
 	enum v4l2_ctrl_type type;
 	s64 minimum, maximum, default_value;
+	u32 rows, cols;
 	u32 elem_size;
 	union {
 		u64 step;
@@ -265,6 +268,8 @@ 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.
+  * @rows:	The number of rows in the matrix.
+  * @cols:	The number of columns in the matrix.
   * @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
@@ -291,6 +296,7 @@ struct v4l2_ctrl_config {
 	s64 max;
 	u64 step;
 	s64 def;
+	u32 rows, cols;
 	u32 elem_size;
 	u32 flags;
 	u64 menu_skip_mask;
-- 
1.8.4.rc3


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

* [REVIEWv3 PATCH 12/35] v4l2-ctrls: replace cur by a union v4l2_ctrl_ptr.
  2014-02-17  9:57 [REVIEWv3 PATCH 00/35] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (10 preceding siblings ...)
  2014-02-17  9:57 ` [REVIEWv3 PATCH 11/35] v4l2-ctrls: prepare for matrix support: add cols & rows fields Hans Verkuil
@ 2014-02-17  9:57 ` Hans Verkuil
  2014-03-12 10:38   ` Mauro Carvalho Chehab
  2014-02-17  9:57 ` [REVIEWv3 PATCH 13/35] v4l2-ctrls: use 'new' to access pointer controls Hans Verkuil
                   ` (23 subsequent siblings)
  35 siblings, 1 reply; 66+ messages in thread
From: Hans Verkuil @ 2014-02-17  9:57 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	sakari.ailus, Hans Verkuil

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

Instead of having to maintain the 'cur' union this patch replaces it by
a v4l2_ctrl_ptr union to be consistent with the future configuration stores,
which also use that union. The number of drivers that use 'cur' is fairly small,
so it is easy enough to convert them all.

Unfortunately, the union for the new value cannot be dropped as easily
since it is used pretty much everywhere.

As a consequence of these changes the v4l2_ctrl struct changes as well.

It was this:

	union { };		 // anonymous union for the 'new' value
	union { } cur;		 // union for the 'cur' value
	union v4l2_ctrl_ptr new; // v4l2_ctrl_ptr to the new value (anonymous union)
	union v4l2_ctrl_ptr stores[]; // v4l2_ctrl_ptr to the cur union

where the stores array contains just one v4l2_ctrl_ptr union when it is
allocated.

It changes to this:

	union { };		 // anonymous union for the 'new' value
	union v4l2_ctrl_ptr *stores; // set to &cur
	union v4l2_ctrl_ptr new; // v4l2_ctrl_ptr to the new value (anonymous union)
	union v4l2_ctrl_ptr cur; // v4l2_ctrl_ptr for the cur value

The end result is the same: stores[0] is a pointer to the current value,
stores[-1] is a pointer to the new value, and the 'cur' field is still
there as well, except that the cur field is now a pointer union to the
actual value, so cur.val is now *cur.p_s32.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 Documentation/video4linux/v4l2-controls.txt   |  4 ++--
 drivers/media/common/cx2341x.c                |  4 ++--
 drivers/media/i2c/adp1653.c                   | 10 +++++-----
 drivers/media/i2c/as3645a.c                   | 22 ++++++++++-----------
 drivers/media/i2c/lm3560.c                    |  2 +-
 drivers/media/i2c/m5mols/m5mols_controls.c    |  6 +++---
 drivers/media/i2c/msp3400-driver.c            |  4 ++--
 drivers/media/i2c/mt9p031.c                   |  4 ++--
 drivers/media/i2c/mt9t001.c                   |  4 ++--
 drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c     |  6 +++---
 drivers/media/i2c/smiapp/smiapp-core.c        | 12 ++++++------
 drivers/media/pci/cx18/cx18-av-core.c         |  2 +-
 drivers/media/pci/cx18/cx18-driver.c          | 10 +++++-----
 drivers/media/platform/exynos4-is/fimc-core.c |  6 +++---
 drivers/media/platform/vivi.c                 | 28 +++++++++++++--------------
 drivers/media/radio/radio-isa.c               |  2 +-
 drivers/media/radio/radio-sf16fmr2.c          |  4 ++--
 drivers/media/usb/gspca/conex.c               |  8 ++++----
 drivers/media/usb/gspca/sn9c20x.c             |  4 ++--
 drivers/media/usb/gspca/topro.c               |  4 ++--
 drivers/media/v4l2-core/v4l2-ctrls.c          | 16 +++++++--------
 include/media/v4l2-ctrls.h                    |  9 ++-------
 22 files changed, 83 insertions(+), 88 deletions(-)

diff --git a/Documentation/video4linux/v4l2-controls.txt b/Documentation/video4linux/v4l2-controls.txt
index 06cf3ac..1c353c2 100644
--- a/Documentation/video4linux/v4l2-controls.txt
+++ b/Documentation/video4linux/v4l2-controls.txt
@@ -362,8 +362,8 @@ 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);
-	printk(KERN_INFO "Integer value is '%s'\n", ctrl2->cur.val);
+	pr_info("String value is '%s'\n", ctrl1->cur.p_char);
+	pr_info("Integer value is '%d'\n", *ctrl2->cur.p_s32);
 	mutex_unlock(&state->ctrl_handler.lock);
 
 
diff --git a/drivers/media/common/cx2341x.c b/drivers/media/common/cx2341x.c
index 103ef6b..909d334 100644
--- a/drivers/media/common/cx2341x.c
+++ b/drivers/media/common/cx2341x.c
@@ -1261,10 +1261,10 @@ static int cx2341x_hdl_api(struct cx2341x_handler *hdl,
 	return hdl->func(hdl->priv, cmd, args, 0, data);
 }
 
-/* ctrl->handler->lock is held, so it is safe to access cur.val */
+/* ctrl->handler->lock is held, so it is safe to access *cur.p_s32 */
 static inline int cx2341x_neq(struct v4l2_ctrl *ctrl)
 {
-	return ctrl && ctrl->val != ctrl->cur.val;
+	return ctrl && ctrl->val != *ctrl->cur.p_s32;
 }
 
 static int cx2341x_try_ctrl(struct v4l2_ctrl *ctrl)
diff --git a/drivers/media/i2c/adp1653.c b/drivers/media/i2c/adp1653.c
index 873fe19..7d478dc 100644
--- a/drivers/media/i2c/adp1653.c
+++ b/drivers/media/i2c/adp1653.c
@@ -158,16 +158,16 @@ static int adp1653_get_ctrl(struct v4l2_ctrl *ctrl)
 	if (IS_ERR_VALUE(rval))
 		return rval;
 
-	ctrl->cur.val = 0;
+	*ctrl->cur.p_s32 = 0;
 
 	if (flash->fault & ADP1653_REG_FAULT_FLT_SCP)
-		ctrl->cur.val |= V4L2_FLASH_FAULT_SHORT_CIRCUIT;
+		*ctrl->cur.p_s32 |= V4L2_FLASH_FAULT_SHORT_CIRCUIT;
 	if (flash->fault & ADP1653_REG_FAULT_FLT_OT)
-		ctrl->cur.val |= V4L2_FLASH_FAULT_OVER_TEMPERATURE;
+		*ctrl->cur.p_s32 |= V4L2_FLASH_FAULT_OVER_TEMPERATURE;
 	if (flash->fault & ADP1653_REG_FAULT_FLT_TMR)
-		ctrl->cur.val |= V4L2_FLASH_FAULT_TIMEOUT;
+		*ctrl->cur.p_s32 |= V4L2_FLASH_FAULT_TIMEOUT;
 	if (flash->fault & ADP1653_REG_FAULT_FLT_OV)
-		ctrl->cur.val |= V4L2_FLASH_FAULT_OVER_VOLTAGE;
+		*ctrl->cur.p_s32 |= V4L2_FLASH_FAULT_OVER_VOLTAGE;
 
 	flash->fault = 0;
 
diff --git a/drivers/media/i2c/as3645a.c b/drivers/media/i2c/as3645a.c
index 301084b..4c6041c 100644
--- a/drivers/media/i2c/as3645a.c
+++ b/drivers/media/i2c/as3645a.c
@@ -334,24 +334,24 @@ static int as3645a_get_ctrl(struct v4l2_ctrl *ctrl)
 		if (value < 0)
 			return value;
 
-		ctrl->cur.val = 0;
+		*ctrl->cur.p_s32 = 0;
 		if (value & AS_FAULT_INFO_SHORT_CIRCUIT)
-			ctrl->cur.val |= V4L2_FLASH_FAULT_SHORT_CIRCUIT;
+			*ctrl->cur.p_s32 |= V4L2_FLASH_FAULT_SHORT_CIRCUIT;
 		if (value & AS_FAULT_INFO_OVER_TEMPERATURE)
-			ctrl->cur.val |= V4L2_FLASH_FAULT_OVER_TEMPERATURE;
+			*ctrl->cur.p_s32 |= V4L2_FLASH_FAULT_OVER_TEMPERATURE;
 		if (value & AS_FAULT_INFO_TIMEOUT)
-			ctrl->cur.val |= V4L2_FLASH_FAULT_TIMEOUT;
+			*ctrl->cur.p_s32 |= V4L2_FLASH_FAULT_TIMEOUT;
 		if (value & AS_FAULT_INFO_OVER_VOLTAGE)
-			ctrl->cur.val |= V4L2_FLASH_FAULT_OVER_VOLTAGE;
+			*ctrl->cur.p_s32 |= V4L2_FLASH_FAULT_OVER_VOLTAGE;
 		if (value & AS_FAULT_INFO_INDUCTOR_PEAK_LIMIT)
-			ctrl->cur.val |= V4L2_FLASH_FAULT_OVER_CURRENT;
+			*ctrl->cur.p_s32 |= V4L2_FLASH_FAULT_OVER_CURRENT;
 		if (value & AS_FAULT_INFO_INDICATOR_LED)
-			ctrl->cur.val |= V4L2_FLASH_FAULT_INDICATOR;
+			*ctrl->cur.p_s32 |= V4L2_FLASH_FAULT_INDICATOR;
 		break;
 
 	case V4L2_CID_FLASH_STROBE_STATUS:
 		if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH) {
-			ctrl->cur.val = 0;
+			*ctrl->cur.p_s32 = 0;
 			break;
 		}
 
@@ -359,11 +359,11 @@ static int as3645a_get_ctrl(struct v4l2_ctrl *ctrl)
 		if (value < 0)
 			return value;
 
-		ctrl->cur.val = value;
+		*ctrl->cur.p_s32 = value;
 		break;
 	}
 
-	dev_dbg(&client->dev, "G_CTRL %08x:%d\n", ctrl->id, ctrl->cur.val);
+	dev_dbg(&client->dev, "G_CTRL %08x:%d\n", ctrl->id, *ctrl->cur.p_s32);
 
 	return 0;
 }
@@ -458,7 +458,7 @@ static int as3645a_set_ctrl(struct v4l2_ctrl *ctrl)
 		if (ret < 0)
 			return ret;
 
-		if ((ctrl->val == 0) == (ctrl->cur.val == 0))
+		if ((ctrl->val == 0) == (*ctrl->cur.p_s32 == 0))
 			break;
 
 		return as3645a_set_output(flash, false);
diff --git a/drivers/media/i2c/lm3560.c b/drivers/media/i2c/lm3560.c
index d98ca3a..edfe746 100644
--- a/drivers/media/i2c/lm3560.c
+++ b/drivers/media/i2c/lm3560.c
@@ -188,7 +188,7 @@ static int lm3560_get_ctrl(struct v4l2_ctrl *ctrl, enum lm3560_led_id led_no)
 			fault |= V4L2_FLASH_FAULT_OVER_TEMPERATURE;
 		if (reg_val & FAULT_TIMEOUT)
 			fault |= V4L2_FLASH_FAULT_TIMEOUT;
-		ctrl->cur.val = fault;
+		*ctrl->cur.p_s32 = fault;
 	}
 
 out:
diff --git a/drivers/media/i2c/m5mols/m5mols_controls.c b/drivers/media/i2c/m5mols/m5mols_controls.c
index a60931e..7851d1f 100644
--- a/drivers/media/i2c/m5mols/m5mols_controls.c
+++ b/drivers/media/i2c/m5mols/m5mols_controls.c
@@ -191,7 +191,7 @@ static int m5mols_3a_lock(struct m5mols_info *info, struct v4l2_ctrl *ctrl)
 	bool af_lock = ctrl->val & V4L2_LOCK_FOCUS;
 	int ret = 0;
 
-	if ((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_EXPOSURE) {
+	if ((ctrl->val ^ *ctrl->cur.p_s32) & V4L2_LOCK_EXPOSURE) {
 		bool ae_lock = ctrl->val & V4L2_LOCK_EXPOSURE;
 
 		ret = m5mols_write(&info->sd, AE_LOCK, ae_lock ?
@@ -200,7 +200,7 @@ static int m5mols_3a_lock(struct m5mols_info *info, struct v4l2_ctrl *ctrl)
 			return ret;
 	}
 
-	if (((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_WHITE_BALANCE)
+	if (((ctrl->val ^ *ctrl->cur.p_s32) & V4L2_LOCK_WHITE_BALANCE)
 	    && info->auto_wb->val) {
 		bool awb_lock = ctrl->val & V4L2_LOCK_WHITE_BALANCE;
 
@@ -213,7 +213,7 @@ static int m5mols_3a_lock(struct m5mols_info *info, struct v4l2_ctrl *ctrl)
 	if (!info->ver.af || !af_lock)
 		return ret;
 
-	if ((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_FOCUS)
+	if ((ctrl->val ^ *ctrl->cur.p_s32) & V4L2_LOCK_FOCUS)
 		ret = m5mols_write(&info->sd, AF_EXECUTE, REG_AF_STOP);
 
 	return ret;
diff --git a/drivers/media/i2c/msp3400-driver.c b/drivers/media/i2c/msp3400-driver.c
index 8190fec..151016d 100644
--- a/drivers/media/i2c/msp3400-driver.c
+++ b/drivers/media/i2c/msp3400-driver.c
@@ -411,8 +411,8 @@ void msp_update_volume(struct msp_state *state)
 {
 	/* Force an update of the volume/mute cluster */
 	v4l2_ctrl_lock(state->volume);
-	state->volume->val = state->volume->cur.val;
-	state->muted->val = state->muted->cur.val;
+	state->volume->val = *state->volume->cur.p_s32;
+	state->muted->val = *state->muted->cur.p_s32;
 	msp_s_ctrl(state->volume);
 	v4l2_ctrl_unlock(state->volume);
 }
diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c
index e5ddf47..28c17e0 100644
--- a/drivers/media/i2c/mt9p031.c
+++ b/drivers/media/i2c/mt9p031.c
@@ -670,12 +670,12 @@ static int mt9p031_s_ctrl(struct v4l2_ctrl *ctrl)
 	case V4L2_CID_TEST_PATTERN:
 		if (!ctrl->val) {
 			/* Restore the black level compensation settings. */
-			if (mt9p031->blc_auto->cur.val != 0) {
+			if (*mt9p031->blc_auto->cur.p_s32 != 0) {
 				ret = mt9p031_s_ctrl(mt9p031->blc_auto);
 				if (ret < 0)
 					return ret;
 			}
-			if (mt9p031->blc_offset->cur.val != 0) {
+			if (*mt9p031->blc_offset->cur.p_s32 != 0) {
 				ret = mt9p031_s_ctrl(mt9p031->blc_offset);
 				if (ret < 0)
 					return ret;
diff --git a/drivers/media/i2c/mt9t001.c b/drivers/media/i2c/mt9t001.c
index d41c70e..6aca05b 100644
--- a/drivers/media/i2c/mt9t001.c
+++ b/drivers/media/i2c/mt9t001.c
@@ -447,7 +447,7 @@ static int mt9t001_s_ctrl(struct v4l2_ctrl *ctrl)
 		for (i = 0, count = 0; i < 4; ++i) {
 			struct v4l2_ctrl *gain = mt9t001->gains[i];
 
-			if (gain->val != gain->cur.val)
+			if (gain->val != *gain->cur.p_s32)
 				count++;
 		}
 
@@ -461,7 +461,7 @@ static int mt9t001_s_ctrl(struct v4l2_ctrl *ctrl)
 		for (i = 0; i < 4; ++i) {
 			struct v4l2_ctrl *gain = mt9t001->gains[i];
 
-			if (gain->val == gain->cur.val)
+			if (gain->val == *gain->cur.p_s32)
 				continue;
 
 			value = mt9t001_gain_value(&gain->val);
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c b/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c
index 8001cde..cb6da84 100644
--- a/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c
+++ b/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c
@@ -195,14 +195,14 @@ static int s5c73m3_3a_lock(struct s5c73m3 *state, struct v4l2_ctrl *ctrl)
 	bool af_lock = ctrl->val & V4L2_LOCK_FOCUS;
 	int ret = 0;
 
-	if ((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_EXPOSURE) {
+	if ((ctrl->val ^ *ctrl->cur.p_s32) & V4L2_LOCK_EXPOSURE) {
 		ret = s5c73m3_isp_command(state, COMM_AE_CON,
 				ae_lock ? COMM_AE_STOP : COMM_AE_START);
 		if (ret)
 			return ret;
 	}
 
-	if (((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_WHITE_BALANCE)
+	if (((ctrl->val ^ *ctrl->cur.p_s32) & V4L2_LOCK_WHITE_BALANCE)
 	    && state->ctrls.auto_wb->val) {
 		ret = s5c73m3_isp_command(state, COMM_AWB_CON,
 			awb_lock ? COMM_AWB_STOP : COMM_AWB_START);
@@ -210,7 +210,7 @@ static int s5c73m3_3a_lock(struct s5c73m3 *state, struct v4l2_ctrl *ctrl)
 			return ret;
 	}
 
-	if ((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_FOCUS)
+	if ((ctrl->val ^ *ctrl->cur.p_s32) & V4L2_LOCK_FOCUS)
 		ret = s5c73m3_af_run(state, ~af_lock);
 
 	return ret;
diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c
index 8741cae..d87c5e8 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->cur.p_s64 = pll->vt_pix_clk_freq_hz;
+	*sensor->pixel_rate_csi->cur.p_s64 = pll->pixel_rate_csi;
 
 	return 0;
 }
@@ -324,8 +324,8 @@ static void __smiapp_update_exposure_limits(struct smiapp_sensor *sensor)
 		ctrl->default_value = max;
 	if (ctrl->val > max)
 		ctrl->val = max;
-	if (ctrl->cur.val > max)
-		ctrl->cur.val = max;
+	if (*ctrl->cur.p_s32 > max)
+		*ctrl->cur.p_s32 = max;
 }
 
 /*
@@ -796,7 +796,7 @@ static void smiapp_update_blanking(struct smiapp_sensor *sensor)
 			      vblank->minimum, vblank->maximum);
 	vblank->default_value = vblank->minimum;
 	vblank->val = vblank->val;
-	vblank->cur.val = vblank->val;
+	*vblank->cur.p_s32 = vblank->val;
 
 	hblank->minimum =
 		max_t(int,
@@ -811,7 +811,7 @@ static void smiapp_update_blanking(struct smiapp_sensor *sensor)
 			      hblank->minimum, hblank->maximum);
 	hblank->default_value = hblank->minimum;
 	hblank->val = hblank->val;
-	hblank->cur.val = hblank->val;
+	*hblank->cur.p_s32 = hblank->val;
 
 	__smiapp_update_exposure_limits(sensor);
 }
diff --git a/drivers/media/pci/cx18/cx18-av-core.c b/drivers/media/pci/cx18/cx18-av-core.c
index c4890a4..d230a9b 100644
--- a/drivers/media/pci/cx18/cx18-av-core.c
+++ b/drivers/media/pci/cx18/cx18-av-core.c
@@ -262,7 +262,7 @@ static void cx18_av_initialize(struct v4l2_subdev *sd)
 		cx18_av_write(cx, 0x8d4, 20);
 	}
 	default_volume = (((228 - default_volume) >> 1) + 23) << 9;
-	state->volume->cur.val = state->volume->default_value = default_volume;
+	*state->volume->cur.p_s32 = state->volume->default_value = default_volume;
 	v4l2_ctrl_handler_setup(&state->hdl);
 }
 
diff --git a/drivers/media/pci/cx18/cx18-driver.c b/drivers/media/pci/cx18/cx18-driver.c
index 716bdc5..e4d0740 100644
--- a/drivers/media/pci/cx18/cx18-driver.c
+++ b/drivers/media/pci/cx18/cx18-driver.c
@@ -756,11 +756,11 @@ static int cx18_init_struct1(struct cx18 *cx)
 		return ret;
 	cx->v4l2_dev.ctrl_handler = &cx->cxhdl.hdl;
 
-	cx->temporal_strength = cx->cxhdl.video_temporal_filter->cur.val;
-	cx->spatial_strength = cx->cxhdl.video_spatial_filter->cur.val;
-	cx->filter_mode = cx->cxhdl.video_spatial_filter_mode->cur.val |
-		(cx->cxhdl.video_temporal_filter_mode->cur.val << 1) |
-		(cx->cxhdl.video_median_filter_type->cur.val << 2);
+	cx->temporal_strength = *cx->cxhdl.video_temporal_filter->cur.p_s32;
+	cx->spatial_strength = *cx->cxhdl.video_spatial_filter->cur.p_s32;
+	cx->filter_mode = *cx->cxhdl.video_spatial_filter_mode->cur.p_s32 |
+		(*cx->cxhdl.video_temporal_filter_mode->cur.p_s32 << 1) |
+		(*cx->cxhdl.video_median_filter_type->cur.p_s32 << 2);
 
 	init_waitqueue_head(&cx->cap_w);
 	init_waitqueue_head(&cx->mb_apu_waitq);
diff --git a/drivers/media/platform/exynos4-is/fimc-core.c b/drivers/media/platform/exynos4-is/fimc-core.c
index a7dfd07..d399699 100644
--- a/drivers/media/platform/exynos4-is/fimc-core.c
+++ b/drivers/media/platform/exynos4-is/fimc-core.c
@@ -664,7 +664,7 @@ void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active)
 		v4l2_ctrl_activate(ctrls->alpha, active && has_alpha);
 
 	if (active) {
-		fimc_set_color_effect(ctx, ctrls->colorfx->cur.val);
+		fimc_set_color_effect(ctx, *ctrls->colorfx->cur.p_s32);
 		ctx->rotation = ctrls->rotate->val;
 		ctx->hflip    = ctrls->hflip->val;
 		ctx->vflip    = ctrls->vflip->val;
@@ -689,8 +689,8 @@ void fimc_alpha_ctrl_update(struct fimc_ctx *ctx)
 	v4l2_ctrl_lock(ctrl);
 	ctrl->maximum = fimc_get_alpha_mask(ctx->d_frame.fmt);
 
-	if (ctrl->cur.val > ctrl->maximum)
-		ctrl->cur.val = ctrl->maximum;
+	if (*ctrl->cur.p_s32 > ctrl->maximum)
+		*ctrl->cur.p_s32 = ctrl->maximum;
 
 	v4l2_ctrl_unlock(ctrl);
 }
diff --git a/drivers/media/platform/vivi.c b/drivers/media/platform/vivi.c
index 3c92ce3..7b9e887 100644
--- a/drivers/media/platform/vivi.c
+++ b/drivers/media/platform/vivi.c
@@ -642,28 +642,28 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
 	gain = v4l2_ctrl_g_ctrl(dev->gain);
 	mutex_lock(dev->ctrl_handler.lock);
 	snprintf(str, sizeof(str), " brightness %3d, contrast %3d, saturation %3d, hue %d ",
-			dev->brightness->cur.val,
-			dev->contrast->cur.val,
-			dev->saturation->cur.val,
-			dev->hue->cur.val);
+			*dev->brightness->cur.p_s32,
+			*dev->contrast->cur.p_s32,
+			*dev->saturation->cur.p_s32,
+			*dev->hue->cur.p_s32);
 	gen_text(dev, vbuf, line++ * 16, 16, str);
 	snprintf(str, sizeof(str), " autogain %d, gain %3d, volume %3d, alpha 0x%02x ",
-			dev->autogain->cur.val, gain, dev->volume->cur.val,
-			dev->alpha->cur.val);
+			*dev->autogain->cur.p_s32, gain, *dev->volume->cur.p_s32,
+			*dev->alpha->cur.p_s32);
 	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->bitmask->cur.val);
+			*dev->int32->cur.p_s32,
+			*dev->int64->cur.p_s64,
+			*dev->bitmask->cur.p_s32);
 	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->boolean->cur.p_s32,
+			dev->menu->qmenu[*dev->menu->cur.p_s32],
+			dev->string->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],
-			dev->int_menu->cur.val);
+			dev->int_menu->qmenu_int[*dev->int_menu->cur.p_s32],
+			*dev->int_menu->cur.p_s32);
 	gen_text(dev, vbuf, line++ * 16, 16, str);
 	mutex_unlock(dev->ctrl_handler.lock);
 	if (dev->button_pressed) {
diff --git a/drivers/media/radio/radio-isa.c b/drivers/media/radio/radio-isa.c
index 6ff3508..46d188d 100644
--- a/drivers/media/radio/radio-isa.c
+++ b/drivers/media/radio/radio-isa.c
@@ -294,7 +294,7 @@ static int radio_isa_common_remove(struct radio_isa_card *isa,
 {
 	const struct radio_isa_ops *ops = isa->drv->ops;
 
-	ops->s_mute_volume(isa, true, isa->volume ? isa->volume->cur.val : 0);
+	ops->s_mute_volume(isa, true, isa->volume ? *isa->volume->cur.p_s32 : 0);
 	video_unregister_device(&isa->vdev);
 	v4l2_ctrl_handler_free(&isa->hdl);
 	v4l2_device_unregister(&isa->v4l2_dev);
diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c
index 93d864e..e393130 100644
--- a/drivers/media/radio/radio-sf16fmr2.c
+++ b/drivers/media/radio/radio-sf16fmr2.c
@@ -154,11 +154,11 @@ static int fmr2_s_ctrl(struct v4l2_ctrl *ctrl)
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_VOLUME:
 		volume = ctrl->val;
-		balance = fmr2->balance->cur.val;
+		balance = *fmr2->balance->cur.p_s32;
 		break;
 	case V4L2_CID_AUDIO_BALANCE:
 		balance = ctrl->val;
-		volume = fmr2->volume->cur.val;
+		volume = *fmr2->volume->cur.p_s32;
 		break;
 	default:
 		return -EINVAL;
diff --git a/drivers/media/usb/gspca/conex.c b/drivers/media/usb/gspca/conex.c
index 2e15c80..e8cfaf3 100644
--- a/drivers/media/usb/gspca/conex.c
+++ b/drivers/media/usb/gspca/conex.c
@@ -887,14 +887,14 @@ static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
 
 	switch (ctrl->id) {
 	case V4L2_CID_BRIGHTNESS:
-		setbrightness(gspca_dev, ctrl->val, sd->sat->cur.val);
+		setbrightness(gspca_dev, ctrl->val, *sd->sat->cur.p_s32);
 		break;
 	case V4L2_CID_CONTRAST:
-		setcontrast(gspca_dev, ctrl->val, sd->sat->cur.val);
+		setcontrast(gspca_dev, ctrl->val, *sd->sat->cur.p_s32);
 		break;
 	case V4L2_CID_SATURATION:
-		setbrightness(gspca_dev, sd->brightness->cur.val, ctrl->val);
-		setcontrast(gspca_dev, sd->contrast->cur.val, ctrl->val);
+		setbrightness(gspca_dev, *sd->brightness->cur.p_s32, ctrl->val);
+		setcontrast(gspca_dev, *sd->contrast->cur.p_s32, ctrl->val);
 		break;
 	}
 	return gspca_dev->usb_err;
diff --git a/drivers/media/usb/gspca/sn9c20x.c b/drivers/media/usb/gspca/sn9c20x.c
index 2a38621..22d93c3 100644
--- a/drivers/media/usb/gspca/sn9c20x.c
+++ b/drivers/media/usb/gspca/sn9c20x.c
@@ -2218,7 +2218,7 @@ static void transfer_check(struct gspca_dev *gspca_dev,
 			/* Note: we are in interrupt context, so we can't
 			   use v4l2_ctrl_g/s_ctrl here. Access the value
 			   directly instead. */
-			s32 curqual = sd->jpegqual->cur.val;
+			s32 curqual = *sd->jpegqual->cur.p_s32;
 			sd->nchg = 0;
 			new_qual += curqual;
 			if (new_qual < sd->jpegqual->minimum)
@@ -2226,7 +2226,7 @@ static void transfer_check(struct gspca_dev *gspca_dev,
 			else if (new_qual > sd->jpegqual->maximum)
 				new_qual = sd->jpegqual->maximum;
 			if (new_qual != curqual) {
-				sd->jpegqual->cur.val = new_qual;
+				*sd->jpegqual->cur.p_s32 = new_qual;
 				queue_work(sd->work_thread, &sd->work);
 			}
 		}
diff --git a/drivers/media/usb/gspca/topro.c b/drivers/media/usb/gspca/topro.c
index 640c2fe..4abe03b 100644
--- a/drivers/media/usb/gspca/topro.c
+++ b/drivers/media/usb/gspca/topro.c
@@ -3976,8 +3976,8 @@ static int sd_setgain(struct gspca_dev *gspca_dev)
 	s32 val = gspca_dev->gain->val;
 
 	if (sd->sensor == SENSOR_CX0342) {
-		s32 old = gspca_dev->gain->cur.val ?
-					gspca_dev->gain->cur.val : 1;
+		s32 old = *gspca_dev->gain->cur.p_s32 ?
+					*gspca_dev->gain->cur.p_s32 : 1;
 
 		sd->blue->val = sd->blue->val * val / old;
 		if (sd->blue->val > 4095)
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index a136cdc..084335a 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -47,7 +47,7 @@ struct v4l2_ctrl_helper {
    mode. */
 static bool is_cur_manual(const struct v4l2_ctrl *master)
 {
-	return master->is_auto && master->cur.val == master->manual_mode_value;
+	return master->is_auto && *master->cur.p_s32 == master->manual_mode_value;
 }
 
 /* Same as above, but this checks the against the new value instead of the
@@ -1106,7 +1106,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->cur.p_s64;
 	ev->u.ctrl.minimum = ctrl->minimum;
 	ev->u.ctrl.maximum = ctrl->maximum;
 	if (ctrl->type == V4L2_CTRL_TYPE_MENU
@@ -1777,13 +1777,13 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 		return NULL;
 	}
 
-	sz_extra = sizeof(union v4l2_ctrl_ptr);
+	sz_extra = elem_size;
 	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 || type >= V4L2_CTRL_COMPLEX_TYPES)
-		sz_extra += 2 * elem_size;
+		sz_extra += elem_size;
 
 	ctrl = kzalloc(sizeof(*ctrl) + sz_extra, GFP_KERNEL);
 	if (ctrl == NULL) {
@@ -1816,7 +1816,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 	else if (type == V4L2_CTRL_TYPE_INTEGER_MENU)
 		ctrl->qmenu_int = qmenu_int;
 	ctrl->priv = priv;
-	ctrl->cur.val = ctrl->val = def;
+	ctrl->stores = &ctrl->cur;
 	data = &ctrl->stores[1];
 
 	if (ctrl->is_ptr) {
@@ -1824,7 +1824,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 		ctrl->stores[0].p = data + elem_size;
 	} else {
 		ctrl->new.p = &ctrl->val;
-		ctrl->stores[0].p = &ctrl->cur.val;
+		ctrl->stores[0].p = data;
 	}
 	for (s = -1; s <= 0; s++)
 		ctrl->type_ops->init(ctrl, ctrl->stores[s]);
@@ -3090,10 +3090,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->cur.p_s32;
 	if (validate_new(ctrl, &c))
 		c.value = def;
-	if (c.value != ctrl->cur.val)
+	if (c.value != *ctrl->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/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
index 9eeb9d9..4f66393 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -198,14 +198,9 @@ struct v4l2_ctrl {
 		char *string;
 		void *p;
 	};
-	union {
-		s32 val;
-		s64 val64;
-		char *string;
-		void *p;
-	} cur;
+	union v4l2_ctrl_ptr *stores;
 	union v4l2_ctrl_ptr new;
-	union v4l2_ctrl_ptr stores[];
+	union v4l2_ctrl_ptr cur;
 };
 
 /** struct v4l2_ctrl_ref - The control reference.
-- 
1.8.4.rc3


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

* [REVIEWv3 PATCH 13/35] v4l2-ctrls: use 'new' to access pointer controls
  2014-02-17  9:57 [REVIEWv3 PATCH 00/35] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (11 preceding siblings ...)
  2014-02-17  9:57 ` [REVIEWv3 PATCH 12/35] v4l2-ctrls: replace cur by a union v4l2_ctrl_ptr Hans Verkuil
@ 2014-02-17  9:57 ` Hans Verkuil
  2014-03-12 10:40   ` Mauro Carvalho Chehab
  2014-02-17  9:57 ` [REVIEWv3 PATCH 14/35] v4l2-ctrls: prepare for matrix support Hans Verkuil
                   ` (22 subsequent siblings)
  35 siblings, 1 reply; 66+ messages in thread
From: Hans Verkuil @ 2014-02-17  9:57 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	sakari.ailus, Hans Verkuil

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

Require that 'new' string and pointer values are accessed through the 'new'
field instead of through the union. This reduces the union to just val and
val64.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Reviewed-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
---
 drivers/media/radio/si4713/si4713.c                | 4 ++--
 drivers/media/v4l2-core/v4l2-ctrls.c               | 4 ++--
 drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c | 2 +-
 include/media/v4l2-ctrls.h                         | 2 --
 4 files changed, 5 insertions(+), 7 deletions(-)

diff --git a/drivers/media/radio/si4713/si4713.c b/drivers/media/radio/si4713/si4713.c
index 07d5153..718e10d 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->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->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 084335a..49ce52e 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1820,8 +1820,8 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 	data = &ctrl->stores[1];
 
 	if (ctrl->is_ptr) {
-		ctrl->p = ctrl->new.p = data;
-		ctrl->stores[0].p = data + elem_size;
+		for (s = -1; s <= 0; s++)
+			ctrl->stores[s].p = data + (s + 1) * elem_size;
 	} else {
 		ctrl->new.p = &ctrl->val;
 		ctrl->stores[0].p = data;
diff --git a/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c b/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
index ce9e5aa..d19743b 100644
--- a/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
+++ b/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
@@ -1127,7 +1127,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->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 4f66393..1b06930 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -195,8 +195,6 @@ struct v4l2_ctrl {
 	union {
 		s32 val;
 		s64 val64;
-		char *string;
-		void *p;
 	};
 	union v4l2_ctrl_ptr *stores;
 	union v4l2_ctrl_ptr new;
-- 
1.8.4.rc3


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

* [REVIEWv3 PATCH 14/35] v4l2-ctrls: prepare for matrix support.
  2014-02-17  9:57 [REVIEWv3 PATCH 00/35] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (12 preceding siblings ...)
  2014-02-17  9:57 ` [REVIEWv3 PATCH 13/35] v4l2-ctrls: use 'new' to access pointer controls Hans Verkuil
@ 2014-02-17  9:57 ` Hans Verkuil
  2014-03-12 10:42   ` Mauro Carvalho Chehab
  2014-02-17  9:57 ` [REVIEWv3 PATCH 15/35] v4l2-ctrls: type_ops can handle matrix elements Hans Verkuil
                   ` (21 subsequent siblings)
  35 siblings, 1 reply; 66+ messages in thread
From: Hans Verkuil @ 2014-02-17  9:57 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	sakari.ailus, Hans Verkuil

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

Add core support for matrices.

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

diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 49ce52e..f76716e 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1132,7 +1132,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)
 {
@@ -1151,7 +1151,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) {
@@ -1178,6 +1178,9 @@ static void std_log(const struct v4l2_ctrl *ctrl)
 {
 	union v4l2_ctrl_ptr ptr = ctrl->stores[0];
 
+	if (ctrl->is_matrix)
+		pr_cont("[%u][%u] ", ctrl->rows, ctrl->cols);
+
 	switch (ctrl->type) {
 	case V4L2_CTRL_TYPE_INTEGER:
 		pr_cont("%d", *ptr.p_s32);
@@ -1220,7 +1223,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;
@@ -1444,7 +1447,7 @@ static int cluster_changed(struct v4l2_ctrl *master)
 
 		if (ctrl == NULL)
 			continue;
-		ctrl->has_changed = !ctrl->type_ops->equal(ctrl,
+		ctrl->has_changed = !ctrl->type_ops->equal(ctrl, 0,
 						ctrl->stores[0], ctrl->new);
 		changed |= ctrl->has_changed;
 	}
@@ -1502,15 +1505,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->p;
-		return ctrl->type_ops->validate(ctrl, ptr);
+		return ctrl->type_ops->validate(ctrl, 0, ptr);
 	}
 }
 
@@ -1736,7 +1739,8 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 			const s64 *qmenu_int, void *priv)
 {
 	struct v4l2_ctrl *ctrl;
-	unsigned sz_extra;
+	bool is_matrix;
+	unsigned sz_extra, tot_ctrl_size;
 	void *data;
 	int err;
 	int s;
@@ -1748,6 +1752,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 		cols = 1;
 	if (rows == 0)
 		rows = 1;
+	is_matrix = cols > 1 || rows > 1;
 
 	if (type == V4L2_CTRL_TYPE_INTEGER64)
 		elem_size = sizeof(s64);
@@ -1755,17 +1760,18 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 		elem_size = max + 1;
 	else if (type < V4L2_CTRL_COMPLEX_TYPES)
 		elem_size = sizeof(s32);
+	tot_ctrl_size = elem_size * cols * rows;
 
 	/* 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);
 		return NULL;
 	}
 	/* Complex controls are always hidden */
-	if (type >= V4L2_CTRL_COMPLEX_TYPES)
+	if (is_matrix || type >= V4L2_CTRL_COMPLEX_TYPES)
 		flags |= V4L2_CTRL_FLAG_HIDDEN;
 	err = check_range(type, min, max, step, def);
 	if (err) {
@@ -1776,14 +1782,21 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 		handler_set_err(hdl, -ERANGE);
 		return NULL;
 	}
+	if (is_matrix &&
+	    (type == V4L2_CTRL_TYPE_BUTTON ||
+	     type == V4L2_CTRL_TYPE_CTRL_CLASS)) {
+		handler_set_err(hdl, -EINVAL);
+		return NULL;
+	}
 
-	sz_extra = elem_size;
+	sz_extra = tot_ctrl_size;
 	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 || type >= V4L2_CTRL_COMPLEX_TYPES)
-		sz_extra += elem_size;
+	else if (type == V4L2_CTRL_TYPE_STRING ||
+		 type >= V4L2_CTRL_COMPLEX_TYPES || is_matrix)
+		sz_extra += tot_ctrl_size;
 
 	ctrl = kzalloc(sizeof(*ctrl) + sz_extra, GFP_KERNEL);
 	if (ctrl == NULL) {
@@ -1805,9 +1818,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_COMPLEX_TYPES || ctrl->is_string;
+	ctrl->is_string = !is_matrix && type == V4L2_CTRL_TYPE_STRING;
+	ctrl->is_ptr = is_matrix || type >= V4L2_CTRL_COMPLEX_TYPES || ctrl->is_string;
 	ctrl->is_int = !ctrl->is_ptr && type != V4L2_CTRL_TYPE_INTEGER64;
+	ctrl->is_matrix = is_matrix;
 	ctrl->cols = cols;
 	ctrl->rows = rows;
 	ctrl->elem_size = elem_size;
@@ -1821,13 +1835,13 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 
 	if (ctrl->is_ptr) {
 		for (s = -1; s <= 0; s++)
-			ctrl->stores[s].p = data + (s + 1) * elem_size;
+			ctrl->stores[s].p = data + (s + 1) * tot_ctrl_size;
 	} else {
 		ctrl->new.p = &ctrl->val;
 		ctrl->stores[0].p = data;
 	}
 	for (s = -1; s <= 0; s++)
-		ctrl->type_ops->init(ctrl, ctrl->stores[s]);
+		ctrl->type_ops->init(ctrl, 0, ctrl->stores[s]);
 
 	if (handler_new_ref(hdl, ctrl)) {
 		kfree(ctrl);
@@ -2734,7 +2748,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;
@@ -3044,7 +3058,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 1b06930..7d72328 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 a matrix and/or has type >= V4L2_CTRL_COMPLEX_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_matrix: If set, then this control contains a matrix.
   * @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_matrix:1;
 	unsigned int has_volatiles:1;
 	unsigned int call_notify:1;
 	unsigned int manual_mode_value:8;
-- 
1.8.4.rc3


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

* [REVIEWv3 PATCH 15/35] v4l2-ctrls: type_ops can handle matrix elements.
  2014-02-17  9:57 [REVIEWv3 PATCH 00/35] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (13 preceding siblings ...)
  2014-02-17  9:57 ` [REVIEWv3 PATCH 14/35] v4l2-ctrls: prepare for matrix support Hans Verkuil
@ 2014-02-17  9:57 ` Hans Verkuil
  2014-02-17  9:57 ` [REVIEWv3 PATCH 16/35] v4l2-ctrls: add matrix support Hans Verkuil
                   ` (20 subsequent siblings)
  35 siblings, 0 replies; 66+ messages in thread
From: Hans Verkuil @ 2014-02-17  9:57 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	sakari.ailus, Hans Verkuil

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

Extend the control type operations to handle matrix 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 f76716e..7dc997d 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1140,14 +1140,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);
 	}
 }
 
@@ -1156,18 +1158,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;
@@ -1230,36 +1233,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)
-- 
1.8.4.rc3


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

* [REVIEWv3 PATCH 16/35] v4l2-ctrls: add matrix support.
  2014-02-17  9:57 [REVIEWv3 PATCH 00/35] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (14 preceding siblings ...)
  2014-02-17  9:57 ` [REVIEWv3 PATCH 15/35] v4l2-ctrls: type_ops can handle matrix elements Hans Verkuil
@ 2014-02-17  9:57 ` Hans Verkuil
  2014-02-17  9:57 ` [REVIEWv3 PATCH 17/35] v4l2-ctrls: return elem_size instead of strlen Hans Verkuil
                   ` (19 subsequent siblings)
  35 siblings, 0 replies; 66+ messages in thread
From: Hans Verkuil @ 2014-02-17  9:57 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	sakari.ailus, Hans Verkuil

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

Finish the userspace-facing matrix support.

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

diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 7dc997d..adc1c53 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1173,6 +1173,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;
 	}
 }
@@ -1290,7 +1292,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->p, ptr.p, ctrl->elem_size);
+		return copy_to_user(c->p, ptr.p, c->size);
 
 	switch (ctrl->type) {
 	case V4L2_CTRL_TYPE_STRING:
@@ -1334,8 +1336,17 @@ 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->p, ctrl->elem_size);
+	if (ctrl->is_ptr && !ctrl->is_string) {
+		unsigned idx;
+
+		ret = copy_from_user(ptr.p, c->p, c->size);
+		if (ret || !ctrl->is_matrix)
+			return ret;
+		for (idx = c->size / ctrl->elem_size;
+		     idx < ctrl->rows * ctrl->cols; idx++)
+			ctrl->type_ops->init(ctrl, idx, ptr);
+		return 0;
+	}
 
 	switch (ctrl->type) {
 	case V4L2_CTRL_TYPE_INTEGER64:
@@ -1378,21 +1389,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->rows * ctrl->cols * ctrl->elem_size);
 }
 
 /* Copy the new value to the current value. */
@@ -1444,15 +1441,20 @@ 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->rows * ctrl->cols; idx++)
+			ctrl_changed = !ctrl->type_ops->equal(ctrl, idx,
 						ctrl->stores[0], ctrl->new);
+		ctrl->has_changed = ctrl_changed;
 		changed |= ctrl->has_changed;
 	}
 	return changed;
@@ -1499,26 +1501,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->p;
-		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->p;
+	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)
@@ -1745,6 +1753,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 	struct v4l2_ctrl *ctrl;
 	bool is_matrix;
 	unsigned sz_extra, tot_ctrl_size;
+	unsigned idx;
 	void *data;
 	int err;
 	int s;
@@ -1845,7 +1854,8 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 		ctrl->stores[0].p = data;
 	}
 	for (s = -1; s <= 0; s++)
-		ctrl->type_ops->init(ctrl, 0, ctrl->stores[s]);
+		for (idx = 0; idx < rows * cols; idx++)
+			ctrl->type_ops->init(ctrl, idx, ctrl->stores[s]);
 
 	if (handler_new_ref(hdl, ctrl)) {
 		kfree(ctrl);
@@ -2542,12 +2552,18 @@ 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->rows * ctrl->cols *
+					    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;
@@ -3087,7 +3103,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) {
@@ -3097,6 +3113,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_matrix)
+			return -EINVAL;
+		ret = check_range(ctrl->type, min, max, step, def);
 		if (ret)
 			return ret;
 		break;
-- 
1.8.4.rc3


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

* [REVIEWv3 PATCH 17/35] v4l2-ctrls: return elem_size instead of strlen
  2014-02-17  9:57 [REVIEWv3 PATCH 00/35] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (15 preceding siblings ...)
  2014-02-17  9:57 ` [REVIEWv3 PATCH 16/35] v4l2-ctrls: add matrix support Hans Verkuil
@ 2014-02-17  9:57 ` Hans Verkuil
  2014-02-17  9:57 ` [REVIEWv3 PATCH 18/35] v4l2-ctrl: fix error return of copy_to/from_user Hans Verkuil
                   ` (18 subsequent siblings)
  35 siblings, 0 replies; 66+ messages in thread
From: Hans Verkuil @ 2014-02-17  9:57 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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 adc1c53..c55cabb 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1298,7 +1298,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) ?
-- 
1.8.4.rc3


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

* [REVIEWv3 PATCH 18/35] v4l2-ctrl: fix error return of copy_to/from_user.
  2014-02-17  9:57 [REVIEWv3 PATCH 00/35] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (16 preceding siblings ...)
  2014-02-17  9:57 ` [REVIEWv3 PATCH 17/35] v4l2-ctrls: return elem_size instead of strlen Hans Verkuil
@ 2014-02-17  9:57 ` Hans Verkuil
  2014-02-17  9:57 ` [REVIEWv3 PATCH 19/35] DocBook media: document VIDIOC_QUERY_EXT_CTRL Hans Verkuil
                   ` (17 subsequent siblings)
  35 siblings, 0 replies; 66+ messages in thread
From: Hans Verkuil @ 2014-02-17  9:57 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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 c55cabb..1886b79 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1292,7 +1292,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->p, ptr.p, c->size);
+		return copy_to_user(c->p, ptr.p, c->size) ?
+		       -EFAULT : 0;
 
 	switch (ctrl->type) {
 	case V4L2_CTRL_TYPE_STRING:
@@ -1302,7 +1303,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;
@@ -1339,7 +1340,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->p, c->size);
+		ret = copy_from_user(ptr.p, c->p, c->size) ? -EFAULT : 0;
 		if (ret || !ctrl->is_matrix)
 			return ret;
 		for (idx = c->size / ctrl->elem_size;
@@ -1358,7 +1359,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];
 
@@ -1368,7 +1369,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;
-- 
1.8.4.rc3


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

* [REVIEWv3 PATCH 19/35] DocBook media: document VIDIOC_QUERY_EXT_CTRL.
  2014-02-17  9:57 [REVIEWv3 PATCH 00/35] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (17 preceding siblings ...)
  2014-02-17  9:57 ` [REVIEWv3 PATCH 18/35] v4l2-ctrl: fix error return of copy_to/from_user Hans Verkuil
@ 2014-02-17  9:57 ` Hans Verkuil
  2014-03-12 14:13   ` Mauro Carvalho Chehab
  2014-02-17  9:57 ` [REVIEWv3 PATCH 20/35] DocBook media: update VIDIOC_G/S/TRY_EXT_CTRLS Hans Verkuil
                   ` (16 subsequent siblings)
  35 siblings, 1 reply; 66+ messages in thread
From: Hans Verkuil @ 2014-02-17  9:57 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	sakari.ailus, Hans Verkuil

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

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Reviewed-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
---
 .../DocBook/media/v4l/vidioc-queryctrl.xml         | 223 +++++++++++++++++----
 1 file changed, 189 insertions(+), 34 deletions(-)

diff --git a/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml b/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml
index e6645b9..da0e534 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>
@@ -91,7 +100,26 @@ prematurely end the enumeration).</para></footnote></para>
 <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>
+<errorcode>EINVAL</errorcode>. Hidden controls (i.e. controls
+with the <constant>V4L2_CTRL_FLAG_HIDDEN</constant> flag set) are
+skipped when using the <constant>V4L2_CTRL_FLAG_NEXT_CTRL</constant>
+flag. Use the <constant>VIDIOC_QUERY_EXT_CTRL</constant> for that.</para>
+
+    <para>The <constant>VIDIOC_QUERY_EXT_CTRL</constant> ioctl was
+introduced in order to better support controls that can use complex
+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.
+In addition, the <constant>V4L2_CTRL_FLAG_NEXT_HIDDEN</constant> flag
+can be specified to enumerate all hidden controls (i.e. controls
+with the <constant>V4L2_CTRL_FLAG_HIDDEN</constant> flag set, which
+includes all controls with complex types). Specify both
+<constant>V4L2_CTRL_FLAG_NEXT_CTRL</constant> and
+<constant>V4L2_CTRL_FLAG_NEXT_HIDDEN</constant> in order to enumerate
+all controls, hidden or not.</para>
 
     <para>Additional information is required for menu controls: the
 names of the menu items. To query them applications set the
@@ -142,38 +170,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 +205,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 +227,129 @@ 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-hidden control with a higher ID. When the
+ID is ORed with <constant>V4L2_CTRL_FLAG_NEXT_HIDDEN</constant> the driver
+clears the flag and returns the first hidden control with a higher ID.
+Set both to get the first control (hidden 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>char</entry>
+	    <entry><structfield>unit</structfield>[32]</entry>
+	    <entry>The name of the unit of the control's value, a NUL-terminated ASCII
+string. This information is intended for the user. This may be an empty string if no
+unit is known or if it is not applicable to this particular control.</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>cols</structfield></entry>
+	    <entry>The number of columns in the matrix. If this control
+is not a matrix, then both <structfield>cols</structfield> and
+<structfield>rows</structfield> are 1. <structfield>cols</structfield>
+can never be 0.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>rows</structfield></entry>
+	    <entry>The number of rows in the matrix. If this control
+is not a matrix, then both <structfield>cols</structfield> and
+<structfield>rows</structfield> are 1. <structfield>rows</structfield>
+can never be 0.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>elem_size</structfield></entry>
+	    <entry>The size in bytes of a single element of the matrix.
+Given a char pointer <constant>p</constant> to the matrix you can find the
+position of cell <constant>(y, x)</constant> as follows:
+<constant>p + (y * cols + x) * elem_size</constant>. <structfield>elem_size</structfield>
+is always valid, also when the control isn't a matrix. For string controls
+<structfield>elem_size</structfield> is equal to <structfield>maximum + 1</structfield>.
+</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>reserved</structfield>[17]</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 +484,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 +590,21 @@ 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_HIDDEN</constant></entry>
+	    <entry>0x0100</entry>
+	    <entry>This control is hidden and should not be shown in a GUI application.
+Hidden controls are skipped when enumerating them using <constant>V4L2_CTRL_FLAG_NEXT_CTRL</constant>,
+and they can only be enumerated by using the <constant>V4L2_CTRL_FLAG_NEXT_HIDDEN</constant>
+flag. All controls that have a complex type have this flag set.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CTRL_FLAG_IS_PTR</constant></entry>
+	    <entry>0x0200</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 a matrix, string, or have a complex type.</entry>
+	  </row>
 	</tbody>
       </tgroup>
     </table>
-- 
1.8.4.rc3


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

* [REVIEWv3 PATCH 20/35] DocBook media: update VIDIOC_G/S/TRY_EXT_CTRLS.
  2014-02-17  9:57 [REVIEWv3 PATCH 00/35] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (18 preceding siblings ...)
  2014-02-17  9:57 ` [REVIEWv3 PATCH 19/35] DocBook media: document VIDIOC_QUERY_EXT_CTRL Hans Verkuil
@ 2014-02-17  9:57 ` Hans Verkuil
  2014-03-12 14:20   ` Mauro Carvalho Chehab
  2014-02-17  9:57 ` [REVIEWv3 PATCH 21/35] DocBook media: fix coding style in the control example code Hans Verkuil
                   ` (15 subsequent siblings)
  35 siblings, 1 reply; 66+ messages in thread
From: Hans Verkuil @ 2014-02-17  9:57 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	sakari.ailus, Hans Verkuil

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

Document the support for the new complex type controls.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 .../DocBook/media/v4l/vidioc-g-ext-ctrls.xml       | 43 ++++++++++++++++++----
 1 file changed, 35 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 b3bb957..d946d6b 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 complex types (<constant>V4L2_CTRL_FLAG_IS_PTR</constant> is set)
+must set the <structfield>p</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>Matrices are set and retrieved row-by-row. You cannot set a partial
+matrix, all elements have to be set or retrieved. The total size is calculated
+as <structfield>rows</structfield> * <structfield>cols</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/p</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,11 +103,17 @@ 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/p</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>
 
+    <para>For matrices it is possible to only set or check only the first
+<constant>X</constant> elements by setting size to <constant>X * elem_size</constant>,
+where <structfield>elem_size</structfield> is obtained by calling &VIDIOC-QUERY-EXT-CTRL;.
+Matrix elements are set row-by-row. Matrix elements that are not explicitly
+set will be initialized to their default value.</para>
+
     <para>When the <structfield>id</structfield> or
 <structfield>ctrl_class</structfield> is invalid drivers return an
 &EINVAL;. When the value is out of bounds drivers can choose to take
@@ -158,19 +171,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_IS_PTR</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_IS_PTR</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>p</structfield></entry>
+	    <entry>A pointer to a complex type which can be a matrix and/or a
+complex type (the control's type is >= <constant>V4L2_CTRL_COMPLEX_TYPES</constant>).
+Valid if <constant>V4L2_CTRL_FLAG_IS_PTR</constant> is set for this control.
+</entry>
 	  </row>
 	</tbody>
       </tgroup>
-- 
1.8.4.rc3


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

* [REVIEWv3 PATCH 21/35] DocBook media: fix coding style in the control example code
  2014-02-17  9:57 [REVIEWv3 PATCH 00/35] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (19 preceding siblings ...)
  2014-02-17  9:57 ` [REVIEWv3 PATCH 20/35] DocBook media: update VIDIOC_G/S/TRY_EXT_CTRLS Hans Verkuil
@ 2014-02-17  9:57 ` Hans Verkuil
  2014-02-17  9:57 ` [REVIEWv3 PATCH 22/35] DocBook media: update control section Hans Verkuil
                   ` (14 subsequent siblings)
  35 siblings, 0 replies; 66+ messages in thread
From: Hans Verkuil @ 2014-02-17  9:57 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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 a5a3188..ef55c3e 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>
 
-- 
1.8.4.rc3


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

* [REVIEWv3 PATCH 22/35] DocBook media: update control section.
  2014-02-17  9:57 [REVIEWv3 PATCH 00/35] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (20 preceding siblings ...)
  2014-02-17  9:57 ` [REVIEWv3 PATCH 21/35] DocBook media: fix coding style in the control example code Hans Verkuil
@ 2014-02-17  9:57 ` Hans Verkuil
  2014-02-19 23:15   ` Sakari Ailus
  2014-03-12 14:27   ` Mauro Carvalho Chehab
  2014-02-17  9:57 ` [REVIEWv3 PATCH 23/35] v4l2-controls.txt: update to the new way of accessing controls Hans Verkuil
                   ` (13 subsequent siblings)
  35 siblings, 2 replies; 66+ messages in thread
From: Hans Verkuil @ 2014-02-17  9:57 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	sakari.ailus, Hans Verkuil

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

Document the support for complex 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 | 104 ++++++++++++++++++++-------
 1 file changed, 78 insertions(+), 26 deletions(-)

diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml
index ef55c3e..85d78d4 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>
@@ -624,16 +660,32 @@ 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 complex types such as arrays/matrices
+and/or structures. All such complex controls will have the
+<constant>V4L2_CTRL_FLAG_HIDDEN</constant> set since such controls cannot
+be displayed in control panel applications. Nor can they be used in the
+user class (for backwards compatibility reasons), and you need to specify
+the <constant>V4L2_CTRL_FLAG_NEXT_HIDDEN</constant> when enumerating controls
+to actually be able to see such hidden controls. In other words, these
+controls with complex types should only be used programmatically.</para>
+
+      <para>Since such complex 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 size of the matrix 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.
@@ -699,7 +751,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>
 
-- 
1.8.4.rc3


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

* [REVIEWv3 PATCH 23/35] v4l2-controls.txt: update to the new way of accessing controls.
  2014-02-17  9:57 [REVIEWv3 PATCH 00/35] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (21 preceding siblings ...)
  2014-02-17  9:57 ` [REVIEWv3 PATCH 22/35] DocBook media: update control section Hans Verkuil
@ 2014-02-17  9:57 ` Hans Verkuil
  2014-02-17  9:57 ` [REVIEWv3 PATCH 24/35] v4l2-ctrls/videodev2.h: add u8 and u16 types Hans Verkuil
                   ` (12 subsequent siblings)
  35 siblings, 0 replies; 66+ messages in thread
From: Hans Verkuil @ 2014-02-17  9:57 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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 | 46 +++++++++++++++++++----------
 1 file changed, 31 insertions(+), 15 deletions(-)

diff --git a/Documentation/video4linux/v4l2-controls.txt b/Documentation/video4linux/v4l2-controls.txt
index 1c353c2..f94dcfd 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,24 +288,40 @@ 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 {
-		s32 val;
-		s64 val64;
-		char *string;
-	} cur;
+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:
 
-	/* The new control value. */
 	union {
 		s32 val;
 		s64 val64;
-		char *string;
 	};
+	union v4l2_ctrl_ptr new;
+	union v4l2_ctrl_ptr cur;
+
+If the control has a simple s32 type or s64 type, then:
+
+	&ctrl->val == ctrl->new.p_s32
+
+or:
+
+	&ctrl->val64 == ctrl->new.p_s64
+
+For all other types use ctrl->new.p<something> instead of ctrl->val/val64.
+Basically the val and val64 fields can be considered aliases since these
+are used so often.
 
 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
+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
-- 
1.8.4.rc3


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

* [REVIEWv3 PATCH 24/35] v4l2-ctrls/videodev2.h: add u8 and u16 types.
  2014-02-17  9:57 [REVIEWv3 PATCH 00/35] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (22 preceding siblings ...)
  2014-02-17  9:57 ` [REVIEWv3 PATCH 23/35] v4l2-controls.txt: update to the new way of accessing controls Hans Verkuil
@ 2014-02-17  9:57 ` Hans Verkuil
  2014-03-12 14:44   ` Mauro Carvalho Chehab
  2014-02-17  9:57 ` [REVIEWv3 PATCH 25/35] DocBook media: document new u8 and u16 control types Hans Verkuil
                   ` (11 subsequent siblings)
  35 siblings, 1 reply; 66+ messages in thread
From: Hans Verkuil @ 2014-02-17  9:57 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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 1886b79..ca4271b 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1145,6 +1145,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];
@@ -1172,6 +1176,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);
@@ -1208,6 +1218,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;
@@ -1238,6 +1254,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];
@@ -1470,6 +1490,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)
@@ -1768,12 +1790,25 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 		rows = 1;
 	is_matrix = cols > 1 || rows > 1;
 
-	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_COMPLEX_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_COMPLEX_TYPES)
+			elem_size = sizeof(s32);
+		break;
+	}
 	tot_ctrl_size = elem_size * cols * rows;
 
 	/* Sanity checks */
@@ -3114,6 +3149,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_matrix)
 			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 7d72328..2ccad5f 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 complex 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 858a6f3..8b70f51 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -1228,6 +1228,8 @@ struct v4l2_ext_control {
 		__s32 value;
 		__s64 value64;
 		char *string;
+		__u8 *p_u8;
+		__u16 *p_u16;
 		void *p;
 	};
 } __attribute__ ((packed));
@@ -1257,6 +1259,8 @@ enum v4l2_ctrl_type {
 
 	/* Complex types are >= 0x0100 */
 	V4L2_CTRL_COMPLEX_TYPES	     = 0x0100,
+	V4L2_CTRL_TYPE_U8	     = 0x0100,
+	V4L2_CTRL_TYPE_U16	     = 0x0101,
 };
 
 /*  Used in the VIDIOC_QUERYCTRL ioctl for querying controls */
-- 
1.8.4.rc3


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

* [REVIEWv3 PATCH 25/35] DocBook media: document new u8 and u16 control types.
  2014-02-17  9:57 [REVIEWv3 PATCH 00/35] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (23 preceding siblings ...)
  2014-02-17  9:57 ` [REVIEWv3 PATCH 24/35] v4l2-ctrls/videodev2.h: add u8 and u16 types Hans Verkuil
@ 2014-02-17  9:57 ` Hans Verkuil
  2014-02-17  9:57 ` [REVIEWv3 PATCH 26/35] v4l2-ctrls: fix comments Hans Verkuil
                   ` (10 subsequent siblings)
  35 siblings, 0 replies; 66+ messages in thread
From: Hans Verkuil @ 2014-02-17  9:57 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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 d946d6b..2dcc284 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
@@ -192,6 +192,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>p</structfield></entry>
 	    <entry>A pointer to a complex type which can be a matrix and/or a
diff --git a/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml b/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml
index da0e534..93c350b 100644
--- a/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml
@@ -301,7 +301,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.
@@ -519,6 +520,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 matrix 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 matrix controls.</entry>
+	  </row>
 	</tbody>
       </tgroup>
     </table>
-- 
1.8.4.rc3


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

* [REVIEWv3 PATCH 26/35] v4l2-ctrls: fix comments
  2014-02-17  9:57 [REVIEWv3 PATCH 00/35] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (24 preceding siblings ...)
  2014-02-17  9:57 ` [REVIEWv3 PATCH 25/35] DocBook media: document new u8 and u16 control types Hans Verkuil
@ 2014-02-17  9:57 ` Hans Verkuil
  2014-02-17  9:57 ` [REVIEWv3 PATCH 27/35] v4l2-ctrls/v4l2-controls.h: add MD controls Hans Verkuil
                   ` (9 subsequent siblings)
  35 siblings, 0 replies; 66+ messages in thread
From: Hans Verkuil @ 2014-02-17  9:57 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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 ca4271b..2a73360 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";
@@ -752,7 +752,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";
@@ -786,8 +786,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";
@@ -810,6 +810,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";
@@ -825,7 +826,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";
@@ -833,18 +834,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";
-- 
1.8.4.rc3


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

* [REVIEWv3 PATCH 27/35] v4l2-ctrls/v4l2-controls.h: add MD controls
  2014-02-17  9:57 [REVIEWv3 PATCH 00/35] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (25 preceding siblings ...)
  2014-02-17  9:57 ` [REVIEWv3 PATCH 26/35] v4l2-ctrls: fix comments Hans Verkuil
@ 2014-02-17  9:57 ` Hans Verkuil
  2014-02-17  9:57 ` [REVIEWv3 PATCH 28/35] DocBook media: document new motion detection controls Hans Verkuil
                   ` (8 subsequent siblings)
  35 siblings, 0 replies; 66+ messages in thread
From: Hans Verkuil @ 2014-02-17  9:57 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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 2a73360..859ac29 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;
@@ -861,6 +870,15 @@ const char *v4l2_ctrl_get_name(u32 id)
 	case V4L2_CID_FM_RX_CLASS:		return "FM Radio Receiver Controls";
 	case V4L2_CID_TUNE_DEEMPHASIS:		return "De-Emphasis";
 	case V4L2_CID_RDS_RECEPTION:		return "RDS Reception";
+
+	/* 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;
 	}
@@ -971,6 +989,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, const char **unit,
 	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:
@@ -996,6 +1015,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, const char **unit,
 	case V4L2_CID_IMAGE_PROC_CLASS:
 	case V4L2_CID_DV_CLASS:
 	case V4L2_CID_FM_RX_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;
@@ -1041,6 +1061,12 @@ void v4l2_ctrl_fill(u32 id, const char **name, const char **unit,
 		*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;
@@ -1077,6 +1103,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, const char **unit,
 	case V4L2_CID_PILOT_TONE_FREQUENCY:
 	case V4L2_CID_TUNE_POWER_LEVEL:
 	case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
+	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 2cbe605..93ff343 100644
--- a/include/uapi/linux/v4l2-controls.h
+++ b/include/uapi/linux/v4l2-controls.h
@@ -60,6 +60,7 @@
 #define V4L2_CTRL_CLASS_IMAGE_PROC	0x009f0000	/* Image processing controls */
 #define V4L2_CTRL_CLASS_DV		0x00a00000	/* Digital Video controls */
 #define V4L2_CTRL_CLASS_FM_RX		0x00a10000	/* FM Receiver controls */
+#define V4L2_CTRL_CLASS_DETECT		0x00a20000	/* Detection controls */
 
 /* User-class control IDs */
 
@@ -895,4 +896,20 @@ enum v4l2_deemphasis {
 
 #define V4L2_CID_RDS_RECEPTION			(V4L2_CID_FM_RX_CLASS_BASE + 2)
 
+
+/*  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
-- 
1.8.4.rc3


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

* [REVIEWv3 PATCH 28/35] DocBook media: document new motion detection controls.
  2014-02-17  9:57 [REVIEWv3 PATCH 00/35] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (26 preceding siblings ...)
  2014-02-17  9:57 ` [REVIEWv3 PATCH 27/35] v4l2-ctrls/v4l2-controls.h: add MD controls Hans Verkuil
@ 2014-02-17  9:57 ` Hans Verkuil
  2014-02-17  9:57 ` [REVIEWv3 PATCH 29/35] v4l2: add a motion detection event Hans Verkuil
                   ` (7 subsequent siblings)
  35 siblings, 0 replies; 66+ messages in thread
From: Hans Verkuil @ 2014-02-17  9:57 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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 | 97 ++++++++++++++++++++++++++++
 1 file changed, 97 insertions(+)

diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml
index 85d78d4..4749216 100644
--- a/Documentation/DocBook/media/v4l/controls.xml
+++ b/Documentation/DocBook/media/v4l/controls.xml
@@ -5022,4 +5022,101 @@ defines possible values for de-emphasis. Here they are:</entry>
       </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>
 </section>
-- 
1.8.4.rc3


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

* [REVIEWv3 PATCH 29/35] v4l2: add a motion detection event.
  2014-02-17  9:57 [REVIEWv3 PATCH 00/35] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (27 preceding siblings ...)
  2014-02-17  9:57 ` [REVIEWv3 PATCH 28/35] DocBook media: document new motion detection controls Hans Verkuil
@ 2014-02-17  9:57 ` Hans Verkuil
  2014-02-17  9:57 ` [REVIEWv3 PATCH 30/35] DocBook: document new v4l " Hans Verkuil
                   ` (6 subsequent siblings)
  35 siblings, 0 replies; 66+ messages in thread
From: Hans Verkuil @ 2014-02-17  9:57 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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 8b70f51..4cbfb16 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -1773,6 +1773,7 @@ struct v4l2_streamparm {
 #define V4L2_EVENT_EOS				2
 #define V4L2_EVENT_CTRL				3
 #define V4L2_EVENT_FRAME_SYNC			4
+#define V4L2_EVENT_MOTION_DET			5
 #define V4L2_EVENT_PRIVATE_START		0x08000000
 
 /* Payload for V4L2_EVENT_VSYNC */
@@ -1804,12 +1805,28 @@ struct v4l2_event_frame_sync {
 	__u32 frame_sequence;
 };
 
+#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 {
 		struct v4l2_event_vsync		vsync;
 		struct v4l2_event_ctrl		ctrl;
 		struct v4l2_event_frame_sync	frame_sync;
+		struct v4l2_event_motion_det	motion_det;
 		__u8				data[64];
 	} u;
 	__u32				pending;
-- 
1.8.4.rc3


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

* [REVIEWv3 PATCH 30/35] DocBook: document new v4l motion detection event.
  2014-02-17  9:57 [REVIEWv3 PATCH 00/35] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (28 preceding siblings ...)
  2014-02-17  9:57 ` [REVIEWv3 PATCH 29/35] v4l2: add a motion detection event Hans Verkuil
@ 2014-02-17  9:57 ` Hans Verkuil
  2014-02-17  9:57 ` [REVIEWv3 PATCH 31/35] solo6x10: implement the new motion detection controls Hans Verkuil
                   ` (5 subsequent siblings)
  35 siblings, 0 replies; 66+ messages in thread
From: Hans Verkuil @ 2014-02-17  9:57 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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 89891ad..ffa1fac 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
@@ -242,6 +248,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 5c70b61..9e68976 100644
--- a/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml
@@ -155,6 +155,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>
-- 
1.8.4.rc3


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

* [REVIEWv3 PATCH 31/35] solo6x10: implement the new motion detection controls.
  2014-02-17  9:57 [REVIEWv3 PATCH 00/35] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (29 preceding siblings ...)
  2014-02-17  9:57 ` [REVIEWv3 PATCH 30/35] DocBook: document new v4l " Hans Verkuil
@ 2014-02-17  9:57 ` Hans Verkuil
  2014-02-17  9:57 ` [REVIEWv3 PATCH 32/35] solo6x10: implement the motion detection event Hans Verkuil
                   ` (4 subsequent siblings)
  35 siblings, 0 replies; 66+ messages in thread
From: Hans Verkuil @ 2014-02-17  9:57 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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, 40 insertions(+), 86 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 d19743b..a56a687 100644
--- a/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
+++ b/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
@@ -1065,31 +1065,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 =
@@ -1108,24 +1083,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;
+		return solo_set_motion_threshold(solo_dev, solo_enc->ch,
+				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_enc->motion_thresh);
 			else
 				solo_set_motion_block(solo_dev, solo_enc->ch,
-						&solo_enc->motion_thresholds);
+					solo_enc->md_thresholds->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->new.p_u16);
+		break;
 	case V4L2_CID_OSD_TEXT:
 		strcpy(solo_enc->osd_text, ctrl->new.p_char);
 		err = solo_osd_print(solo_enc);
@@ -1177,7 +1158,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 = {
@@ -1193,33 +1173,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,
@@ -1229,13 +1182,23 @@ 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,
+	.rows = SOLO_MOTION_SZ,
+	.cols = 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)
@@ -1256,9 +1219,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;
@@ -1279,11 +1249,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 */
-- 
1.8.4.rc3


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

* [REVIEWv3 PATCH 32/35] solo6x10: implement the motion detection event.
  2014-02-17  9:57 [REVIEWv3 PATCH 00/35] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (30 preceding siblings ...)
  2014-02-17  9:57 ` [REVIEWv3 PATCH 31/35] solo6x10: implement the new motion detection controls Hans Verkuil
@ 2014-02-17  9:57 ` Hans Verkuil
  2014-02-17  9:57 ` [REVIEWv3 PATCH 33/35] solo6x10: fix 'dma from stack' warning Hans Verkuil
                   ` (3 subsequent siblings)
  35 siblings, 0 replies; 66+ messages in thread
From: Hans Verkuil @ 2014-02-17  9:57 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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 a56a687..ccdf0f3 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);
@@ -1118,6 +1151,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,
@@ -1156,7 +1204,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;
 
-- 
1.8.4.rc3


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

* [REVIEWv3 PATCH 33/35] solo6x10: fix 'dma from stack' warning.
  2014-02-17  9:57 [REVIEWv3 PATCH 00/35] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (31 preceding siblings ...)
  2014-02-17  9:57 ` [REVIEWv3 PATCH 32/35] solo6x10: implement the motion detection event Hans Verkuil
@ 2014-02-17  9:57 ` Hans Verkuil
  2014-02-17  9:57 ` [REVIEWv3 PATCH 34/35] solo6x10: check dma_map_sg() return value Hans Verkuil
                   ` (2 subsequent siblings)
  35 siblings, 0 replies; 66+ messages in thread
From: Hans Verkuil @ 2014-02-17  9:57 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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;
 }
 
-- 
1.8.4.rc3


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

* [REVIEWv3 PATCH 34/35] solo6x10: check dma_map_sg() return value
  2014-02-17  9:57 [REVIEWv3 PATCH 00/35] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (32 preceding siblings ...)
  2014-02-17  9:57 ` [REVIEWv3 PATCH 33/35] solo6x10: fix 'dma from stack' warning Hans Verkuil
@ 2014-02-17  9:57 ` Hans Verkuil
  2014-02-17  9:57 ` [REVIEWv3 PATCH 35/35] go7007: add motion detection support Hans Verkuil
  2014-02-19  8:28 ` [REVIEWv3 PATCH 00/35] Add support for complex controls, use in solo/go7007 Ricardo Ribalda Delgado
  35 siblings, 0 replies; 66+ messages in thread
From: Hans Verkuil @ 2014-02-17  9:57 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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 ccdf0f3..fa5e8ab 100644
--- a/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
+++ b/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
@@ -479,8 +479,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,
 		& ~(DMA_ALIGN - 1);
 
 	/* 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));
-- 
1.8.4.rc3


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

* [REVIEWv3 PATCH 35/35] go7007: add motion detection support.
  2014-02-17  9:57 [REVIEWv3 PATCH 00/35] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (33 preceding siblings ...)
  2014-02-17  9:57 ` [REVIEWv3 PATCH 34/35] solo6x10: check dma_map_sg() return value Hans Verkuil
@ 2014-02-17  9:57 ` Hans Verkuil
  2014-02-19  8:28 ` [REVIEWv3 PATCH 00/35] Add support for complex controls, use in solo/go7007 Ricardo Ribalda Delgado
  35 siblings, 0 replies; 66+ messages in thread
From: Hans Verkuil @ 2014-02-17  9:57 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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    | 318 ++++++++++++++++++--------
 drivers/staging/media/go7007/go7007.h         |  40 ----
 drivers/staging/media/go7007/saa7134-go7007.c |   1 -
 6 files changed, 346 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 edc52e2..ad41483 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;
@@ -848,41 +786,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->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,
@@ -924,7 +897,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,
 };
 
@@ -936,12 +909,145 @@ 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,
+	.rows = 576 / 16,
+	.cols = 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,
@@ -964,6 +1070,24 @@ int go7007_v4l2_ctrl_init(struct go7007 *go)
 			V4L2_JPEG_ACTIVE_MARKER_DQT | 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 6e2ca33..8300856 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*/
-- 
1.8.4.rc3


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

* Re: [REVIEWv3 PATCH 00/35] Add support for complex controls, use in solo/go7007
  2014-02-17  9:57 [REVIEWv3 PATCH 00/35] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (34 preceding siblings ...)
  2014-02-17  9:57 ` [REVIEWv3 PATCH 35/35] go7007: add motion detection support Hans Verkuil
@ 2014-02-19  8:28 ` Ricardo Ribalda Delgado
  2014-02-19  8:54   ` Hans Verkuil
  35 siblings, 1 reply; 66+ messages in thread
From: Ricardo Ribalda Delgado @ 2014-02-19  8:28 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: linux-media, Mauro Carvalho Chehab, Laurent Pinchart,
	Sylwester Nawrocki, Ismael Luceno, pete, Sakari Ailus

Hello.

I did tried stressfully the previous patchset (REVIEWv2). I am
specially interested in the matrix controls.

Since this is identical to that patchset:

Tested-by: Ricardo Ribalda <ricardo.ribalda@gmail.com>

Thanks!

On Mon, Feb 17, 2014 at 10:57 AM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
> This patch series adds support for complex controls (aka 'Properties') to
> the control framework and uses them in the go7007 and solo6x10 drivers.
> It is the first part of a larger patch series that adds support for configuration
> stores and support for 'Multiple Selections'.
>
> This patch series is identical to the REVIEWv2 series:
>
> http://www.spinics.net/lists/linux-media/msg72748.html
>
> except that patches 35-40 have been folded into the main series (except for patch
> 40 which is added as a new patch since it is a standalone bug fix).
>
> If there are no more objections, then I am going to make a pull request for this
> in one week time.
>
> I will post a pull request based on this series today as well.
>
> Regards,
>
>         Hans
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-media" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html



-- 
Ricardo Ribalda

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

* Re: [REVIEWv3 PATCH 00/35] Add support for complex controls, use in solo/go7007
  2014-02-19  8:28 ` [REVIEWv3 PATCH 00/35] Add support for complex controls, use in solo/go7007 Ricardo Ribalda Delgado
@ 2014-02-19  8:54   ` Hans Verkuil
  0 siblings, 0 replies; 66+ messages in thread
From: Hans Verkuil @ 2014-02-19  8:54 UTC (permalink / raw)
  To: Ricardo Ribalda Delgado
  Cc: linux-media, Mauro Carvalho Chehab, Laurent Pinchart,
	Sylwester Nawrocki, Ismael Luceno, pete, Sakari Ailus

On 02/19/14 09:28, Ricardo Ribalda Delgado wrote:
> Hello.
> 
> I did tried stressfully the previous patchset (REVIEWv2). I am
> specially interested in the matrix controls.
> 
> Since this is identical to that patchset:
> 
> Tested-by: Ricardo Ribalda <ricardo.ribalda@gmail.com>

Thanks! Much appreciated.

Regards,

	Hans

> 
> Thanks!
> 
> On Mon, Feb 17, 2014 at 10:57 AM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
>> This patch series adds support for complex controls (aka 'Properties') to
>> the control framework and uses them in the go7007 and solo6x10 drivers.
>> It is the first part of a larger patch series that adds support for configuration
>> stores and support for 'Multiple Selections'.
>>
>> This patch series is identical to the REVIEWv2 series:
>>
>> http://www.spinics.net/lists/linux-media/msg72748.html
>>
>> except that patches 35-40 have been folded into the main series (except for patch
>> 40 which is added as a new patch since it is a standalone bug fix).
>>
>> If there are no more objections, then I am going to make a pull request for this
>> in one week time.
>>
>> I will post a pull request based on this series today as well.
>>
>> Regards,
>>
>>         Hans
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-media" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
> 
> 


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

* Re: [REVIEWv3 PATCH 22/35] DocBook media: update control section.
  2014-02-17  9:57 ` [REVIEWv3 PATCH 22/35] DocBook media: update control section Hans Verkuil
@ 2014-02-19 23:15   ` Sakari Ailus
  2014-03-12 14:27   ` Mauro Carvalho Chehab
  1 sibling, 0 replies; 66+ messages in thread
From: Sakari Ailus @ 2014-02-19 23:15 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: linux-media, m.chehab, laurent.pinchart, s.nawrocki,
	ismael.luceno, pete, Hans Verkuil

Hi Hans,

On Mon, Feb 17, 2014 at 10:57:37AM +0100, Hans Verkuil wrote:
...
> @@ -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);
> +}

This is wrong; errno is guaranteed to be valid only if there's been an
error.

-- 
Kind regards,

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

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

* Re: [REVIEWv3 PATCH 04/35] videodev2.h: add initial support for complex controls.
  2014-02-17  9:57 ` [REVIEWv3 PATCH 04/35] videodev2.h: add initial support for complex controls Hans Verkuil
@ 2014-03-11 19:34   ` Mauro Carvalho Chehab
  2014-03-11 20:23     ` Hans Verkuil
  0 siblings, 1 reply; 66+ messages in thread
From: Mauro Carvalho Chehab @ 2014-03-11 19:34 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: linux-media, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	sakari.ailus, Hans Verkuil

Em Mon, 17 Feb 2014 10:57:19 +0100
Hans Verkuil <hverkuil@xs4all.nl> escreveu:

> From: Hans Verkuil <hans.verkuil@cisco.com>
> 
> Complex controls are controls that can be used for compound and array
> types. This allows for more complex data structures to be used with the
> control framework.
> 
> Such controls always have the V4L2_CTRL_FLAG_HIDDEN flag set. Note that
> 'simple' controls can also set that flag.
> 
> The existing V4L2_CTRL_FLAG_NEXT_CTRL flag will only enumerate controls
> that do not have the HIDDEN flag, so a new V4L2_CTRL_FLAG_NEXT_HIDDEN flag
> is added to enumerate hidden controls. Set both flags to enumerate any
> controls (hidden or not).
> 
> Complex control types will start at V4L2_CTRL_COMPLEX_TYPES. In addition, any
> control that uses the new 'p' field or the existing 'string' field will have
> flag V4L2_CTRL_FLAG_IS_PTR 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 | 11 +++++++++--
>  1 file changed, 9 insertions(+), 2 deletions(-)
> 
> diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
> index 6ae7bbe..4d7782a 100644
> --- a/include/uapi/linux/videodev2.h
> +++ b/include/uapi/linux/videodev2.h
> @@ -1228,6 +1228,7 @@ struct v4l2_ext_control {
>  		__s32 value;
>  		__s64 value64;
>  		char *string;
> +		void *p;

Hmm... don't we have already "string" for pointers? Also, calling it
as "p" inside an userspace api doesn't seem to nice ("ptr" would be
better).

Btw, you likely already noticed the mess, as, when you added 
this email's comment, you said that complex controls could
either use "p" or "string".

Nack. It should just use "string". Let's not add even more complexity
to this "complex" controls.

>  	};
>  } __attribute__ ((packed));
>  
> @@ -1252,7 +1253,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,
> +
> +	/* Complex types are >= 0x0100 */
> +	V4L2_CTRL_COMPLEX_TYPES	     = 0x0100,
>  };

Not sure if I got why you're calling it as "TYPES" and saying that
everything >= 0x100 is complex. What's your idea here?

Also, at least for me with my engineering formation, "complex"
means a number with an imaginary component.

And yes, we do have complex numbers on some usecases for
V4L (for example, SDR in-phase/quadrature, e. g.  I/Q
representation can be seen as an array of complex numbers).

So, I won't doubt that someone might propose some day to add a
way to set a complex number via a V4L2 control.

So, please use a better naming here to avoid troubles.

>  /*  Used in the VIDIOC_QUERYCTRL ioctl for querying controls */
> @@ -1288,9 +1292,12 @@ 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_HIDDEN		0x0100
> +#define V4L2_CTRL_FLAG_IS_PTR		0x0200
>  
> -/*  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_HIDDEN	0x40000000
>  
>  /*  User-class control IDs defined by V4L2 */
>  #define V4L2_CID_MAX_CTRLS		1024


-- 

Regards,
Mauro

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

* Re: [REVIEWv3 PATCH 05/35] videodev2.h: add struct v4l2_query_ext_ctrl and VIDIOC_QUERY_EXT_CTRL.
  2014-02-17  9:57 ` [REVIEWv3 PATCH 05/35] videodev2.h: add struct v4l2_query_ext_ctrl and VIDIOC_QUERY_EXT_CTRL Hans Verkuil
@ 2014-03-11 19:42   ` Mauro Carvalho Chehab
  2014-03-11 20:29     ` Hans Verkuil
  0 siblings, 1 reply; 66+ messages in thread
From: Mauro Carvalho Chehab @ 2014-03-11 19:42 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: linux-media, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	sakari.ailus, Hans Verkuil

Em Mon, 17 Feb 2014 10:57:20 +0100
Hans Verkuil <hverkuil@xs4all.nl> escreveu:

> 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.
> 
> It gives back a unit string, the range is now a s64 type, and the matrix
> and element size can be reported through cols/rows/elem_size.
> 
> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
> ---
>  include/uapi/linux/videodev2.h | 31 +++++++++++++++++++++++++++++++
>  1 file changed, 31 insertions(+)
> 
> diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
> index 4d7782a..858a6f3 100644
> --- a/include/uapi/linux/videodev2.h
> +++ b/include/uapi/linux/videodev2.h
> @@ -1272,6 +1272,35 @@ 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];
> +	char		     unit[32];
> +	union {
> +		__s64 val;
> +		__u32 reserved[4];

Why to reserve 16 bytes here? for anything bigger than 64
bits, we could use a pointer.

Same applies to the other unions.

> +	} min;
> +	union {
> +		__s64 val;
> +		__u32 reserved[4];
> +	} max;
> +	union {
> +		__u64 val;
> +		__u32 reserved[4];
> +	} step;
> +	union {
> +		__s64 val;
> +		__u32 reserved[4];
> +	} def;

Please call it default. It is ok to simplify names inside a driver,
but better to not do it at the API.

> +	__u32                flags;

> +	__u32                cols;
> +	__u32                rows;
> +	__u32                elem_size;

The three above seem to be too specific for an array.

I would put those on a separate struct and add here an union,
like:

	union {
		struct v4l2_array arr;
		__u32 reserved[8];
	}

> +	__u32		     reserved[17];

This also seems too much. Why 17?

> +};

> +
>  /*  Used in the VIDIOC_QUERYMENU ioctl for querying menu items */
>  struct v4l2_querymenu {
>  	__u32		id;
> @@ -1965,6 +1994,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,
Mauro

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

* Re: [REVIEWv3 PATCH 06/35] v4l2-ctrls: add support for complex types.
  2014-02-17  9:57 ` [REVIEWv3 PATCH 06/35] v4l2-ctrls: add support for complex types Hans Verkuil
@ 2014-03-11 20:14   ` Mauro Carvalho Chehab
  2014-03-11 20:43     ` Hans Verkuil
  0 siblings, 1 reply; 66+ messages in thread
From: Mauro Carvalho Chehab @ 2014-03-11 20:14 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: linux-media, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	sakari.ailus, Hans Verkuil

Em Mon, 17 Feb 2014 10:57:21 +0100
Hans Verkuil <hverkuil@xs4all.nl> escreveu:

> From: Hans Verkuil <hans.verkuil@cisco.com>
> 
> This patch implements initial support for complex types.
> 
> For the most part 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), but one change needs more explanation:
> 
> The v4l2_ctrl struct adds a 'new' field and a 'stores' array at the end
> of the struct. This is in preparation for future patches where each control
> can have multiple configuration stores. The idea is that stores[0] is the current
> control value, stores[1] etc. are the control values for each configuration store
> and the 'new' value can be accessed through 'stores[-1]', i.e. the 'new' field.
> However, for now only stores[-1] and stores[0] is used.
> 
> Drivers are not expected to use the stores array (at least not while support
> for configuration stores is not yet fully added), but the stores array will
> be used inside the control framework.
> 
> These new fields use the v4l2_ctrl_ptr union, which is a pointer to a control
> value.
> 
> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
> Reviewed-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
> ---
>  drivers/media/v4l2-core/v4l2-ctrls.c | 236 ++++++++++++++++++++++++++---------
>  include/media/v4l2-ctrls.h           |  38 +++++-
>  2 files changed, 210 insertions(+), 64 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
> index df8ed0a..5d1eeea 100644
> --- a/drivers/media/v4l2-core/v4l2-ctrls.c
> +++ b/drivers/media/v4l2-core/v4l2-ctrls.c
> @@ -1095,20 +1095,6 @@ void v4l2_ctrl_fill(u32 id, const char **name, const char **unit,
>  }
>  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));
> @@ -1117,7 +1103,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;
> @@ -1152,6 +1138,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->p, ctrl->cur.p, ctrl->elem_size);
> +
>  	switch (ctrl->type) {
>  	case V4L2_CTRL_TYPE_STRING:
>  		len = strlen(ctrl->cur.string);
> @@ -1179,6 +1168,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->p, ctrl->elem_size);
> +

It is a little hard to follow all copy_*_user and memcpy/memcpy cases.

On all such calls, the elem_size data is coming from the driver?

It doesn't seem right to tust on userspace for that, if this could
be a border case.

>  	switch (ctrl->type) {
>  	case V4L2_CTRL_TYPE_INTEGER64:
>  		ctrl->val64 = c->value64;
> @@ -1213,6 +1205,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->p, ctrl->p, ctrl->elem_size);
> +
>  	switch (ctrl->type) {
>  	case V4L2_CTRL_TYPE_STRING:
>  		len = strlen(ctrl->string);
> @@ -1239,6 +1234,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;
> @@ -1253,8 +1249,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) {
> @@ -1294,7 +1295,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;
>  	}
>  }
> @@ -1507,7 +1511,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;
> @@ -1577,8 +1581,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 hidden.
> +	 */
> +	if (!(ctrl->flags & V4L2_CTRL_FLAG_HIDDEN) &&
> +	    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;
>  
> @@ -1640,23 +1648,36 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
>  			u32 id, const char *name, const char *unit,
>  			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_COMPLEX_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);
>  		return NULL;
>  	}
> +	/* Complex controls are always hidden */
> +	if (type >= V4L2_CTRL_COMPLEX_TYPES)
> +		flags |= V4L2_CTRL_FLAG_HIDDEN;
>  	err = check_range(type, min, max, step, def);
>  	if (err) {
>  		handler_set_err(hdl, err);
> @@ -1667,12 +1688,13 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
>  		return NULL;
>  	}
>  
> +	sz_extra = sizeof(union v4l2_ctrl_ptr);
>  	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_COMPLEX_TYPES)
> +		sz_extra += 2 * elem_size;
>  
>  	ctrl = kzalloc(sizeof(*ctrl) + sz_extra, GFP_KERNEL);
>  	if (ctrl == NULL) {
> @@ -1692,18 +1714,31 @@ 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_COMPLEX_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->stores[1];
> +
> +	if (ctrl->is_string) {
> +		ctrl->string = ctrl->new.p_char = data;
> +		ctrl->stores[0].p_char = 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 = ctrl->new.p = data;
> +		ctrl->stores[0].p = data + elem_size;
> +	} else {
> +		ctrl->new.p = &ctrl->val;
> +		ctrl->stores[0].p = &ctrl->cur.val;
>  	}
>  	if (handler_new_ref(hdl, ctrl)) {
>  		kfree(ctrl);
> @@ -1752,7 +1787,8 @@ struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl,
>  	ctrl = v4l2_ctrl_new(hdl, cfg->ops, cfg->id, name, unit,
>  			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;
> @@ -1770,13 +1806,15 @@ struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl,
>  	u32 flags;
>  
>  	v4l2_ctrl_fill(id, &name, &unit, &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_COMPLEX_TYPES) {
>  		handler_set_err(hdl, -EINVAL);
>  		return NULL;
>  	}
>  	return v4l2_ctrl_new(hdl, ops, id, name, unit, type,
> -			     min, max, step, def, flags, NULL, NULL, NULL);
> +			     min, max, step, def, 0,
> +			     flags, NULL, NULL, NULL);
>  }
>  EXPORT_SYMBOL(v4l2_ctrl_new_std);
>  
> @@ -1809,7 +1847,8 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl,
>  		return NULL;
>  	}
>  	return v4l2_ctrl_new(hdl, ops, id, name, unit, 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);
>  
> @@ -1841,7 +1880,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, unit, type, 0, max, mask, def,
> -			     flags, qmenu, NULL, NULL);
> +			     0, flags, qmenu, NULL, NULL);
>  
>  }
>  EXPORT_SYMBOL(v4l2_ctrl_new_std_menu_items);
> @@ -1866,7 +1905,8 @@ struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl,
>  		return NULL;
>  	}
>  	return v4l2_ctrl_new(hdl, ops, id, name, unit, 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);
>  
> @@ -2154,9 +2194,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_HIDDEN;
>  	u32 id = qc->id & V4L2_CTRL_ID_MASK;
>  	struct v4l2_ctrl_ref *ref;
>  	struct v4l2_ctrl *ctrl;
> @@ -2169,7 +2210,22 @@ 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)) {
> +		unsigned mask;
> +		unsigned match;
> +
> +		if ((qc->id & next_flags) == V4L2_CTRL_FLAG_NEXT_HIDDEN) {
> +			/* Match any hidden control */
> +			mask = match = V4L2_CTRL_FLAG_HIDDEN;
> +		} else if ((qc->id & next_flags) == next_flags) {
> +			/* Match any control, hidden or not */
> +			mask = match = 0;
> +		} else {
> +			/* Match any control that is not hidden */
> +			mask = V4L2_CTRL_FLAG_HIDDEN;
> +			match = 0;
> +		}
> +
>  		/* Find the next control with ID > qc->id */
>  
>  		/* Did we reach the end of the control list? */
> @@ -2177,19 +2233,28 @@ 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)
> +				if (id < ref->ctrl->id &&
> +				    (ref->ctrl->flags & 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)
> +				if (id < ref->ctrl->id &&
> +				    (ref->ctrl->flags & mask) == match)
>  					break;
> +			if (&ref->node == &hdl->ctrl_refs)
> +				ref = NULL;
>  		}
>  	}
>  	mutex_unlock(hdl->lock);
> +
>  	if (!ref)
>  		return -EINVAL;
>  
> @@ -2200,23 +2265,66 @@ 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->minimum = ctrl->minimum;
> -	qc->maximum = ctrl->maximum;
> -	qc->default_value = ctrl->default_value;
> +	qc->flags = ctrl->flags;
> +	qc->type = ctrl->type;
> +	if (ctrl->is_ptr)
> +		qc->flags |= V4L2_CTRL_FLAG_IS_PTR;
> +	if (ctrl->unit)
> +		strlcpy(qc->unit, ctrl->unit, sizeof(qc->unit));
> +	qc->elem_size = ctrl->elem_size;
> +	qc->min.val = ctrl->minimum;
> +	qc->max.val = ctrl->maximum;
> +	qc->def.val = ctrl->default_value;
> +	qc->cols = qc->rows = 1;
>  	if (ctrl->type == V4L2_CTRL_TYPE_MENU
>  	    || ctrl->type == V4L2_CTRL_TYPE_INTEGER_MENU)
> -		qc->step = 1;
> +		qc->step.val = 1;
>  	else
> -		qc->step = ctrl->step;
> -	qc->flags = ctrl->flags;
> -	qc->type = ctrl->type;
> +		qc->step.val = ctrl->step;
> +	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;
> +
> +	/* VIDIOC_QUERYCTRL cannot be used to enumerate hidden controls */

Why not?

> +	if (qc->id & V4L2_CTRL_FLAG_NEXT_HIDDEN)
> +		return -EINVAL;
> +	rc = v4l2_query_ext_ctrl(hdl, &qec);
> +	if (rc)
> +		return rc;
> +
> +	/* VIDIOC_QUERYCTRL is not allowed to see hidden controls */
> +	if (qc->flags & V4L2_CTRL_FLAG_HIDDEN)
> +		return -EINVAL;
> +	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.min.val;
> +		qc->maximum = qec.max.val;
> +		qc->step = qec.step.val;
> +		qc->default_value = qec.def.val;
> +		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_HIDDEN))
>  		return -EINVAL;
>  	return v4l2_queryctrl(sd->ctrl_handler, qc);
>  }
> @@ -2316,7 +2424,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;
> @@ -2348,6 +2457,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;
> @@ -2428,7 +2544,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++)
> @@ -2490,11 +2606,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
> +	/* Complex 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)
> @@ -2520,7 +2636,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;
> @@ -2539,7 +2655,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;
> @@ -2675,7 +2791,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)
> @@ -2780,11 +2896,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
> +	/* Complex 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().
>  	 */

The new text also has an error. From the code below, what's not supported
below are actually non-integer controls.

> -	if (ctrl->type == V4L2_CTRL_TYPE_STRING)
> +	if (!ctrl->is_int)
>  		return -EINVAL;
>  
>  	/* Reset the 'is_new' flags of the cluster */
> @@ -2826,7 +2942,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)
> @@ -2850,7 +2966,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 3998049..515c1ba 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 complex value.
> + */
> +union v4l2_ctrl_ptr {
> +	s32 *p_s32;
> +	s64 *p_s64;
> +	char *p_char;
> +	void *p;
> +};

I can't see where the above is used.

> +
>  /** 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
> @@ -73,6 +86,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 a matrix and/or has type >= V4L2_CTRL_COMPLEX_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
> @@ -91,6 +110,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
> @@ -105,7 +125,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
> @@ -124,6 +143,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;
> @@ -134,6 +156,7 @@ struct v4l2_ctrl {
>  	const char *unit;
>  	enum v4l2_ctrl_type type;
>  	s64 minimum, maximum, default_value;
> +	u32 elem_size;
>  	union {
>  		u64 step;
>  		u64 menu_skip_mask;
> @@ -143,17 +166,21 @@ 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;
> +	union v4l2_ctrl_ptr new;
> +	union v4l2_ctrl_ptr stores[];
>  };
>  
>  /** struct v4l2_ctrl_ref - The control reference.
> @@ -215,6 +242,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,
> @@ -239,6 +267,7 @@ struct v4l2_ctrl_config {
>  	s64 max;
>  	u64 step;
>  	s64 def;
> +	u32 elem_size;
>  	u32 flags;
>  	u64 menu_skip_mask;
>  	const char * const *qmenu;
> @@ -664,6 +693,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,


-- 

Regards,
Mauro

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

* Re: [REVIEWv3 PATCH 08/35] v4l2-ctrls: create type_ops.
  2014-02-17  9:57 ` [REVIEWv3 PATCH 08/35] v4l2-ctrls: create type_ops Hans Verkuil
@ 2014-03-11 20:22   ` Mauro Carvalho Chehab
  2014-03-11 20:49     ` Hans Verkuil
  0 siblings, 1 reply; 66+ messages in thread
From: Mauro Carvalho Chehab @ 2014-03-11 20:22 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: linux-media, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	sakari.ailus, Hans Verkuil

Em Mon, 17 Feb 2014 10:57:23 +0100
Hans Verkuil <hverkuil@xs4all.nl> escreveu:

> From: Hans Verkuil <hans.verkuil@cisco.com>
> 
> Since complex 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

So far, I failed to see why this is needed, as all code below is actually
related to non-complex controls, but your comment is confusing, saying that
this is related to complex controls.

Maybe a latter patch will help me to better understand this one.

> This patch uses the v4l2_ctrl_ptr union for the first time.

Then move v4l2_ctrl_ptr union addition to this patch.

> 
> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
> Reviewed-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
> ---
>  drivers/media/v4l2-core/v4l2-ctrls.c | 267 ++++++++++++++++++++++-------------
>  include/media/v4l2-ctrls.h           |  21 +++
>  2 files changed, 190 insertions(+), 98 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
> index 5d1eeea..fa737a5 100644
> --- a/drivers/media/v4l2-core/v4l2-ctrls.c
> +++ b/drivers/media/v4l2-core/v4l2-ctrls.c
> @@ -1132,6 +1132,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->stores[0];
> +
> +	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)
> @@ -1315,21 +1458,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->stores[0], ctrl->new);
>  	}
>  	return diff;
>  }
> @@ -1370,65 +1499,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->p;
> +		return ctrl->type_ops->validate(ctrl, ptr);
>  	}
>  }
>  
> @@ -1645,6 +1739,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, const char *unit,
>  			enum v4l2_ctrl_type type,
>  			s64 min, s64 max, u64 step, s64 def,
> @@ -1656,6 +1751,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
>  	unsigned sz_extra;
>  	void *data;
>  	int err;
> +	int s;
>  
>  	if (hdl->error)
>  		return NULL;
> @@ -1706,6 +1802,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->unit = unit;
> @@ -1727,19 +1824,16 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
>  	ctrl->cur.val = ctrl->val = def;
>  	data = &ctrl->stores[1];
>  
> -	if (ctrl->is_string) {
> -		ctrl->string = ctrl->new.p_char = data;
> -		ctrl->stores[0].p_char = data + elem_size;
> -
> -		if (ctrl->minimum)
> -			memset(ctrl->cur.string, ' ', ctrl->minimum);
> -	} else if (ctrl->is_ptr) {
> +	if (ctrl->is_ptr) {
>  		ctrl->p = ctrl->new.p = data;
>  		ctrl->stores[0].p = data + elem_size;
>  	} else {
>  		ctrl->new.p = &ctrl->val;
>  		ctrl->stores[0].p = &ctrl->cur.val;
>  	}
> +	for (s = -1; s <= 0; s++)
> +		ctrl->type_ops->init(ctrl, ctrl->stores[s]);
> +
>  	if (handler_new_ref(hdl, ctrl)) {
>  		kfree(ctrl);
>  		return NULL;
> @@ -1784,7 +1878,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, unit,
> +	ctrl = v4l2_ctrl_new(hdl, cfg->ops, cfg->type_ops, cfg->id, name, unit,
>  			type, min, max,
>  			is_menu ? cfg->menu_skip_mask : step,
>  			def, cfg->elem_size,
> @@ -1812,7 +1906,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, unit, type,
> +	return v4l2_ctrl_new(hdl, ops, NULL, id, name, unit, type,
>  			     min, max, step, def, 0,
>  			     flags, NULL, NULL, NULL);
>  }
> @@ -1846,7 +1940,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, unit, type,
> +	return v4l2_ctrl_new(hdl, ops, NULL, id, name, unit, type,
>  			     0, max, mask, def, 0,
>  			     flags, qmenu, qmenu_int, NULL);
>  }
> @@ -1879,7 +1973,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, unit, type, 0, max, mask, def,
> +	return v4l2_ctrl_new(hdl, ops, NULL, id, name, unit, type,
> +			     0, max, mask, def,
>  			     0, flags, qmenu, NULL, NULL);
>  
>  }
> @@ -1904,7 +1999,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, unit, type,
> +	return v4l2_ctrl_new(hdl, ops, NULL, id, name, unit, type,
>  			     0, max, 0, def, 0,
>  			     flags, NULL, qmenu_int, NULL);
>  }
> @@ -2087,32 +2182,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 515c1ba..aaf7333 100644
> --- a/include/media/v4l2-ctrls.h
> +++ b/include/media/v4l2-ctrls.h
> @@ -67,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.
> @@ -102,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.
>    * @unit:	The control's unit. May be NULL.
> @@ -151,6 +169,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;
>  	const char *unit;
> @@ -234,6 +253,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 complex controls.
>    * @id:	The control ID.
>    * @name:	The control name.
>    * @unit:	The control's unit.
> @@ -259,6 +279,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;
>  	const char *unit;


-- 

Regards,
Mauro

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

* Re: [REVIEWv3 PATCH 04/35] videodev2.h: add initial support for complex controls.
  2014-03-11 19:34   ` Mauro Carvalho Chehab
@ 2014-03-11 20:23     ` Hans Verkuil
  2014-03-11 23:48       ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 66+ messages in thread
From: Hans Verkuil @ 2014-03-11 20:23 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: linux-media, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	sakari.ailus, Hans Verkuil

Hi Mauro,

On 03/11/2014 08:34 PM, Mauro Carvalho Chehab wrote:
> Em Mon, 17 Feb 2014 10:57:19 +0100
> Hans Verkuil <hverkuil@xs4all.nl> escreveu:
> 
>> From: Hans Verkuil <hans.verkuil@cisco.com>
>>
>> Complex controls are controls that can be used for compound and array
>> types. This allows for more complex data structures to be used with the
>> control framework.
>>
>> Such controls always have the V4L2_CTRL_FLAG_HIDDEN flag set. Note that
>> 'simple' controls can also set that flag.
>>
>> The existing V4L2_CTRL_FLAG_NEXT_CTRL flag will only enumerate controls
>> that do not have the HIDDEN flag, so a new V4L2_CTRL_FLAG_NEXT_HIDDEN flag
>> is added to enumerate hidden controls. Set both flags to enumerate any
>> controls (hidden or not).
>>
>> Complex control types will start at V4L2_CTRL_COMPLEX_TYPES. In addition, any
>> control that uses the new 'p' field or the existing 'string' field will have
>> flag V4L2_CTRL_FLAG_IS_PTR 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 | 11 +++++++++--
>>  1 file changed, 9 insertions(+), 2 deletions(-)
>>
>> diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
>> index 6ae7bbe..4d7782a 100644
>> --- a/include/uapi/linux/videodev2.h
>> +++ b/include/uapi/linux/videodev2.h
>> @@ -1228,6 +1228,7 @@ struct v4l2_ext_control {
>>  		__s32 value;
>>  		__s64 value64;
>>  		char *string;
>> +		void *p;
> 
> Hmm... don't we have already "string" for pointers? Also, calling it
> as "p" inside an userspace api doesn't seem to nice ("ptr" would be
> better).
> 
> Btw, you likely already noticed the mess, as, when you added 
> this email's comment, you said that complex controls could
> either use "p" or "string".
> 
> Nack. It should just use "string". Let's not add even more complexity
> to this "complex" controls.

It is really, really weird to refer to a matrix type or struct type
through a 'string'. Also, the type of 'string' is a char pointer
which is totally wrong unless the type is really a string.

Finally there is a slight difference in handling strings: the size of
the memory 'string' points to just has to be large enough to store the
0-terminated string instead of being able to store the maximum possible
size of the string (max + 1). This is IMHO a design mistake regarding
strings on my part. I should always have required that the memory is
always sizes for the worst-case.

I might take another look if I can change this behavior without
breaking existing applications.

I don't mind changing 'p' to 'ptr', no problem.

> 
>>  	};
>>  } __attribute__ ((packed));
>>  
>> @@ -1252,7 +1253,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,
>> +
>> +	/* Complex types are >= 0x0100 */
>> +	V4L2_CTRL_COMPLEX_TYPES	     = 0x0100,
>>  };
> 
> Not sure if I got why you're calling it as "TYPES" and saying that
> everything >= 0x100 is complex. What's your idea here?

Types divide into 'simple' types (the ones we have today) and the
new complex (compound?) types. I need an easy way to determine
which it is, so any types with values >= 0x100 fall into the latter
category. Later in the patch series when such types are actually
added the meaning becomes more obvious.
 
> Also, at least for me with my engineering formation, "complex"
> means a number with an imaginary component.
> 
> And yes, we do have complex numbers on some usecases for
> V4L (for example, SDR in-phase/quadrature, e. g.  I/Q
> representation can be seen as an array of complex numbers).
> 
> So, I won't doubt that someone might propose some day to add a
> way to set a complex number via a V4L2 control.
> 
> So, please use a better naming here to avoid troubles.

COMPOUND_TYPES? Not a bad name, I think.

Regards,

	Hans

> 
>>  /*  Used in the VIDIOC_QUERYCTRL ioctl for querying controls */
>> @@ -1288,9 +1292,12 @@ 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_HIDDEN		0x0100
>> +#define V4L2_CTRL_FLAG_IS_PTR		0x0200
>>  
>> -/*  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_HIDDEN	0x40000000
>>  
>>  /*  User-class control IDs defined by V4L2 */
>>  #define V4L2_CID_MAX_CTRLS		1024
> 
> 


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

* Re: [REVIEWv3 PATCH 05/35] videodev2.h: add struct v4l2_query_ext_ctrl and VIDIOC_QUERY_EXT_CTRL.
  2014-03-11 19:42   ` Mauro Carvalho Chehab
@ 2014-03-11 20:29     ` Hans Verkuil
  2014-03-11 23:35       ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 66+ messages in thread
From: Hans Verkuil @ 2014-03-11 20:29 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: linux-media, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	sakari.ailus, Hans Verkuil

On 03/11/2014 08:42 PM, Mauro Carvalho Chehab wrote:
> Em Mon, 17 Feb 2014 10:57:20 +0100
> Hans Verkuil <hverkuil@xs4all.nl> escreveu:
> 
>> 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.
>>
>> It gives back a unit string, the range is now a s64 type, and the matrix
>> and element size can be reported through cols/rows/elem_size.
>>
>> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
>> ---
>>  include/uapi/linux/videodev2.h | 31 +++++++++++++++++++++++++++++++
>>  1 file changed, 31 insertions(+)
>>
>> diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
>> index 4d7782a..858a6f3 100644
>> --- a/include/uapi/linux/videodev2.h
>> +++ b/include/uapi/linux/videodev2.h
>> @@ -1272,6 +1272,35 @@ 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];
>> +	char		     unit[32];
>> +	union {
>> +		__s64 val;
>> +		__u32 reserved[4];
> 
> Why to reserve 16 bytes here? for anything bigger than 64
> bits, we could use a pointer.
> 
> Same applies to the other unions.

The idea was to allow space for min/max/step/def values for compound types
if applicable. But that may have been overengineering.

> 
>> +	} min;
>> +	union {
>> +		__s64 val;
>> +		__u32 reserved[4];
>> +	} max;
>> +	union {
>> +		__u64 val;
>> +		__u32 reserved[4];
>> +	} step;
>> +	union {
>> +		__s64 val;
>> +		__u32 reserved[4];
>> +	} def;
> 
> Please call it default. It is ok to simplify names inside a driver,
> but better to not do it at the API.

default_value, then. 'default' is a keyword. I should probably rename min and max
to minimum and maximum to stay in sync with v4l2_queryctrl.

> 
>> +	__u32                flags;
> 
>> +	__u32                cols;
>> +	__u32                rows;
>> +	__u32                elem_size;
> 
> The three above seem to be too specific for an array.
> 
> I would put those on a separate struct and add here an union,
> like:
> 
> 	union {
> 		struct v4l2_array arr;
> 		__u32 reserved[8];
> 	}

I have to sleep on this. I'm not sure this helps in any way.

> 
>> +	__u32		     reserved[17];
> 
> This also seems too much. Why 17?

It aligned the struct up to some nice number. Also, experience tells me that
whenever I limit the number of reserved fields it bites me later.

> 
>> +};
> 
>> +
>>  /*  Used in the VIDIOC_QUERYMENU ioctl for querying menu items */
>>  struct v4l2_querymenu {
>>  	__u32		id;
>> @@ -1965,6 +1994,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,

	Hans

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

* Re: [REVIEWv3 PATCH 06/35] v4l2-ctrls: add support for complex types.
  2014-03-11 20:14   ` Mauro Carvalho Chehab
@ 2014-03-11 20:43     ` Hans Verkuil
  2014-03-11 23:43       ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 66+ messages in thread
From: Hans Verkuil @ 2014-03-11 20:43 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: linux-media, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	sakari.ailus, Hans Verkuil

Hi Mauro,

On 03/11/2014 09:14 PM, Mauro Carvalho Chehab wrote:
> Em Mon, 17 Feb 2014 10:57:21 +0100
> Hans Verkuil <hverkuil@xs4all.nl> escreveu:
> 
>> From: Hans Verkuil <hans.verkuil@cisco.com>
>>
>> This patch implements initial support for complex types.
>>
>> For the most part 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), but one change needs more explanation:
>>
>> The v4l2_ctrl struct adds a 'new' field and a 'stores' array at the end
>> of the struct. This is in preparation for future patches where each control
>> can have multiple configuration stores. The idea is that stores[0] is the current
>> control value, stores[1] etc. are the control values for each configuration store
>> and the 'new' value can be accessed through 'stores[-1]', i.e. the 'new' field.
>> However, for now only stores[-1] and stores[0] is used.
>>
>> Drivers are not expected to use the stores array (at least not while support
>> for configuration stores is not yet fully added), but the stores array will
>> be used inside the control framework.
>>
>> These new fields use the v4l2_ctrl_ptr union, which is a pointer to a control
>> value.
>>
>> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
>> Reviewed-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
>> ---
>>  drivers/media/v4l2-core/v4l2-ctrls.c | 236 ++++++++++++++++++++++++++---------
>>  include/media/v4l2-ctrls.h           |  38 +++++-
>>  2 files changed, 210 insertions(+), 64 deletions(-)
>>
>> diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
>> index df8ed0a..5d1eeea 100644
>> --- a/drivers/media/v4l2-core/v4l2-ctrls.c
>> +++ b/drivers/media/v4l2-core/v4l2-ctrls.c
>> @@ -1095,20 +1095,6 @@ void v4l2_ctrl_fill(u32 id, const char **name, const char **unit,
>>  }
>>  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));
>> @@ -1117,7 +1103,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;
>> @@ -1152,6 +1138,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->p, ctrl->cur.p, ctrl->elem_size);
>> +
>>  	switch (ctrl->type) {
>>  	case V4L2_CTRL_TYPE_STRING:
>>  		len = strlen(ctrl->cur.string);
>> @@ -1179,6 +1168,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->p, ctrl->elem_size);
>> +
> 
> It is a little hard to follow all copy_*_user and memcpy/memcpy cases.
> 
> On all such calls, the elem_size data is coming from the driver?

Absolutely.

> It doesn't seem right to tust on userspace for that, if this could
> be a border case.
> 
>>  	switch (ctrl->type) {
>>  	case V4L2_CTRL_TYPE_INTEGER64:
>>  		ctrl->val64 = c->value64;
>> @@ -1213,6 +1205,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->p, ctrl->p, ctrl->elem_size);
>> +
>>  	switch (ctrl->type) {
>>  	case V4L2_CTRL_TYPE_STRING:
>>  		len = strlen(ctrl->string);
>> @@ -1239,6 +1234,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;
>> @@ -1253,8 +1249,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) {
>> @@ -1294,7 +1295,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;
>>  	}
>>  }
>> @@ -1507,7 +1511,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;
>> @@ -1577,8 +1581,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 hidden.
>> +	 */
>> +	if (!(ctrl->flags & V4L2_CTRL_FLAG_HIDDEN) &&
>> +	    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;
>>  
>> @@ -1640,23 +1648,36 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
>>  			u32 id, const char *name, const char *unit,
>>  			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_COMPLEX_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);
>>  		return NULL;
>>  	}
>> +	/* Complex controls are always hidden */
>> +	if (type >= V4L2_CTRL_COMPLEX_TYPES)
>> +		flags |= V4L2_CTRL_FLAG_HIDDEN;
>>  	err = check_range(type, min, max, step, def);
>>  	if (err) {
>>  		handler_set_err(hdl, err);
>> @@ -1667,12 +1688,13 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
>>  		return NULL;
>>  	}
>>  
>> +	sz_extra = sizeof(union v4l2_ctrl_ptr);
>>  	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_COMPLEX_TYPES)
>> +		sz_extra += 2 * elem_size;
>>  
>>  	ctrl = kzalloc(sizeof(*ctrl) + sz_extra, GFP_KERNEL);
>>  	if (ctrl == NULL) {
>> @@ -1692,18 +1714,31 @@ 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_COMPLEX_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->stores[1];
>> +
>> +	if (ctrl->is_string) {
>> +		ctrl->string = ctrl->new.p_char = data;
>> +		ctrl->stores[0].p_char = 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 = ctrl->new.p = data;
>> +		ctrl->stores[0].p = data + elem_size;
>> +	} else {
>> +		ctrl->new.p = &ctrl->val;
>> +		ctrl->stores[0].p = &ctrl->cur.val;
>>  	}
>>  	if (handler_new_ref(hdl, ctrl)) {
>>  		kfree(ctrl);
>> @@ -1752,7 +1787,8 @@ struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl,
>>  	ctrl = v4l2_ctrl_new(hdl, cfg->ops, cfg->id, name, unit,
>>  			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;
>> @@ -1770,13 +1806,15 @@ struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl,
>>  	u32 flags;
>>  
>>  	v4l2_ctrl_fill(id, &name, &unit, &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_COMPLEX_TYPES) {
>>  		handler_set_err(hdl, -EINVAL);
>>  		return NULL;
>>  	}
>>  	return v4l2_ctrl_new(hdl, ops, id, name, unit, type,
>> -			     min, max, step, def, flags, NULL, NULL, NULL);
>> +			     min, max, step, def, 0,
>> +			     flags, NULL, NULL, NULL);
>>  }
>>  EXPORT_SYMBOL(v4l2_ctrl_new_std);
>>  
>> @@ -1809,7 +1847,8 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl,
>>  		return NULL;
>>  	}
>>  	return v4l2_ctrl_new(hdl, ops, id, name, unit, 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);
>>  
>> @@ -1841,7 +1880,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, unit, type, 0, max, mask, def,
>> -			     flags, qmenu, NULL, NULL);
>> +			     0, flags, qmenu, NULL, NULL);
>>  
>>  }
>>  EXPORT_SYMBOL(v4l2_ctrl_new_std_menu_items);
>> @@ -1866,7 +1905,8 @@ struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl,
>>  		return NULL;
>>  	}
>>  	return v4l2_ctrl_new(hdl, ops, id, name, unit, 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);
>>  
>> @@ -2154,9 +2194,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_HIDDEN;
>>  	u32 id = qc->id & V4L2_CTRL_ID_MASK;
>>  	struct v4l2_ctrl_ref *ref;
>>  	struct v4l2_ctrl *ctrl;
>> @@ -2169,7 +2210,22 @@ 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)) {
>> +		unsigned mask;
>> +		unsigned match;
>> +
>> +		if ((qc->id & next_flags) == V4L2_CTRL_FLAG_NEXT_HIDDEN) {
>> +			/* Match any hidden control */
>> +			mask = match = V4L2_CTRL_FLAG_HIDDEN;
>> +		} else if ((qc->id & next_flags) == next_flags) {
>> +			/* Match any control, hidden or not */
>> +			mask = match = 0;
>> +		} else {
>> +			/* Match any control that is not hidden */
>> +			mask = V4L2_CTRL_FLAG_HIDDEN;
>> +			match = 0;
>> +		}
>> +
>>  		/* Find the next control with ID > qc->id */
>>  
>>  		/* Did we reach the end of the control list? */
>> @@ -2177,19 +2233,28 @@ 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)
>> +				if (id < ref->ctrl->id &&
>> +				    (ref->ctrl->flags & 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)
>> +				if (id < ref->ctrl->id &&
>> +				    (ref->ctrl->flags & mask) == match)
>>  					break;
>> +			if (&ref->node == &hdl->ctrl_refs)
>> +				ref = NULL;
>>  		}
>>  	}
>>  	mutex_unlock(hdl->lock);
>> +
>>  	if (!ref)
>>  		return -EINVAL;
>>  
>> @@ -2200,23 +2265,66 @@ 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->minimum = ctrl->minimum;
>> -	qc->maximum = ctrl->maximum;
>> -	qc->default_value = ctrl->default_value;
>> +	qc->flags = ctrl->flags;
>> +	qc->type = ctrl->type;
>> +	if (ctrl->is_ptr)
>> +		qc->flags |= V4L2_CTRL_FLAG_IS_PTR;
>> +	if (ctrl->unit)
>> +		strlcpy(qc->unit, ctrl->unit, sizeof(qc->unit));
>> +	qc->elem_size = ctrl->elem_size;
>> +	qc->min.val = ctrl->minimum;
>> +	qc->max.val = ctrl->maximum;
>> +	qc->def.val = ctrl->default_value;
>> +	qc->cols = qc->rows = 1;
>>  	if (ctrl->type == V4L2_CTRL_TYPE_MENU
>>  	    || ctrl->type == V4L2_CTRL_TYPE_INTEGER_MENU)
>> -		qc->step = 1;
>> +		qc->step.val = 1;
>>  	else
>> -		qc->step = ctrl->step;
>> -	qc->flags = ctrl->flags;
>> -	qc->type = ctrl->type;
>> +		qc->step.val = ctrl->step;
>> +	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;
>> +
>> +	/* VIDIOC_QUERYCTRL cannot be used to enumerate hidden controls */
> 
> Why not?

Good question, actually. QUERYCTRL cannot properly represent the full information
about compound types (let's call it that for now), so I sort of assumed you
wouldn't want to use it for this anyway. But on the other hand, you can just
fill in what you can and leave it at that. Userspace can call QUERY_EXT_CTRL if
it wants the full information.

I think it would be a good improvement to allow this for queryctrl as well.

> 
>> +	if (qc->id & V4L2_CTRL_FLAG_NEXT_HIDDEN)
>> +		return -EINVAL;
>> +	rc = v4l2_query_ext_ctrl(hdl, &qec);
>> +	if (rc)
>> +		return rc;
>> +
>> +	/* VIDIOC_QUERYCTRL is not allowed to see hidden controls */
>> +	if (qc->flags & V4L2_CTRL_FLAG_HIDDEN)
>> +		return -EINVAL;
>> +	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.min.val;
>> +		qc->maximum = qec.max.val;
>> +		qc->step = qec.step.val;
>> +		qc->default_value = qec.def.val;
>> +		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_HIDDEN))
>>  		return -EINVAL;
>>  	return v4l2_queryctrl(sd->ctrl_handler, qc);
>>  }
>> @@ -2316,7 +2424,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;
>> @@ -2348,6 +2457,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;
>> @@ -2428,7 +2544,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++)
>> @@ -2490,11 +2606,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
>> +	/* Complex 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)
>> @@ -2520,7 +2636,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;
>> @@ -2539,7 +2655,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;
>> @@ -2675,7 +2791,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)
>> @@ -2780,11 +2896,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
>> +	/* Complex 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().
>>  	 */
> 
> The new text also has an error. From the code below, what's not supported
> below are actually non-integer controls.

Well spotted:

>> -	if (ctrl->type == V4L2_CTRL_TYPE_STRING)
>> +	if (!ctrl->is_int)

This should have been 'if (ctrl->is_ptr)'

>>  		return -EINVAL;
>>  
>>  	/* Reset the 'is_new' flags of the cluster */
>> @@ -2826,7 +2942,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)
>> @@ -2850,7 +2966,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 3998049..515c1ba 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 complex value.
>> + */
>> +union v4l2_ctrl_ptr {
>> +	s32 *p_s32;
>> +	s64 *p_s64;
>> +	char *p_char;
>> +	void *p;
>> +};
> 
> I can't see where the above is used.

It's used at the end of the v4l2_ctrl struct.

> 
>> +
>>  /** 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
>> @@ -73,6 +86,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 a matrix and/or has type >= V4L2_CTRL_COMPLEX_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
>> @@ -91,6 +110,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
>> @@ -105,7 +125,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
>> @@ -124,6 +143,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;
>> @@ -134,6 +156,7 @@ struct v4l2_ctrl {
>>  	const char *unit;
>>  	enum v4l2_ctrl_type type;
>>  	s64 minimum, maximum, default_value;
>> +	u32 elem_size;
>>  	union {
>>  		u64 step;
>>  		u64 menu_skip_mask;
>> @@ -143,17 +166,21 @@ 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;
>> +	union v4l2_ctrl_ptr new;
>> +	union v4l2_ctrl_ptr stores[];

^^^^^^^^^^^^^^^^^^^^

Here!

>>  };
>>  
>>  /** struct v4l2_ctrl_ref - The control reference.
>> @@ -215,6 +242,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,
>> @@ -239,6 +267,7 @@ struct v4l2_ctrl_config {
>>  	s64 max;
>>  	u64 step;
>>  	s64 def;
>> +	u32 elem_size;
>>  	u32 flags;
>>  	u64 menu_skip_mask;
>>  	const char * const *qmenu;
>> @@ -664,6 +693,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,
> 
> 

Regards,

	Hans

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

* Re: [REVIEWv3 PATCH 08/35] v4l2-ctrls: create type_ops.
  2014-03-11 20:22   ` Mauro Carvalho Chehab
@ 2014-03-11 20:49     ` Hans Verkuil
  2014-03-11 23:56       ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 66+ messages in thread
From: Hans Verkuil @ 2014-03-11 20:49 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: linux-media, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	sakari.ailus, Hans Verkuil

On 03/11/2014 09:22 PM, Mauro Carvalho Chehab wrote:
> Em Mon, 17 Feb 2014 10:57:23 +0100
> Hans Verkuil <hverkuil@xs4all.nl> escreveu:
> 
>> From: Hans Verkuil <hans.verkuil@cisco.com>
>>
>> Since complex 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
> 
> So far, I failed to see why this is needed, as all code below is actually
> related to non-complex controls, but your comment is confusing, saying that
> this is related to complex controls.

If a driver adds support for a complex control specific to that driver you
want to allow the driver to add these type operations to support the control.
So instead of hardcoding it in the control framework you want to implement it
as type ops that a driver can replace with its own.

But the first step is to implement the current type operations as type ops.

> Maybe a latter patch will help me to better understand this one.
> 
>> This patch uses the v4l2_ctrl_ptr union for the first time.

This sentence is not true, ignore it. The union was already used in patch 6
where it was introduced. It's a left-over from an earlier version of the patch
series.

Regards,

	Hans

> 
> Then move v4l2_ctrl_ptr union addition to this patch.
> 
>>
>> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
>> Reviewed-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
>> ---
>>  drivers/media/v4l2-core/v4l2-ctrls.c | 267 ++++++++++++++++++++++-------------
>>  include/media/v4l2-ctrls.h           |  21 +++
>>  2 files changed, 190 insertions(+), 98 deletions(-)
>>
>> diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
>> index 5d1eeea..fa737a5 100644
>> --- a/drivers/media/v4l2-core/v4l2-ctrls.c
>> +++ b/drivers/media/v4l2-core/v4l2-ctrls.c
>> @@ -1132,6 +1132,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->stores[0];
>> +
>> +	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)
>> @@ -1315,21 +1458,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->stores[0], ctrl->new);
>>  	}
>>  	return diff;
>>  }
>> @@ -1370,65 +1499,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->p;
>> +		return ctrl->type_ops->validate(ctrl, ptr);
>>  	}
>>  }
>>  
>> @@ -1645,6 +1739,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, const char *unit,
>>  			enum v4l2_ctrl_type type,
>>  			s64 min, s64 max, u64 step, s64 def,
>> @@ -1656,6 +1751,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
>>  	unsigned sz_extra;
>>  	void *data;
>>  	int err;
>> +	int s;
>>  
>>  	if (hdl->error)
>>  		return NULL;
>> @@ -1706,6 +1802,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->unit = unit;
>> @@ -1727,19 +1824,16 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
>>  	ctrl->cur.val = ctrl->val = def;
>>  	data = &ctrl->stores[1];
>>  
>> -	if (ctrl->is_string) {
>> -		ctrl->string = ctrl->new.p_char = data;
>> -		ctrl->stores[0].p_char = data + elem_size;
>> -
>> -		if (ctrl->minimum)
>> -			memset(ctrl->cur.string, ' ', ctrl->minimum);
>> -	} else if (ctrl->is_ptr) {
>> +	if (ctrl->is_ptr) {
>>  		ctrl->p = ctrl->new.p = data;
>>  		ctrl->stores[0].p = data + elem_size;
>>  	} else {
>>  		ctrl->new.p = &ctrl->val;
>>  		ctrl->stores[0].p = &ctrl->cur.val;
>>  	}
>> +	for (s = -1; s <= 0; s++)
>> +		ctrl->type_ops->init(ctrl, ctrl->stores[s]);
>> +
>>  	if (handler_new_ref(hdl, ctrl)) {
>>  		kfree(ctrl);
>>  		return NULL;
>> @@ -1784,7 +1878,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, unit,
>> +	ctrl = v4l2_ctrl_new(hdl, cfg->ops, cfg->type_ops, cfg->id, name, unit,
>>  			type, min, max,
>>  			is_menu ? cfg->menu_skip_mask : step,
>>  			def, cfg->elem_size,
>> @@ -1812,7 +1906,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, unit, type,
>> +	return v4l2_ctrl_new(hdl, ops, NULL, id, name, unit, type,
>>  			     min, max, step, def, 0,
>>  			     flags, NULL, NULL, NULL);
>>  }
>> @@ -1846,7 +1940,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, unit, type,
>> +	return v4l2_ctrl_new(hdl, ops, NULL, id, name, unit, type,
>>  			     0, max, mask, def, 0,
>>  			     flags, qmenu, qmenu_int, NULL);
>>  }
>> @@ -1879,7 +1973,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, unit, type, 0, max, mask, def,
>> +	return v4l2_ctrl_new(hdl, ops, NULL, id, name, unit, type,
>> +			     0, max, mask, def,
>>  			     0, flags, qmenu, NULL, NULL);
>>  
>>  }
>> @@ -1904,7 +1999,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, unit, type,
>> +	return v4l2_ctrl_new(hdl, ops, NULL, id, name, unit, type,
>>  			     0, max, 0, def, 0,
>>  			     flags, NULL, qmenu_int, NULL);
>>  }
>> @@ -2087,32 +2182,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 515c1ba..aaf7333 100644
>> --- a/include/media/v4l2-ctrls.h
>> +++ b/include/media/v4l2-ctrls.h
>> @@ -67,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.
>> @@ -102,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.
>>    * @unit:	The control's unit. May be NULL.
>> @@ -151,6 +169,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;
>>  	const char *unit;
>> @@ -234,6 +253,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 complex controls.
>>    * @id:	The control ID.
>>    * @name:	The control name.
>>    * @unit:	The control's unit.
>> @@ -259,6 +279,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;
>>  	const char *unit;
> 
> 


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

* Re: [REVIEWv3 PATCH 05/35] videodev2.h: add struct v4l2_query_ext_ctrl and VIDIOC_QUERY_EXT_CTRL.
  2014-03-11 20:29     ` Hans Verkuil
@ 2014-03-11 23:35       ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 66+ messages in thread
From: Mauro Carvalho Chehab @ 2014-03-11 23:35 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: linux-media, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	sakari.ailus, Hans Verkuil

Em Tue, 11 Mar 2014 21:29:29 +0100
Hans Verkuil <hverkuil@xs4all.nl> escreveu:

> On 03/11/2014 08:42 PM, Mauro Carvalho Chehab wrote:
> > Em Mon, 17 Feb 2014 10:57:20 +0100
> > Hans Verkuil <hverkuil@xs4all.nl> escreveu:
> > 
> >> 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.
> >>
> >> It gives back a unit string, the range is now a s64 type, and the matrix
> >> and element size can be reported through cols/rows/elem_size.
> >>
> >> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
> >> ---
> >>  include/uapi/linux/videodev2.h | 31 +++++++++++++++++++++++++++++++
> >>  1 file changed, 31 insertions(+)
> >>
> >> diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
> >> index 4d7782a..858a6f3 100644
> >> --- a/include/uapi/linux/videodev2.h
> >> +++ b/include/uapi/linux/videodev2.h
> >> @@ -1272,6 +1272,35 @@ 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];
> >> +	char		     unit[32];
> >> +	union {
> >> +		__s64 val;
> >> +		__u32 reserved[4];
> > 
> > Why to reserve 16 bytes here? for anything bigger than 64
> > bits, we could use a pointer.
> > 
> > Same applies to the other unions.
> 
> The idea was to allow space for min/max/step/def values for compound types
> if applicable. But that may have been overengineering.

It seems overengineering for me ;)

> 
> > 
> >> +	} min;
> >> +	union {
> >> +		__s64 val;
> >> +		__u32 reserved[4];
> >> +	} max;
> >> +	union {
> >> +		__u64 val;
> >> +		__u32 reserved[4];
> >> +	} step;
> >> +	union {
> >> +		__s64 val;
> >> +		__u32 reserved[4];
> >> +	} def;
> > 
> > Please call it default. It is ok to simplify names inside a driver,
> > but better to not do it at the API.
> 
> default_value, then. 'default' is a keyword. I should probably rename min and max
> to minimum and maximum to stay in sync with v4l2_queryctrl.

OK.

> > 
> >> +	__u32                flags;
> > 
> >> +	__u32                cols;
> >> +	__u32                rows;
> >> +	__u32                elem_size;
> > 
> > The three above seem to be too specific for an array.
> > 
> > I would put those on a separate struct and add here an union,
> > like:
> > 
> > 	union {
> > 		struct v4l2_array arr;
> > 		__u32 reserved[8];
> > 	}
> 
> I have to sleep on this. I'm not sure this helps in any way.

Well, for today's needs this may not bring any difference, but it may
help if we need to add something else there.

Also, it helps to make clear, at the documentation which parts of the
struct will be filled every time, and with part is array-specific.

> 
> > 
> >> +	__u32		     reserved[17];
> > 
> > This also seems too much. Why 17?
> 
> It aligned the struct up to some nice number. Also, experience tells me that
> whenever I limit the number of reserved fields it bites me later.
> 
> > 
> >> +};
> > 
> >> +
> >>  /*  Used in the VIDIOC_QUERYMENU ioctl for querying menu items */
> >>  struct v4l2_querymenu {
> >>  	__u32		id;
> >> @@ -1965,6 +1994,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,
> 
> 	Hans


-- 

Regards,
Mauro

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

* Re: [REVIEWv3 PATCH 06/35] v4l2-ctrls: add support for complex types.
  2014-03-11 20:43     ` Hans Verkuil
@ 2014-03-11 23:43       ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 66+ messages in thread
From: Mauro Carvalho Chehab @ 2014-03-11 23:43 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: linux-media, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	sakari.ailus, Hans Verkuil

Em Tue, 11 Mar 2014 21:43:47 +0100
Hans Verkuil <hverkuil@xs4all.nl> escreveu:

> Hi Mauro,
> 
> On 03/11/2014 09:14 PM, Mauro Carvalho Chehab wrote:
> > Em Mon, 17 Feb 2014 10:57:21 +0100
> > Hans Verkuil <hverkuil@xs4all.nl> escreveu:
> > 
> >> From: Hans Verkuil <hans.verkuil@cisco.com>
> >>
> >> This patch implements initial support for complex types.
> >>
> >> For the most part 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), but one change needs more explanation:
> >>
> >> The v4l2_ctrl struct adds a 'new' field and a 'stores' array at the end
> >> of the struct. This is in preparation for future patches where each control
> >> can have multiple configuration stores. The idea is that stores[0] is the current
> >> control value, stores[1] etc. are the control values for each configuration store
> >> and the 'new' value can be accessed through 'stores[-1]', i.e. the 'new' field.
> >> However, for now only stores[-1] and stores[0] is used.
> >>
> >> Drivers are not expected to use the stores array (at least not while support
> >> for configuration stores is not yet fully added), but the stores array will
> >> be used inside the control framework.
> >>
> >> These new fields use the v4l2_ctrl_ptr union, which is a pointer to a control
> >> value.
> >>
> >> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
> >> Reviewed-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
> >> ---
> >>  drivers/media/v4l2-core/v4l2-ctrls.c | 236 ++++++++++++++++++++++++++---------
> >>  include/media/v4l2-ctrls.h           |  38 +++++-
> >>  2 files changed, 210 insertions(+), 64 deletions(-)
> >>
> >> diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
> >> index df8ed0a..5d1eeea 100644
> >> --- a/drivers/media/v4l2-core/v4l2-ctrls.c
> >> +++ b/drivers/media/v4l2-core/v4l2-ctrls.c
> >> @@ -1095,20 +1095,6 @@ void v4l2_ctrl_fill(u32 id, const char **name, const char **unit,
> >>  }
> >>  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));
> >> @@ -1117,7 +1103,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;
> >> @@ -1152,6 +1138,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->p, ctrl->cur.p, ctrl->elem_size);
> >> +
> >>  	switch (ctrl->type) {
> >>  	case V4L2_CTRL_TYPE_STRING:
> >>  		len = strlen(ctrl->cur.string);
> >> @@ -1179,6 +1168,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->p, ctrl->elem_size);
> >> +
> > 
> > It is a little hard to follow all copy_*_user and memcpy/memcpy cases.
> > 
> > On all such calls, the elem_size data is coming from the driver?
> 
> Absolutely.
> 
> > It doesn't seem right to tust on userspace for that, if this could
> > be a border case.
> > 
> >>  	switch (ctrl->type) {
> >>  	case V4L2_CTRL_TYPE_INTEGER64:
> >>  		ctrl->val64 = c->value64;
> >> @@ -1213,6 +1205,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->p, ctrl->p, ctrl->elem_size);
> >> +
> >>  	switch (ctrl->type) {
> >>  	case V4L2_CTRL_TYPE_STRING:
> >>  		len = strlen(ctrl->string);
> >> @@ -1239,6 +1234,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;
> >> @@ -1253,8 +1249,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) {
> >> @@ -1294,7 +1295,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;
> >>  	}
> >>  }
> >> @@ -1507,7 +1511,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;
> >> @@ -1577,8 +1581,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 hidden.
> >> +	 */
> >> +	if (!(ctrl->flags & V4L2_CTRL_FLAG_HIDDEN) &&
> >> +	    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;
> >>  
> >> @@ -1640,23 +1648,36 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
> >>  			u32 id, const char *name, const char *unit,
> >>  			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_COMPLEX_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);
> >>  		return NULL;
> >>  	}
> >> +	/* Complex controls are always hidden */
> >> +	if (type >= V4L2_CTRL_COMPLEX_TYPES)
> >> +		flags |= V4L2_CTRL_FLAG_HIDDEN;
> >>  	err = check_range(type, min, max, step, def);
> >>  	if (err) {
> >>  		handler_set_err(hdl, err);
> >> @@ -1667,12 +1688,13 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
> >>  		return NULL;
> >>  	}
> >>  
> >> +	sz_extra = sizeof(union v4l2_ctrl_ptr);
> >>  	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_COMPLEX_TYPES)
> >> +		sz_extra += 2 * elem_size;
> >>  
> >>  	ctrl = kzalloc(sizeof(*ctrl) + sz_extra, GFP_KERNEL);
> >>  	if (ctrl == NULL) {
> >> @@ -1692,18 +1714,31 @@ 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_COMPLEX_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->stores[1];
> >> +
> >> +	if (ctrl->is_string) {
> >> +		ctrl->string = ctrl->new.p_char = data;
> >> +		ctrl->stores[0].p_char = 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 = ctrl->new.p = data;
> >> +		ctrl->stores[0].p = data + elem_size;
> >> +	} else {
> >> +		ctrl->new.p = &ctrl->val;
> >> +		ctrl->stores[0].p = &ctrl->cur.val;
> >>  	}
> >>  	if (handler_new_ref(hdl, ctrl)) {
> >>  		kfree(ctrl);
> >> @@ -1752,7 +1787,8 @@ struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl,
> >>  	ctrl = v4l2_ctrl_new(hdl, cfg->ops, cfg->id, name, unit,
> >>  			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;
> >> @@ -1770,13 +1806,15 @@ struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl,
> >>  	u32 flags;
> >>  
> >>  	v4l2_ctrl_fill(id, &name, &unit, &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_COMPLEX_TYPES) {
> >>  		handler_set_err(hdl, -EINVAL);
> >>  		return NULL;
> >>  	}
> >>  	return v4l2_ctrl_new(hdl, ops, id, name, unit, type,
> >> -			     min, max, step, def, flags, NULL, NULL, NULL);
> >> +			     min, max, step, def, 0,
> >> +			     flags, NULL, NULL, NULL);
> >>  }
> >>  EXPORT_SYMBOL(v4l2_ctrl_new_std);
> >>  
> >> @@ -1809,7 +1847,8 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl,
> >>  		return NULL;
> >>  	}
> >>  	return v4l2_ctrl_new(hdl, ops, id, name, unit, 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);
> >>  
> >> @@ -1841,7 +1880,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, unit, type, 0, max, mask, def,
> >> -			     flags, qmenu, NULL, NULL);
> >> +			     0, flags, qmenu, NULL, NULL);
> >>  
> >>  }
> >>  EXPORT_SYMBOL(v4l2_ctrl_new_std_menu_items);
> >> @@ -1866,7 +1905,8 @@ struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl,
> >>  		return NULL;
> >>  	}
> >>  	return v4l2_ctrl_new(hdl, ops, id, name, unit, 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);
> >>  
> >> @@ -2154,9 +2194,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_HIDDEN;
> >>  	u32 id = qc->id & V4L2_CTRL_ID_MASK;
> >>  	struct v4l2_ctrl_ref *ref;
> >>  	struct v4l2_ctrl *ctrl;
> >> @@ -2169,7 +2210,22 @@ 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)) {
> >> +		unsigned mask;
> >> +		unsigned match;
> >> +
> >> +		if ((qc->id & next_flags) == V4L2_CTRL_FLAG_NEXT_HIDDEN) {
> >> +			/* Match any hidden control */
> >> +			mask = match = V4L2_CTRL_FLAG_HIDDEN;
> >> +		} else if ((qc->id & next_flags) == next_flags) {
> >> +			/* Match any control, hidden or not */
> >> +			mask = match = 0;
> >> +		} else {
> >> +			/* Match any control that is not hidden */
> >> +			mask = V4L2_CTRL_FLAG_HIDDEN;
> >> +			match = 0;
> >> +		}
> >> +
> >>  		/* Find the next control with ID > qc->id */
> >>  
> >>  		/* Did we reach the end of the control list? */
> >> @@ -2177,19 +2233,28 @@ 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)
> >> +				if (id < ref->ctrl->id &&
> >> +				    (ref->ctrl->flags & 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)
> >> +				if (id < ref->ctrl->id &&
> >> +				    (ref->ctrl->flags & mask) == match)
> >>  					break;
> >> +			if (&ref->node == &hdl->ctrl_refs)
> >> +				ref = NULL;
> >>  		}
> >>  	}
> >>  	mutex_unlock(hdl->lock);
> >> +
> >>  	if (!ref)
> >>  		return -EINVAL;
> >>  
> >> @@ -2200,23 +2265,66 @@ 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->minimum = ctrl->minimum;
> >> -	qc->maximum = ctrl->maximum;
> >> -	qc->default_value = ctrl->default_value;
> >> +	qc->flags = ctrl->flags;
> >> +	qc->type = ctrl->type;
> >> +	if (ctrl->is_ptr)
> >> +		qc->flags |= V4L2_CTRL_FLAG_IS_PTR;
> >> +	if (ctrl->unit)
> >> +		strlcpy(qc->unit, ctrl->unit, sizeof(qc->unit));
> >> +	qc->elem_size = ctrl->elem_size;
> >> +	qc->min.val = ctrl->minimum;
> >> +	qc->max.val = ctrl->maximum;
> >> +	qc->def.val = ctrl->default_value;
> >> +	qc->cols = qc->rows = 1;
> >>  	if (ctrl->type == V4L2_CTRL_TYPE_MENU
> >>  	    || ctrl->type == V4L2_CTRL_TYPE_INTEGER_MENU)
> >> -		qc->step = 1;
> >> +		qc->step.val = 1;
> >>  	else
> >> -		qc->step = ctrl->step;
> >> -	qc->flags = ctrl->flags;
> >> -	qc->type = ctrl->type;
> >> +		qc->step.val = ctrl->step;
> >> +	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;
> >> +
> >> +	/* VIDIOC_QUERYCTRL cannot be used to enumerate hidden controls */
> > 
> > Why not?
> 
> Good question, actually. QUERYCTRL cannot properly represent the full information
> about compound types (let's call it that for now), so I sort of assumed you
> wouldn't want to use it for this anyway. But on the other hand, you can just
> fill in what you can and leave it at that. Userspace can call QUERY_EXT_CTRL if
> it wants the full information.
> 
> I think it would be a good improvement to allow this for queryctrl as well.

Well, I would remove that limit. I mean: if the user is explicitly
using VIDIOC_QUERYCTRL to see the hidden controls, why not exposing
them? They may not be a complex element that would require the
extra data provided via the EXT_CTRL call.

> 
> > 
> >> +	if (qc->id & V4L2_CTRL_FLAG_NEXT_HIDDEN)
> >> +		return -EINVAL;
> >> +	rc = v4l2_query_ext_ctrl(hdl, &qec);
> >> +	if (rc)
> >> +		return rc;
> >> +
> >> +	/* VIDIOC_QUERYCTRL is not allowed to see hidden controls */
> >> +	if (qc->flags & V4L2_CTRL_FLAG_HIDDEN)
> >> +		return -EINVAL;
> >> +	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.min.val;
> >> +		qc->maximum = qec.max.val;
> >> +		qc->step = qec.step.val;
> >> +		qc->default_value = qec.def.val;
> >> +		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_HIDDEN))
> >>  		return -EINVAL;
> >>  	return v4l2_queryctrl(sd->ctrl_handler, qc);
> >>  }
> >> @@ -2316,7 +2424,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;
> >> @@ -2348,6 +2457,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;
> >> @@ -2428,7 +2544,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++)
> >> @@ -2490,11 +2606,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
> >> +	/* Complex 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)
> >> @@ -2520,7 +2636,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;
> >> @@ -2539,7 +2655,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;
> >> @@ -2675,7 +2791,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)
> >> @@ -2780,11 +2896,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
> >> +	/* Complex 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().
> >>  	 */
> > 
> > The new text also has an error. From the code below, what's not supported
> > below are actually non-integer controls.
> 
> Well spotted:
> 
> >> -	if (ctrl->type == V4L2_CTRL_TYPE_STRING)
> >> +	if (!ctrl->is_int)
> 
> This should have been 'if (ctrl->is_ptr)'
> 
> >>  		return -EINVAL;
> >>  
> >>  	/* Reset the 'is_new' flags of the cluster */
> >> @@ -2826,7 +2942,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)
> >> @@ -2850,7 +2966,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 3998049..515c1ba 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 complex value.
> >> + */
> >> +union v4l2_ctrl_ptr {
> >> +	s32 *p_s32;
> >> +	s64 *p_s64;
> >> +	char *p_char;
> >> +	void *p;
> >> +};
> > 
> > I can't see where the above is used.
> 
> It's used at the end of the v4l2_ctrl struct.
> 
> > 
> >> +
> >>  /** 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
> >> @@ -73,6 +86,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 a matrix and/or has type >= V4L2_CTRL_COMPLEX_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
> >> @@ -91,6 +110,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
> >> @@ -105,7 +125,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
> >> @@ -124,6 +143,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;
> >> @@ -134,6 +156,7 @@ struct v4l2_ctrl {
> >>  	const char *unit;
> >>  	enum v4l2_ctrl_type type;
> >>  	s64 minimum, maximum, default_value;
> >> +	u32 elem_size;
> >>  	union {
> >>  		u64 step;
> >>  		u64 menu_skip_mask;
> >> @@ -143,17 +166,21 @@ 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;
> >> +	union v4l2_ctrl_ptr new;
> >> +	union v4l2_ctrl_ptr stores[];
> 
> ^^^^^^^^^^^^^^^^^^^^
> 
> Here!

You're not  using it here... you're just declaring it. You're actually
using it on a latter patch ;)

Btw, the declaration for stores[] seems weird or wrong on the above, as
this is actually allocating space for just a pointer. 

IMO, you should, instead, be declaring it as either:

	size_t stores_size;
	union v4l2_ctrl_ptr *stores;

or
	size_t stores_size;
	union v4l2_ctrl_ptr stores[MAX_STORES];

> 
> >>  };
> >>  
> >>  /** struct v4l2_ctrl_ref - The control reference.
> >> @@ -215,6 +242,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,
> >> @@ -239,6 +267,7 @@ struct v4l2_ctrl_config {
> >>  	s64 max;
> >>  	u64 step;
> >>  	s64 def;
> >> +	u32 elem_size;
> >>  	u32 flags;
> >>  	u64 menu_skip_mask;
> >>  	const char * const *qmenu;
> >> @@ -664,6 +693,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,
> > 
> > 
> 
> Regards,
> 
> 	Hans


-- 

Regards,
Mauro

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

* Re: [REVIEWv3 PATCH 04/35] videodev2.h: add initial support for complex controls.
  2014-03-11 20:23     ` Hans Verkuil
@ 2014-03-11 23:48       ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 66+ messages in thread
From: Mauro Carvalho Chehab @ 2014-03-11 23:48 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: linux-media, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	sakari.ailus, Hans Verkuil

Em Tue, 11 Mar 2014 21:23:26 +0100
Hans Verkuil <hverkuil@xs4all.nl> escreveu:

> Hi Mauro,
> 
> On 03/11/2014 08:34 PM, Mauro Carvalho Chehab wrote:
> > Em Mon, 17 Feb 2014 10:57:19 +0100
> > Hans Verkuil <hverkuil@xs4all.nl> escreveu:
> > 
> >> From: Hans Verkuil <hans.verkuil@cisco.com>
> >>
> >> Complex controls are controls that can be used for compound and array
> >> types. This allows for more complex data structures to be used with the
> >> control framework.
> >>
> >> Such controls always have the V4L2_CTRL_FLAG_HIDDEN flag set. Note that
> >> 'simple' controls can also set that flag.
> >>
> >> The existing V4L2_CTRL_FLAG_NEXT_CTRL flag will only enumerate controls
> >> that do not have the HIDDEN flag, so a new V4L2_CTRL_FLAG_NEXT_HIDDEN flag
> >> is added to enumerate hidden controls. Set both flags to enumerate any
> >> controls (hidden or not).
> >>
> >> Complex control types will start at V4L2_CTRL_COMPLEX_TYPES. In addition, any
> >> control that uses the new 'p' field or the existing 'string' field will have
> >> flag V4L2_CTRL_FLAG_IS_PTR 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 | 11 +++++++++--
> >>  1 file changed, 9 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
> >> index 6ae7bbe..4d7782a 100644
> >> --- a/include/uapi/linux/videodev2.h
> >> +++ b/include/uapi/linux/videodev2.h
> >> @@ -1228,6 +1228,7 @@ struct v4l2_ext_control {
> >>  		__s32 value;
> >>  		__s64 value64;
> >>  		char *string;
> >> +		void *p;
> > 
> > Hmm... don't we have already "string" for pointers? Also, calling it
> > as "p" inside an userspace api doesn't seem to nice ("ptr" would be
> > better).
> > 
> > Btw, you likely already noticed the mess, as, when you added 
> > this email's comment, you said that complex controls could
> > either use "p" or "string".
> > 
> > Nack. It should just use "string". Let's not add even more complexity
> > to this "complex" controls.
> 
> It is really, really weird to refer to a matrix type or struct type
> through a 'string'. Also, the type of 'string' is a char pointer
> which is totally wrong unless the type is really a string.
> 
> Finally there is a slight difference in handling strings: the size of
> the memory 'string' points to just has to be large enough to store the
> 0-terminated string instead of being able to store the maximum possible
> size of the string (max + 1). This is IMHO a design mistake regarding
> strings on my part. I should always have required that the memory is
> always sizes for the worst-case.

I see. Ok, given that string means a NUL-terminated sequence, but we
should let it very clear at DocBook that the difference between
a STRING type and a "COMPLEX" type is that on the latter, the size
is determined by a field, and not by a NUL character.

> 
> I might take another look if I can change this behavior without
> breaking existing applications.
> 
> I don't mind changing 'p' to 'ptr', no problem.
> 
> > 
> >>  	};
> >>  } __attribute__ ((packed));
> >>  
> >> @@ -1252,7 +1253,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,
> >> +
> >> +	/* Complex types are >= 0x0100 */
> >> +	V4L2_CTRL_COMPLEX_TYPES	     = 0x0100,
> >>  };
> > 
> > Not sure if I got why you're calling it as "TYPES" and saying that
> > everything >= 0x100 is complex. What's your idea here?
> 
> Types divide into 'simple' types (the ones we have today) and the
> new complex (compound?) types. I need an easy way to determine
> which it is, so any types with values >= 0x100 fall into the latter
> category. Later in the patch series when such types are actually
> added the meaning becomes more obvious.

Ok.

> > Also, at least for me with my engineering formation, "complex"
> > means a number with an imaginary component.
> > 
> > And yes, we do have complex numbers on some usecases for
> > V4L (for example, SDR in-phase/quadrature, e. g.  I/Q
> > representation can be seen as an array of complex numbers).
> > 
> > So, I won't doubt that someone might propose some day to add a
> > way to set a complex number via a V4L2 control.
> > 
> > So, please use a better naming here to avoid troubles.
> 
> COMPOUND_TYPES? Not a bad name, I think.

Sounds a better name for me. 

> Regards,
> 
> 	Hans
> 
> > 
> >>  /*  Used in the VIDIOC_QUERYCTRL ioctl for querying controls */
> >> @@ -1288,9 +1292,12 @@ 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_HIDDEN		0x0100
> >> +#define V4L2_CTRL_FLAG_IS_PTR		0x0200
> >>  
> >> -/*  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_HIDDEN	0x40000000
> >>  
> >>  /*  User-class control IDs defined by V4L2 */
> >>  #define V4L2_CID_MAX_CTRLS		1024
> > 
> > 
> 


-- 

Regards,
Mauro

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

* Re: [REVIEWv3 PATCH 08/35] v4l2-ctrls: create type_ops.
  2014-03-11 20:49     ` Hans Verkuil
@ 2014-03-11 23:56       ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 66+ messages in thread
From: Mauro Carvalho Chehab @ 2014-03-11 23:56 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: linux-media, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	sakari.ailus, Hans Verkuil

Em Tue, 11 Mar 2014 21:49:51 +0100
Hans Verkuil <hverkuil@xs4all.nl> escreveu:

> On 03/11/2014 09:22 PM, Mauro Carvalho Chehab wrote:
> > Em Mon, 17 Feb 2014 10:57:23 +0100
> > Hans Verkuil <hverkuil@xs4all.nl> escreveu:
> > 
> >> From: Hans Verkuil <hans.verkuil@cisco.com>
> >>
> >> Since complex 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
> > 
> > So far, I failed to see why this is needed, as all code below is actually
> > related to non-complex controls, but your comment is confusing, saying that
> > this is related to complex controls.
> 
> If a driver adds support for a complex control specific to that driver you
> want to allow the driver to add these type operations to support the control.
> So instead of hardcoding it in the control framework you want to implement it
> as type ops that a driver can replace with its own.

Not sure if I bought the idea of letting the compound controls to be
driver-specific.

IMO, we should define them at the core, in order to be sure that:
1) it will be properly documented;
2) all implementations will handle it at the same way.

> 
> But the first step is to implement the current type operations as type ops.
> 
> > Maybe a latter patch will help me to better understand this one.
> > 
> >> This patch uses the v4l2_ctrl_ptr union for the first time.
> 
> This sentence is not true, ignore it. The union was already used in patch 6
> where it was introduced. It's a left-over from an earlier version of the patch
> series.
> 
> Regards,
> 
> 	Hans
> 
> > 
> > Then move v4l2_ctrl_ptr union addition to this patch.
> > 
> >>
> >> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
> >> Reviewed-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
> >> ---
> >>  drivers/media/v4l2-core/v4l2-ctrls.c | 267 ++++++++++++++++++++++-------------
> >>  include/media/v4l2-ctrls.h           |  21 +++
> >>  2 files changed, 190 insertions(+), 98 deletions(-)
> >>
> >> diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
> >> index 5d1eeea..fa737a5 100644
> >> --- a/drivers/media/v4l2-core/v4l2-ctrls.c
> >> +++ b/drivers/media/v4l2-core/v4l2-ctrls.c
> >> @@ -1132,6 +1132,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->stores[0];
> >> +
> >> +	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)
> >> @@ -1315,21 +1458,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->stores[0], ctrl->new);
> >>  	}
> >>  	return diff;
> >>  }
> >> @@ -1370,65 +1499,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->p;
> >> +		return ctrl->type_ops->validate(ctrl, ptr);
> >>  	}
> >>  }
> >>  
> >> @@ -1645,6 +1739,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, const char *unit,
> >>  			enum v4l2_ctrl_type type,
> >>  			s64 min, s64 max, u64 step, s64 def,
> >> @@ -1656,6 +1751,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
> >>  	unsigned sz_extra;
> >>  	void *data;
> >>  	int err;
> >> +	int s;
> >>  
> >>  	if (hdl->error)
> >>  		return NULL;
> >> @@ -1706,6 +1802,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->unit = unit;
> >> @@ -1727,19 +1824,16 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
> >>  	ctrl->cur.val = ctrl->val = def;
> >>  	data = &ctrl->stores[1];
> >>  
> >> -	if (ctrl->is_string) {
> >> -		ctrl->string = ctrl->new.p_char = data;
> >> -		ctrl->stores[0].p_char = data + elem_size;
> >> -
> >> -		if (ctrl->minimum)
> >> -			memset(ctrl->cur.string, ' ', ctrl->minimum);
> >> -	} else if (ctrl->is_ptr) {
> >> +	if (ctrl->is_ptr) {
> >>  		ctrl->p = ctrl->new.p = data;
> >>  		ctrl->stores[0].p = data + elem_size;
> >>  	} else {
> >>  		ctrl->new.p = &ctrl->val;
> >>  		ctrl->stores[0].p = &ctrl->cur.val;
> >>  	}
> >> +	for (s = -1; s <= 0; s++)
> >> +		ctrl->type_ops->init(ctrl, ctrl->stores[s]);
> >> +
> >>  	if (handler_new_ref(hdl, ctrl)) {
> >>  		kfree(ctrl);
> >>  		return NULL;
> >> @@ -1784,7 +1878,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, unit,
> >> +	ctrl = v4l2_ctrl_new(hdl, cfg->ops, cfg->type_ops, cfg->id, name, unit,
> >>  			type, min, max,
> >>  			is_menu ? cfg->menu_skip_mask : step,
> >>  			def, cfg->elem_size,
> >> @@ -1812,7 +1906,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, unit, type,
> >> +	return v4l2_ctrl_new(hdl, ops, NULL, id, name, unit, type,
> >>  			     min, max, step, def, 0,
> >>  			     flags, NULL, NULL, NULL);
> >>  }
> >> @@ -1846,7 +1940,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, unit, type,
> >> +	return v4l2_ctrl_new(hdl, ops, NULL, id, name, unit, type,
> >>  			     0, max, mask, def, 0,
> >>  			     flags, qmenu, qmenu_int, NULL);
> >>  }
> >> @@ -1879,7 +1973,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, unit, type, 0, max, mask, def,
> >> +	return v4l2_ctrl_new(hdl, ops, NULL, id, name, unit, type,
> >> +			     0, max, mask, def,
> >>  			     0, flags, qmenu, NULL, NULL);
> >>  
> >>  }
> >> @@ -1904,7 +1999,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, unit, type,
> >> +	return v4l2_ctrl_new(hdl, ops, NULL, id, name, unit, type,
> >>  			     0, max, 0, def, 0,
> >>  			     flags, NULL, qmenu_int, NULL);
> >>  }
> >> @@ -2087,32 +2182,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 515c1ba..aaf7333 100644
> >> --- a/include/media/v4l2-ctrls.h
> >> +++ b/include/media/v4l2-ctrls.h
> >> @@ -67,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.
> >> @@ -102,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.
> >>    * @unit:	The control's unit. May be NULL.
> >> @@ -151,6 +169,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;
> >>  	const char *unit;
> >> @@ -234,6 +253,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 complex controls.
> >>    * @id:	The control ID.
> >>    * @name:	The control name.
> >>    * @unit:	The control's unit.
> >> @@ -259,6 +279,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;
> >>  	const char *unit;
> > 
> > 
> 


-- 

Regards,
Mauro

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

* Re: [REVIEWv3 PATCH 11/35] v4l2-ctrls: prepare for matrix support: add cols & rows fields.
  2014-02-17  9:57 ` [REVIEWv3 PATCH 11/35] v4l2-ctrls: prepare for matrix support: add cols & rows fields Hans Verkuil
@ 2014-03-12 10:34   ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 66+ messages in thread
From: Mauro Carvalho Chehab @ 2014-03-12 10:34 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: linux-media, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	sakari.ailus, Hans Verkuil

Em Mon, 17 Feb 2014 10:57:26 +0100
Hans Verkuil <hverkuil@xs4all.nl> escreveu:

> From: Hans Verkuil <hans.verkuil@cisco.com>
> 
> Add cols and rows fields to the core control structures in preparation
> for matrix support.
> 
> 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 +++++++++++++++++---------
>  include/media/v4l2-ctrls.h           |  6 ++++++
>  2 files changed, 23 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
> index ad8e5e4..a136cdc 100644
> --- a/drivers/media/v4l2-core/v4l2-ctrls.c
> +++ b/drivers/media/v4l2-core/v4l2-ctrls.c
> @@ -1731,7 +1731,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
>  			u32 id, const char *name, const char *unit,
>  			enum v4l2_ctrl_type type,
>  			s64 min, s64 max, u64 step, s64 def,
> -			u32 elem_size,
> +			u32 cols, u32 rows, u32 elem_size,
>  			u32 flags, const char * const *qmenu,
>  			const s64 *qmenu_int, void *priv)
>  {
> @@ -1744,6 +1744,11 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
>  	if (hdl->error)
>  		return NULL;
>  
> +	if (cols == 0)
> +		cols = 1;
> +	if (rows == 0)
> +		rows = 1;
> +
>  	if (type == V4L2_CTRL_TYPE_INTEGER64)
>  		elem_size = sizeof(s64);
>  	else if (type == V4L2_CTRL_TYPE_STRING)
> @@ -1803,6 +1808,8 @@ 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_COMPLEX_TYPES || ctrl->is_string;
>  	ctrl->is_int = !ctrl->is_ptr && type != V4L2_CTRL_TYPE_INTEGER64;
> +	ctrl->cols = cols;
> +	ctrl->rows = rows;
>  	ctrl->elem_size = elem_size;
>  	if (type == V4L2_CTRL_TYPE_MENU)
>  		ctrl->qmenu = qmenu;
> @@ -1868,8 +1875,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, unit,
>  			type, min, max,
> -			is_menu ? cfg->menu_skip_mask : step,
> -			def, cfg->elem_size,
> +			is_menu ? cfg->menu_skip_mask : step, def,
> +			cfg->cols, cfg->rows, cfg->elem_size,
>  			flags, qmenu, qmenu_int, priv);
>  	if (ctrl)
>  		ctrl->is_private = cfg->is_private;
> @@ -1895,7 +1902,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl,
>  		return NULL;
>  	}
>  	return v4l2_ctrl_new(hdl, ops, NULL, id, name, unit, type,
> -			     min, max, step, def, 0,
> +			     min, max, step, def, 0, 0, 0,
>  			     flags, NULL, NULL, NULL);

Gah, the number of parameters here is too big... 18 parameters on this
function call! Please replace it by an structure.

>  }
>  EXPORT_SYMBOL(v4l2_ctrl_new_std);
> @@ -1929,7 +1936,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, unit, type,
> -			     0, max, mask, def, 0,
> +			     0, max, mask, def, 0, 0, 0,
>  			     flags, qmenu, qmenu_int, NULL);
>  }
>  EXPORT_SYMBOL(v4l2_ctrl_new_std_menu);
> @@ -1962,8 +1969,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, unit, type,
> -			     0, max, mask, def,
> -			     0, flags, qmenu, NULL, NULL);
> +			     0, max, mask, def, 0, 0, 0,
> +			     flags, qmenu, NULL, NULL);
>  
>  }
>  EXPORT_SYMBOL(v4l2_ctrl_new_std_menu_items);
> @@ -1988,7 +1995,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, unit, type,
> -			     0, max, 0, def, 0,
> +			     0, max, 0, def, 0, 0, 0,
>  			     flags, NULL, qmenu_int, NULL);
>  }
>  EXPORT_SYMBOL(v4l2_ctrl_new_int_menu);
> @@ -2334,7 +2341,8 @@ int v4l2_query_ext_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_query_ext_ctr
>  	qc->min.val = ctrl->minimum;
>  	qc->max.val = ctrl->maximum;
>  	qc->def.val = ctrl->default_value;
> -	qc->cols = qc->rows = 1;
> +	qc->cols = ctrl->cols;
> +	qc->rows = ctrl->rows;
>  	if (ctrl->type == V4L2_CTRL_TYPE_MENU
>  	    || ctrl->type == V4L2_CTRL_TYPE_INTEGER_MENU)
>  		qc->step.val = 1;
> diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
> index 5a39877..9eeb9d9 100644
> --- a/include/media/v4l2-ctrls.h
> +++ b/include/media/v4l2-ctrls.h
> @@ -129,6 +129,8 @@ typedef void (*v4l2_ctrl_notify_fnc)(struct v4l2_ctrl *ctrl, void *priv);
>    * @minimum:	The control's minimum value.
>    * @maximum:	The control's maximum value.
>    * @default_value: The control's default value.
> +  * @rows:	The number of rows in the matrix.
> +  * @cols:	The number of columns in the matrix.
>    * @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
> @@ -178,6 +180,7 @@ struct v4l2_ctrl {
>  	const char *unit;
>  	enum v4l2_ctrl_type type;
>  	s64 minimum, maximum, default_value;
> +	u32 rows, cols;
>  	u32 elem_size;
>  	union {
>  		u64 step;
> @@ -265,6 +268,8 @@ 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.
> +  * @rows:	The number of rows in the matrix.
> +  * @cols:	The number of columns in the matrix.
>    * @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
> @@ -291,6 +296,7 @@ struct v4l2_ctrl_config {
>  	s64 max;
>  	u64 step;
>  	s64 def;
> +	u32 rows, cols;
>  	u32 elem_size;
>  	u32 flags;
>  	u64 menu_skip_mask;


-- 

Regards,
Mauro

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

* Re: [REVIEWv3 PATCH 12/35] v4l2-ctrls: replace cur by a union v4l2_ctrl_ptr.
  2014-02-17  9:57 ` [REVIEWv3 PATCH 12/35] v4l2-ctrls: replace cur by a union v4l2_ctrl_ptr Hans Verkuil
@ 2014-03-12 10:38   ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 66+ messages in thread
From: Mauro Carvalho Chehab @ 2014-03-12 10:38 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: linux-media, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	sakari.ailus, Hans Verkuil

Em Mon, 17 Feb 2014 10:57:27 +0100
Hans Verkuil <hverkuil@xs4all.nl> escreveu:

> From: Hans Verkuil <hans.verkuil@cisco.com>
> 
> Instead of having to maintain the 'cur' union this patch replaces it by
> a v4l2_ctrl_ptr union to be consistent with the future configuration stores,
> which also use that union. The number of drivers that use 'cur' is fairly small,
> so it is easy enough to convert them all.
> 
> Unfortunately, the union for the new value cannot be dropped as easily
> since it is used pretty much everywhere.
> 
> As a consequence of these changes the v4l2_ctrl struct changes as well.
> 
> It was this:
> 
> 	union { };		 // anonymous union for the 'new' value
> 	union { } cur;		 // union for the 'cur' value
> 	union v4l2_ctrl_ptr new; // v4l2_ctrl_ptr to the new value (anonymous union)
> 	union v4l2_ctrl_ptr stores[]; // v4l2_ctrl_ptr to the cur union
> 
> where the stores array contains just one v4l2_ctrl_ptr union when it is
> allocated.
> 
> It changes to this:
> 
> 	union { };		 // anonymous union for the 'new' value
> 	union v4l2_ctrl_ptr *stores; // set to &cur
> 	union v4l2_ctrl_ptr new; // v4l2_ctrl_ptr to the new value (anonymous union)
> 	union v4l2_ctrl_ptr cur; // v4l2_ctrl_ptr for the cur value
> 
> The end result is the same: stores[0] is a pointer to the current value,
> stores[-1] is a pointer to the new value, and the 'cur' field is still
> there as well, except that the cur field is now a pointer union to the
> actual value, so cur.val is now *cur.p_s32.

Huh??? Do you want to use a negative value for the array index???

That sounds crazy. Also, I'm pretty sure that all static analyzers will 
complain about that.

> 
> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
> ---
>  Documentation/video4linux/v4l2-controls.txt   |  4 ++--
>  drivers/media/common/cx2341x.c                |  4 ++--
>  drivers/media/i2c/adp1653.c                   | 10 +++++-----
>  drivers/media/i2c/as3645a.c                   | 22 ++++++++++-----------
>  drivers/media/i2c/lm3560.c                    |  2 +-
>  drivers/media/i2c/m5mols/m5mols_controls.c    |  6 +++---
>  drivers/media/i2c/msp3400-driver.c            |  4 ++--
>  drivers/media/i2c/mt9p031.c                   |  4 ++--
>  drivers/media/i2c/mt9t001.c                   |  4 ++--
>  drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c     |  6 +++---
>  drivers/media/i2c/smiapp/smiapp-core.c        | 12 ++++++------
>  drivers/media/pci/cx18/cx18-av-core.c         |  2 +-
>  drivers/media/pci/cx18/cx18-driver.c          | 10 +++++-----
>  drivers/media/platform/exynos4-is/fimc-core.c |  6 +++---
>  drivers/media/platform/vivi.c                 | 28 +++++++++++++--------------
>  drivers/media/radio/radio-isa.c               |  2 +-
>  drivers/media/radio/radio-sf16fmr2.c          |  4 ++--
>  drivers/media/usb/gspca/conex.c               |  8 ++++----
>  drivers/media/usb/gspca/sn9c20x.c             |  4 ++--
>  drivers/media/usb/gspca/topro.c               |  4 ++--
>  drivers/media/v4l2-core/v4l2-ctrls.c          | 16 +++++++--------
>  include/media/v4l2-ctrls.h                    |  9 ++-------
>  22 files changed, 83 insertions(+), 88 deletions(-)
> 
> diff --git a/Documentation/video4linux/v4l2-controls.txt b/Documentation/video4linux/v4l2-controls.txt
> index 06cf3ac..1c353c2 100644
> --- a/Documentation/video4linux/v4l2-controls.txt
> +++ b/Documentation/video4linux/v4l2-controls.txt
> @@ -362,8 +362,8 @@ 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);
> -	printk(KERN_INFO "Integer value is '%s'\n", ctrl2->cur.val);
> +	pr_info("String value is '%s'\n", ctrl1->cur.p_char);
> +	pr_info("Integer value is '%d'\n", *ctrl2->cur.p_s32);
>  	mutex_unlock(&state->ctrl_handler.lock);
>  
>  
> diff --git a/drivers/media/common/cx2341x.c b/drivers/media/common/cx2341x.c
> index 103ef6b..909d334 100644
> --- a/drivers/media/common/cx2341x.c
> +++ b/drivers/media/common/cx2341x.c
> @@ -1261,10 +1261,10 @@ static int cx2341x_hdl_api(struct cx2341x_handler *hdl,
>  	return hdl->func(hdl->priv, cmd, args, 0, data);
>  }
>  
> -/* ctrl->handler->lock is held, so it is safe to access cur.val */
> +/* ctrl->handler->lock is held, so it is safe to access *cur.p_s32 */
>  static inline int cx2341x_neq(struct v4l2_ctrl *ctrl)
>  {
> -	return ctrl && ctrl->val != ctrl->cur.val;
> +	return ctrl && ctrl->val != *ctrl->cur.p_s32;
>  }
>  
>  static int cx2341x_try_ctrl(struct v4l2_ctrl *ctrl)
> diff --git a/drivers/media/i2c/adp1653.c b/drivers/media/i2c/adp1653.c
> index 873fe19..7d478dc 100644
> --- a/drivers/media/i2c/adp1653.c
> +++ b/drivers/media/i2c/adp1653.c
> @@ -158,16 +158,16 @@ static int adp1653_get_ctrl(struct v4l2_ctrl *ctrl)
>  	if (IS_ERR_VALUE(rval))
>  		return rval;
>  
> -	ctrl->cur.val = 0;
> +	*ctrl->cur.p_s32 = 0;
>  
>  	if (flash->fault & ADP1653_REG_FAULT_FLT_SCP)
> -		ctrl->cur.val |= V4L2_FLASH_FAULT_SHORT_CIRCUIT;
> +		*ctrl->cur.p_s32 |= V4L2_FLASH_FAULT_SHORT_CIRCUIT;
>  	if (flash->fault & ADP1653_REG_FAULT_FLT_OT)
> -		ctrl->cur.val |= V4L2_FLASH_FAULT_OVER_TEMPERATURE;
> +		*ctrl->cur.p_s32 |= V4L2_FLASH_FAULT_OVER_TEMPERATURE;
>  	if (flash->fault & ADP1653_REG_FAULT_FLT_TMR)
> -		ctrl->cur.val |= V4L2_FLASH_FAULT_TIMEOUT;
> +		*ctrl->cur.p_s32 |= V4L2_FLASH_FAULT_TIMEOUT;
>  	if (flash->fault & ADP1653_REG_FAULT_FLT_OV)
> -		ctrl->cur.val |= V4L2_FLASH_FAULT_OVER_VOLTAGE;
> +		*ctrl->cur.p_s32 |= V4L2_FLASH_FAULT_OVER_VOLTAGE;
>  
>  	flash->fault = 0;
>  
> diff --git a/drivers/media/i2c/as3645a.c b/drivers/media/i2c/as3645a.c
> index 301084b..4c6041c 100644
> --- a/drivers/media/i2c/as3645a.c
> +++ b/drivers/media/i2c/as3645a.c
> @@ -334,24 +334,24 @@ static int as3645a_get_ctrl(struct v4l2_ctrl *ctrl)
>  		if (value < 0)
>  			return value;
>  
> -		ctrl->cur.val = 0;
> +		*ctrl->cur.p_s32 = 0;
>  		if (value & AS_FAULT_INFO_SHORT_CIRCUIT)
> -			ctrl->cur.val |= V4L2_FLASH_FAULT_SHORT_CIRCUIT;
> +			*ctrl->cur.p_s32 |= V4L2_FLASH_FAULT_SHORT_CIRCUIT;
>  		if (value & AS_FAULT_INFO_OVER_TEMPERATURE)
> -			ctrl->cur.val |= V4L2_FLASH_FAULT_OVER_TEMPERATURE;
> +			*ctrl->cur.p_s32 |= V4L2_FLASH_FAULT_OVER_TEMPERATURE;
>  		if (value & AS_FAULT_INFO_TIMEOUT)
> -			ctrl->cur.val |= V4L2_FLASH_FAULT_TIMEOUT;
> +			*ctrl->cur.p_s32 |= V4L2_FLASH_FAULT_TIMEOUT;
>  		if (value & AS_FAULT_INFO_OVER_VOLTAGE)
> -			ctrl->cur.val |= V4L2_FLASH_FAULT_OVER_VOLTAGE;
> +			*ctrl->cur.p_s32 |= V4L2_FLASH_FAULT_OVER_VOLTAGE;
>  		if (value & AS_FAULT_INFO_INDUCTOR_PEAK_LIMIT)
> -			ctrl->cur.val |= V4L2_FLASH_FAULT_OVER_CURRENT;
> +			*ctrl->cur.p_s32 |= V4L2_FLASH_FAULT_OVER_CURRENT;
>  		if (value & AS_FAULT_INFO_INDICATOR_LED)
> -			ctrl->cur.val |= V4L2_FLASH_FAULT_INDICATOR;
> +			*ctrl->cur.p_s32 |= V4L2_FLASH_FAULT_INDICATOR;
>  		break;
>  
>  	case V4L2_CID_FLASH_STROBE_STATUS:
>  		if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH) {
> -			ctrl->cur.val = 0;
> +			*ctrl->cur.p_s32 = 0;
>  			break;
>  		}
>  
> @@ -359,11 +359,11 @@ static int as3645a_get_ctrl(struct v4l2_ctrl *ctrl)
>  		if (value < 0)
>  			return value;
>  
> -		ctrl->cur.val = value;
> +		*ctrl->cur.p_s32 = value;
>  		break;
>  	}
>  
> -	dev_dbg(&client->dev, "G_CTRL %08x:%d\n", ctrl->id, ctrl->cur.val);
> +	dev_dbg(&client->dev, "G_CTRL %08x:%d\n", ctrl->id, *ctrl->cur.p_s32);
>  
>  	return 0;
>  }
> @@ -458,7 +458,7 @@ static int as3645a_set_ctrl(struct v4l2_ctrl *ctrl)
>  		if (ret < 0)
>  			return ret;
>  
> -		if ((ctrl->val == 0) == (ctrl->cur.val == 0))
> +		if ((ctrl->val == 0) == (*ctrl->cur.p_s32 == 0))
>  			break;
>  
>  		return as3645a_set_output(flash, false);
> diff --git a/drivers/media/i2c/lm3560.c b/drivers/media/i2c/lm3560.c
> index d98ca3a..edfe746 100644
> --- a/drivers/media/i2c/lm3560.c
> +++ b/drivers/media/i2c/lm3560.c
> @@ -188,7 +188,7 @@ static int lm3560_get_ctrl(struct v4l2_ctrl *ctrl, enum lm3560_led_id led_no)
>  			fault |= V4L2_FLASH_FAULT_OVER_TEMPERATURE;
>  		if (reg_val & FAULT_TIMEOUT)
>  			fault |= V4L2_FLASH_FAULT_TIMEOUT;
> -		ctrl->cur.val = fault;
> +		*ctrl->cur.p_s32 = fault;
>  	}
>  
>  out:
> diff --git a/drivers/media/i2c/m5mols/m5mols_controls.c b/drivers/media/i2c/m5mols/m5mols_controls.c
> index a60931e..7851d1f 100644
> --- a/drivers/media/i2c/m5mols/m5mols_controls.c
> +++ b/drivers/media/i2c/m5mols/m5mols_controls.c
> @@ -191,7 +191,7 @@ static int m5mols_3a_lock(struct m5mols_info *info, struct v4l2_ctrl *ctrl)
>  	bool af_lock = ctrl->val & V4L2_LOCK_FOCUS;
>  	int ret = 0;
>  
> -	if ((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_EXPOSURE) {
> +	if ((ctrl->val ^ *ctrl->cur.p_s32) & V4L2_LOCK_EXPOSURE) {
>  		bool ae_lock = ctrl->val & V4L2_LOCK_EXPOSURE;
>  
>  		ret = m5mols_write(&info->sd, AE_LOCK, ae_lock ?
> @@ -200,7 +200,7 @@ static int m5mols_3a_lock(struct m5mols_info *info, struct v4l2_ctrl *ctrl)
>  			return ret;
>  	}
>  
> -	if (((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_WHITE_BALANCE)
> +	if (((ctrl->val ^ *ctrl->cur.p_s32) & V4L2_LOCK_WHITE_BALANCE)
>  	    && info->auto_wb->val) {
>  		bool awb_lock = ctrl->val & V4L2_LOCK_WHITE_BALANCE;
>  
> @@ -213,7 +213,7 @@ static int m5mols_3a_lock(struct m5mols_info *info, struct v4l2_ctrl *ctrl)
>  	if (!info->ver.af || !af_lock)
>  		return ret;
>  
> -	if ((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_FOCUS)
> +	if ((ctrl->val ^ *ctrl->cur.p_s32) & V4L2_LOCK_FOCUS)
>  		ret = m5mols_write(&info->sd, AF_EXECUTE, REG_AF_STOP);
>  
>  	return ret;
> diff --git a/drivers/media/i2c/msp3400-driver.c b/drivers/media/i2c/msp3400-driver.c
> index 8190fec..151016d 100644
> --- a/drivers/media/i2c/msp3400-driver.c
> +++ b/drivers/media/i2c/msp3400-driver.c
> @@ -411,8 +411,8 @@ void msp_update_volume(struct msp_state *state)
>  {
>  	/* Force an update of the volume/mute cluster */
>  	v4l2_ctrl_lock(state->volume);
> -	state->volume->val = state->volume->cur.val;
> -	state->muted->val = state->muted->cur.val;
> +	state->volume->val = *state->volume->cur.p_s32;
> +	state->muted->val = *state->muted->cur.p_s32;
>  	msp_s_ctrl(state->volume);
>  	v4l2_ctrl_unlock(state->volume);
>  }
> diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c
> index e5ddf47..28c17e0 100644
> --- a/drivers/media/i2c/mt9p031.c
> +++ b/drivers/media/i2c/mt9p031.c
> @@ -670,12 +670,12 @@ static int mt9p031_s_ctrl(struct v4l2_ctrl *ctrl)
>  	case V4L2_CID_TEST_PATTERN:
>  		if (!ctrl->val) {
>  			/* Restore the black level compensation settings. */
> -			if (mt9p031->blc_auto->cur.val != 0) {
> +			if (*mt9p031->blc_auto->cur.p_s32 != 0) {
>  				ret = mt9p031_s_ctrl(mt9p031->blc_auto);
>  				if (ret < 0)
>  					return ret;
>  			}
> -			if (mt9p031->blc_offset->cur.val != 0) {
> +			if (*mt9p031->blc_offset->cur.p_s32 != 0) {
>  				ret = mt9p031_s_ctrl(mt9p031->blc_offset);
>  				if (ret < 0)
>  					return ret;
> diff --git a/drivers/media/i2c/mt9t001.c b/drivers/media/i2c/mt9t001.c
> index d41c70e..6aca05b 100644
> --- a/drivers/media/i2c/mt9t001.c
> +++ b/drivers/media/i2c/mt9t001.c
> @@ -447,7 +447,7 @@ static int mt9t001_s_ctrl(struct v4l2_ctrl *ctrl)
>  		for (i = 0, count = 0; i < 4; ++i) {
>  			struct v4l2_ctrl *gain = mt9t001->gains[i];
>  
> -			if (gain->val != gain->cur.val)
> +			if (gain->val != *gain->cur.p_s32)
>  				count++;
>  		}
>  
> @@ -461,7 +461,7 @@ static int mt9t001_s_ctrl(struct v4l2_ctrl *ctrl)
>  		for (i = 0; i < 4; ++i) {
>  			struct v4l2_ctrl *gain = mt9t001->gains[i];
>  
> -			if (gain->val == gain->cur.val)
> +			if (gain->val == *gain->cur.p_s32)
>  				continue;
>  
>  			value = mt9t001_gain_value(&gain->val);
> diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c b/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c
> index 8001cde..cb6da84 100644
> --- a/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c
> +++ b/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c
> @@ -195,14 +195,14 @@ static int s5c73m3_3a_lock(struct s5c73m3 *state, struct v4l2_ctrl *ctrl)
>  	bool af_lock = ctrl->val & V4L2_LOCK_FOCUS;
>  	int ret = 0;
>  
> -	if ((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_EXPOSURE) {
> +	if ((ctrl->val ^ *ctrl->cur.p_s32) & V4L2_LOCK_EXPOSURE) {
>  		ret = s5c73m3_isp_command(state, COMM_AE_CON,
>  				ae_lock ? COMM_AE_STOP : COMM_AE_START);
>  		if (ret)
>  			return ret;
>  	}
>  
> -	if (((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_WHITE_BALANCE)
> +	if (((ctrl->val ^ *ctrl->cur.p_s32) & V4L2_LOCK_WHITE_BALANCE)
>  	    && state->ctrls.auto_wb->val) {
>  		ret = s5c73m3_isp_command(state, COMM_AWB_CON,
>  			awb_lock ? COMM_AWB_STOP : COMM_AWB_START);
> @@ -210,7 +210,7 @@ static int s5c73m3_3a_lock(struct s5c73m3 *state, struct v4l2_ctrl *ctrl)
>  			return ret;
>  	}
>  
> -	if ((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_FOCUS)
> +	if ((ctrl->val ^ *ctrl->cur.p_s32) & V4L2_LOCK_FOCUS)
>  		ret = s5c73m3_af_run(state, ~af_lock);
>  
>  	return ret;
> diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c
> index 8741cae..d87c5e8 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->cur.p_s64 = pll->vt_pix_clk_freq_hz;
> +	*sensor->pixel_rate_csi->cur.p_s64 = pll->pixel_rate_csi;
>  
>  	return 0;
>  }
> @@ -324,8 +324,8 @@ static void __smiapp_update_exposure_limits(struct smiapp_sensor *sensor)
>  		ctrl->default_value = max;
>  	if (ctrl->val > max)
>  		ctrl->val = max;
> -	if (ctrl->cur.val > max)
> -		ctrl->cur.val = max;
> +	if (*ctrl->cur.p_s32 > max)
> +		*ctrl->cur.p_s32 = max;
>  }
>  
>  /*
> @@ -796,7 +796,7 @@ static void smiapp_update_blanking(struct smiapp_sensor *sensor)
>  			      vblank->minimum, vblank->maximum);
>  	vblank->default_value = vblank->minimum;
>  	vblank->val = vblank->val;
> -	vblank->cur.val = vblank->val;
> +	*vblank->cur.p_s32 = vblank->val;
>  
>  	hblank->minimum =
>  		max_t(int,
> @@ -811,7 +811,7 @@ static void smiapp_update_blanking(struct smiapp_sensor *sensor)
>  			      hblank->minimum, hblank->maximum);
>  	hblank->default_value = hblank->minimum;
>  	hblank->val = hblank->val;
> -	hblank->cur.val = hblank->val;
> +	*hblank->cur.p_s32 = hblank->val;
>  
>  	__smiapp_update_exposure_limits(sensor);
>  }
> diff --git a/drivers/media/pci/cx18/cx18-av-core.c b/drivers/media/pci/cx18/cx18-av-core.c
> index c4890a4..d230a9b 100644
> --- a/drivers/media/pci/cx18/cx18-av-core.c
> +++ b/drivers/media/pci/cx18/cx18-av-core.c
> @@ -262,7 +262,7 @@ static void cx18_av_initialize(struct v4l2_subdev *sd)
>  		cx18_av_write(cx, 0x8d4, 20);
>  	}
>  	default_volume = (((228 - default_volume) >> 1) + 23) << 9;
> -	state->volume->cur.val = state->volume->default_value = default_volume;
> +	*state->volume->cur.p_s32 = state->volume->default_value = default_volume;
>  	v4l2_ctrl_handler_setup(&state->hdl);
>  }
>  
> diff --git a/drivers/media/pci/cx18/cx18-driver.c b/drivers/media/pci/cx18/cx18-driver.c
> index 716bdc5..e4d0740 100644
> --- a/drivers/media/pci/cx18/cx18-driver.c
> +++ b/drivers/media/pci/cx18/cx18-driver.c
> @@ -756,11 +756,11 @@ static int cx18_init_struct1(struct cx18 *cx)
>  		return ret;
>  	cx->v4l2_dev.ctrl_handler = &cx->cxhdl.hdl;
>  
> -	cx->temporal_strength = cx->cxhdl.video_temporal_filter->cur.val;
> -	cx->spatial_strength = cx->cxhdl.video_spatial_filter->cur.val;
> -	cx->filter_mode = cx->cxhdl.video_spatial_filter_mode->cur.val |
> -		(cx->cxhdl.video_temporal_filter_mode->cur.val << 1) |
> -		(cx->cxhdl.video_median_filter_type->cur.val << 2);
> +	cx->temporal_strength = *cx->cxhdl.video_temporal_filter->cur.p_s32;
> +	cx->spatial_strength = *cx->cxhdl.video_spatial_filter->cur.p_s32;
> +	cx->filter_mode = *cx->cxhdl.video_spatial_filter_mode->cur.p_s32 |
> +		(*cx->cxhdl.video_temporal_filter_mode->cur.p_s32 << 1) |
> +		(*cx->cxhdl.video_median_filter_type->cur.p_s32 << 2);
>  
>  	init_waitqueue_head(&cx->cap_w);
>  	init_waitqueue_head(&cx->mb_apu_waitq);
> diff --git a/drivers/media/platform/exynos4-is/fimc-core.c b/drivers/media/platform/exynos4-is/fimc-core.c
> index a7dfd07..d399699 100644
> --- a/drivers/media/platform/exynos4-is/fimc-core.c
> +++ b/drivers/media/platform/exynos4-is/fimc-core.c
> @@ -664,7 +664,7 @@ void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active)
>  		v4l2_ctrl_activate(ctrls->alpha, active && has_alpha);
>  
>  	if (active) {
> -		fimc_set_color_effect(ctx, ctrls->colorfx->cur.val);
> +		fimc_set_color_effect(ctx, *ctrls->colorfx->cur.p_s32);
>  		ctx->rotation = ctrls->rotate->val;
>  		ctx->hflip    = ctrls->hflip->val;
>  		ctx->vflip    = ctrls->vflip->val;
> @@ -689,8 +689,8 @@ void fimc_alpha_ctrl_update(struct fimc_ctx *ctx)
>  	v4l2_ctrl_lock(ctrl);
>  	ctrl->maximum = fimc_get_alpha_mask(ctx->d_frame.fmt);
>  
> -	if (ctrl->cur.val > ctrl->maximum)
> -		ctrl->cur.val = ctrl->maximum;
> +	if (*ctrl->cur.p_s32 > ctrl->maximum)
> +		*ctrl->cur.p_s32 = ctrl->maximum;
>  
>  	v4l2_ctrl_unlock(ctrl);
>  }
> diff --git a/drivers/media/platform/vivi.c b/drivers/media/platform/vivi.c
> index 3c92ce3..7b9e887 100644
> --- a/drivers/media/platform/vivi.c
> +++ b/drivers/media/platform/vivi.c
> @@ -642,28 +642,28 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
>  	gain = v4l2_ctrl_g_ctrl(dev->gain);
>  	mutex_lock(dev->ctrl_handler.lock);
>  	snprintf(str, sizeof(str), " brightness %3d, contrast %3d, saturation %3d, hue %d ",
> -			dev->brightness->cur.val,
> -			dev->contrast->cur.val,
> -			dev->saturation->cur.val,
> -			dev->hue->cur.val);
> +			*dev->brightness->cur.p_s32,
> +			*dev->contrast->cur.p_s32,
> +			*dev->saturation->cur.p_s32,
> +			*dev->hue->cur.p_s32);
>  	gen_text(dev, vbuf, line++ * 16, 16, str);
>  	snprintf(str, sizeof(str), " autogain %d, gain %3d, volume %3d, alpha 0x%02x ",
> -			dev->autogain->cur.val, gain, dev->volume->cur.val,
> -			dev->alpha->cur.val);
> +			*dev->autogain->cur.p_s32, gain, *dev->volume->cur.p_s32,
> +			*dev->alpha->cur.p_s32);
>  	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->bitmask->cur.val);
> +			*dev->int32->cur.p_s32,
> +			*dev->int64->cur.p_s64,
> +			*dev->bitmask->cur.p_s32);
>  	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->boolean->cur.p_s32,
> +			dev->menu->qmenu[*dev->menu->cur.p_s32],
> +			dev->string->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],
> -			dev->int_menu->cur.val);
> +			dev->int_menu->qmenu_int[*dev->int_menu->cur.p_s32],
> +			*dev->int_menu->cur.p_s32);
>  	gen_text(dev, vbuf, line++ * 16, 16, str);
>  	mutex_unlock(dev->ctrl_handler.lock);
>  	if (dev->button_pressed) {
> diff --git a/drivers/media/radio/radio-isa.c b/drivers/media/radio/radio-isa.c
> index 6ff3508..46d188d 100644
> --- a/drivers/media/radio/radio-isa.c
> +++ b/drivers/media/radio/radio-isa.c
> @@ -294,7 +294,7 @@ static int radio_isa_common_remove(struct radio_isa_card *isa,
>  {
>  	const struct radio_isa_ops *ops = isa->drv->ops;
>  
> -	ops->s_mute_volume(isa, true, isa->volume ? isa->volume->cur.val : 0);
> +	ops->s_mute_volume(isa, true, isa->volume ? *isa->volume->cur.p_s32 : 0);
>  	video_unregister_device(&isa->vdev);
>  	v4l2_ctrl_handler_free(&isa->hdl);
>  	v4l2_device_unregister(&isa->v4l2_dev);
> diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c
> index 93d864e..e393130 100644
> --- a/drivers/media/radio/radio-sf16fmr2.c
> +++ b/drivers/media/radio/radio-sf16fmr2.c
> @@ -154,11 +154,11 @@ static int fmr2_s_ctrl(struct v4l2_ctrl *ctrl)
>  	switch (ctrl->id) {
>  	case V4L2_CID_AUDIO_VOLUME:
>  		volume = ctrl->val;
> -		balance = fmr2->balance->cur.val;
> +		balance = *fmr2->balance->cur.p_s32;
>  		break;
>  	case V4L2_CID_AUDIO_BALANCE:
>  		balance = ctrl->val;
> -		volume = fmr2->volume->cur.val;
> +		volume = *fmr2->volume->cur.p_s32;
>  		break;
>  	default:
>  		return -EINVAL;
> diff --git a/drivers/media/usb/gspca/conex.c b/drivers/media/usb/gspca/conex.c
> index 2e15c80..e8cfaf3 100644
> --- a/drivers/media/usb/gspca/conex.c
> +++ b/drivers/media/usb/gspca/conex.c
> @@ -887,14 +887,14 @@ static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
>  
>  	switch (ctrl->id) {
>  	case V4L2_CID_BRIGHTNESS:
> -		setbrightness(gspca_dev, ctrl->val, sd->sat->cur.val);
> +		setbrightness(gspca_dev, ctrl->val, *sd->sat->cur.p_s32);
>  		break;
>  	case V4L2_CID_CONTRAST:
> -		setcontrast(gspca_dev, ctrl->val, sd->sat->cur.val);
> +		setcontrast(gspca_dev, ctrl->val, *sd->sat->cur.p_s32);
>  		break;
>  	case V4L2_CID_SATURATION:
> -		setbrightness(gspca_dev, sd->brightness->cur.val, ctrl->val);
> -		setcontrast(gspca_dev, sd->contrast->cur.val, ctrl->val);
> +		setbrightness(gspca_dev, *sd->brightness->cur.p_s32, ctrl->val);
> +		setcontrast(gspca_dev, *sd->contrast->cur.p_s32, ctrl->val);
>  		break;
>  	}
>  	return gspca_dev->usb_err;
> diff --git a/drivers/media/usb/gspca/sn9c20x.c b/drivers/media/usb/gspca/sn9c20x.c
> index 2a38621..22d93c3 100644
> --- a/drivers/media/usb/gspca/sn9c20x.c
> +++ b/drivers/media/usb/gspca/sn9c20x.c
> @@ -2218,7 +2218,7 @@ static void transfer_check(struct gspca_dev *gspca_dev,
>  			/* Note: we are in interrupt context, so we can't
>  			   use v4l2_ctrl_g/s_ctrl here. Access the value
>  			   directly instead. */
> -			s32 curqual = sd->jpegqual->cur.val;
> +			s32 curqual = *sd->jpegqual->cur.p_s32;
>  			sd->nchg = 0;
>  			new_qual += curqual;
>  			if (new_qual < sd->jpegqual->minimum)
> @@ -2226,7 +2226,7 @@ static void transfer_check(struct gspca_dev *gspca_dev,
>  			else if (new_qual > sd->jpegqual->maximum)
>  				new_qual = sd->jpegqual->maximum;
>  			if (new_qual != curqual) {
> -				sd->jpegqual->cur.val = new_qual;
> +				*sd->jpegqual->cur.p_s32 = new_qual;
>  				queue_work(sd->work_thread, &sd->work);
>  			}
>  		}
> diff --git a/drivers/media/usb/gspca/topro.c b/drivers/media/usb/gspca/topro.c
> index 640c2fe..4abe03b 100644
> --- a/drivers/media/usb/gspca/topro.c
> +++ b/drivers/media/usb/gspca/topro.c
> @@ -3976,8 +3976,8 @@ static int sd_setgain(struct gspca_dev *gspca_dev)
>  	s32 val = gspca_dev->gain->val;
>  
>  	if (sd->sensor == SENSOR_CX0342) {
> -		s32 old = gspca_dev->gain->cur.val ?
> -					gspca_dev->gain->cur.val : 1;
> +		s32 old = *gspca_dev->gain->cur.p_s32 ?
> +					*gspca_dev->gain->cur.p_s32 : 1;
>  
>  		sd->blue->val = sd->blue->val * val / old;
>  		if (sd->blue->val > 4095)
> diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
> index a136cdc..084335a 100644
> --- a/drivers/media/v4l2-core/v4l2-ctrls.c
> +++ b/drivers/media/v4l2-core/v4l2-ctrls.c
> @@ -47,7 +47,7 @@ struct v4l2_ctrl_helper {
>     mode. */
>  static bool is_cur_manual(const struct v4l2_ctrl *master)
>  {
> -	return master->is_auto && master->cur.val == master->manual_mode_value;
> +	return master->is_auto && *master->cur.p_s32 == master->manual_mode_value;
>  }
>  
>  /* Same as above, but this checks the against the new value instead of the
> @@ -1106,7 +1106,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->cur.p_s64;
>  	ev->u.ctrl.minimum = ctrl->minimum;
>  	ev->u.ctrl.maximum = ctrl->maximum;
>  	if (ctrl->type == V4L2_CTRL_TYPE_MENU
> @@ -1777,13 +1777,13 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
>  		return NULL;
>  	}
>  
> -	sz_extra = sizeof(union v4l2_ctrl_ptr);
> +	sz_extra = elem_size;
>  	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 || type >= V4L2_CTRL_COMPLEX_TYPES)
> -		sz_extra += 2 * elem_size;
> +		sz_extra += elem_size;
>  
>  	ctrl = kzalloc(sizeof(*ctrl) + sz_extra, GFP_KERNEL);
>  	if (ctrl == NULL) {
> @@ -1816,7 +1816,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
>  	else if (type == V4L2_CTRL_TYPE_INTEGER_MENU)
>  		ctrl->qmenu_int = qmenu_int;
>  	ctrl->priv = priv;
> -	ctrl->cur.val = ctrl->val = def;
> +	ctrl->stores = &ctrl->cur;
>  	data = &ctrl->stores[1];
>  
>  	if (ctrl->is_ptr) {
> @@ -1824,7 +1824,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
>  		ctrl->stores[0].p = data + elem_size;
>  	} else {
>  		ctrl->new.p = &ctrl->val;
> -		ctrl->stores[0].p = &ctrl->cur.val;
> +		ctrl->stores[0].p = data;
>  	}
>  	for (s = -1; s <= 0; s++)
>  		ctrl->type_ops->init(ctrl, ctrl->stores[s]);
> @@ -3090,10 +3090,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->cur.p_s32;
>  	if (validate_new(ctrl, &c))
>  		c.value = def;
> -	if (c.value != ctrl->cur.val)
> +	if (c.value != *ctrl->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/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
> index 9eeb9d9..4f66393 100644
> --- a/include/media/v4l2-ctrls.h
> +++ b/include/media/v4l2-ctrls.h
> @@ -198,14 +198,9 @@ struct v4l2_ctrl {
>  		char *string;
>  		void *p;
>  	};
> -	union {
> -		s32 val;
> -		s64 val64;
> -		char *string;
> -		void *p;
> -	} cur;
> +	union v4l2_ctrl_ptr *stores;
>  	union v4l2_ctrl_ptr new;
> -	union v4l2_ctrl_ptr stores[];
> +	union v4l2_ctrl_ptr cur;
>  };
>  
>  /** struct v4l2_ctrl_ref - The control reference.


-- 

Regards,
Mauro

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

* Re: [REVIEWv3 PATCH 13/35] v4l2-ctrls: use 'new' to access pointer controls
  2014-02-17  9:57 ` [REVIEWv3 PATCH 13/35] v4l2-ctrls: use 'new' to access pointer controls Hans Verkuil
@ 2014-03-12 10:40   ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 66+ messages in thread
From: Mauro Carvalho Chehab @ 2014-03-12 10:40 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: linux-media, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	sakari.ailus, Hans Verkuil

Em Mon, 17 Feb 2014 10:57:28 +0100
Hans Verkuil <hverkuil@xs4all.nl> escreveu:

> From: Hans Verkuil <hans.verkuil@cisco.com>
> 
> Require that 'new' string and pointer values are accessed through the 'new'
> field instead of through the union. This reduces the union to just val and
> val64.
> 
> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
> Reviewed-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
> ---
>  drivers/media/radio/si4713/si4713.c                | 4 ++--
>  drivers/media/v4l2-core/v4l2-ctrls.c               | 4 ++--
>  drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c | 2 +-
>  include/media/v4l2-ctrls.h                         | 2 --
>  4 files changed, 5 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/media/radio/si4713/si4713.c b/drivers/media/radio/si4713/si4713.c
> index 07d5153..718e10d 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->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->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 084335a..49ce52e 100644
> --- a/drivers/media/v4l2-core/v4l2-ctrls.c
> +++ b/drivers/media/v4l2-core/v4l2-ctrls.c
> @@ -1820,8 +1820,8 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
>  	data = &ctrl->stores[1];
>  
>  	if (ctrl->is_ptr) {
> -		ctrl->p = ctrl->new.p = data;
> -		ctrl->stores[0].p = data + elem_size;
> +		for (s = -1; s <= 0; s++)
> +			ctrl->stores[s].p = data + (s + 1) * elem_size;

NACK! Don't use negative values for arrays.

>  	} else {
>  		ctrl->new.p = &ctrl->val;
>  		ctrl->stores[0].p = data;
> diff --git a/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c b/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
> index ce9e5aa..d19743b 100644
> --- a/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
> +++ b/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
> @@ -1127,7 +1127,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->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 4f66393..1b06930 100644
> --- a/include/media/v4l2-ctrls.h
> +++ b/include/media/v4l2-ctrls.h
> @@ -195,8 +195,6 @@ struct v4l2_ctrl {
>  	union {
>  		s32 val;
>  		s64 val64;
> -		char *string;
> -		void *p;
>  	};
>  	union v4l2_ctrl_ptr *stores;
>  	union v4l2_ctrl_ptr new;


-- 

Regards,
Mauro

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

* Re: [REVIEWv3 PATCH 14/35] v4l2-ctrls: prepare for matrix support.
  2014-02-17  9:57 ` [REVIEWv3 PATCH 14/35] v4l2-ctrls: prepare for matrix support Hans Verkuil
@ 2014-03-12 10:42   ` Mauro Carvalho Chehab
  2014-03-12 12:21     ` Hans Verkuil
  0 siblings, 1 reply; 66+ messages in thread
From: Mauro Carvalho Chehab @ 2014-03-12 10:42 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: linux-media, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	sakari.ailus, Hans Verkuil

Em Mon, 17 Feb 2014 10:57:29 +0100
Hans Verkuil <hverkuil@xs4all.nl> escreveu:

> From: Hans Verkuil <hans.verkuil@cisco.com>
> 
> Add core support for matrices.

Again, this patch has negative values for array index.

I'll stop analyzing here, as it is hard to keep the mind in a
sane state seeing those crazy things ;)

> 
> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
> ---
>  drivers/media/v4l2-core/v4l2-ctrls.c | 54 +++++++++++++++++++++++-------------
>  include/media/v4l2-ctrls.h           |  8 ++++--
>  2 files changed, 39 insertions(+), 23 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
> index 49ce52e..f76716e 100644
> --- a/drivers/media/v4l2-core/v4l2-ctrls.c
> +++ b/drivers/media/v4l2-core/v4l2-ctrls.c
> @@ -1132,7 +1132,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)
>  {
> @@ -1151,7 +1151,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) {
> @@ -1178,6 +1178,9 @@ static void std_log(const struct v4l2_ctrl *ctrl)
>  {
>  	union v4l2_ctrl_ptr ptr = ctrl->stores[0];
>  
> +	if (ctrl->is_matrix)
> +		pr_cont("[%u][%u] ", ctrl->rows, ctrl->cols);
> +
>  	switch (ctrl->type) {
>  	case V4L2_CTRL_TYPE_INTEGER:
>  		pr_cont("%d", *ptr.p_s32);
> @@ -1220,7 +1223,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;
> @@ -1444,7 +1447,7 @@ static int cluster_changed(struct v4l2_ctrl *master)
>  
>  		if (ctrl == NULL)
>  			continue;
> -		ctrl->has_changed = !ctrl->type_ops->equal(ctrl,
> +		ctrl->has_changed = !ctrl->type_ops->equal(ctrl, 0,
>  						ctrl->stores[0], ctrl->new);
>  		changed |= ctrl->has_changed;
>  	}
> @@ -1502,15 +1505,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->p;
> -		return ctrl->type_ops->validate(ctrl, ptr);
> +		return ctrl->type_ops->validate(ctrl, 0, ptr);
>  	}
>  }
>  
> @@ -1736,7 +1739,8 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
>  			const s64 *qmenu_int, void *priv)
>  {
>  	struct v4l2_ctrl *ctrl;
> -	unsigned sz_extra;
> +	bool is_matrix;
> +	unsigned sz_extra, tot_ctrl_size;
>  	void *data;
>  	int err;
>  	int s;
> @@ -1748,6 +1752,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
>  		cols = 1;
>  	if (rows == 0)
>  		rows = 1;
> +	is_matrix = cols > 1 || rows > 1;
>  
>  	if (type == V4L2_CTRL_TYPE_INTEGER64)
>  		elem_size = sizeof(s64);
> @@ -1755,17 +1760,18 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
>  		elem_size = max + 1;
>  	else if (type < V4L2_CTRL_COMPLEX_TYPES)
>  		elem_size = sizeof(s32);
> +	tot_ctrl_size = elem_size * cols * rows;
>  
>  	/* 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);
>  		return NULL;
>  	}
>  	/* Complex controls are always hidden */
> -	if (type >= V4L2_CTRL_COMPLEX_TYPES)
> +	if (is_matrix || type >= V4L2_CTRL_COMPLEX_TYPES)
>  		flags |= V4L2_CTRL_FLAG_HIDDEN;
>  	err = check_range(type, min, max, step, def);
>  	if (err) {
> @@ -1776,14 +1782,21 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
>  		handler_set_err(hdl, -ERANGE);
>  		return NULL;
>  	}
> +	if (is_matrix &&
> +	    (type == V4L2_CTRL_TYPE_BUTTON ||
> +	     type == V4L2_CTRL_TYPE_CTRL_CLASS)) {
> +		handler_set_err(hdl, -EINVAL);
> +		return NULL;
> +	}
>  
> -	sz_extra = elem_size;
> +	sz_extra = tot_ctrl_size;
>  	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 || type >= V4L2_CTRL_COMPLEX_TYPES)
> -		sz_extra += elem_size;
> +	else if (type == V4L2_CTRL_TYPE_STRING ||
> +		 type >= V4L2_CTRL_COMPLEX_TYPES || is_matrix)
> +		sz_extra += tot_ctrl_size;
>  
>  	ctrl = kzalloc(sizeof(*ctrl) + sz_extra, GFP_KERNEL);
>  	if (ctrl == NULL) {
> @@ -1805,9 +1818,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_COMPLEX_TYPES || ctrl->is_string;
> +	ctrl->is_string = !is_matrix && type == V4L2_CTRL_TYPE_STRING;
> +	ctrl->is_ptr = is_matrix || type >= V4L2_CTRL_COMPLEX_TYPES || ctrl->is_string;
>  	ctrl->is_int = !ctrl->is_ptr && type != V4L2_CTRL_TYPE_INTEGER64;
> +	ctrl->is_matrix = is_matrix;
>  	ctrl->cols = cols;
>  	ctrl->rows = rows;
>  	ctrl->elem_size = elem_size;
> @@ -1821,13 +1835,13 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
>  
>  	if (ctrl->is_ptr) {
>  		for (s = -1; s <= 0; s++)
> -			ctrl->stores[s].p = data + (s + 1) * elem_size;
> +			ctrl->stores[s].p = data + (s + 1) * tot_ctrl_size;
>  	} else {
>  		ctrl->new.p = &ctrl->val;
>  		ctrl->stores[0].p = data;
>  	}
>  	for (s = -1; s <= 0; s++)
> -		ctrl->type_ops->init(ctrl, ctrl->stores[s]);
> +		ctrl->type_ops->init(ctrl, 0, ctrl->stores[s]);
>  
>  	if (handler_new_ref(hdl, ctrl)) {
>  		kfree(ctrl);
> @@ -2734,7 +2748,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;
> @@ -3044,7 +3058,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 1b06930..7d72328 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 a matrix and/or has type >= V4L2_CTRL_COMPLEX_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_matrix: If set, then this control contains a matrix.
>    * @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_matrix:1;
>  	unsigned int has_volatiles:1;
>  	unsigned int call_notify:1;
>  	unsigned int manual_mode_value:8;


-- 

Regards,
Mauro

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

* Re: [REVIEWv3 PATCH 14/35] v4l2-ctrls: prepare for matrix support.
  2014-03-12 10:42   ` Mauro Carvalho Chehab
@ 2014-03-12 12:21     ` Hans Verkuil
  2014-03-12 13:00       ` Mauro Carvalho Chehab
  2014-03-12 13:00       ` Mauro Carvalho Chehab
  0 siblings, 2 replies; 66+ messages in thread
From: Hans Verkuil @ 2014-03-12 12:21 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: linux-media, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	sakari.ailus, Hans Verkuil

On 03/12/14 11:42, Mauro Carvalho Chehab wrote:
> Em Mon, 17 Feb 2014 10:57:29 +0100
> Hans Verkuil <hverkuil@xs4all.nl> escreveu:
> 
>> From: Hans Verkuil <hans.verkuil@cisco.com>
>>
>> Add core support for matrices.
> 
> Again, this patch has negative values for array index.
> 
> I'll stop analyzing here, as it is hard to keep the mind in a
> sane state seeing those crazy things ;)

Rather than getting bogged down in these details can you please give
your opinion on the public API aspects. There is no point for me to
spend time on this and then get it NACKed because you don't like the
API itself and want something completely different.

Internal things I can change, but I'm not going to spend a second on
that unless I know the concept stands. Otherwise it is wasted time.

This is something we need to improve on with regards to our
processes: when it comes to API enhancements you really need to be
involved earlier or it's going to be a huge waste of everyones time
it is gets NACked. Not to mention demotivating and frustrating for
all concerned.

Regards,

	Hans

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

* Re: [REVIEWv3 PATCH 14/35] v4l2-ctrls: prepare for matrix support.
  2014-03-12 12:21     ` Hans Verkuil
@ 2014-03-12 13:00       ` Mauro Carvalho Chehab
  2014-03-12 13:00       ` Mauro Carvalho Chehab
  1 sibling, 0 replies; 66+ messages in thread
From: Mauro Carvalho Chehab @ 2014-03-12 13:00 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: linux-media, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	sakari.ailus, Hans Verkuil

Em Wed, 12 Mar 2014 13:21:41 +0100
Hans Verkuil <hverkuil@xs4all.nl> escreveu:

> On 03/12/14 11:42, Mauro Carvalho Chehab wrote:
> > Em Mon, 17 Feb 2014 10:57:29 +0100
> > Hans Verkuil <hverkuil@xs4all.nl> escreveu:
> > 
> >> From: Hans Verkuil <hans.verkuil@cisco.com>
> >>
> >> Add core support for matrices.
> > 
> > Again, this patch has negative values for array index.
> > 
> > I'll stop analyzing here, as it is hard to keep the mind in a
> > sane state seeing those crazy things ;)
> 
> Rather than getting bogged down in these details can you please give
> your opinion on the public API aspects. There is no point for me to
> spend time on this and then get it NACKed because you don't like the
> API itself and want something completely different.
> 
> Internal things I can change, but I'm not going to spend a second on
> that unless I know the concept stands. Otherwise it is wasted time.

Ok, what patches after 16/35 contains the API bits?

The changes I saw so far seem ok, with the adjustments I pointed.

> This is something we need to improve on with regards to our
> processes: when it comes to API enhancements you really need to be
> involved earlier or it's going to be a huge waste of everyones time
> it is gets NACked. Not to mention demotivating and frustrating for
> all concerned.

As I commented before: those complex API changes should ideally
be discussed during our mini-summits, as it allows us to better
understand the hole proposal.

-- 

Regards,
Mauro

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

* Re: [REVIEWv3 PATCH 14/35] v4l2-ctrls: prepare for matrix support.
  2014-03-12 12:21     ` Hans Verkuil
  2014-03-12 13:00       ` Mauro Carvalho Chehab
@ 2014-03-12 13:00       ` Mauro Carvalho Chehab
  2014-03-12 13:41         ` Hans Verkuil
  2014-03-12 13:44         ` Sylwester Nawrocki
  1 sibling, 2 replies; 66+ messages in thread
From: Mauro Carvalho Chehab @ 2014-03-12 13:00 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: linux-media, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	sakari.ailus, Hans Verkuil

Em Wed, 12 Mar 2014 13:21:41 +0100
Hans Verkuil <hverkuil@xs4all.nl> escreveu:

> On 03/12/14 11:42, Mauro Carvalho Chehab wrote:
> > Em Mon, 17 Feb 2014 10:57:29 +0100
> > Hans Verkuil <hverkuil@xs4all.nl> escreveu:
> > 
> >> From: Hans Verkuil <hans.verkuil@cisco.com>
> >>
> >> Add core support for matrices.
> > 
> > Again, this patch has negative values for array index.
> > 
> > I'll stop analyzing here, as it is hard to keep the mind in a
> > sane state seeing those crazy things ;)
> 
> Rather than getting bogged down in these details can you please give
> your opinion on the public API aspects. There is no point for me to
> spend time on this and then get it NACKed because you don't like the
> API itself and want something completely different.
> 
> Internal things I can change, but I'm not going to spend a second on
> that unless I know the concept stands. Otherwise it is wasted time.

Ok, what patches after 16/35 contains the API bits?

The changes I saw so far seem ok, with the adjustments I pointed.

> This is something we need to improve on with regards to our
> processes: when it comes to API enhancements you really need to be
> involved earlier or it's going to be a huge waste of everyones time
> it is gets NACked. Not to mention demotivating and frustrating for
> all concerned.

As I commented before: those complex API changes should ideally
be discussed during our mini-summits, as it allows us to better
understand the hole proposal and the taken approach.

-- 

Regards,
Mauro

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

* Re: [REVIEWv3 PATCH 14/35] v4l2-ctrls: prepare for matrix support.
  2014-03-12 13:00       ` Mauro Carvalho Chehab
@ 2014-03-12 13:41         ` Hans Verkuil
  2014-03-12 13:44         ` Sylwester Nawrocki
  1 sibling, 0 replies; 66+ messages in thread
From: Hans Verkuil @ 2014-03-12 13:41 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: linux-media, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	sakari.ailus, Hans Verkuil

On 03/12/2014 02:00 PM, Mauro Carvalho Chehab wrote:
> Em Wed, 12 Mar 2014 13:21:41 +0100
> Hans Verkuil <hverkuil@xs4all.nl> escreveu:
> 
>> On 03/12/14 11:42, Mauro Carvalho Chehab wrote:
>>> Em Mon, 17 Feb 2014 10:57:29 +0100
>>> Hans Verkuil <hverkuil@xs4all.nl> escreveu:
>>>
>>>> From: Hans Verkuil <hans.verkuil@cisco.com>
>>>>
>>>> Add core support for matrices.
>>>
>>> Again, this patch has negative values for array index.
>>>
>>> I'll stop analyzing here, as it is hard to keep the mind in a
>>> sane state seeing those crazy things ;)
>>
>> Rather than getting bogged down in these details can you please give
>> your opinion on the public API aspects. There is no point for me to
>> spend time on this and then get it NACKed because you don't like the
>> API itself and want something completely different.
>>
>> Internal things I can change, but I'm not going to spend a second on
>> that unless I know the concept stands. Otherwise it is wasted time.
> 
> Ok, what patches after 16/35 contains the API bits?

Core control functionality: 4, 5, 19-22.

Adding support for the motion detection matrices: 24, 25, 27, 28.

Adding support for the motion detection event: 29, 30.

Sorry for sounding so irritated in my email: today is one of those
frustrating days where nothing works out the way you want it and
where I should have stayed in bed in the morning, and that spilled
over in my mail.

Regards,

	Hans

> 
> The changes I saw so far seem ok, with the adjustments I pointed.
> 
>> This is something we need to improve on with regards to our
>> processes: when it comes to API enhancements you really need to be
>> involved earlier or it's going to be a huge waste of everyones time
>> it is gets NACked. Not to mention demotivating and frustrating for
>> all concerned.
> 
> As I commented before: those complex API changes should ideally
> be discussed during our mini-summits, as it allows us to better
> understand the hole proposal and the taken approach.
> 


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

* Re: [REVIEWv3 PATCH 14/35] v4l2-ctrls: prepare for matrix support.
  2014-03-12 13:00       ` Mauro Carvalho Chehab
  2014-03-12 13:41         ` Hans Verkuil
@ 2014-03-12 13:44         ` Sylwester Nawrocki
  1 sibling, 0 replies; 66+ messages in thread
From: Sylwester Nawrocki @ 2014-03-12 13:44 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Hans Verkuil
  Cc: linux-media, laurent.pinchart, ismael.luceno, pete, sakari.ailus,
	Hans Verkuil

Hi Mauro,

On 12/03/14 14:00, Mauro Carvalho Chehab wrote:
[...]
> As I commented before: those complex API changes should ideally
> be discussed during our mini-summits, as it allows us to better
> understand the hole proposal and the taken approach.

We discussed this in a dedicated brainstorming meeting in Edinburgh,
with Sakari, Laurent, Andrzej. IIRC you didn't take part in that
discussions for some reason.
After we initially agreed on the API Hans started working on the
actual implementation. He put much effort and did a pretty good
job IMO. I guess we just need to refine any controversial aspects
that might be there and move forward with the API. :)

--
Regards,
Sylwester

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

* Re: [REVIEWv3 PATCH 19/35] DocBook media: document VIDIOC_QUERY_EXT_CTRL.
  2014-02-17  9:57 ` [REVIEWv3 PATCH 19/35] DocBook media: document VIDIOC_QUERY_EXT_CTRL Hans Verkuil
@ 2014-03-12 14:13   ` Mauro Carvalho Chehab
  2014-03-13  7:58     ` Hans Verkuil
  0 siblings, 1 reply; 66+ messages in thread
From: Mauro Carvalho Chehab @ 2014-03-12 14:13 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: linux-media, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	sakari.ailus, Hans Verkuil

Em Mon, 17 Feb 2014 10:57:34 +0100
Hans Verkuil <hverkuil@xs4all.nl> escreveu:

> From: Hans Verkuil <hans.verkuil@cisco.com>
> 
> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
> Reviewed-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
> ---
>  .../DocBook/media/v4l/vidioc-queryctrl.xml         | 223 +++++++++++++++++----
>  1 file changed, 189 insertions(+), 34 deletions(-)
> 
> diff --git a/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml b/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml
> index e6645b9..da0e534 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>
> @@ -91,7 +100,26 @@ prematurely end the enumeration).</para></footnote></para>
>  <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>
> +<errorcode>EINVAL</errorcode>. Hidden controls (i.e. controls
> +with the <constant>V4L2_CTRL_FLAG_HIDDEN</constant> flag set) are
> +skipped when using the <constant>V4L2_CTRL_FLAG_NEXT_CTRL</constant>
> +flag. Use the <constant>VIDIOC_QUERY_EXT_CTRL</constant> for that.</para>

I suspect that most of the things (if not all) here already commented
on the initial patches)

In this case, as already commented, I don't see any reason why
to deny VIDIOC_QUERYCTRL to get the hidden controls if V4L2_CTRL_FLAG_HIDDEN
is used.

> +
> +    <para>The <constant>VIDIOC_QUERY_EXT_CTRL</constant> ioctl was
> +introduced in order to better support controls that can use complex
> +types, and to expose additional control information that cannot be
> +returned in &v4l2-queryctrl; since that structure is full.</para>

s/complex/compound/g

> +
> +    <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.
> +In addition, the <constant>V4L2_CTRL_FLAG_NEXT_HIDDEN</constant> flag
> +can be specified to enumerate all hidden controls (i.e. controls
> +with the <constant>V4L2_CTRL_FLAG_HIDDEN</constant> flag set, which
> +includes all controls with complex types). Specify both
> +<constant>V4L2_CTRL_FLAG_NEXT_CTRL</constant> and
> +<constant>V4L2_CTRL_FLAG_NEXT_HIDDEN</constant> in order to enumerate
> +all controls, hidden or not.</para>
>  
>      <para>Additional information is required for menu controls: the
>  names of the menu items. To query them applications set the
> @@ -142,38 +170,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 +205,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 +227,129 @@ 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-hidden control with a higher ID. When the
> +ID is ORed with <constant>V4L2_CTRL_FLAG_NEXT_HIDDEN</constant> the driver
> +clears the flag and returns the first hidden control with a higher ID.
> +Set both to get the first control (hidden 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>char</entry>
> +	    <entry><structfield>unit</structfield>[32]</entry>
> +	    <entry>The name of the unit of the control's value, a NUL-terminated ASCII
> +string. This information is intended for the user. This may be an empty string if no
> +unit is known or if it is not applicable to this particular control.</entry>

Charset? There are some units, like  ångström (Å) that are not ASCII.
Also, there are several units that use greek letters. So, I think we need
to specify a charset here. IMHO, the better is to use UTF-8.

> +	  </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>cols</structfield></entry>
> +	    <entry>The number of columns in the matrix. If this control
> +is not a matrix, then both <structfield>cols</structfield> and
> +<structfield>rows</structfield> are 1. <structfield>cols</structfield>
> +can never be 0.</entry>
> +	  </row>
> +	  <row>
> +	    <entry>__u32</entry>
> +	    <entry><structfield>rows</structfield></entry>
> +	    <entry>The number of rows in the matrix. If this control
> +is not a matrix, then both <structfield>cols</structfield> and
> +<structfield>rows</structfield> are 1. <structfield>rows</structfield>
> +can never be 0.</entry>
> +	  </row>

As already commented, cols/rows are matrix specific. If the control type 
is not a matrix, those makes no sense.

> +	  <row>
> +	    <entry>__u32</entry>
> +	    <entry><structfield>elem_size</structfield></entry>
> +	    <entry>The size in bytes of a single element of the matrix.
> +Given a char pointer <constant>p</constant> to the matrix you can find the
> +position of cell <constant>(y, x)</constant> as follows:
> +<constant>p + (y * cols + x) * elem_size</constant>. <structfield>elem_size</structfield>
> +is always valid, also when the control isn't a matrix. For string controls
> +<structfield>elem_size</structfield> is equal to <structfield>maximum + 1</structfield>.
> +</entry>
> +	  </row>
> +	  <row>
> +	    <entry>__u32</entry>
> +	    <entry><structfield>reserved</structfield>[17]</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 +484,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 +590,21 @@ 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_HIDDEN</constant></entry>
> +	    <entry>0x0100</entry>
> +	    <entry>This control is hidden and should not be shown in a GUI application.
> +Hidden controls are skipped when enumerating them using <constant>V4L2_CTRL_FLAG_NEXT_CTRL</constant>,
> +and they can only be enumerated by using the <constant>V4L2_CTRL_FLAG_NEXT_HIDDEN</constant>
> +flag. All controls that have a complex type have this flag set.</entry>
> +	  </row>
> +	  <row>
> +	    <entry><constant>V4L2_CTRL_FLAG_IS_PTR</constant></entry>
> +	    <entry>0x0200</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 a matrix, string, or have a complex type.</entry>

This seems messy: use IS_PTR for string too. As already pointed, string
is a NUL-terminated sequence, while pointer is a size defined
element, sequence or matrix. Let's not mix this at the API. This is already
complex enough.

> +	  </row>
>  	</tbody>
>        </tgroup>
>      </table>


-- 

Regards,
Mauro

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

* Re: [REVIEWv3 PATCH 20/35] DocBook media: update VIDIOC_G/S/TRY_EXT_CTRLS.
  2014-02-17  9:57 ` [REVIEWv3 PATCH 20/35] DocBook media: update VIDIOC_G/S/TRY_EXT_CTRLS Hans Verkuil
@ 2014-03-12 14:20   ` Mauro Carvalho Chehab
  2014-03-13 12:18     ` Hans Verkuil
  0 siblings, 1 reply; 66+ messages in thread
From: Mauro Carvalho Chehab @ 2014-03-12 14:20 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: linux-media, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	sakari.ailus, Hans Verkuil

Em Mon, 17 Feb 2014 10:57:35 +0100
Hans Verkuil <hverkuil@xs4all.nl> escreveu:

> From: Hans Verkuil <hans.verkuil@cisco.com>
> 
> Document the support for the new complex type controls.
> 
> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
> ---
>  .../DocBook/media/v4l/vidioc-g-ext-ctrls.xml       | 43 ++++++++++++++++++----
>  1 file changed, 35 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 b3bb957..d946d6b 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 complex types (<constant>V4L2_CTRL_FLAG_IS_PTR</constant> is set)
> +must set the <structfield>p</structfield> field.</para>

Same notes I did to the other patches apply here:
	- s/complex/compound/
	- Let's not mix strings with compound types
	- etc

>      <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>Matrices are set and retrieved row-by-row. You cannot set a partial
> +matrix, all elements have to be set or retrieved. The total size is calculated
> +as <structfield>rows</structfield> * <structfield>cols</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/p</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,11 +103,17 @@ 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/p</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>
>  
> +    <para>For matrices it is possible to only set or check only the first
> +<constant>X</constant> elements by setting size to <constant>X * elem_size</constant>,
> +where <structfield>elem_size</structfield> is obtained by calling &VIDIOC-QUERY-EXT-CTRL;.
> +Matrix elements are set row-by-row. Matrix elements that are not explicitly
> +set will be initialized to their default value.</para>
> +

That sounds confusing: what are the defaults?

Also, what happens if the size is set to, let's say, 1,5 * elem_size?

Will it fill one element, will it return an error (what error?) or will it
fill two elements, the second one with some wrong value?

>      <para>When the <structfield>id</structfield> or
>  <structfield>ctrl_class</structfield> is invalid drivers return an
>  &EINVAL;. When the value is out of bounds drivers can choose to take
> @@ -158,19 +171,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_IS_PTR</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_IS_PTR</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>p</structfield></entry>
> +	    <entry>A pointer to a complex type which can be a matrix and/or a
> +complex type (the control's type is >= <constant>V4L2_CTRL_COMPLEX_TYPES</constant>).
> +Valid if <constant>V4L2_CTRL_FLAG_IS_PTR</constant> is set for this control.
> +</entry>
>  	  </row>
>  	</tbody>
>        </tgroup>


-- 

Regards,
Mauro

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

* Re: [REVIEWv3 PATCH 22/35] DocBook media: update control section.
  2014-02-17  9:57 ` [REVIEWv3 PATCH 22/35] DocBook media: update control section Hans Verkuil
  2014-02-19 23:15   ` Sakari Ailus
@ 2014-03-12 14:27   ` Mauro Carvalho Chehab
  1 sibling, 0 replies; 66+ messages in thread
From: Mauro Carvalho Chehab @ 2014-03-12 14:27 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: linux-media, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	sakari.ailus, Hans Verkuil

Em Mon, 17 Feb 2014 10:57:37 +0100
Hans Verkuil <hverkuil@xs4all.nl> escreveu:

> From: Hans Verkuil <hans.verkuil@cisco.com>
> 
> Document the support for complex 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 | 104 ++++++++++++++++++++-------
>  1 file changed, 78 insertions(+), 26 deletions(-)
> 
> diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml
> index ef55c3e..85d78d4 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

Hmm... &eg; above seems weird (ok, this is not part of your changes, but
do you care take a look on the above line?)

>  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>
> @@ -624,16 +660,32 @@ 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 complex types such as arrays/matrices

s/complex/compound/g

> +and/or structures. All such complex controls will have the
> +<constant>V4L2_CTRL_FLAG_HIDDEN</constant> set since such controls cannot
> +be displayed in control panel applications. Nor can they be used in the
> +user class (for backwards compatibility reasons), and you need to specify
> +the <constant>V4L2_CTRL_FLAG_NEXT_HIDDEN</constant> when enumerating controls
> +to actually be able to see such hidden controls. In other words, these
> +controls with complex types should only be used programmatically.</para>
> +
> +      <para>Since such complex 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 size of the matrix 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.
> @@ -699,7 +751,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>
>  


-- 

Regards,
Mauro

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

* Re: [REVIEWv3 PATCH 24/35] v4l2-ctrls/videodev2.h: add u8 and u16 types.
  2014-02-17  9:57 ` [REVIEWv3 PATCH 24/35] v4l2-ctrls/videodev2.h: add u8 and u16 types Hans Verkuil
@ 2014-03-12 14:44   ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 66+ messages in thread
From: Mauro Carvalho Chehab @ 2014-03-12 14:44 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: linux-media, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	sakari.ailus, Hans Verkuil

Em Mon, 17 Feb 2014 10:57:39 +0100
Hans Verkuil <hverkuil@xs4all.nl> escreveu:

> 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 1886b79..ca4271b 100644
> --- a/drivers/media/v4l2-core/v4l2-ctrls.c
> +++ b/drivers/media/v4l2-core/v4l2-ctrls.c
> @@ -1145,6 +1145,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];

Please replace V4L2_CTRL_TYPE_INTEGER64 and V4L2_CTRL_TYPE_INTEGER to
V4L2_CTRL_TYPE_S64 and V4L2_CTRL_TYPE_S32 and add an alias for those previous
names at videodev2.h:

#define V4L2_CTRL_TYPE_INTEGER64	V4L2_CTRL_TYPE_S64
#define V4L2_CTRL_TYPE_INTEGER		V4L2_CTRL_TYPE_S32

Please notice that there's no reason at all to deprecate the old names,
so we'll keep the above defines forever.

Yet, now that we're using U<bitsize> for some types, let's standardize this to
the other types too, as it makes the API more consistent.

Also, I won't doubt that we'll eventually need S8, S16, U32, U64 types in
the future.

>  	default:
>  		if (ctrl->is_int)
>  			return ptr1.p_s32[idx] == ptr2.p_s32[idx];
> @@ -1172,6 +1176,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);
> @@ -1208,6 +1218,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;
> @@ -1238,6 +1254,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];
> @@ -1470,6 +1490,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)
> @@ -1768,12 +1790,25 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
>  		rows = 1;
>  	is_matrix = cols > 1 || rows > 1;
>  
> -	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_COMPLEX_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_COMPLEX_TYPES)
> +			elem_size = sizeof(s32);
> +		break;
> +	}
>  	tot_ctrl_size = elem_size * cols * rows;
>  
>  	/* Sanity checks */
> @@ -3114,6 +3149,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_matrix)
>  			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 7d72328..2ccad5f 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 complex 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 858a6f3..8b70f51 100644
> --- a/include/uapi/linux/videodev2.h
> +++ b/include/uapi/linux/videodev2.h
> @@ -1228,6 +1228,8 @@ struct v4l2_ext_control {
>  		__s32 value;
>  		__s64 value64;
>  		char *string;
> +		__u8 *p_u8;
> +		__u16 *p_u16;
>  		void *p;
>  	};
>  } __attribute__ ((packed));
> @@ -1257,6 +1259,8 @@ enum v4l2_ctrl_type {
>  
>  	/* Complex types are >= 0x0100 */
>  	V4L2_CTRL_COMPLEX_TYPES	     = 0x0100,
> +	V4L2_CTRL_TYPE_U8	     = 0x0100,
> +	V4L2_CTRL_TYPE_U16	     = 0x0101,

Huh? Why are those two compound types?

If all you want is to have a "matrix" set of types, IMO, the
best would be to do, instead

enum v4l2_ctrl_type {
	/* Basic types */
	V4L2_CTRL_TYPE_S32	     = 1,
	V4L2_CTRL_TYPE_BOOLEAN	     = 2,
	V4L2_CTRL_TYPE_MENU	     = 3,
	V4L2_CTRL_TYPE_BUTTON	     = 4,
	V4L2_CTRL_TYPE_S64           = 5,
	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_U8	     = 10,
	V4L2_CTRL_TYPE_U16	     = 11,

	/* Modifiers */
	V4L2_CTRL_TYPE_MATRIX	     = 0x100
};

That way, a matrix of S32 would have type = V4L2_CTRL_TYPE_S32 | V4L2_CTRL_TYPE_MATRIX.

A matrix of U16 would be V4L2_CTRL_TYPE_U16 | V4L2_CTRL_TYPE_MATRIX, and so on.


>  };
>  
>  /*  Used in the VIDIOC_QUERYCTRL ioctl for querying controls */


-- 

Regards,
Mauro

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

* Re: [REVIEWv3 PATCH 19/35] DocBook media: document VIDIOC_QUERY_EXT_CTRL.
  2014-03-12 14:13   ` Mauro Carvalho Chehab
@ 2014-03-13  7:58     ` Hans Verkuil
  0 siblings, 0 replies; 66+ messages in thread
From: Hans Verkuil @ 2014-03-13  7:58 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: linux-media, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	sakari.ailus, Hans Verkuil

On 03/12/2014 03:13 PM, Mauro Carvalho Chehab wrote:
> Em Mon, 17 Feb 2014 10:57:34 +0100
> Hans Verkuil <hverkuil@xs4all.nl> escreveu:
> 
>> From: Hans Verkuil <hans.verkuil@cisco.com>
>>
>> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
>> Reviewed-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
>> ---
>>  .../DocBook/media/v4l/vidioc-queryctrl.xml         | 223 +++++++++++++++++----
>>  1 file changed, 189 insertions(+), 34 deletions(-)
>>
>> diff --git a/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml b/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml
>> index e6645b9..da0e534 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>
>> @@ -91,7 +100,26 @@ prematurely end the enumeration).</para></footnote></para>
>>  <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>
>> +<errorcode>EINVAL</errorcode>. Hidden controls (i.e. controls
>> +with the <constant>V4L2_CTRL_FLAG_HIDDEN</constant> flag set) are
>> +skipped when using the <constant>V4L2_CTRL_FLAG_NEXT_CTRL</constant>
>> +flag. Use the <constant>VIDIOC_QUERY_EXT_CTRL</constant> for that.</para>
> 
> I suspect that most of the things (if not all) here already commented
> on the initial patches)
> 
> In this case, as already commented, I don't see any reason why
> to deny VIDIOC_QUERYCTRL to get the hidden controls if V4L2_CTRL_FLAG_HIDDEN
> is used.
> 
>> +
>> +    <para>The <constant>VIDIOC_QUERY_EXT_CTRL</constant> ioctl was
>> +introduced in order to better support controls that can use complex
>> +types, and to expose additional control information that cannot be
>> +returned in &v4l2-queryctrl; since that structure is full.</para>
> 
> s/complex/compound/g
> 
>> +
>> +    <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.
>> +In addition, the <constant>V4L2_CTRL_FLAG_NEXT_HIDDEN</constant> flag
>> +can be specified to enumerate all hidden controls (i.e. controls
>> +with the <constant>V4L2_CTRL_FLAG_HIDDEN</constant> flag set, which
>> +includes all controls with complex types). Specify both
>> +<constant>V4L2_CTRL_FLAG_NEXT_CTRL</constant> and
>> +<constant>V4L2_CTRL_FLAG_NEXT_HIDDEN</constant> in order to enumerate
>> +all controls, hidden or not.</para>
>>  
>>      <para>Additional information is required for menu controls: the
>>  names of the menu items. To query them applications set the
>> @@ -142,38 +170,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 +205,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 +227,129 @@ 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-hidden control with a higher ID. When the
>> +ID is ORed with <constant>V4L2_CTRL_FLAG_NEXT_HIDDEN</constant> the driver
>> +clears the flag and returns the first hidden control with a higher ID.
>> +Set both to get the first control (hidden 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>

This is something I should point your attention to: the type of name[] has changed
from u8 in v4l2_queryctrl to char here. The use of u8 in v4l2_queryctrl always
causes problems (e.g. you can't assign it directly to a std::string in C++ since
that expects a char *). I never understood why u8 was ever chosen in the first
place. But is this something you agree with?

>> +	  <row>
>> +	    <entry>char</entry>
>> +	    <entry><structfield>unit</structfield>[32]</entry>
>> +	    <entry>The name of the unit of the control's value, a NUL-terminated ASCII
>> +string. This information is intended for the user. This may be an empty string if no
>> +unit is known or if it is not applicable to this particular control.</entry>
> 
> Charset? There are some units, like  ångström (Å) that are not ASCII.
> Also, there are several units that use greek letters. So, I think we need
> to specify a charset here. IMHO, the better is to use UTF-8.

I agree. Should I specify the same for name[] in both this struct and in v4l2_queryctrl?

> 
>> +	  </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>cols</structfield></entry>
>> +	    <entry>The number of columns in the matrix. If this control
>> +is not a matrix, then both <structfield>cols</structfield> and
>> +<structfield>rows</structfield> are 1. <structfield>cols</structfield>
>> +can never be 0.</entry>
>> +	  </row>
>> +	  <row>
>> +	    <entry>__u32</entry>
>> +	    <entry><structfield>rows</structfield></entry>
>> +	    <entry>The number of rows in the matrix. If this control
>> +is not a matrix, then both <structfield>cols</structfield> and
>> +<structfield>rows</structfield> are 1. <structfield>rows</structfield>
>> +can never be 0.</entry>
>> +	  </row>
> 
> As already commented, cols/rows are matrix specific. If the control type 
> is not a matrix, those makes no sense.
> 
>> +	  <row>
>> +	    <entry>__u32</entry>
>> +	    <entry><structfield>elem_size</structfield></entry>
>> +	    <entry>The size in bytes of a single element of the matrix.
>> +Given a char pointer <constant>p</constant> to the matrix you can find the
>> +position of cell <constant>(y, x)</constant> as follows:
>> +<constant>p + (y * cols + x) * elem_size</constant>. <structfield>elem_size</structfield>
>> +is always valid, also when the control isn't a matrix. For string controls
>> +<structfield>elem_size</structfield> is equal to <structfield>maximum + 1</structfield>.
>> +</entry>
>> +	  </row>
>> +	  <row>
>> +	    <entry>__u32</entry>
>> +	    <entry><structfield>reserved</structfield>[17]</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 +484,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 +590,21 @@ 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_HIDDEN</constant></entry>
>> +	    <entry>0x0100</entry>
>> +	    <entry>This control is hidden and should not be shown in a GUI application.
>> +Hidden controls are skipped when enumerating them using <constant>V4L2_CTRL_FLAG_NEXT_CTRL</constant>,
>> +and they can only be enumerated by using the <constant>V4L2_CTRL_FLAG_NEXT_HIDDEN</constant>
>> +flag. All controls that have a complex type have this flag set.</entry>
>> +	  </row>
>> +	  <row>
>> +	    <entry><constant>V4L2_CTRL_FLAG_IS_PTR</constant></entry>
>> +	    <entry>0x0200</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 a matrix, string, or have a complex type.</entry>
> 
> This seems messy: use IS_PTR for string too. As already pointed, string
> is a NUL-terminated sequence, while pointer is a size defined
> element, sequence or matrix. Let's not mix this at the API. This is already
> complex enough.

How about this: HAS_PAYLOAD? What I discovered when trying to use the API in an application
is that you need a simple way to discover if the type is a simple s32 or s64 type which is
just set as part of v4l2_ext_control, or if it is a more complicated type where you need to
use the size field and allocate memory to store the value. In the past that was a simple
'type == STRING' test, but that does not suffice anymore. And in order to be able to do
generic control manipulation you do not want to have to test for all sorts of types or
create complicated conditions.

I found that a simple flag actually made life much easier.

Regards,

	Hans

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

* Re: [REVIEWv3 PATCH 20/35] DocBook media: update VIDIOC_G/S/TRY_EXT_CTRLS.
  2014-03-12 14:20   ` Mauro Carvalho Chehab
@ 2014-03-13 12:18     ` Hans Verkuil
  0 siblings, 0 replies; 66+ messages in thread
From: Hans Verkuil @ 2014-03-13 12:18 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: linux-media, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	sakari.ailus, Hans Verkuil

On 03/12/14 15:20, Mauro Carvalho Chehab wrote:
> Em Mon, 17 Feb 2014 10:57:35 +0100
> Hans Verkuil <hverkuil@xs4all.nl> escreveu:
> 
>> From: Hans Verkuil <hans.verkuil@cisco.com>
>>
>> Document the support for the new complex type controls.
>>
>> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
>> ---
>>  .../DocBook/media/v4l/vidioc-g-ext-ctrls.xml       | 43 ++++++++++++++++++----
>>  1 file changed, 35 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 b3bb957..d946d6b 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 complex types (<constant>V4L2_CTRL_FLAG_IS_PTR</constant> is set)
>> +must set the <structfield>p</structfield> field.</para>
> 
> Same notes I did to the other patches apply here:
> 	- s/complex/compound/
> 	- Let's not mix strings with compound types
> 	- etc
> 
>>      <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>Matrices are set and retrieved row-by-row. You cannot set a partial
>> +matrix, all elements have to be set or retrieved. The total size is calculated
>> +as <structfield>rows</structfield> * <structfield>cols</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/p</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,11 +103,17 @@ 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/p</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>
>>  
>> +    <para>For matrices it is possible to only set or check only the first
>> +<constant>X</constant> elements by setting size to <constant>X * elem_size</constant>,
>> +where <structfield>elem_size</structfield> is obtained by calling &VIDIOC-QUERY-EXT-CTRL;.
>> +Matrix elements are set row-by-row. Matrix elements that are not explicitly
>> +set will be initialized to their default value.</para>
>> +
> 
> That sounds confusing: what are the defaults?
> 
> Also, what happens if the size is set to, let's say, 1,5 * elem_size?
> 
> Will it fill one element, will it return an error (what error?) or will it
> fill two elements, the second one with some wrong value?

I would have to double-check but I think this may be a left-over from an earlier
version. I think the text is wrong and that you always have to set the full
matrix, for pretty much the reasons you mentioned as well. I've played around
with it, originally even being able to set a sub-matrix within the full matrix,
but you run into all sorts of complexities. For now the requirement is that
you set all values at once, later this might be relaxed but we need to have
a much better understanding of such use-cases.

Regards,

	Hans

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

end of thread, other threads:[~2014-03-13 12:19 UTC | newest]

Thread overview: 66+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-02-17  9:57 [REVIEWv3 PATCH 00/35] Add support for complex controls, use in solo/go7007 Hans Verkuil
2014-02-17  9:57 ` [REVIEWv3 PATCH 01/35] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
2014-02-17  9:57 ` [REVIEWv3 PATCH 02/35] v4l2-ctrls: add unit string Hans Verkuil
2014-02-17  9:57 ` [REVIEWv3 PATCH 03/35] v4l2-ctrls: use pr_info/cont instead of printk Hans Verkuil
2014-02-17  9:57 ` [REVIEWv3 PATCH 04/35] videodev2.h: add initial support for complex controls Hans Verkuil
2014-03-11 19:34   ` Mauro Carvalho Chehab
2014-03-11 20:23     ` Hans Verkuil
2014-03-11 23:48       ` Mauro Carvalho Chehab
2014-02-17  9:57 ` [REVIEWv3 PATCH 05/35] videodev2.h: add struct v4l2_query_ext_ctrl and VIDIOC_QUERY_EXT_CTRL Hans Verkuil
2014-03-11 19:42   ` Mauro Carvalho Chehab
2014-03-11 20:29     ` Hans Verkuil
2014-03-11 23:35       ` Mauro Carvalho Chehab
2014-02-17  9:57 ` [REVIEWv3 PATCH 06/35] v4l2-ctrls: add support for complex types Hans Verkuil
2014-03-11 20:14   ` Mauro Carvalho Chehab
2014-03-11 20:43     ` Hans Verkuil
2014-03-11 23:43       ` Mauro Carvalho Chehab
2014-02-17  9:57 ` [REVIEWv3 PATCH 07/35] v4l2: integrate support for VIDIOC_QUERY_EXT_CTRL Hans Verkuil
2014-02-17  9:57 ` [REVIEWv3 PATCH 08/35] v4l2-ctrls: create type_ops Hans Verkuil
2014-03-11 20:22   ` Mauro Carvalho Chehab
2014-03-11 20:49     ` Hans Verkuil
2014-03-11 23:56       ` Mauro Carvalho Chehab
2014-02-17  9:57 ` [REVIEWv3 PATCH 09/35] v4l2-ctrls: rewrite copy routines to operate on union v4l2_ctrl_ptr Hans Verkuil
2014-02-17  9:57 ` [REVIEWv3 PATCH 10/35] v4l2-ctrls: compare values only once Hans Verkuil
2014-02-17  9:57 ` [REVIEWv3 PATCH 11/35] v4l2-ctrls: prepare for matrix support: add cols & rows fields Hans Verkuil
2014-03-12 10:34   ` Mauro Carvalho Chehab
2014-02-17  9:57 ` [REVIEWv3 PATCH 12/35] v4l2-ctrls: replace cur by a union v4l2_ctrl_ptr Hans Verkuil
2014-03-12 10:38   ` Mauro Carvalho Chehab
2014-02-17  9:57 ` [REVIEWv3 PATCH 13/35] v4l2-ctrls: use 'new' to access pointer controls Hans Verkuil
2014-03-12 10:40   ` Mauro Carvalho Chehab
2014-02-17  9:57 ` [REVIEWv3 PATCH 14/35] v4l2-ctrls: prepare for matrix support Hans Verkuil
2014-03-12 10:42   ` Mauro Carvalho Chehab
2014-03-12 12:21     ` Hans Verkuil
2014-03-12 13:00       ` Mauro Carvalho Chehab
2014-03-12 13:00       ` Mauro Carvalho Chehab
2014-03-12 13:41         ` Hans Verkuil
2014-03-12 13:44         ` Sylwester Nawrocki
2014-02-17  9:57 ` [REVIEWv3 PATCH 15/35] v4l2-ctrls: type_ops can handle matrix elements Hans Verkuil
2014-02-17  9:57 ` [REVIEWv3 PATCH 16/35] v4l2-ctrls: add matrix support Hans Verkuil
2014-02-17  9:57 ` [REVIEWv3 PATCH 17/35] v4l2-ctrls: return elem_size instead of strlen Hans Verkuil
2014-02-17  9:57 ` [REVIEWv3 PATCH 18/35] v4l2-ctrl: fix error return of copy_to/from_user Hans Verkuil
2014-02-17  9:57 ` [REVIEWv3 PATCH 19/35] DocBook media: document VIDIOC_QUERY_EXT_CTRL Hans Verkuil
2014-03-12 14:13   ` Mauro Carvalho Chehab
2014-03-13  7:58     ` Hans Verkuil
2014-02-17  9:57 ` [REVIEWv3 PATCH 20/35] DocBook media: update VIDIOC_G/S/TRY_EXT_CTRLS Hans Verkuil
2014-03-12 14:20   ` Mauro Carvalho Chehab
2014-03-13 12:18     ` Hans Verkuil
2014-02-17  9:57 ` [REVIEWv3 PATCH 21/35] DocBook media: fix coding style in the control example code Hans Verkuil
2014-02-17  9:57 ` [REVIEWv3 PATCH 22/35] DocBook media: update control section Hans Verkuil
2014-02-19 23:15   ` Sakari Ailus
2014-03-12 14:27   ` Mauro Carvalho Chehab
2014-02-17  9:57 ` [REVIEWv3 PATCH 23/35] v4l2-controls.txt: update to the new way of accessing controls Hans Verkuil
2014-02-17  9:57 ` [REVIEWv3 PATCH 24/35] v4l2-ctrls/videodev2.h: add u8 and u16 types Hans Verkuil
2014-03-12 14:44   ` Mauro Carvalho Chehab
2014-02-17  9:57 ` [REVIEWv3 PATCH 25/35] DocBook media: document new u8 and u16 control types Hans Verkuil
2014-02-17  9:57 ` [REVIEWv3 PATCH 26/35] v4l2-ctrls: fix comments Hans Verkuil
2014-02-17  9:57 ` [REVIEWv3 PATCH 27/35] v4l2-ctrls/v4l2-controls.h: add MD controls Hans Verkuil
2014-02-17  9:57 ` [REVIEWv3 PATCH 28/35] DocBook media: document new motion detection controls Hans Verkuil
2014-02-17  9:57 ` [REVIEWv3 PATCH 29/35] v4l2: add a motion detection event Hans Verkuil
2014-02-17  9:57 ` [REVIEWv3 PATCH 30/35] DocBook: document new v4l " Hans Verkuil
2014-02-17  9:57 ` [REVIEWv3 PATCH 31/35] solo6x10: implement the new motion detection controls Hans Verkuil
2014-02-17  9:57 ` [REVIEWv3 PATCH 32/35] solo6x10: implement the motion detection event Hans Verkuil
2014-02-17  9:57 ` [REVIEWv3 PATCH 33/35] solo6x10: fix 'dma from stack' warning Hans Verkuil
2014-02-17  9:57 ` [REVIEWv3 PATCH 34/35] solo6x10: check dma_map_sg() return value Hans Verkuil
2014-02-17  9:57 ` [REVIEWv3 PATCH 35/35] go7007: add motion detection support Hans Verkuil
2014-02-19  8:28 ` [REVIEWv3 PATCH 00/35] Add support for complex controls, use in solo/go7007 Ricardo Ribalda Delgado
2014-02-19  8:54   ` 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).