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

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 based on this RFCv3:

http://lwn.net/Articles/582694/

and this earlier REVIEW patch series:

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

Changes since this last REVIEW series are:

- add a patch to fix a pre-existing bug in the handling of the return code
  of copy_to/from_user.

- Tested motion detection for the go7007 and solo6x10 drivers (was on my TODO list)
  and as a result added a patch for the DMA handling when DMA-ing the motion detection
  matrix (was DMAed from stack) and made some minor changes in the solo and go7007
  patches (in both drivers the Motion Detection Mode control wasn't setup correctly
  and in go7007 there was no motion detection event sent when there was no more
  motion).

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

Regards,

	Hans


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

* [REVIEWv2 PATCH 01/34] v4l2-ctrls: increase internal min/max/step/def to 64 bit
  2014-02-10  8:46 [REVIEWv2 PATCH 00/34] Add support for complex controls, use in solo/go7007 Hans Verkuil
@ 2014-02-10  8:46 ` Hans Verkuil
  2014-02-10  8:46 ` [REVIEWv2 PATCH 02/34] v4l2-ctrls: add unit string Hans Verkuil
                   ` (34 subsequent siblings)
  35 siblings, 0 replies; 52+ messages in thread
From: Hans Verkuil @ 2014-02-10  8:46 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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.5.2


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

* [REVIEWv2 PATCH 02/34] v4l2-ctrls: add unit string.
  2014-02-10  8:46 [REVIEWv2 PATCH 00/34] Add support for complex controls, use in solo/go7007 Hans Verkuil
  2014-02-10  8:46 ` [REVIEWv2 PATCH 01/34] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
@ 2014-02-10  8:46 ` Hans Verkuil
  2014-02-10  8:46 ` [REVIEWv2 PATCH 03/34] v4l2-ctrls: use pr_info/cont instead of printk Hans Verkuil
                   ` (33 subsequent siblings)
  35 siblings, 0 replies; 52+ messages in thread
From: Hans Verkuil @ 2014-02-10  8:46 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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.5.2


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

* [REVIEWv2 PATCH 03/34] v4l2-ctrls: use pr_info/cont instead of printk.
  2014-02-10  8:46 [REVIEWv2 PATCH 00/34] Add support for complex controls, use in solo/go7007 Hans Verkuil
  2014-02-10  8:46 ` [REVIEWv2 PATCH 01/34] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
  2014-02-10  8:46 ` [REVIEWv2 PATCH 02/34] v4l2-ctrls: add unit string Hans Verkuil
@ 2014-02-10  8:46 ` Hans Verkuil
  2014-02-10  8:46 ` [REVIEWv2 PATCH 04/34] videodev2.h: add initial support for complex controls Hans Verkuil
                   ` (32 subsequent siblings)
  35 siblings, 0 replies; 52+ messages in thread
From: Hans Verkuil @ 2014-02-10  8:46 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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.5.2


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

* [REVIEWv2 PATCH 04/34] videodev2.h: add initial support for complex controls.
  2014-02-10  8:46 [REVIEWv2 PATCH 00/34] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (2 preceding siblings ...)
  2014-02-10  8:46 ` [REVIEWv2 PATCH 03/34] v4l2-ctrls: use pr_info/cont instead of printk Hans Verkuil
@ 2014-02-10  8:46 ` Hans Verkuil
  2014-02-10  8:46 ` [REVIEWv2 PATCH 05/34] videodev2.h: add struct v4l2_query_ext_ctrl and VIDIOC_QUERY_EXT_CTRL Hans Verkuil
                   ` (31 subsequent siblings)
  35 siblings, 0 replies; 52+ messages in thread
From: Hans Verkuil @ 2014-02-10  8:46 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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.5.2


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

* [REVIEWv2 PATCH 05/34] videodev2.h: add struct v4l2_query_ext_ctrl and VIDIOC_QUERY_EXT_CTRL.
  2014-02-10  8:46 [REVIEWv2 PATCH 00/34] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (3 preceding siblings ...)
  2014-02-10  8:46 ` [REVIEWv2 PATCH 04/34] videodev2.h: add initial support for complex controls Hans Verkuil
@ 2014-02-10  8:46 ` Hans Verkuil
  2014-02-10  8:46 ` [REVIEWv2 PATCH 06/34] v4l2-ctrls: add support for complex types Hans Verkuil
                   ` (30 subsequent siblings)
  35 siblings, 0 replies; 52+ messages in thread
From: Hans Verkuil @ 2014-02-10  8:46 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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.5.2


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

* [REVIEWv2 PATCH 06/34] v4l2-ctrls: add support for complex types.
  2014-02-10  8:46 [REVIEWv2 PATCH 00/34] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (4 preceding siblings ...)
  2014-02-10  8:46 ` [REVIEWv2 PATCH 05/34] videodev2.h: add struct v4l2_query_ext_ctrl and VIDIOC_QUERY_EXT_CTRL Hans Verkuil
@ 2014-02-10  8:46 ` Hans Verkuil
  2014-02-10  8:46 ` [REVIEWv2 PATCH 07/34] v4l2: integrate support for VIDIOC_QUERY_EXT_CTRL Hans Verkuil
                   ` (29 subsequent siblings)
  35 siblings, 0 replies; 52+ messages in thread
From: Hans Verkuil @ 2014-02-10  8:46 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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 | 242 ++++++++++++++++++++++++++---------
 include/media/v4l2-ctrls.h           |  38 +++++-
 2 files changed, 216 insertions(+), 64 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index df8ed0a..67e5d1e 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,45 @@ 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;
+	/*
+	 * No hidden controls are allowed in the USER class
+	 * due to backwards compatibility with old applications.
+	 */
+	if (V4L2_CTRL_ID2CLASS(id) == V4L2_CTRL_CLASS_USER &&
+	    (flags & V4L2_CTRL_FLAG_HIDDEN)) {
+		handler_set_err(hdl, -EINVAL);
+		return NULL;
+	}
 	err = check_range(type, min, max, step, def);
 	if (err) {
 		handler_set_err(hdl, err);
@@ -1667,12 +1697,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 +1723,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 +1796,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 +1815,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 +1856,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 +1889,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 +1914,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 +2203,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 +2219,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 +2242,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 +2274,63 @@ 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;
+
+	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 +2430,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 +2463,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 +2550,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 +2612,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 +2642,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 +2661,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 +2797,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 +2902,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 +2948,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 +2972,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.5.2


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

* [REVIEWv2 PATCH 07/34] v4l2: integrate support for VIDIOC_QUERY_EXT_CTRL.
  2014-02-10  8:46 [REVIEWv2 PATCH 00/34] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (5 preceding siblings ...)
  2014-02-10  8:46 ` [REVIEWv2 PATCH 06/34] v4l2-ctrls: add support for complex types Hans Verkuil
@ 2014-02-10  8:46 ` Hans Verkuil
  2014-02-10  8:46 ` [REVIEWv2 PATCH 08/34] v4l2-ctrls: create type_ops Hans Verkuil
                   ` (28 subsequent siblings)
  35 siblings, 0 replies; 52+ messages in thread
From: Hans Verkuil @ 2014-02-10  8:46 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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.5.2


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

* [REVIEWv2 PATCH 08/34] v4l2-ctrls: create type_ops.
  2014-02-10  8:46 [REVIEWv2 PATCH 00/34] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (6 preceding siblings ...)
  2014-02-10  8:46 ` [REVIEWv2 PATCH 07/34] v4l2: integrate support for VIDIOC_QUERY_EXT_CTRL Hans Verkuil
@ 2014-02-10  8:46 ` Hans Verkuil
  2014-02-12 10:55   ` Ricardo Ribalda Delgado
  2014-02-10  8:46 ` [REVIEWv2 PATCH 09/34] v4l2-ctrls: rewrite copy routines to operate on union v4l2_ctrl_ptr Hans Verkuil
                   ` (27 subsequent siblings)
  35 siblings, 1 reply; 52+ messages in thread
From: Hans Verkuil @ 2014-02-10  8:46 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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 67e5d1e..988a2bd8 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;
@@ -1715,6 +1811,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;
@@ -1736,19 +1833,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;
@@ -1793,7 +1887,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,
@@ -1821,7 +1915,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);
 }
@@ -1855,7 +1949,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);
 }
@@ -1888,7 +1982,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);
 
 }
@@ -1913,7 +2008,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);
 }
@@ -2096,32 +2191,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.5.2


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

* [REVIEWv2 PATCH 09/34] v4l2-ctrls: rewrite copy routines to operate on union v4l2_ctrl_ptr.
  2014-02-10  8:46 [REVIEWv2 PATCH 00/34] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (7 preceding siblings ...)
  2014-02-10  8:46 ` [REVIEWv2 PATCH 08/34] v4l2-ctrls: create type_ops Hans Verkuil
@ 2014-02-10  8:46 ` Hans Verkuil
  2014-02-10  8:46 ` [REVIEWv2 PATCH 10/34] v4l2-ctrls: compare values only once Hans Verkuil
                   ` (26 subsequent siblings)
  35 siblings, 0 replies; 52+ messages in thread
From: Hans Verkuil @ 2014-02-10  8:46 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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 988a2bd8..b945008 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.5.2


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

* [REVIEWv2 PATCH 10/34] v4l2-ctrls: compare values only once.
  2014-02-10  8:46 [REVIEWv2 PATCH 00/34] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (8 preceding siblings ...)
  2014-02-10  8:46 ` [REVIEWv2 PATCH 09/34] v4l2-ctrls: rewrite copy routines to operate on union v4l2_ctrl_ptr Hans Verkuil
@ 2014-02-10  8:46 ` Hans Verkuil
  2014-02-10  8:46 ` [REVIEWv2 PATCH 11/34] v4l2-ctrls: prepare for matrix support: add cols & rows fields Hans Verkuil
                   ` (25 subsequent siblings)
  35 siblings, 0 replies; 52+ messages in thread
From: Hans Verkuil @ 2014-02-10  8:46 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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 b945008..87f9a4e 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.5.2


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

* [REVIEWv2 PATCH 11/34] v4l2-ctrls: prepare for matrix support: add cols & rows fields.
  2014-02-10  8:46 [REVIEWv2 PATCH 00/34] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (9 preceding siblings ...)
  2014-02-10  8:46 ` [REVIEWv2 PATCH 10/34] v4l2-ctrls: compare values only once Hans Verkuil
@ 2014-02-10  8:46 ` Hans Verkuil
  2014-02-10  8:46 ` [REVIEWv2 PATCH 12/34] v4l2-ctrls: replace cur by a union v4l2_ctrl_ptr Hans Verkuil
                   ` (24 subsequent siblings)
  35 siblings, 0 replies; 52+ messages in thread
From: Hans Verkuil @ 2014-02-10  8:46 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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 87f9a4e..7dcccbf 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)
@@ -1812,6 +1817,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;
@@ -1877,8 +1884,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;
@@ -1904,7 +1911,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);
@@ -1938,7 +1945,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);
@@ -1971,8 +1978,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);
@@ -1997,7 +2004,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);
@@ -2343,7 +2350,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.5.2


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

* [REVIEWv2 PATCH 12/34] v4l2-ctrls: replace cur by a union v4l2_ctrl_ptr.
  2014-02-10  8:46 [REVIEWv2 PATCH 00/34] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (10 preceding siblings ...)
  2014-02-10  8:46 ` [REVIEWv2 PATCH 11/34] v4l2-ctrls: prepare for matrix support: add cols & rows fields Hans Verkuil
@ 2014-02-10  8:46 ` Hans Verkuil
  2014-02-10  8:46 ` [REVIEWv2 PATCH 13/34] v4l2-ctrls: use 'new' to access pointer controls Hans Verkuil
                   ` (23 subsequent siblings)
  35 siblings, 0 replies; 52+ messages in thread
From: Hans Verkuil @ 2014-02-10  8:46 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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 7dcccbf..9f8af88 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
@@ -1786,13 +1786,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) {
@@ -1825,7 +1825,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) {
@@ -1833,7 +1833,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]);
@@ -3096,10 +3096,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.5.2


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

* [REVIEWv2 PATCH 13/34] v4l2-ctrls: use 'new' to access pointer controls
  2014-02-10  8:46 [REVIEWv2 PATCH 00/34] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (11 preceding siblings ...)
  2014-02-10  8:46 ` [REVIEWv2 PATCH 12/34] v4l2-ctrls: replace cur by a union v4l2_ctrl_ptr Hans Verkuil
@ 2014-02-10  8:46 ` Hans Verkuil
  2014-02-10  8:46 ` [REVIEWv2 PATCH 14/34] v4l2-ctrls: prepare for matrix support Hans Verkuil
                   ` (22 subsequent siblings)
  35 siblings, 0 replies; 52+ messages in thread
From: Hans Verkuil @ 2014-02-10  8:46 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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 9f8af88..86a27af 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1829,8 +1829,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.5.2


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

* [REVIEWv2 PATCH 14/34] v4l2-ctrls: prepare for matrix support.
  2014-02-10  8:46 [REVIEWv2 PATCH 00/34] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (12 preceding siblings ...)
  2014-02-10  8:46 ` [REVIEWv2 PATCH 13/34] v4l2-ctrls: use 'new' to access pointer controls Hans Verkuil
@ 2014-02-10  8:46 ` Hans Verkuil
  2014-02-10  8:46 ` [REVIEWv2 PATCH 15/34] v4l2-ctrls: type_ops can handle matrix elements Hans Verkuil
                   ` (21 subsequent siblings)
  35 siblings, 0 replies; 52+ messages in thread
From: Hans Verkuil @ 2014-02-10  8:46 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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 86a27af..16c29e1 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;
 	/*
 	 * No hidden controls are allowed in the USER class
@@ -1785,14 +1791,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) {
@@ -1814,9 +1827,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;
@@ -1830,13 +1844,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);
@@ -2740,7 +2754,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;
@@ -3050,7 +3064,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.5.2


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

* [REVIEWv2 PATCH 15/34] v4l2-ctrls: type_ops can handle matrix elements.
  2014-02-10  8:46 [REVIEWv2 PATCH 00/34] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (13 preceding siblings ...)
  2014-02-10  8:46 ` [REVIEWv2 PATCH 14/34] v4l2-ctrls: prepare for matrix support Hans Verkuil
@ 2014-02-10  8:46 ` Hans Verkuil
  2014-02-10  8:46 ` [REVIEWv2 PATCH 16/34] v4l2-ctrls: add matrix support Hans Verkuil
                   ` (20 subsequent siblings)
  35 siblings, 0 replies; 52+ messages in thread
From: Hans Verkuil @ 2014-02-10  8:46 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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 16c29e1..a61e602 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.5.2


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

* [REVIEWv2 PATCH 16/34] v4l2-ctrls: add matrix support.
  2014-02-10  8:46 [REVIEWv2 PATCH 00/34] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (14 preceding siblings ...)
  2014-02-10  8:46 ` [REVIEWv2 PATCH 15/34] v4l2-ctrls: type_ops can handle matrix elements Hans Verkuil
@ 2014-02-10  8:46 ` Hans Verkuil
  2014-02-10  8:46 ` [REVIEWv2 PATCH 17/34] v4l2-ctrls: return elem_size instead of strlen Hans Verkuil
                   ` (19 subsequent siblings)
  35 siblings, 0 replies; 52+ messages in thread
From: Hans Verkuil @ 2014-02-10  8:46 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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 | 108 ++++++++++++++++++++---------------
 1 file changed, 63 insertions(+), 45 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index a61e602..b4a9ada 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,19 @@ static void cur_to_new(struct v4l2_ctrl *ctrl)
 static int cluster_changed(struct v4l2_ctrl *master)
 {
 	bool changed = false;
+	unsigned idx;
 	int i;
 
 	for (i = 0; i < master->ncontrols; i++) {
 		struct v4l2_ctrl *ctrl = master->cluster[i];
+		bool ctrl_changed = false;
 
 		if (ctrl == NULL)
 			continue;
-		ctrl->has_changed = !ctrl->type_ops->equal(ctrl, 0,
+		for (idx = 0; 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 +1500,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 +1752,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;
@@ -1854,7 +1862,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);
@@ -2548,12 +2557,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;
@@ -3093,7 +3108,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) {
@@ -3103,6 +3118,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.5.2


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

* [REVIEWv2 PATCH 17/34] v4l2-ctrls: return elem_size instead of strlen
  2014-02-10  8:46 [REVIEWv2 PATCH 00/34] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (15 preceding siblings ...)
  2014-02-10  8:46 ` [REVIEWv2 PATCH 16/34] v4l2-ctrls: add matrix support Hans Verkuil
@ 2014-02-10  8:46 ` Hans Verkuil
  2014-02-10  8:46 ` [REVIEWv2 PATCH 18/34] v4l2-ctrl: fix error return of copy_to/from_user Hans Verkuil
                   ` (18 subsequent siblings)
  35 siblings, 0 replies; 52+ messages in thread
From: Hans Verkuil @ 2014-02-10  8:46 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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 b4a9ada..160e4c7 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.5.2


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

* [REVIEWv2 PATCH 18/34] v4l2-ctrl: fix error return of copy_to/from_user.
  2014-02-10  8:46 [REVIEWv2 PATCH 00/34] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (16 preceding siblings ...)
  2014-02-10  8:46 ` [REVIEWv2 PATCH 17/34] v4l2-ctrls: return elem_size instead of strlen Hans Verkuil
@ 2014-02-10  8:46 ` Hans Verkuil
  2014-02-10  8:46 ` [REVIEWv2 PATCH 19/34] DocBook media: document VIDIOC_QUERY_EXT_CTRL Hans Verkuil
                   ` (17 subsequent siblings)
  35 siblings, 0 replies; 52+ messages in thread
From: Hans Verkuil @ 2014-02-10  8:46 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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 160e4c7..c81ebcf 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.5.2


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

* [REVIEWv2 PATCH 19/34] DocBook media: document VIDIOC_QUERY_EXT_CTRL.
  2014-02-10  8:46 [REVIEWv2 PATCH 00/34] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (17 preceding siblings ...)
  2014-02-10  8:46 ` [REVIEWv2 PATCH 18/34] v4l2-ctrl: fix error return of copy_to/from_user Hans Verkuil
@ 2014-02-10  8:46 ` Hans Verkuil
  2014-02-10  8:46 ` [REVIEWv2 PATCH 20/34] DocBook media: update VIDIOC_G/S/TRY_EXT_CTRLS Hans Verkuil
                   ` (16 subsequent siblings)
  35 siblings, 0 replies; 52+ messages in thread
From: Hans Verkuil @ 2014-02-10  8:46 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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.5.2


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

* [REVIEWv2 PATCH 20/34] DocBook media: update VIDIOC_G/S/TRY_EXT_CTRLS.
  2014-02-10  8:46 [REVIEWv2 PATCH 00/34] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (18 preceding siblings ...)
  2014-02-10  8:46 ` [REVIEWv2 PATCH 19/34] DocBook media: document VIDIOC_QUERY_EXT_CTRL Hans Verkuil
@ 2014-02-10  8:46 ` Hans Verkuil
  2014-02-10  8:46 ` [REVIEWv2 PATCH 21/34] DocBook media: fix coding style in the control example code Hans Verkuil
                   ` (15 subsequent siblings)
  35 siblings, 0 replies; 52+ messages in thread
From: Hans Verkuil @ 2014-02-10  8:46 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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.5.2


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

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


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

* [REVIEWv2 PATCH 22/34] DocBook media: update control section.
  2014-02-10  8:46 [REVIEWv2 PATCH 00/34] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (20 preceding siblings ...)
  2014-02-10  8:46 ` [REVIEWv2 PATCH 21/34] DocBook media: fix coding style in the control example code Hans Verkuil
@ 2014-02-10  8:46 ` Hans Verkuil
  2014-02-10  8:46 ` [REVIEWv2 PATCH 23/34] v4l2-controls.txt: update to the new way of accessing controls Hans Verkuil
                   ` (13 subsequent siblings)
  35 siblings, 0 replies; 52+ messages in thread
From: Hans Verkuil @ 2014-02-10  8:46 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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.5.2


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

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


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

* [REVIEWv2 PATCH 24/34] v4l2-ctrls/videodev2.h: add u8 and u16 types.
  2014-02-10  8:46 [REVIEWv2 PATCH 00/34] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (22 preceding siblings ...)
  2014-02-10  8:46 ` [REVIEWv2 PATCH 23/34] v4l2-controls.txt: update to the new way of accessing controls Hans Verkuil
@ 2014-02-10  8:46 ` Hans Verkuil
  2014-02-12 10:44   ` Ricardo Ribalda Delgado
  2014-02-10  8:46 ` [REVIEWv2 PATCH 25/34] DocBook media: document new u8 and u16 control types Hans Verkuil
                   ` (11 subsequent siblings)
  35 siblings, 1 reply; 52+ messages in thread
From: Hans Verkuil @ 2014-02-10  8:46 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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 | 24 ++++++++++++++++++++++++
 include/media/v4l2-ctrls.h           |  4 ++++
 include/uapi/linux/videodev2.h       |  4 ++++
 3 files changed, 32 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index c81ebcf..0b200dd 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];
@@ -1469,6 +1489,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)
@@ -3119,6 +3141,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.5.2


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

* [REVIEWv2 PATCH 25/34] DocBook media: document new u8 and u16 control types.
  2014-02-10  8:46 [REVIEWv2 PATCH 00/34] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (23 preceding siblings ...)
  2014-02-10  8:46 ` [REVIEWv2 PATCH 24/34] v4l2-ctrls/videodev2.h: add u8 and u16 types Hans Verkuil
@ 2014-02-10  8:46 ` Hans Verkuil
  2014-02-10  8:46 ` [REVIEWv2 PATCH 26/34] v4l2-ctrls: fix comments Hans Verkuil
                   ` (10 subsequent siblings)
  35 siblings, 0 replies; 52+ messages in thread
From: Hans Verkuil @ 2014-02-10  8:46 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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.5.2


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

* [REVIEWv2 PATCH 26/34] v4l2-ctrls: fix comments
  2014-02-10  8:46 [REVIEWv2 PATCH 00/34] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (24 preceding siblings ...)
  2014-02-10  8:46 ` [REVIEWv2 PATCH 25/34] DocBook media: document new u8 and u16 control types Hans Verkuil
@ 2014-02-10  8:46 ` Hans Verkuil
  2014-02-10  8:46 ` [REVIEWv2 PATCH 27/34] v4l2-ctrls/v4l2-controls.h: add MD controls Hans Verkuil
                   ` (9 subsequent siblings)
  35 siblings, 0 replies; 52+ messages in thread
From: Hans Verkuil @ 2014-02-10  8:46 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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 0b200dd..d99ce90 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.5.2


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

* [REVIEWv2 PATCH 27/34] v4l2-ctrls/v4l2-controls.h: add MD controls
  2014-02-10  8:46 [REVIEWv2 PATCH 00/34] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (25 preceding siblings ...)
  2014-02-10  8:46 ` [REVIEWv2 PATCH 26/34] v4l2-ctrls: fix comments Hans Verkuil
@ 2014-02-10  8:46 ` Hans Verkuil
  2014-02-10  8:46 ` [REVIEWv2 PATCH 28/34] DocBook media: document new motion detection controls Hans Verkuil
                   ` (8 subsequent siblings)
  35 siblings, 0 replies; 52+ messages in thread
From: Hans Verkuil @ 2014-02-10  8:46 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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 d99ce90..e8e2caa 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.5.2


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

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

diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml
index 85d78d4..5f3e138 100644
--- a/Documentation/DocBook/media/v4l/controls.xml
+++ b/Documentation/DocBook/media/v4l/controls.xml
@@ -5022,4 +5022,99 @@ 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.</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.</entry>
+          </row>
+        </tbody>
+      </tgroup>
+      </table>
+
+      </section>
 </section>
-- 
1.8.5.2


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

* [REVIEWv2 PATCH 29/34] v4l2: add a motion detection event.
  2014-02-10  8:46 [REVIEWv2 PATCH 00/34] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (27 preceding siblings ...)
  2014-02-10  8:46 ` [REVIEWv2 PATCH 28/34] DocBook media: document new motion detection controls Hans Verkuil
@ 2014-02-10  8:46 ` Hans Verkuil
  2014-02-10  8:46 ` [REVIEWv2 PATCH 30/34] DocBook: document new v4l " Hans Verkuil
                   ` (6 subsequent siblings)
  35 siblings, 0 replies; 52+ messages in thread
From: Hans Verkuil @ 2014-02-10  8:46 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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.5.2


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

* [REVIEWv2 PATCH 30/34] DocBook: document new v4l motion detection event.
  2014-02-10  8:46 [REVIEWv2 PATCH 00/34] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (28 preceding siblings ...)
  2014-02-10  8:46 ` [REVIEWv2 PATCH 29/34] v4l2: add a motion detection event Hans Verkuil
@ 2014-02-10  8:46 ` Hans Verkuil
  2014-02-10  8:46 ` [REVIEWv2 PATCH 31/34] solo6x10: implement the new motion detection controls Hans Verkuil
                   ` (5 subsequent siblings)
  35 siblings, 0 replies; 52+ messages in thread
From: Hans Verkuil @ 2014-02-10  8:46 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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.5.2


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

* [REVIEWv2 PATCH 31/34] solo6x10: implement the new motion detection controls.
  2014-02-10  8:46 [REVIEWv2 PATCH 00/34] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (29 preceding siblings ...)
  2014-02-10  8:46 ` [REVIEWv2 PATCH 30/34] DocBook: document new v4l " Hans Verkuil
@ 2014-02-10  8:46 ` Hans Verkuil
  2014-02-10  8:46 ` [REVIEWv2 PATCH 32/34] solo6x10: implement the motion detection event Hans Verkuil
                   ` (4 subsequent siblings)
  35 siblings, 0 replies; 52+ messages in thread
From: Hans Verkuil @ 2014-02-10  8:46 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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 | 104 +++++++--------------
 drivers/staging/media/solo6x10/solo6x10.h          |  19 +---
 3 files changed, 41 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..7489ffb 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,24 @@ 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,
+	.elem_size = 2,
+	.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 +1220,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 +1250,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.5.2


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

* [REVIEWv2 PATCH 32/34] solo6x10: implement the motion detection event.
  2014-02-10  8:46 [REVIEWv2 PATCH 00/34] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (30 preceding siblings ...)
  2014-02-10  8:46 ` [REVIEWv2 PATCH 31/34] solo6x10: implement the new motion detection controls Hans Verkuil
@ 2014-02-10  8:46 ` Hans Verkuil
  2014-02-10  8:46 ` [REVIEWv2 PATCH 33/34] solo6x10: fix 'dma from stack' warning Hans Verkuil
                   ` (3 subsequent siblings)
  35 siblings, 0 replies; 52+ messages in thread
From: Hans Verkuil @ 2014-02-10  8:46 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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 7489ffb..3b994d7 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.5.2


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

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


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

* [REVIEWv2 PATCH 34/34] go7007: add motion detection support.
  2014-02-10  8:46 [REVIEWv2 PATCH 00/34] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (32 preceding siblings ...)
  2014-02-10  8:46 ` [REVIEWv2 PATCH 33/34] solo6x10: fix 'dma from stack' warning Hans Verkuil
@ 2014-02-10  8:46 ` Hans Verkuil
  2014-02-12  7:56   ` [REVIEWv2 PATCH 35/34] DocBook media: clarify how the matrix maps to the grid Hans Verkuil
  2014-02-12 11:39 ` [REVIEWv2 PATCH 36/34] v4l2-ctrls: break off loop on first changed element Hans Verkuil
  2014-02-16 20:14 ` [REVIEWv2 PATCH 00/34] Add support for complex controls, use in solo/go7007 Sakari Ailus
  35 siblings, 1 reply; 52+ messages in thread
From: Hans Verkuil @ 2014-02-10  8:46 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	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    | 319 ++++++++++++++++++--------
 drivers/staging/media/go7007/go7007.h         |  40 ----
 drivers/staging/media/go7007/saa7134-go7007.c |   1 -
 6 files changed, 347 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..4cf78d2 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,146 @@ 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,
+	.elem_size = 1,
+	.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 +1071,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.5.2


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

* [REVIEWv2 PATCH 35/34] DocBook media: clarify how the matrix maps to the grid.
  2014-02-10  8:46 ` [REVIEWv2 PATCH 34/34] go7007: add motion detection support Hans Verkuil
@ 2014-02-12  7:56   ` Hans Verkuil
  0 siblings, 0 replies; 52+ messages in thread
From: Hans Verkuil @ 2014-02-12  7:56 UTC (permalink / raw)
  To: linux-media
  Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete,
	Hans Verkuil

(This patch is an addition to the "Add support for complex controls, use in solo/go7007"
patch series)

Make it explicit that matrix element (0, 0) maps to the top-left cell
of the grid.

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

diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml
index 5f3e138..4749216 100644
--- a/Documentation/DocBook/media/v4l/controls.xml
+++ b/Documentation/DocBook/media/v4l/controls.xml
@@ -5102,7 +5102,8 @@ description of this control class.</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.</entry>
+	  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>
@@ -5110,7 +5111,8 @@ description of this control class.</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.</entry>
+	  motion detection mode. Matrix element (0, 0) represents the cell at the top-left of the
+	  grid.</entry>
           </row>
         </tbody>
       </tgroup>
-- 
1.8.5.2



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

* Re: [REVIEWv2 PATCH 24/34] v4l2-ctrls/videodev2.h: add u8 and u16 types.
  2014-02-10  8:46 ` [REVIEWv2 PATCH 24/34] v4l2-ctrls/videodev2.h: add u8 and u16 types Hans Verkuil
@ 2014-02-12 10:44   ` Ricardo Ribalda Delgado
  2014-02-12 11:20     ` Hans Verkuil
  0 siblings, 1 reply; 52+ messages in thread
From: Ricardo Ribalda Delgado @ 2014-02-12 10:44 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: linux-media, Mauro Carvalho Chehab, Laurent Pinchart,
	Sylwester Nawrocki, Ismael Luceno, pete, Hans Verkuil

Hello Hans

In the case of U8 and U16 data types. Why dont you fill the elem_size
automatically in v4l2_ctrl and request the driver to fill the field?

Other option would be not declaring the basic data types (U8, U16,
U32...) and use elem_size. Ie. If type==V4L2_CTRL_COMPLEX_TYPES, then
the type is basic and elem_size is the size of the type. If the type
>V4L2_CTRL_COMPLEX_TYPES the type is not basic.

Thanks!

On Mon, Feb 10, 2014 at 9:46 AM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
> 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 | 24 ++++++++++++++++++++++++
>  include/media/v4l2-ctrls.h           |  4 ++++
>  include/uapi/linux/videodev2.h       |  4 ++++
>  3 files changed, 32 insertions(+)
>
> diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
> index c81ebcf..0b200dd 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];
> @@ -1469,6 +1489,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)
> @@ -3119,6 +3141,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.5.2
>
> --
> 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] 52+ messages in thread

* Re: [REVIEWv2 PATCH 08/34] v4l2-ctrls: create type_ops.
  2014-02-10  8:46 ` [REVIEWv2 PATCH 08/34] v4l2-ctrls: create type_ops Hans Verkuil
@ 2014-02-12 10:55   ` Ricardo Ribalda Delgado
  2014-02-12 11:36     ` Hans Verkuil
  0 siblings, 1 reply; 52+ messages in thread
From: Ricardo Ribalda Delgado @ 2014-02-12 10:55 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: linux-media, Mauro Carvalho Chehab, Laurent Pinchart,
	Sylwester Nawrocki, Ismael Luceno, pete, Hans Verkuil

Hello Hans

If we have a matrix control with a huge number of elements (ie, the
number of pixels), a control validation will imply over ahuge number
of function calls.

In the case of the matrix you are always validating/init all the
values of of the array. Why dont we modify the type_ops so they
operate on the whole matrix (remove the idx from the function).

Anyway we should modify

for (idx = 0; idx < ctrl->rows * ctrl->cols; idx++)
               ctrl_changed |= !ctrl->type_ops->equal(ctrl, idx,
ctrl->stores[0], ctrl->new);

to

for (idx = 0; idx < ctrl->rows * ctrl->cols; idx++)
               if (!ctrl->type_ops->equal(ctrl, idx, ctrl->stores[0],
ctrl->new))
                                break

if (idx==ctrl->rows * ctrl->col)
 ctrol_changed=true;

Saving us some calls when we already know that the control has changed.


Thanks!


ps: consider all my code pseudocode :P


On Mon, Feb 10, 2014 at 9:46 AM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
> 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 67e5d1e..988a2bd8 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;
> @@ -1715,6 +1811,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;
> @@ -1736,19 +1833,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;
> @@ -1793,7 +1887,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,
> @@ -1821,7 +1915,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);
>  }
> @@ -1855,7 +1949,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);
>  }
> @@ -1888,7 +1982,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);
>
>  }
> @@ -1913,7 +2008,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);
>  }
> @@ -2096,32 +2191,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.5.2
>
> --
> 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] 52+ messages in thread

* Re: [REVIEWv2 PATCH 24/34] v4l2-ctrls/videodev2.h: add u8 and u16 types.
  2014-02-12 10:44   ` Ricardo Ribalda Delgado
@ 2014-02-12 11:20     ` Hans Verkuil
  2014-02-12 12:11       ` Ricardo Ribalda Delgado
  0 siblings, 1 reply; 52+ messages in thread
From: Hans Verkuil @ 2014-02-12 11:20 UTC (permalink / raw)
  To: Ricardo Ribalda Delgado
  Cc: linux-media, Mauro Carvalho Chehab, Laurent Pinchart,
	Sylwester Nawrocki, Ismael Luceno, pete, Hans Verkuil

Hi Ricardo,

On 02/12/14 11:44, Ricardo Ribalda Delgado wrote:
> Hello Hans
> 
> In the case of U8 and U16 data types. Why dont you fill the elem_size
> automatically in v4l2_ctrl and request the driver to fill the field?

When you create the control the control framework has to know the element
size beforehand as it will use that to allocate the memory containing the
control's value. The control framework is aware of the 'old' control types
and will fill in the elem_size accordingly, but it cannot do that in the
general case for these complex types. I guess it could be filled in by the
framework for the more common types (U8, U16) but I felt it was more
consistent to just require drivers to fill it in manually, rather than have
it set for some types but not for others.

> 
> Other option would be not declaring the basic data types (U8, U16,
> U32...) and use elem_size. Ie. If type==V4L2_CTRL_COMPLEX_TYPES, then
> the type is basic and elem_size is the size of the type. If the type
>> V4L2_CTRL_COMPLEX_TYPES the type is not basic.

You still need to know the type. Applications have to be able to check for
the type, the element size by itself doesn't tell you how to interpret the
data, you need the type identifier as well.

Regards,

	Hans

> 
> Thanks!
> 
> On Mon, Feb 10, 2014 at 9:46 AM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
>> 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 | 24 ++++++++++++++++++++++++
>>  include/media/v4l2-ctrls.h           |  4 ++++
>>  include/uapi/linux/videodev2.h       |  4 ++++
>>  3 files changed, 32 insertions(+)
>>
>> diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
>> index c81ebcf..0b200dd 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];
>> @@ -1469,6 +1489,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)
>> @@ -3119,6 +3141,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.5.2
>>
>> --
>> 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] 52+ messages in thread

* Re: [REVIEWv2 PATCH 08/34] v4l2-ctrls: create type_ops.
  2014-02-12 10:55   ` Ricardo Ribalda Delgado
@ 2014-02-12 11:36     ` Hans Verkuil
  2014-02-12 12:03       ` Ricardo Ribalda Delgado
  0 siblings, 1 reply; 52+ messages in thread
From: Hans Verkuil @ 2014-02-12 11:36 UTC (permalink / raw)
  To: Ricardo Ribalda Delgado
  Cc: linux-media, Mauro Carvalho Chehab, Laurent Pinchart,
	Sylwester Nawrocki, Ismael Luceno, pete, Hans Verkuil

On 02/12/14 11:55, Ricardo Ribalda Delgado wrote:
> Hello Hans
> 
> If we have a matrix control with a huge number of elements (ie, the
> number of pixels), a control validation will imply over ahuge number
> of function calls.
> 
> In the case of the matrix you are always validating/init all the
> values of of the array. Why dont we modify the type_ops so they
> operate on the whole matrix (remove the idx from the function).

I actually considered that, but rejected it (for now) because I want
to see a realistic use-case first. If you get such large matrices, then
you have to ask yourself whether the control framework is the right
approach anyway, and if it is, whether you want to do these validations
in the first place.

Also note that validations typically will still have to be done on a
per-element basis (so pushing down the loop over all elements into the
validation function will have little effect) and ditto for the more
complex comparisons. Only if you are able to do something like memcmp
to compare two matrices will it become beneficial to optimize this.

I see this as a possible future performance enhancement and before doing
that I need to see a good use-case and also see some performence measurements.

> Anyway we should modify
> 
> for (idx = 0; idx < ctrl->rows * ctrl->cols; idx++)
>                ctrl_changed |= !ctrl->type_ops->equal(ctrl, idx,
> ctrl->stores[0], ctrl->new);
> 
> to
> 
> for (idx = 0; idx < ctrl->rows * ctrl->cols; idx++)
>                if (!ctrl->type_ops->equal(ctrl, idx, ctrl->stores[0],
> ctrl->new))
>                                 break
> 
> if (idx==ctrl->rows * ctrl->col)
>  ctrol_changed=true;
> 
> Saving us some calls when we already know that the control has changed.

Oops! Absolutely, thanks for pointing this out.  That's a left-over from
older code.

I'll post a patch for this.

Regards,

	Hans

> 
> 
> Thanks!
> 
> 
> ps: consider all my code pseudocode :P
> 
> 
> On Mon, Feb 10, 2014 at 9:46 AM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
>> 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 67e5d1e..988a2bd8 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;
>> @@ -1715,6 +1811,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;
>> @@ -1736,19 +1833,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;
>> @@ -1793,7 +1887,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,
>> @@ -1821,7 +1915,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);
>>  }
>> @@ -1855,7 +1949,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);
>>  }
>> @@ -1888,7 +1982,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);
>>
>>  }
>> @@ -1913,7 +2008,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);
>>  }
>> @@ -2096,32 +2191,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.5.2
>>
>> --
>> 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] 52+ messages in thread

* [REVIEWv2 PATCH 36/34] v4l2-ctrls: break off loop on first changed element
  2014-02-10  8:46 [REVIEWv2 PATCH 00/34] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (33 preceding siblings ...)
  2014-02-10  8:46 ` [REVIEWv2 PATCH 34/34] go7007: add motion detection support Hans Verkuil
@ 2014-02-12 11:39 ` Hans Verkuil
  2014-02-16 20:14 ` [REVIEWv2 PATCH 00/34] Add support for complex controls, use in solo/go7007 Sakari Ailus
  35 siblings, 0 replies; 52+ messages in thread
From: Hans Verkuil @ 2014-02-12 11:39 UTC (permalink / raw)
  To: linux-media; +Cc: m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete

There is no need to loop over all elements of a matrix checking if
there are changes. Just stop at the first changed element.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Reported-by: Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com>
---
 drivers/media/v4l2-core/v4l2-ctrls.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index e8e2caa..23febc4 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1502,8 +1502,9 @@ static int cluster_changed(struct v4l2_ctrl *master)
 
 		if (ctrl == NULL)
 			continue;
-		for (idx = 0; idx < ctrl->rows * ctrl->cols; idx++)
-			ctrl_changed |= !ctrl->type_ops->equal(ctrl, idx,
+		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;
-- 
1.8.5.2



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

* Re: [REVIEWv2 PATCH 08/34] v4l2-ctrls: create type_ops.
  2014-02-12 11:36     ` Hans Verkuil
@ 2014-02-12 12:03       ` Ricardo Ribalda Delgado
  2014-02-12 12:31         ` Hans Verkuil
  0 siblings, 1 reply; 52+ messages in thread
From: Ricardo Ribalda Delgado @ 2014-02-12 12:03 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: linux-media, Mauro Carvalho Chehab, Laurent Pinchart,
	Sylwester Nawrocki, Ismael Luceno, pete, Hans Verkuil

Hello Hans

My usercase is different gain and offset per pixel (non uniformity
correction). My sensor is now 4 Mpx, and probably 12 Mpx soon :)

Right now it is implemented as a video output... but I think that I am
exploiting an API :)

Regards!

On Wed, Feb 12, 2014 at 12:36 PM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
> On 02/12/14 11:55, Ricardo Ribalda Delgado wrote:
>> Hello Hans
>>
>> If we have a matrix control with a huge number of elements (ie, the
>> number of pixels), a control validation will imply over ahuge number
>> of function calls.
>>
>> In the case of the matrix you are always validating/init all the
>> values of of the array. Why dont we modify the type_ops so they
>> operate on the whole matrix (remove the idx from the function).
>
> I actually considered that, but rejected it (for now) because I want
> to see a realistic use-case first. If you get such large matrices, then
> you have to ask yourself whether the control framework is the right
> approach anyway, and if it is, whether you want to do these validations
> in the first place.
>
> Also note that validations typically will still have to be done on a
> per-element basis (so pushing down the loop over all elements into the
> validation function will have little effect) and ditto for the more
> complex comparisons. Only if you are able to do something like memcmp
> to compare two matrices will it become beneficial to optimize this.
>
> I see this as a possible future performance enhancement and before doing
> that I need to see a good use-case and also see some performence measurements.
>
>> Anyway we should modify
>>
>> for (idx = 0; idx < ctrl->rows * ctrl->cols; idx++)
>>                ctrl_changed |= !ctrl->type_ops->equal(ctrl, idx,
>> ctrl->stores[0], ctrl->new);
>>
>> to
>>
>> for (idx = 0; idx < ctrl->rows * ctrl->cols; idx++)
>>                if (!ctrl->type_ops->equal(ctrl, idx, ctrl->stores[0],
>> ctrl->new))
>>                                 break
>>
>> if (idx==ctrl->rows * ctrl->col)
>>  ctrol_changed=true;
>>
>> Saving us some calls when we already know that the control has changed.
>
> Oops! Absolutely, thanks for pointing this out.  That's a left-over from
> older code.
>
> I'll post a patch for this.
>
> Regards,
>
>         Hans
>
>>
>>
>> Thanks!
>>
>>
>> ps: consider all my code pseudocode :P
>>
>>
>> On Mon, Feb 10, 2014 at 9:46 AM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
>>> 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 67e5d1e..988a2bd8 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;
>>> @@ -1715,6 +1811,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;
>>> @@ -1736,19 +1833,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;
>>> @@ -1793,7 +1887,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,
>>> @@ -1821,7 +1915,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);
>>>  }
>>> @@ -1855,7 +1949,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);
>>>  }
>>> @@ -1888,7 +1982,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);
>>>
>>>  }
>>> @@ -1913,7 +2008,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);
>>>  }
>>> @@ -2096,32 +2191,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.5.2
>>>
>>> --
>>> 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] 52+ messages in thread

* Re: [REVIEWv2 PATCH 24/34] v4l2-ctrls/videodev2.h: add u8 and u16 types.
  2014-02-12 11:20     ` Hans Verkuil
@ 2014-02-12 12:11       ` Ricardo Ribalda Delgado
  2014-02-12 12:40         ` Hans Verkuil
  0 siblings, 1 reply; 52+ messages in thread
From: Ricardo Ribalda Delgado @ 2014-02-12 12:11 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: linux-media, Mauro Carvalho Chehab, Laurent Pinchart,
	Sylwester Nawrocki, Ismael Luceno, pete, Hans Verkuil

Hi Hans

Thanks for your reply

On Wed, Feb 12, 2014 at 12:20 PM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
> Hi Ricardo,
>
> On 02/12/14 11:44, Ricardo Ribalda Delgado wrote:
>> Hello Hans
>>
>> In the case of U8 and U16 data types. Why dont you fill the elem_size
>> automatically in v4l2_ctrl and request the driver to fill the field?
>
> When you create the control the control framework has to know the element
> size beforehand as it will use that to allocate the memory containing the
> control's value. The control framework is aware of the 'old' control types
> and will fill in the elem_size accordingly, but it cannot do that in the
> general case for these complex types. I guess it could be filled in by the
> framework for the more common types (U8, U16) but I felt it was more
> consistent to just require drivers to fill it in manually, rather than have
> it set for some types but not for others.
>
>>
>> Other option would be not declaring the basic data types (U8, U16,
>> U32...) and use elem_size. Ie. If type==V4L2_CTRL_COMPLEX_TYPES, then
>> the type is basic and elem_size is the size of the type. If the type
>>> V4L2_CTRL_COMPLEX_TYPES the type is not basic.
>
> You still need to know the type. Applications have to be able to check for
> the type, the element size by itself doesn't tell you how to interpret the
> data, you need the type identifier as well.

I think that the driver is setting twice the same info. I see no gain
in declaring U8, U16 types etc if we still have to set the element
size. This is why I believe that we should only declare the "structs".

what about something like: V4L2_CTRL_COMPLEX_TYPE_SIGNED_INTEGER +
size, V4L2_CTRL_COMPLEX_TYPES_UNSIGNED_INTEGER + size.... instead of
V4L2_CTRL_COMPLEX_TYPES_U8, V4L2_CTRL_COMPLEX_TYPES_U16,
V4L2_CTRL_COMPLEX_TYPES_U32, V4L2_CTRL_COMPLEX_TYPES_S8 ....

Btw, I am trying to implement a dead pixel control on the top of you
api. Shall I wait until you patchset is merged or shall I send the
patches right away?


Thanks!!!!

>
> Regards,
>
>         Hans
>
>>
>> Thanks!
>>
>> On Mon, Feb 10, 2014 at 9:46 AM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
>>> 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 | 24 ++++++++++++++++++++++++
>>>  include/media/v4l2-ctrls.h           |  4 ++++
>>>  include/uapi/linux/videodev2.h       |  4 ++++
>>>  3 files changed, 32 insertions(+)
>>>
>>> diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
>>> index c81ebcf..0b200dd 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];
>>> @@ -1469,6 +1489,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)
>>> @@ -3119,6 +3141,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.5.2
>>>
>>> --
>>> 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] 52+ messages in thread

* Re: [REVIEWv2 PATCH 08/34] v4l2-ctrls: create type_ops.
  2014-02-12 12:03       ` Ricardo Ribalda Delgado
@ 2014-02-12 12:31         ` Hans Verkuil
  2014-02-12 13:03           ` Ricardo Ribalda Delgado
  0 siblings, 1 reply; 52+ messages in thread
From: Hans Verkuil @ 2014-02-12 12:31 UTC (permalink / raw)
  To: Ricardo Ribalda Delgado
  Cc: linux-media, Mauro Carvalho Chehab, Laurent Pinchart,
	Sylwester Nawrocki, Ismael Luceno, pete, Hans Verkuil

On 02/12/14 13:03, Ricardo Ribalda Delgado wrote:
> Hello Hans
> 
> My usercase is different gain and offset per pixel (non uniformity
> correction). My sensor is now 4 Mpx, and probably 12 Mpx soon :)

The hardware actually supports per pixel gain and offset?! Wow.

Anyway, I am not opposed to making changes in this area (although I want
this to be merged first), provided you also do some performance measurements.

I am also assuming that such large matrices only rarely change, so to
what extent performance improvements have any real-life effect may be
debatable.

Regards,

	Hans

> 
> Right now it is implemented as a video output... but I think that I am
> exploiting an API :)
> 
> Regards!
> 
> On Wed, Feb 12, 2014 at 12:36 PM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
>> On 02/12/14 11:55, Ricardo Ribalda Delgado wrote:
>>> Hello Hans
>>>
>>> If we have a matrix control with a huge number of elements (ie, the
>>> number of pixels), a control validation will imply over ahuge number
>>> of function calls.
>>>
>>> In the case of the matrix you are always validating/init all the
>>> values of of the array. Why dont we modify the type_ops so they
>>> operate on the whole matrix (remove the idx from the function).
>>
>> I actually considered that, but rejected it (for now) because I want
>> to see a realistic use-case first. If you get such large matrices, then
>> you have to ask yourself whether the control framework is the right
>> approach anyway, and if it is, whether you want to do these validations
>> in the first place.
>>
>> Also note that validations typically will still have to be done on a
>> per-element basis (so pushing down the loop over all elements into the
>> validation function will have little effect) and ditto for the more
>> complex comparisons. Only if you are able to do something like memcmp
>> to compare two matrices will it become beneficial to optimize this.
>>
>> I see this as a possible future performance enhancement and before doing
>> that I need to see a good use-case and also see some performence measurements.
>>
>>> Anyway we should modify
>>>
>>> for (idx = 0; idx < ctrl->rows * ctrl->cols; idx++)
>>>                ctrl_changed |= !ctrl->type_ops->equal(ctrl, idx,
>>> ctrl->stores[0], ctrl->new);
>>>
>>> to
>>>
>>> for (idx = 0; idx < ctrl->rows * ctrl->cols; idx++)
>>>                if (!ctrl->type_ops->equal(ctrl, idx, ctrl->stores[0],
>>> ctrl->new))
>>>                                 break
>>>
>>> if (idx==ctrl->rows * ctrl->col)
>>>  ctrol_changed=true;
>>>
>>> Saving us some calls when we already know that the control has changed.
>>
>> Oops! Absolutely, thanks for pointing this out.  That's a left-over from
>> older code.
>>
>> I'll post a patch for this.
>>
>> Regards,
>>
>>         Hans
>>
>>>
>>>
>>> Thanks!
>>>
>>>
>>> ps: consider all my code pseudocode :P
>>>
>>>
>>> On Mon, Feb 10, 2014 at 9:46 AM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
>>>> 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 67e5d1e..988a2bd8 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;
>>>> @@ -1715,6 +1811,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;
>>>> @@ -1736,19 +1833,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;
>>>> @@ -1793,7 +1887,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,
>>>> @@ -1821,7 +1915,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);
>>>>  }
>>>> @@ -1855,7 +1949,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);
>>>>  }
>>>> @@ -1888,7 +1982,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);
>>>>
>>>>  }
>>>> @@ -1913,7 +2008,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);
>>>>  }
>>>> @@ -2096,32 +2191,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.5.2
>>>>
>>>> --
>>>> 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] 52+ messages in thread

* Re: [REVIEWv2 PATCH 24/34] v4l2-ctrls/videodev2.h: add u8 and u16 types.
  2014-02-12 12:11       ` Ricardo Ribalda Delgado
@ 2014-02-12 12:40         ` Hans Verkuil
  2014-02-12 13:13           ` Ricardo Ribalda Delgado
  0 siblings, 1 reply; 52+ messages in thread
From: Hans Verkuil @ 2014-02-12 12:40 UTC (permalink / raw)
  To: Ricardo Ribalda Delgado
  Cc: linux-media, Mauro Carvalho Chehab, Laurent Pinchart,
	Sylwester Nawrocki, Ismael Luceno, pete, Hans Verkuil

On 02/12/14 13:11, Ricardo Ribalda Delgado wrote:
> Hi Hans
> 
> Thanks for your reply
> 
> On Wed, Feb 12, 2014 at 12:20 PM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
>> Hi Ricardo,
>>
>> On 02/12/14 11:44, Ricardo Ribalda Delgado wrote:
>>> Hello Hans
>>>
>>> In the case of U8 and U16 data types. Why dont you fill the elem_size
>>> automatically in v4l2_ctrl and request the driver to fill the field?
>>
>> When you create the control the control framework has to know the element
>> size beforehand as it will use that to allocate the memory containing the
>> control's value. The control framework is aware of the 'old' control types
>> and will fill in the elem_size accordingly, but it cannot do that in the
>> general case for these complex types. I guess it could be filled in by the
>> framework for the more common types (U8, U16) but I felt it was more
>> consistent to just require drivers to fill it in manually, rather than have
>> it set for some types but not for others.
>>
>>>
>>> Other option would be not declaring the basic data types (U8, U16,
>>> U32...) and use elem_size. Ie. If type==V4L2_CTRL_COMPLEX_TYPES, then
>>> the type is basic and elem_size is the size of the type. If the type
>>>> V4L2_CTRL_COMPLEX_TYPES the type is not basic.
>>
>> You still need to know the type. Applications have to be able to check for
>> the type, the element size by itself doesn't tell you how to interpret the
>> data, you need the type identifier as well.
> 
> I think that the driver is setting twice the same info. I see no gain
> in declaring U8, U16 types etc if we still have to set the element
> size. This is why I believe that we should only declare the "structs".

Just to make sure I understand you: for simple types like U8/U16 you want
the control framework to fill in elem_size, for more complex types (structs)
you want the driver to fill in elem_size?
 
> what about something like: V4L2_CTRL_COMPLEX_TYPE_SIGNED_INTEGER +
> size, V4L2_CTRL_COMPLEX_TYPES_UNSIGNED_INTEGER + size.... instead of
> V4L2_CTRL_COMPLEX_TYPES_U8, V4L2_CTRL_COMPLEX_TYPES_U16,
> V4L2_CTRL_COMPLEX_TYPES_U32, V4L2_CTRL_COMPLEX_TYPES_S8 ....
> 
> Btw, I am trying to implement a dead pixel control on the top of you
> api. Shall I wait until you patchset is merged or shall I send the
> patches right away?

You're free to experiment, but I am not going to ask Mauro to pull additional
patches as long as this initial patch set isn't merged.

Regards,

	Hans

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

* Re: [REVIEWv2 PATCH 08/34] v4l2-ctrls: create type_ops.
  2014-02-12 12:31         ` Hans Verkuil
@ 2014-02-12 13:03           ` Ricardo Ribalda Delgado
  0 siblings, 0 replies; 52+ messages in thread
From: Ricardo Ribalda Delgado @ 2014-02-12 13:03 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: linux-media, Mauro Carvalho Chehab, Laurent Pinchart,
	Sylwester Nawrocki, Ismael Luceno, pete, Hans Verkuil

Agree

I wont complain until I have some  performance measurement :)


Thanks!

On Wed, Feb 12, 2014 at 1:31 PM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
> On 02/12/14 13:03, Ricardo Ribalda Delgado wrote:
>> Hello Hans
>>
>> My usercase is different gain and offset per pixel (non uniformity
>> correction). My sensor is now 4 Mpx, and probably 12 Mpx soon :)
>
> The hardware actually supports per pixel gain and offset?! Wow.
>
> Anyway, I am not opposed to making changes in this area (although I want
> this to be merged first), provided you also do some performance measurements.
>
> I am also assuming that such large matrices only rarely change, so to
> what extent performance improvements have any real-life effect may be
> debatable.
>
> Regards,
>
>         Hans
>
>>
>> Right now it is implemented as a video output... but I think that I am
>> exploiting an API :)
>>
>> Regards!
>>
>> On Wed, Feb 12, 2014 at 12:36 PM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
>>> On 02/12/14 11:55, Ricardo Ribalda Delgado wrote:
>>>> Hello Hans
>>>>
>>>> If we have a matrix control with a huge number of elements (ie, the
>>>> number of pixels), a control validation will imply over ahuge number
>>>> of function calls.
>>>>
>>>> In the case of the matrix you are always validating/init all the
>>>> values of of the array. Why dont we modify the type_ops so they
>>>> operate on the whole matrix (remove the idx from the function).
>>>
>>> I actually considered that, but rejected it (for now) because I want
>>> to see a realistic use-case first. If you get such large matrices, then
>>> you have to ask yourself whether the control framework is the right
>>> approach anyway, and if it is, whether you want to do these validations
>>> in the first place.
>>>
>>> Also note that validations typically will still have to be done on a
>>> per-element basis (so pushing down the loop over all elements into the
>>> validation function will have little effect) and ditto for the more
>>> complex comparisons. Only if you are able to do something like memcmp
>>> to compare two matrices will it become beneficial to optimize this.
>>>
>>> I see this as a possible future performance enhancement and before doing
>>> that I need to see a good use-case and also see some performence measurements.
>>>
>>>> Anyway we should modify
>>>>
>>>> for (idx = 0; idx < ctrl->rows * ctrl->cols; idx++)
>>>>                ctrl_changed |= !ctrl->type_ops->equal(ctrl, idx,
>>>> ctrl->stores[0], ctrl->new);
>>>>
>>>> to
>>>>
>>>> for (idx = 0; idx < ctrl->rows * ctrl->cols; idx++)
>>>>                if (!ctrl->type_ops->equal(ctrl, idx, ctrl->stores[0],
>>>> ctrl->new))
>>>>                                 break
>>>>
>>>> if (idx==ctrl->rows * ctrl->col)
>>>>  ctrol_changed=true;
>>>>
>>>> Saving us some calls when we already know that the control has changed.
>>>
>>> Oops! Absolutely, thanks for pointing this out.  That's a left-over from
>>> older code.
>>>
>>> I'll post a patch for this.
>>>
>>> Regards,
>>>
>>>         Hans
>>>
>>>>
>>>>
>>>> Thanks!
>>>>
>>>>
>>>> ps: consider all my code pseudocode :P
>>>>
>>>>
>>>> On Mon, Feb 10, 2014 at 9:46 AM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
>>>>> 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 67e5d1e..988a2bd8 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;
>>>>> @@ -1715,6 +1811,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;
>>>>> @@ -1736,19 +1833,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;
>>>>> @@ -1793,7 +1887,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,
>>>>> @@ -1821,7 +1915,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);
>>>>>  }
>>>>> @@ -1855,7 +1949,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);
>>>>>  }
>>>>> @@ -1888,7 +1982,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);
>>>>>
>>>>>  }
>>>>> @@ -1913,7 +2008,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);
>>>>>  }
>>>>> @@ -2096,32 +2191,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.5.2
>>>>>
>>>>> --
>>>>> 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] 52+ messages in thread

* Re: [REVIEWv2 PATCH 24/34] v4l2-ctrls/videodev2.h: add u8 and u16 types.
  2014-02-12 12:40         ` Hans Verkuil
@ 2014-02-12 13:13           ` Ricardo Ribalda Delgado
  2014-02-12 13:26             ` Hans Verkuil
  0 siblings, 1 reply; 52+ messages in thread
From: Ricardo Ribalda Delgado @ 2014-02-12 13:13 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: linux-media, Mauro Carvalho Chehab, Laurent Pinchart,
	Sylwester Nawrocki, Ismael Luceno, pete, Hans Verkuil

Hello Hans

Thanks for you promptly response

On Wed, Feb 12, 2014 at 1:40 PM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
> On 02/12/14 13:11, Ricardo Ribalda Delgado wrote:
>> Hi Hans
>>
>> Thanks for your reply
>>
>> On Wed, Feb 12, 2014 at 12:20 PM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
>>> Hi Ricardo,
>>>
>>> On 02/12/14 11:44, Ricardo Ribalda Delgado wrote:
>>>> Hello Hans
>>>>
>>>> In the case of U8 and U16 data types. Why dont you fill the elem_size
>>>> automatically in v4l2_ctrl and request the driver to fill the field?
>>>
>>> When you create the control the control framework has to know the element
>>> size beforehand as it will use that to allocate the memory containing the
>>> control's value. The control framework is aware of the 'old' control types
>>> and will fill in the elem_size accordingly, but it cannot do that in the
>>> general case for these complex types. I guess it could be filled in by the
>>> framework for the more common types (U8, U16) but I felt it was more
>>> consistent to just require drivers to fill it in manually, rather than have
>>> it set for some types but not for others.
>>>
>>>>
>>>> Other option would be not declaring the basic data types (U8, U16,
>>>> U32...) and use elem_size. Ie. If type==V4L2_CTRL_COMPLEX_TYPES, then
>>>> the type is basic and elem_size is the size of the type. If the type
>>>>> V4L2_CTRL_COMPLEX_TYPES the type is not basic.
>>>
>>> You still need to know the type. Applications have to be able to check for
>>> the type, the element size by itself doesn't tell you how to interpret the
>>> data, you need the type identifier as well.
>>
>> I think that the driver is setting twice the same info. I see no gain
>> in declaring U8, U16 types etc if we still have to set the element
>> size. This is why I believe that we should only declare the "structs".
>
> Just to make sure I understand you: for simple types like U8/U16 you want
> the control framework to fill in elem_size, for more complex types (structs)
> you want the driver to fill in elem_size?

I dont like that the type contains the size of the element, and then I
have to provide the size again. (Hungarian notation)

Instead, I think it is better:

Defines ONLY this two types for simple types:
V4L2_CTRL_COMPLEX_TYPE_SIGNED_INTEGER and
V4L2_CTRL_COMPLEX_TYPE_UNSIGNED_INTEGER and use elem_size to determine
the size.

And then one define per "structured types"  ie:
V4L2_CTRL_COMPLEX_TYPE_POINT V4L2_CTRL_COMPLEX_TYPE_IRRATIONAL.. with
elem_size determining the size.

But if you dont like that idea, as second preference  then I think
elem_size should be filled by the subsystem for simple types.


Thanks!
>
>> what about something like: V4L2_CTRL_COMPLEX_TYPE_SIGNED_INTEGER +
>> size, V4L2_CTRL_COMPLEX_TYPES_UNSIGNED_INTEGER + size.... instead of
>> V4L2_CTRL_COMPLEX_TYPES_U8, V4L2_CTRL_COMPLEX_TYPES_U16,
>> V4L2_CTRL_COMPLEX_TYPES_U32, V4L2_CTRL_COMPLEX_TYPES_S8 ....
>>
>> Btw, I am trying to implement a dead pixel control on the top of you
>> api. Shall I wait until you patchset is merged or shall I send the
>> patches right away?
>
> You're free to experiment, but I am not going to ask Mauro to pull additional
> patches as long as this initial patch set isn't merged.
>
> Regards,
>
>         Hans





-- 
Ricardo Ribalda

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

* Re: [REVIEWv2 PATCH 24/34] v4l2-ctrls/videodev2.h: add u8 and u16 types.
  2014-02-12 13:13           ` Ricardo Ribalda Delgado
@ 2014-02-12 13:26             ` Hans Verkuil
  2014-02-12 13:40               ` Ricardo Ribalda Delgado
  0 siblings, 1 reply; 52+ messages in thread
From: Hans Verkuil @ 2014-02-12 13:26 UTC (permalink / raw)
  To: Ricardo Ribalda Delgado
  Cc: linux-media, Mauro Carvalho Chehab, Laurent Pinchart,
	Sylwester Nawrocki, Ismael Luceno, pete, Hans Verkuil

On 02/12/14 14:13, Ricardo Ribalda Delgado wrote:
> Hello Hans
> 
> Thanks for you promptly response
> 
> On Wed, Feb 12, 2014 at 1:40 PM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
>> On 02/12/14 13:11, Ricardo Ribalda Delgado wrote:
>>> Hi Hans
>>>
>>> Thanks for your reply
>>>
>>> On Wed, Feb 12, 2014 at 12:20 PM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
>>>> Hi Ricardo,
>>>>
>>>> On 02/12/14 11:44, Ricardo Ribalda Delgado wrote:
>>>>> Hello Hans
>>>>>
>>>>> In the case of U8 and U16 data types. Why dont you fill the elem_size
>>>>> automatically in v4l2_ctrl and request the driver to fill the field?
>>>>
>>>> When you create the control the control framework has to know the element
>>>> size beforehand as it will use that to allocate the memory containing the
>>>> control's value. The control framework is aware of the 'old' control types
>>>> and will fill in the elem_size accordingly, but it cannot do that in the
>>>> general case for these complex types. I guess it could be filled in by the
>>>> framework for the more common types (U8, U16) but I felt it was more
>>>> consistent to just require drivers to fill it in manually, rather than have
>>>> it set for some types but not for others.
>>>>
>>>>>
>>>>> Other option would be not declaring the basic data types (U8, U16,
>>>>> U32...) and use elem_size. Ie. If type==V4L2_CTRL_COMPLEX_TYPES, then
>>>>> the type is basic and elem_size is the size of the type. If the type
>>>>>> V4L2_CTRL_COMPLEX_TYPES the type is not basic.
>>>>
>>>> You still need to know the type. Applications have to be able to check for
>>>> the type, the element size by itself doesn't tell you how to interpret the
>>>> data, you need the type identifier as well.
>>>
>>> I think that the driver is setting twice the same info. I see no gain
>>> in declaring U8, U16 types etc if we still have to set the element
>>> size. This is why I believe that we should only declare the "structs".
>>
>> Just to make sure I understand you: for simple types like U8/U16 you want
>> the control framework to fill in elem_size, for more complex types (structs)
>> you want the driver to fill in elem_size?
> 
> I dont like that the type contains the size of the element, and then I
> have to provide the size again. (Hungarian notation)
> 
> Instead, I think it is better:
> 
> Defines ONLY this two types for simple types:
> V4L2_CTRL_COMPLEX_TYPE_SIGNED_INTEGER and
> V4L2_CTRL_COMPLEX_TYPE_UNSIGNED_INTEGER and use elem_size to determine
> the size.

It sounds great, but it isn't in practice because this will produce awful
code like this:

switch (type) {
case V4L2_CTRL_COMPLEX_TYPE_SIGNED_INTEGER:
	switch (elem_size) {
	case 1: // it's a u8!
		break;
	case 2: // it's a u16!
		break;
	}
etc.
}

It makes for very awkward code, both in the kernel and in applications.

> And then one define per "structured types"  ie:
> V4L2_CTRL_COMPLEX_TYPE_POINT V4L2_CTRL_COMPLEX_TYPE_IRRATIONAL.. with
> elem_size determining the size.
> 
> But if you dont like that idea, as second preference  then I think
> elem_size should be filled by the subsystem for simple types.

I think having the framework fill in elem_size for the basic types such
as u8 and u16 does make sense. These are already handled by the standard
number validators, so we should probably have the elem_size set as well.

Regards,

	Hans

> 
> 
> Thanks!
>>
>>> what about something like: V4L2_CTRL_COMPLEX_TYPE_SIGNED_INTEGER +
>>> size, V4L2_CTRL_COMPLEX_TYPES_UNSIGNED_INTEGER + size.... instead of
>>> V4L2_CTRL_COMPLEX_TYPES_U8, V4L2_CTRL_COMPLEX_TYPES_U16,
>>> V4L2_CTRL_COMPLEX_TYPES_U32, V4L2_CTRL_COMPLEX_TYPES_S8 ....
>>>
>>> Btw, I am trying to implement a dead pixel control on the top of you
>>> api. Shall I wait until you patchset is merged or shall I send the
>>> patches right away?
>>
>> You're free to experiment, but I am not going to ask Mauro to pull additional
>> patches as long as this initial patch set isn't merged.
>>
>> Regards,
>>
>>         Hans
> 
> 
> 
> 
> 


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

* Re: [REVIEWv2 PATCH 24/34] v4l2-ctrls/videodev2.h: add u8 and u16 types.
  2014-02-12 13:26             ` Hans Verkuil
@ 2014-02-12 13:40               ` Ricardo Ribalda Delgado
  2014-02-12 14:05                 ` Hans Verkuil
  0 siblings, 1 reply; 52+ messages in thread
From: Ricardo Ribalda Delgado @ 2014-02-12 13:40 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: linux-media, Mauro Carvalho Chehab, Laurent Pinchart,
	Sylwester Nawrocki, Ismael Luceno, pete, Hans Verkuil

Hello Hans



On Wed, Feb 12, 2014 at 2:26 PM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
> On 02/12/14 14:13, Ricardo Ribalda Delgado wrote:
>> Hello Hans
>>
>> Thanks for you promptly response
>>
>> On Wed, Feb 12, 2014 at 1:40 PM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
>>> On 02/12/14 13:11, Ricardo Ribalda Delgado wrote:
>>>> Hi Hans
>>>>
>>>> Thanks for your reply
>>>>
>>>> On Wed, Feb 12, 2014 at 12:20 PM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
>>>>> Hi Ricardo,
>>>>>
>>>>> On 02/12/14 11:44, Ricardo Ribalda Delgado wrote:
>>>>>> Hello Hans
>>>>>>
>>>>>> In the case of U8 and U16 data types. Why dont you fill the elem_size
>>>>>> automatically in v4l2_ctrl and request the driver to fill the field?
>>>>>
>>>>> When you create the control the control framework has to know the element
>>>>> size beforehand as it will use that to allocate the memory containing the
>>>>> control's value. The control framework is aware of the 'old' control types
>>>>> and will fill in the elem_size accordingly, but it cannot do that in the
>>>>> general case for these complex types. I guess it could be filled in by the
>>>>> framework for the more common types (U8, U16) but I felt it was more
>>>>> consistent to just require drivers to fill it in manually, rather than have
>>>>> it set for some types but not for others.
>>>>>
>>>>>>
>>>>>> Other option would be not declaring the basic data types (U8, U16,
>>>>>> U32...) and use elem_size. Ie. If type==V4L2_CTRL_COMPLEX_TYPES, then
>>>>>> the type is basic and elem_size is the size of the type. If the type
>>>>>>> V4L2_CTRL_COMPLEX_TYPES the type is not basic.
>>>>>
>>>>> You still need to know the type. Applications have to be able to check for
>>>>> the type, the element size by itself doesn't tell you how to interpret the
>>>>> data, you need the type identifier as well.
>>>>
>>>> I think that the driver is setting twice the same info. I see no gain
>>>> in declaring U8, U16 types etc if we still have to set the element
>>>> size. This is why I believe that we should only declare the "structs".
>>>
>>> Just to make sure I understand you: for simple types like U8/U16 you want
>>> the control framework to fill in elem_size, for more complex types (structs)
>>> you want the driver to fill in elem_size?
>>
>> I dont like that the type contains the size of the element, and then I
>> have to provide the size again. (Hungarian notation)
>>
>> Instead, I think it is better:
>>
>> Defines ONLY this two types for simple types:
>> V4L2_CTRL_COMPLEX_TYPE_SIGNED_INTEGER and
>> V4L2_CTRL_COMPLEX_TYPE_UNSIGNED_INTEGER and use elem_size to determine
>> the size.
>
> It sounds great, but it isn't in practice because this will produce awful
> code like this:
>
> switch (type) {
> case V4L2_CTRL_COMPLEX_TYPE_SIGNED_INTEGER:
>         switch (elem_size) {
>         case 1: // it's a u8!
>                 break;
>         case 2: // it's a u16!
>                 break;
>         }
> etc.
> }

I slightly disagree here. Your proposal will produce this code:


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;
case V4L2_CTRL_TYPE_U32:
ptr.p_s32[idx] = ctrl->default_value;
break;
case V4L2_CTRL_TYPE_U64:
ptr.p_s64[idx] = ctrl->default_value;
break;
case V4L2_CTRL_TYPE_S8:
ptr.p_s8[idx] = ctrl->default_value;
break;
case V4L2_CTRL_TYPE_S16:
ptr.p_s16[idx] = ctrl->default_value;
break;
case V4L2_CTRL_TYPE_S32:
ptr.p_s32[idx] = ctrl->default_value;
break;
case V4L2_CTRL_TYPE_S64:
ptr.p_s64[idx] = ctrl->default_value;
break;

instead of:


case V4L2_CTRL_COMPLEX_TYPE_SIGNED_INTEGER:
case V4L2_CTRL_COMPLEX_TYPE_UNSIGNED_INTEGER:
memcpy(&ptr.p[idx],&ctrl->default_value,ctrl->elem_size)


Anyway, this is just a opinion, technically, both solutions are fine,
and yours is already implemented and reviewed.

Regards!

>
> It makes for very awkward code, both in the kernel and in applications.
>
>> And then one define per "structured types"  ie:
>> V4L2_CTRL_COMPLEX_TYPE_POINT V4L2_CTRL_COMPLEX_TYPE_IRRATIONAL.. with
>> elem_size determining the size.
>>
>> But if you dont like that idea, as second preference  then I think
>> elem_size should be filled by the subsystem for simple types.
>
> I think having the framework fill in elem_size for the basic types such
> as u8 and u16 does make sense. These are already handled by the standard
> number validators, so we should probably have the elem_size set as well.
>
> Regards,
>
>         Hans
>
>>
>>
>> Thanks!
>>>
>>>> what about something like: V4L2_CTRL_COMPLEX_TYPE_SIGNED_INTEGER +
>>>> size, V4L2_CTRL_COMPLEX_TYPES_UNSIGNED_INTEGER + size.... instead of
>>>> V4L2_CTRL_COMPLEX_TYPES_U8, V4L2_CTRL_COMPLEX_TYPES_U16,
>>>> V4L2_CTRL_COMPLEX_TYPES_U32, V4L2_CTRL_COMPLEX_TYPES_S8 ....
>>>>
>>>> Btw, I am trying to implement a dead pixel control on the top of you
>>>> api. Shall I wait until you patchset is merged or shall I send the
>>>> patches right away?
>>>
>>> You're free to experiment, but I am not going to ask Mauro to pull additional
>>> patches as long as this initial patch set isn't merged.
>>>
>>> Regards,
>>>
>>>         Hans
>>
>>
>>
>>
>>
>



-- 
Ricardo Ribalda

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

* Re: [REVIEWv2 PATCH 24/34] v4l2-ctrls/videodev2.h: add u8 and u16 types.
  2014-02-12 13:40               ` Ricardo Ribalda Delgado
@ 2014-02-12 14:05                 ` Hans Verkuil
  0 siblings, 0 replies; 52+ messages in thread
From: Hans Verkuil @ 2014-02-12 14:05 UTC (permalink / raw)
  To: Ricardo Ribalda Delgado
  Cc: Hans Verkuil, linux-media, Mauro Carvalho Chehab,
	Laurent Pinchart, Sylwester Nawrocki, Ismael Luceno, pete,
	Hans Verkuil



On 02/12/14 14:40, Ricardo Ribalda Delgado wrote:
> Hello Hans
> 
> 
> 
> On Wed, Feb 12, 2014 at 2:26 PM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
>> On 02/12/14 14:13, Ricardo Ribalda Delgado wrote:
>>> Hello Hans
>>>
>>> Thanks for you promptly response
>>>
>>> On Wed, Feb 12, 2014 at 1:40 PM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
>>>> On 02/12/14 13:11, Ricardo Ribalda Delgado wrote:
>>>>> Hi Hans
>>>>>
>>>>> Thanks for your reply
>>>>>
>>>>> On Wed, Feb 12, 2014 at 12:20 PM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
>>>>>> Hi Ricardo,
>>>>>>
>>>>>> On 02/12/14 11:44, Ricardo Ribalda Delgado wrote:
>>>>>>> Hello Hans
>>>>>>>
>>>>>>> In the case of U8 and U16 data types. Why dont you fill the elem_size
>>>>>>> automatically in v4l2_ctrl and request the driver to fill the field?
>>>>>>
>>>>>> When you create the control the control framework has to know the element
>>>>>> size beforehand as it will use that to allocate the memory containing the
>>>>>> control's value. The control framework is aware of the 'old' control types
>>>>>> and will fill in the elem_size accordingly, but it cannot do that in the
>>>>>> general case for these complex types. I guess it could be filled in by the
>>>>>> framework for the more common types (U8, U16) but I felt it was more
>>>>>> consistent to just require drivers to fill it in manually, rather than have
>>>>>> it set for some types but not for others.
>>>>>>
>>>>>>>
>>>>>>> Other option would be not declaring the basic data types (U8, U16,
>>>>>>> U32...) and use elem_size. Ie. If type==V4L2_CTRL_COMPLEX_TYPES, then
>>>>>>> the type is basic and elem_size is the size of the type. If the type
>>>>>>>> V4L2_CTRL_COMPLEX_TYPES the type is not basic.
>>>>>>
>>>>>> You still need to know the type. Applications have to be able to check for
>>>>>> the type, the element size by itself doesn't tell you how to interpret the
>>>>>> data, you need the type identifier as well.
>>>>>
>>>>> I think that the driver is setting twice the same info. I see no gain
>>>>> in declaring U8, U16 types etc if we still have to set the element
>>>>> size. This is why I believe that we should only declare the "structs".
>>>>
>>>> Just to make sure I understand you: for simple types like U8/U16 you want
>>>> the control framework to fill in elem_size, for more complex types (structs)
>>>> you want the driver to fill in elem_size?
>>>
>>> I dont like that the type contains the size of the element, and then I
>>> have to provide the size again. (Hungarian notation)
>>>
>>> Instead, I think it is better:
>>>
>>> Defines ONLY this two types for simple types:
>>> V4L2_CTRL_COMPLEX_TYPE_SIGNED_INTEGER and
>>> V4L2_CTRL_COMPLEX_TYPE_UNSIGNED_INTEGER and use elem_size to determine
>>> the size.
>>
>> It sounds great, but it isn't in practice because this will produce awful
>> code like this:
>>
>> switch (type) {
>> case V4L2_CTRL_COMPLEX_TYPE_SIGNED_INTEGER:
>>         switch (elem_size) {
>>         case 1: // it's a u8!
>>                 break;
>>         case 2: // it's a u16!
>>                 break;
>>         }
>> etc.
>> }
> 
> I slightly disagree here. Your proposal will produce this code:
> 
> 
> 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;
> case V4L2_CTRL_TYPE_U32:
> ptr.p_s32[idx] = ctrl->default_value;
> break;
> case V4L2_CTRL_TYPE_U64:
> ptr.p_s64[idx] = ctrl->default_value;
> break;
> case V4L2_CTRL_TYPE_S8:
> ptr.p_s8[idx] = ctrl->default_value;
> break;
> case V4L2_CTRL_TYPE_S16:
> ptr.p_s16[idx] = ctrl->default_value;
> break;
> case V4L2_CTRL_TYPE_S32:
> ptr.p_s32[idx] = ctrl->default_value;
> break;
> case V4L2_CTRL_TYPE_S64:
> ptr.p_s64[idx] = ctrl->default_value;
> break;
> 
> instead of:
> 
> 
> case V4L2_CTRL_COMPLEX_TYPE_SIGNED_INTEGER:
> case V4L2_CTRL_COMPLEX_TYPE_UNSIGNED_INTEGER:
> memcpy(&ptr.p[idx],&ctrl->default_value,ctrl->elem_size)

Well, no. default_value is a 64-bit value that you can't just memcpy to
a u8 (certainly not on a big-endian system). It's basically why I split
it up, otherwise I would have used the same trick instead of writing it
out for every type.

Regards,

	Hans

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

* Re: [REVIEWv2 PATCH 00/34] Add support for complex controls, use in solo/go7007
  2014-02-10  8:46 [REVIEWv2 PATCH 00/34] Add support for complex controls, use in solo/go7007 Hans Verkuil
                   ` (34 preceding siblings ...)
  2014-02-12 11:39 ` [REVIEWv2 PATCH 36/34] v4l2-ctrls: break off loop on first changed element Hans Verkuil
@ 2014-02-16 20:14 ` Sakari Ailus
  2014-02-17  9:45   ` Hans Verkuil
  35 siblings, 1 reply; 52+ messages in thread
From: Sakari Ailus @ 2014-02-16 20:14 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: linux-media, m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete

Hi Hans,

On Mon, Feb 10, 2014 at 09:46:25AM +0100, Hans Verkuil wrote:
> This patch series adds support for complex controls (aka 'Properties') to

While the patchset extends the concept of extended controls by adding more
data types, they should not be called "properties" since they are not. The
defining aspect of "properties" is to be able to specify to which entity,
sub-device, pad, video buffer queue, flash led etc. object the said property
is related to. This is mostly orthogonal to what kind of data types the
property could have.

There's just a single 32-bit reserved field in struct v4l2_ext_control so
extending the current extended controls (S/G/TRY) interface is not an option
to support properties. A new ABI (but not necessarily even if probably an
API as well) would be needed in any case.

So for the time being I'd wish we continue to use the name "controls" even
if the control type is not one of the traditional ones.

-- 
Kind regards,

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

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

* Re: [REVIEWv2 PATCH 00/34] Add support for complex controls, use in solo/go7007
  2014-02-16 20:14 ` [REVIEWv2 PATCH 00/34] Add support for complex controls, use in solo/go7007 Sakari Ailus
@ 2014-02-17  9:45   ` Hans Verkuil
  0 siblings, 0 replies; 52+ messages in thread
From: Hans Verkuil @ 2014-02-17  9:45 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, m.chehab, laurent.pinchart, s.nawrocki, ismael.luceno, pete

On 02/16/2014 09:14 PM, Sakari Ailus wrote:
> Hi Hans,
> 
> On Mon, Feb 10, 2014 at 09:46:25AM +0100, Hans Verkuil wrote:
>> This patch series adds support for complex controls (aka 'Properties') to
> 
> While the patchset extends the concept of extended controls by adding more
> data types, they should not be called "properties" since they are not. The
> defining aspect of "properties" is to be able to specify to which entity,
> sub-device, pad, video buffer queue, flash led etc. object the said property
> is related to. This is mostly orthogonal to what kind of data types the
> property could have.

For all practical purposes controls are properties. They are properties of
v4l2_subdev, v4l2_device, video_device or v4l2_fh. While we cannot at the moment
assign controls to other v4l2 objects, there is nothing that prevents us from
doing so.

> 
> There's just a single 32-bit reserved field in struct v4l2_ext_control so
> extending the current extended controls (S/G/TRY) interface is not an option
> to support properties. A new ABI (but not necessarily even if probably an
> API as well) would be needed in any case.

Why? I would use that remaining field: the top X bits define the object type
(e.g. PAD) and the lower bits are the object ID (pad number).

> 
> So for the time being I'd wish we continue to use the name "controls" even
> if the control type is not one of the traditional ones.

The cover letter is the only place where the term 'property' is used, mostly
to link into the 'property' discussion we had in the past. But it is a bad idea
to use the that term because they are traditionally called control in V4L2 land.

Mixing those names is just very confusing.

Regards,

	Hans

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

end of thread, other threads:[~2014-02-17  9:47 UTC | newest]

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

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