* [RFCv1 PATCH 00/27] Add property & configuration store support
@ 2014-01-06 14:20 Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 01/27] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
` (27 more replies)
0 siblings, 28 replies; 29+ messages in thread
From: Hans Verkuil @ 2014-01-06 14:20 UTC (permalink / raw)
To: linux-media
This patch series adds support for properties, matrices and configuration
stores to the control framework.
See this RFCv2 for a more detailed discussion:
http://permalink.gmane.org/gmane.linux.drivers.video-input-infrastructure/71822
Changes since that RFCv2 are:
- I dropped the 'property' bit in the control ID, instead a new flag is
added: V4L2_CTRL_FLAG_PROPERTY.
- A V4L2_CTRL_FLAG_IS_PTR flag is added to simplify applications: if set, then
applications need to use the 'p' field instead of 'val' or 'val64'. This can
be deduced from various other fields as well, but that leads to ugly code.
This flag is cheap to set and very helpful in applications.
- Matrix types have been dropped. If cols or rows are > 1, then you have a
matrix, so there is no need for specific matrix types.
- As a result it is no longer possible to set just a sub-rectangle of a
matrix. It is however possible to just set the first X elements of
a matrix/array. It became too complex to deal with the sub-rectangle,
both in the framework, for drivers and for applications, and there are
not enough benefits to warrant that effort.
Other than those changes this patch series implements all the ideas described
in RFCv2.
The first 21 patches are pretty definitive and the only thing missing are
the DocBook patches and a v4l2-controls.txt patch.
Before I write those I would like to get feedback for this API enhancement.
The actual API changes are surprisingly small, and most of the work done in
the patches has more to do with data structure changes needed to simplify
handling the more complex control types than with actual new code.
Patch 22 adds a new event that can deal with the new 64-bit ranges and that
adds a config_store field. However, I am not yet convinced that this is
really needed. Feedback would be welcome.
Patches 23-27 add test code for vivi to test matrices and to test the new
selection properties. This code needs more work, particularly with regards
to naming.
A working v4l2-ctl that can handle the new stuff is available here:
http://git.linuxtv.org/hverkuil/v4l-utils.git/shortlog/refs/heads/propapi
Regards,
Hans
^ permalink raw reply [flat|nested] 29+ messages in thread
* [RFCv1 PATCH 01/27] v4l2-ctrls: increase internal min/max/step/def to 64 bit
2014-01-06 14:20 [RFCv1 PATCH 00/27] Add property & configuration store support Hans Verkuil
@ 2014-01-06 14:21 ` Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 02/27] v4l2-ctrls: add unit string Hans Verkuil
` (26 subsequent siblings)
27 siblings, 0 replies; 29+ messages in thread
From: Hans Verkuil @ 2014-01-06 14:21 UTC (permalink / raw)
To: linux-media; +Cc: 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.
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
drivers/media/v4l2-core/v4l2-common.c | 6 ++-
drivers/media/v4l2-core/v4l2-ctrls.c | 76 +++++++++++++++++------------
drivers/staging/media/msi3101/sdr-msi3101.c | 2 +-
include/media/v4l2-ctrls.h | 38 +++++++--------
4 files changed, 69 insertions(+), 53 deletions(-)
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 fb46790..d36d7f5 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -859,7 +859,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;
@@ -1317,7 +1317,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:
@@ -1325,7 +1325,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:
@@ -1350,23 +1351,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;
@@ -1392,9 +1400,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)
@@ -1618,7 +1623,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)
{
@@ -1703,10 +1708,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,
@@ -1739,7 +1744,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;
@@ -1759,15 +1764,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);
@@ -1788,14 +1795,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.
@@ -1819,12 +1828,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);
@@ -2851,13 +2862,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] 29+ messages in thread
* [RFCv1 PATCH 02/27] v4l2-ctrls: add unit string.
2014-01-06 14:20 [RFCv1 PATCH 00/27] Add property & configuration store support Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 01/27] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
@ 2014-01-06 14:21 ` Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 03/27] v4l2-ctrls: use pr_info/cont instead of printk Hans Verkuil
` (25 subsequent siblings)
27 siblings, 0 replies; 29+ messages in thread
From: Hans Verkuil @ 2014-01-06 14:21 UTC (permalink / raw)
To: linux-media; +Cc: 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>
---
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 d36d7f5..bb63d2a 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -858,8 +858,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;
@@ -1622,7 +1623,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)
@@ -1670,6 +1672,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;
@@ -1704,6 +1707,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;
@@ -1714,8 +1718,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);
@@ -1731,7 +1735,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);
@@ -1747,16 +1751,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);
@@ -1770,6 +1775,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;
@@ -1777,7 +1783,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);
@@ -1788,7 +1794,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);
@@ -1800,6 +1806,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;
@@ -1814,12 +1821,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);
}
@@ -1831,6 +1838,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;
@@ -1838,12 +1846,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] 29+ messages in thread
* [RFCv1 PATCH 03/27] v4l2-ctrls: use pr_info/cont instead of printk.
2014-01-06 14:20 [RFCv1 PATCH 00/27] Add property & configuration store support Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 01/27] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 02/27] v4l2-ctrls: add unit string Hans Verkuil
@ 2014-01-06 14:21 ` Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 04/27] videodev2.h: add initial support for properties Hans Verkuil
` (24 subsequent siblings)
27 siblings, 0 replies; 29+ messages in thread
From: Hans Verkuil @ 2014-01-06 14:21 UTC (permalink / raw)
To: linux-media; +Cc: Hans Verkuil
From: Hans Verkuil <hans.verkuil@cisco.com>
Codingstyle fix.
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.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 bb63d2a..10bfab6 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -2031,45 +2031,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] 29+ messages in thread
* [RFCv1 PATCH 04/27] videodev2.h: add initial support for properties.
2014-01-06 14:20 [RFCv1 PATCH 00/27] Add property & configuration store support Hans Verkuil
` (2 preceding siblings ...)
2014-01-06 14:21 ` [RFCv1 PATCH 03/27] v4l2-ctrls: use pr_info/cont instead of printk Hans Verkuil
@ 2014-01-06 14:21 ` Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 05/27] videodev2.h: add struct v4l2_query_ext_ctrl and VIDIOC_QUERY_EXT_CTRL Hans Verkuil
` (23 subsequent siblings)
27 siblings, 0 replies; 29+ messages in thread
From: Hans Verkuil @ 2014-01-06 14:21 UTC (permalink / raw)
To: linux-media; +Cc: Hans Verkuil
From: Hans Verkuil <hans.verkuil@cisco.com>
Properties are controls that are not shown in GUIs and can be used for
compound and array types.
This allows for more complex datastructures to be used with the
control framework.
Properties will have the V4L2_CTRL_FLAG_PROPERTY flag set. The existing
V4L2_CTRL_FLAG_NEXT_CTRL flag will only enumerate controls, so a new
V4L2_CTRL_FLAG_NEXT_PROP flag is added to enumerate properties. Set both
flags to enumerate both controls and properties.
Property-specific types will start at V4L2_PROP_TYPES. In addition, any
control or property 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>
---
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 437f1b0..c8e2259 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,
+
+ /* Property types are >= 0x0100 */
+ V4L2_PROP_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_PROPERTY 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_PROP 0x40000000
/* User-class control IDs defined by V4L2 */
#define V4L2_CID_MAX_CTRLS 1024
--
1.8.5.2
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [RFCv1 PATCH 05/27] videodev2.h: add struct v4l2_query_ext_ctrl and VIDIOC_QUERY_EXT_CTRL.
2014-01-06 14:20 [RFCv1 PATCH 00/27] Add property & configuration store support Hans Verkuil
` (3 preceding siblings ...)
2014-01-06 14:21 ` [RFCv1 PATCH 04/27] videodev2.h: add initial support for properties Hans Verkuil
@ 2014-01-06 14:21 ` Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 06/27] v4l2-ctrls: add support for properties Hans Verkuil
` (22 subsequent siblings)
27 siblings, 0 replies; 29+ messages in thread
From: Hans Verkuil @ 2014-01-06 14:21 UTC (permalink / raw)
To: linux-media; +Cc: 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/property.
It allows you to query controls in a specific configuration store, 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 c8e2259..2dda52d 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 config_store;
+ __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, rows;
+ __u32 elem_size;
+ __u32 reserved[16];
+};
+
/* 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] 29+ messages in thread
* [RFCv1 PATCH 06/27] v4l2-ctrls: add support for properties.
2014-01-06 14:20 [RFCv1 PATCH 00/27] Add property & configuration store support Hans Verkuil
` (4 preceding siblings ...)
2014-01-06 14:21 ` [RFCv1 PATCH 05/27] videodev2.h: add struct v4l2_query_ext_ctrl and VIDIOC_QUERY_EXT_CTRL Hans Verkuil
@ 2014-01-06 14:21 ` Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 07/27] v4l2: integrate support for VIDIOC_QUERY_EXT_CTRL Hans Verkuil
` (21 subsequent siblings)
27 siblings, 0 replies; 29+ messages in thread
From: Hans Verkuil @ 2014-01-06 14:21 UTC (permalink / raw)
To: linux-media; +Cc: Hans Verkuil
From: Hans Verkuil <hans.verkuil@cisco.com>
This patch implements initial support for simple properties.
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 following 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.
These new fields use the v4l2_ctrl_ptr union, which is a pointer to a control
value.
Note that these two new fields are not yet actually used.
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
drivers/media/v4l2-core/v4l2-ctrls.c | 231 ++++++++++++++++++++++++++---------
include/media/v4l2-ctrls.h | 38 +++++-
2 files changed, 206 insertions(+), 63 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 10bfab6..3927755 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1081,20 +1081,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));
@@ -1103,7 +1089,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;
@@ -1138,6 +1124,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);
@@ -1165,6 +1154,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;
@@ -1199,6 +1191,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);
@@ -1225,6 +1220,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;
@@ -1239,8 +1235,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) {
@@ -1280,7 +1281,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;
}
}
@@ -1493,7 +1497,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;
@@ -1626,23 +1630,46 @@ 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 *props;
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_PROP_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;
}
+ /*
+ * No properties 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_PROPERTY)) {
+ handler_set_err(hdl, -EINVAL);
+ return NULL;
+ }
+ if (!(flags & V4L2_CTRL_FLAG_PROPERTY) && type >= V4L2_PROP_TYPES) {
+ handler_set_err(hdl, -EINVAL);
+ return NULL;
+ }
err = check_range(type, min, max, step, def);
if (err) {
handler_set_err(hdl, err);
@@ -1653,12 +1680,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_PROP_TYPES)
+ sz_extra += 2 * elem_size;
ctrl = kzalloc(sizeof(*ctrl) + sz_extra, GFP_KERNEL);
if (ctrl == NULL) {
@@ -1678,18 +1706,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_PROP_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;
+ props = &ctrl->stores[1];
+
+ if (ctrl->is_string) {
+ ctrl->string = ctrl->new.p_char = props;
+ ctrl->stores[0].p_char = props + 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 = props;
+ ctrl->stores[0].p = props + elem_size;
+ } else {
+ ctrl->new.p = &ctrl->val;
+ ctrl->stores[0].p = &ctrl->cur.val;
}
if (handler_new_ref(hdl, ctrl)) {
kfree(ctrl);
@@ -1738,7 +1779,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;
@@ -1756,13 +1798,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_PROP_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);
@@ -1795,7 +1839,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);
@@ -1827,7 +1872,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);
@@ -1852,7 +1897,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);
@@ -2140,14 +2186,16 @@ 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_PROP;
u32 id = qc->id & V4L2_CTRL_ID_MASK;
+ unsigned store = qc->config_store;
struct v4l2_ctrl_ref *ref;
struct v4l2_ctrl *ctrl;
- if (hdl == NULL)
+ if (hdl == NULL || store)
return -EINVAL;
mutex_lock(hdl->lock);
@@ -2155,7 +2203,15 @@ 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 = V4L2_CTRL_FLAG_PROPERTY;
+ unsigned match = 0;
+
+ if ((qc->id & next_flags) == V4L2_CTRL_FLAG_NEXT_PROP)
+ match = mask;
+ if ((qc->id & next_flags) == next_flags)
+ mask = 0;
+
/* Find the next control with ID > qc->id */
/* Did we reach the end of the control list? */
@@ -2163,19 +2219,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;
@@ -2186,23 +2251,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 = { 0, qc->id };
+ int rc;
+
+ /* VIDIOC_QUERYCTRL cannot be used to enumerate properties */
+ if (qc->flags & V4L2_CTRL_FLAG_NEXT_PROP)
+ 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_PROP))
return -EINVAL;
return v4l2_queryctrl(sd->ctrl_handler, qc);
}
@@ -2302,7 +2407,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;
@@ -2334,6 +2440,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;
@@ -2414,7 +2527,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++)
@@ -2476,11 +2589,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)
@@ -2506,7 +2619,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;
@@ -2525,7 +2638,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;
@@ -2661,7 +2774,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)
@@ -2766,11 +2879,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 */
@@ -2812,7 +2925,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)
@@ -2836,7 +2949,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..38aa230 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.
+ * @val: Pointer to a 32-bit signed value.
+ * @val64: Pointer to a 64-bit signed value.
+ * @string: Pointer to a string.
+ * @p: Pointer to a property 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_PROP_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] 29+ messages in thread
* [RFCv1 PATCH 07/27] v4l2: integrate support for VIDIOC_QUERY_EXT_CTRL.
2014-01-06 14:20 [RFCv1 PATCH 00/27] Add property & configuration store support Hans Verkuil
` (5 preceding siblings ...)
2014-01-06 14:21 ` [RFCv1 PATCH 06/27] v4l2-ctrls: add support for properties Hans Verkuil
@ 2014-01-06 14:21 ` Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 08/27] videodev2.h: add V4L2_CTRL_FLAG_CAN_STORE Hans Verkuil
` (20 subsequent siblings)
27 siblings, 0 replies; 29+ messages in thread
From: Hans Verkuil @ 2014-01-06 14:21 UTC (permalink / raw)
To: linux-media; +Cc: Hans Verkuil
From: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.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 1cc1749..0418871 100644
--- a/drivers/media/v4l2-core/v4l2-dev.c
+++ b/drivers/media/v4l2-core/v4l2-dev.c
@@ -585,6 +585,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 68e6b5e..8d3b2d3 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -512,6 +512,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("config_store=%d, 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->config_store, 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;
@@ -1502,6 +1515,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)
{
@@ -2055,6 +2085,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] 29+ messages in thread
* [RFCv1 PATCH 08/27] videodev2.h: add V4L2_CTRL_FLAG_CAN_STORE
2014-01-06 14:20 [RFCv1 PATCH 00/27] Add property & configuration store support Hans Verkuil
` (6 preceding siblings ...)
2014-01-06 14:21 ` [RFCv1 PATCH 07/27] v4l2: integrate support for VIDIOC_QUERY_EXT_CTRL Hans Verkuil
@ 2014-01-06 14:21 ` Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 09/27] videodev2.h: add config_store to v4l2_ext_controls Hans Verkuil
` (19 subsequent siblings)
27 siblings, 0 replies; 29+ messages in thread
From: Hans Verkuil @ 2014-01-06 14:21 UTC (permalink / raw)
To: linux-media; +Cc: Hans Verkuil
From: Hans Verkuil <hans.verkuil@cisco.com>
Controls/properties that have a configuration store will set this flag.
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
include/uapi/linux/videodev2.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 2dda52d..0803da9 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -1323,6 +1323,7 @@ struct v4l2_querymenu {
#define V4L2_CTRL_FLAG_VOLATILE 0x0080
#define V4L2_CTRL_FLAG_PROPERTY 0x0100
#define V4L2_CTRL_FLAG_IS_PTR 0x0200
+#define V4L2_CTRL_FLAG_CAN_STORE 0x0400
/* Query flags, to be ORed with the control ID */
#define V4L2_CTRL_FLAG_NEXT_CTRL 0x80000000
--
1.8.5.2
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [RFCv1 PATCH 09/27] videodev2.h: add config_store to v4l2_ext_controls
2014-01-06 14:20 [RFCv1 PATCH 00/27] Add property & configuration store support Hans Verkuil
` (7 preceding siblings ...)
2014-01-06 14:21 ` [RFCv1 PATCH 08/27] videodev2.h: add V4L2_CTRL_FLAG_CAN_STORE Hans Verkuil
@ 2014-01-06 14:21 ` Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 10/27] v4l2-ctrls: create type_ops Hans Verkuil
` (18 subsequent siblings)
27 siblings, 0 replies; 29+ messages in thread
From: Hans Verkuil @ 2014-01-06 14:21 UTC (permalink / raw)
To: linux-media; +Cc: Hans Verkuil
From: Hans Verkuil <hans.verkuil@cisco.com>
The ctrl_class is fairly pointless when used with drivers that use the control
framework: you can just fill in 0 and it will just work fine. There are still
some old unconverted drivers that do not support 0 and instead want the control
class there. The idea being that all controls in the list all belong to that
class. This was done to simplify drivers in the absence of the control framework.
When using the control framework the framework itself is smart enough to allow
controls of any class to be included in the control list.
Since configuration store IDs are in the range 1..255 (or so, in any case a relatively
small non-zero positive integer) it makes sense to effectively rename ctrl_class
to config_store. Set it to 0 and you get the normal behavior (you change the current
control value), set it to a configuration store ID and you get/set the control for
that store.
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
include/uapi/linux/videodev2.h | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 0803da9..789f876 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -1233,7 +1233,10 @@ struct v4l2_ext_control {
} __attribute__ ((packed));
struct v4l2_ext_controls {
- __u32 ctrl_class;
+ union {
+ __u32 ctrl_class;
+ __u32 config_store;
+ };
__u32 count;
__u32 error_idx;
__u32 reserved[2];
--
1.8.5.2
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [RFCv1 PATCH 10/27] v4l2-ctrls: create type_ops.
2014-01-06 14:20 [RFCv1 PATCH 00/27] Add property & configuration store support Hans Verkuil
` (8 preceding siblings ...)
2014-01-06 14:21 ` [RFCv1 PATCH 09/27] videodev2.h: add config_store to v4l2_ext_controls Hans Verkuil
@ 2014-01-06 14:21 ` Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 11/27] v4l2-ctrls: rewrite copy routines to operate on union v4l2_ctrl_ptr Hans Verkuil
` (17 subsequent siblings)
27 siblings, 0 replies; 29+ messages in thread
From: Hans Verkuil @ 2014-01-06 14:21 UTC (permalink / raw)
To: linux-media; +Cc: Hans Verkuil
From: Hans Verkuil <hans.verkuil@cisco.com>
Since properties 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>
---
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 3927755..688ca31 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1118,6 +1118,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)
@@ -1301,21 +1444,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;
}
@@ -1356,65 +1485,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);
}
}
@@ -1627,6 +1721,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,
@@ -1638,6 +1733,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
unsigned sz_extra;
void *props;
int err;
+ int s;
if (hdl->error)
return NULL;
@@ -1698,6 +1794,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;
@@ -1719,19 +1816,16 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
ctrl->cur.val = ctrl->val = def;
props = &ctrl->stores[1];
- if (ctrl->is_string) {
- ctrl->string = ctrl->new.p_char = props;
- ctrl->stores[0].p_char = props + 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 = props;
ctrl->stores[0].p = props + 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;
@@ -1776,7 +1870,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,
@@ -1804,7 +1898,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);
}
@@ -1838,7 +1932,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);
}
@@ -1871,7 +1965,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);
}
@@ -1896,7 +1991,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);
}
@@ -2079,32 +2174,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 38aa230..b889778 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 custom properties.
* @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] 29+ messages in thread
* [RFCv1 PATCH 11/27] v4l2-ctrls: rewrite copy routines to operate on union v4l2_ctrl_ptr.
2014-01-06 14:20 [RFCv1 PATCH 00/27] Add property & configuration store support Hans Verkuil
` (9 preceding siblings ...)
2014-01-06 14:21 ` [RFCv1 PATCH 10/27] v4l2-ctrls: create type_ops Hans Verkuil
@ 2014-01-06 14:21 ` Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 12/27] v4l2-ctrls: add initial support for configuration stores Hans Verkuil
` (16 subsequent siblings)
27 siblings, 0 replies; 29+ messages in thread
From: Hans Verkuil @ 2014-01-06 14:21 UTC (permalink / raw)
To: linux-media; +Cc: Hans Verkuil
From: Hans Verkuil <hans.verkuil@cisco.com>
In order to implement 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 688ca31..9b0362e 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1261,48 +1261,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;
@@ -1310,83 +1326,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 &=
@@ -1415,21 +1412,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] 29+ messages in thread
* [RFCv1 PATCH 12/27] v4l2-ctrls: add initial support for configuration stores.
2014-01-06 14:20 [RFCv1 PATCH 00/27] Add property & configuration store support Hans Verkuil
` (10 preceding siblings ...)
2014-01-06 14:21 ` [RFCv1 PATCH 11/27] v4l2-ctrls: rewrite copy routines to operate on union v4l2_ctrl_ptr Hans Verkuil
@ 2014-01-06 14:21 ` Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 13/27] v4l2-ctrls: add function to apply a configuration store Hans Verkuil
` (15 subsequent siblings)
27 siblings, 0 replies; 29+ messages in thread
From: Hans Verkuil @ 2014-01-06 14:21 UTC (permalink / raw)
To: linux-media; +Cc: Hans Verkuil
From: Hans Verkuil <hans.verkuil@cisco.com>
Add support for multiple configuration stores. Three new fields are added to
v4l2_ctrl:
nstores: the number of stores for this control
store: the current store: for use by the control ops
cur_store: the store associated with the current value. Normally 0, but
it can be a specific store if stores map to shadow registers.
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
drivers/media/v4l2-core/v4l2-ctrls.c | 157 +++++++++++++++++++++++++----------
include/media/v4l2-ctrls.h | 11 ++-
2 files changed, 122 insertions(+), 46 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 9b0362e..3e32e21 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1162,7 +1162,7 @@ static void std_init(const struct v4l2_ctrl *ctrl,
static void std_log(const struct v4l2_ctrl *ctrl)
{
- union v4l2_ctrl_ptr ptr = ctrl->stores[0];
+ union v4l2_ctrl_ptr ptr = ctrl->stores[ctrl->cur_store];
switch (ctrl->type) {
case V4L2_CTRL_TYPE_INTEGER:
@@ -1304,6 +1304,13 @@ static int new_to_user(struct v4l2_ext_control *c,
return ptr_to_user(c, ctrl, ctrl->new);
}
+static int store_to_user(struct v4l2_ext_control *c,
+ struct v4l2_ctrl *ctrl,
+ unsigned store)
+{
+ return ptr_to_user(c, ctrl, ctrl->stores[store ? store : ctrl->cur_store]);
+}
+
/* 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,
@@ -1375,14 +1382,15 @@ static void ptr_to_ptr(struct v4l2_ctrl *ctrl,
}
/* Copy the new value to the current value. */
-static void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags)
+static void new_to_store(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags)
{
+ union v4l2_ctrl_ptr store = ctrl->stores[ctrl->store];
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]);
+ changed = !ctrl->type_ops->equal(ctrl, store, ctrl->new);
+ ptr_to_ptr(ctrl, ctrl->new, store);
if (ch_flags & V4L2_EVENT_CTRL_CH_FLAGS) {
/* Note: CH_FLAGS is only set for auto clusters. */
@@ -1709,6 +1717,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
enum v4l2_ctrl_type type,
s64 min, s64 max, u64 step, s64 def,
u32 elem_size,
+ u32 nstores, u32 initial_store,
u32 flags, const char * const *qmenu,
const s64 *qmenu_int, void *priv)
{
@@ -1758,14 +1767,25 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
handler_set_err(hdl, -ERANGE);
return NULL;
}
+ if (nstores &&
+ (type == V4L2_CTRL_TYPE_BUTTON ||
+ type == V4L2_CTRL_TYPE_CTRL_CLASS)) {
+ handler_set_err(hdl, -EINVAL);
+ return NULL;
+ }
+
+ if (nstores)
+ flags |= V4L2_CTRL_FLAG_CAN_STORE;
+ sz_extra = (1 + nstores) * sizeof(union v4l2_ctrl_ptr);
- 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 || type >= V4L2_PROP_TYPES)
- sz_extra += 2 * elem_size;
+ sz_extra += (2 + nstores) * elem_size;
+ else
+ sz_extra += nstores * elem_size;
ctrl = kzalloc(sizeof(*ctrl) + sz_extra, GFP_KERNEL);
if (ctrl == NULL) {
@@ -1791,22 +1811,27 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
ctrl->is_ptr = type >= V4L2_PROP_TYPES || ctrl->is_string;
ctrl->is_int = !ctrl->is_ptr && type != V4L2_CTRL_TYPE_INTEGER64;
ctrl->elem_size = elem_size;
+ ctrl->nstores = nstores;
+ ctrl->cur_store = initial_store;
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 = def;
- props = &ctrl->stores[1];
+ props = &ctrl->stores[1 + nstores];
if (ctrl->is_ptr) {
ctrl->p = ctrl->new.p = props;
- ctrl->stores[0].p = props + elem_size;
+ for (s = 0; s <= nstores; s++)
+ ctrl->stores[s].p = props + (s + 1) * elem_size;
} else {
ctrl->new.p = &ctrl->val;
ctrl->stores[0].p = &ctrl->cur.val;
+ for (s = 1; s <= nstores; s++)
+ ctrl->stores[s].p = props + (s - 1) * elem_size;
}
- for (s = -1; s <= 0; s++)
+ for (s = -1; s <= (int)nstores; s++)
ctrl->type_ops->init(ctrl, ctrl->stores[s]);
if (handler_new_ref(hdl, ctrl)) {
@@ -1857,6 +1882,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl,
type, min, max,
is_menu ? cfg->menu_skip_mask : step,
def, cfg->elem_size,
+ cfg->nstores, cfg->initial_store,
flags, qmenu, qmenu_int, priv);
if (ctrl)
ctrl->is_private = cfg->is_private;
@@ -1882,7 +1908,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);
@@ -1916,7 +1942,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);
@@ -1949,8 +1975,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);
@@ -1975,7 +2001,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);
@@ -2225,11 +2251,12 @@ int v4l2_ctrl_handler_setup(struct v4l2_ctrl_handler *hdl)
continue;
for (i = 0; i < master->ncontrols; i++) {
- if (master->cluster[i]) {
- cur_to_new(master->cluster[i]);
- master->cluster[i]->is_new = 1;
- master->cluster[i]->done = true;
- }
+ if (master->cluster[i] == NULL)
+ continue;
+ cur_to_new(master->cluster[i]);
+ master->cluster[i]->is_new = 1;
+ master->cluster[i]->done = true;
+ master->cluster[i]->store = master->cur_store;
}
ret = call_op(master, s_ctrl);
if (ret)
@@ -2249,7 +2276,7 @@ int v4l2_query_ext_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_query_ext_ctr
struct v4l2_ctrl_ref *ref;
struct v4l2_ctrl *ctrl;
- if (hdl == NULL || store)
+ if (hdl == NULL)
return -EINVAL;
mutex_lock(hdl->lock);
@@ -2276,6 +2303,7 @@ int v4l2_query_ext_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_query_ext_ctr
the next valid one in the list. */
list_for_each_entry_continue(ref, &hdl->ctrl_refs, node)
if (id < ref->ctrl->id &&
+ store <= ref->ctrl->nstores &&
(ref->ctrl->flags & mask) == match)
break;
if (&ref->node == &hdl->ctrl_refs)
@@ -2287,6 +2315,7 @@ int v4l2_query_ext_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_query_ext_ctr
been true. */
list_for_each_entry(ref, &hdl->ctrl_refs, node)
if (id < ref->ctrl->id &&
+ store <= ref->ctrl->nstores &&
(ref->ctrl->flags & mask) == match)
break;
if (&ref->node == &hdl->ctrl_refs)
@@ -2312,6 +2341,7 @@ int v4l2_query_ext_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_query_ext_ctr
if (ctrl->unit)
strlcpy(qc->unit, ctrl->unit, sizeof(qc->unit));
qc->elem_size = ctrl->elem_size;
+ qc->config_store = store;
qc->min.val = ctrl->minimum;
qc->max.val = ctrl->maximum;
qc->def.val = ctrl->default_value;
@@ -2465,6 +2495,8 @@ static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl,
bool get)
{
struct v4l2_ctrl_helper *h;
+ u32 ctrl_class = V4L2_CTRL_ID2CLASS(cs->ctrl_class);
+ unsigned store = cs->config_store & 0xffff;
bool have_clusters = false;
u32 i;
@@ -2476,7 +2508,7 @@ static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl,
cs->error_idx = i;
- if (cs->ctrl_class && V4L2_CTRL_ID2CLASS(id) != cs->ctrl_class)
+ if (ctrl_class && V4L2_CTRL_ID2CLASS(id) != ctrl_class)
return -EINVAL;
/* Old-style private controls are not allowed for
@@ -2489,6 +2521,8 @@ static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl,
ctrl = ref->ctrl;
if (ctrl->flags & V4L2_CTRL_FLAG_DISABLED)
return -EINVAL;
+ if (store > ctrl->nstores)
+ return -EINVAL;
if (ctrl->cluster[0]->ncontrols > 1)
have_clusters = true;
@@ -2562,17 +2596,21 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs
{
struct v4l2_ctrl_helper helper[4];
struct v4l2_ctrl_helper *helpers = helper;
+ unsigned store = 0;
int ret;
int i, j;
cs->error_idx = cs->count;
- cs->ctrl_class = V4L2_CTRL_ID2CLASS(cs->ctrl_class);
+ if (V4L2_CTRL_ID2CLASS(cs->ctrl_class))
+ cs->ctrl_class = V4L2_CTRL_ID2CLASS(cs->ctrl_class);
+ else
+ store = cs->config_store;
if (hdl == NULL)
return -EINVAL;
if (cs->count == 0)
- return class_check(hdl, cs->ctrl_class);
+ return class_check(hdl, V4L2_CTRL_ID2CLASS(cs->ctrl_class));
if (cs->count > ARRAY_SIZE(helper)) {
helpers = kmalloc_array(cs->count, sizeof(helper[0]),
@@ -2589,8 +2627,7 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs
ret = -EACCES;
for (i = 0; !ret && i < cs->count; i++) {
- int (*ctrl_to_user)(struct v4l2_ext_control *c,
- struct v4l2_ctrl *ctrl) = cur_to_user;
+ bool from_new = false;
struct v4l2_ctrl *master;
if (helpers[i].mref == NULL)
@@ -2602,12 +2639,18 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs
v4l2_ctrl_lock(master);
/* g_volatile_ctrl will update the new control values */
- if ((master->flags & V4L2_CTRL_FLAG_VOLATILE) ||
- (master->has_volatiles && !is_cur_manual(master))) {
- for (j = 0; j < master->ncontrols; j++)
+ /* Note: volatile configuration stores are not supported (yet) */
+ if (store == master->cur_store &&
+ ((master->flags & V4L2_CTRL_FLAG_VOLATILE) ||
+ (master->has_volatiles && !is_cur_manual(master)))) {
+ for (j = 0; j < master->ncontrols; j++) {
+ if (master->cluster[j] == NULL)
+ continue;
cur_to_new(master->cluster[j]);
+ master->cluster[j]->store = store;
+ }
ret = call_op(master, g_volatile_ctrl);
- ctrl_to_user = new_to_user;
+ from_new = true;
}
/* If OK, then copy the current (for non-volatile controls)
or the new (for volatile controls) control values to the
@@ -2616,8 +2659,13 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs
u32 idx = i;
do {
- ret = ctrl_to_user(cs->controls + idx,
+ if (from_new)
+ ret = new_to_user(cs->controls + idx,
helpers[idx].ctrl);
+ else
+ ret = store_to_user(cs->controls + idx,
+ helpers[idx].ctrl,
+ store);
idx = helpers[idx].next;
} while (!ret && idx);
}
@@ -2656,8 +2704,12 @@ static int get_ctrl(struct v4l2_ctrl *ctrl, struct v4l2_ext_control *c)
v4l2_ctrl_lock(master);
/* g_volatile_ctrl will update the current control values */
if (ctrl->flags & V4L2_CTRL_FLAG_VOLATILE) {
- for (i = 0; i < master->ncontrols; i++)
+ for (i = 0; i < master->ncontrols; i++) {
+ if (master->cluster[i] == NULL)
+ continue;
cur_to_new(master->cluster[i]);
+ master->cluster[i]->store = master->cur_store;
+ }
ret = call_op(master, g_volatile_ctrl);
new_to_user(c, ctrl);
} else {
@@ -2716,7 +2768,7 @@ EXPORT_SYMBOL(v4l2_ctrl_g_ctrl_int64);
copied to the current value on a set.
Must be called with ctrl->handler->lock held. */
static int try_or_set_cluster(struct v4l2_fh *fh, struct v4l2_ctrl *master,
- bool set, u32 ch_flags)
+ u32 store, bool set, u32 ch_flags)
{
bool update_flag;
int ret;
@@ -2732,6 +2784,7 @@ static int try_or_set_cluster(struct v4l2_fh *fh, struct v4l2_ctrl *master,
if (ctrl == NULL)
continue;
+ ctrl->store = store;
if (!ctrl->is_new) {
cur_to_new(ctrl);
continue;
@@ -2754,7 +2807,7 @@ static int try_or_set_cluster(struct v4l2_fh *fh, struct v4l2_ctrl *master,
/* If OK, then make the new values permanent. */
update_flag = is_cur_manual(master) != is_new_manual(master);
for (i = 0; i < master->ncontrols; i++)
- new_to_cur(fh, master->cluster[i], ch_flags |
+ new_to_store(fh, master->cluster[i], ch_flags |
((update_flag && i > 0) ? V4L2_EVENT_CTRL_CH_FLAGS : 0));
return 0;
}
@@ -2795,8 +2848,12 @@ static void update_from_auto_cluster(struct v4l2_ctrl *master)
{
int i;
- for (i = 0; i < master->ncontrols; i++)
+ for (i = 0; i < master->ncontrols; i++) {
+ if (master->cluster[i] == NULL)
+ continue;
cur_to_new(master->cluster[i]);
+ master->cluster[i]->store = master->cur_store;
+ }
if (!call_op(master, g_volatile_ctrl))
for (i = 1; i < master->ncontrols; i++)
if (master->cluster[i])
@@ -2810,17 +2867,21 @@ static int try_set_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
{
struct v4l2_ctrl_helper helper[4];
struct v4l2_ctrl_helper *helpers = helper;
+ unsigned store = 0;
unsigned i, j;
int ret;
cs->error_idx = cs->count;
- cs->ctrl_class = V4L2_CTRL_ID2CLASS(cs->ctrl_class);
+ if (V4L2_CTRL_ID2CLASS(cs->ctrl_class))
+ cs->ctrl_class = V4L2_CTRL_ID2CLASS(cs->ctrl_class);
+ else
+ store = cs->config_store;
if (hdl == NULL)
return -EINVAL;
if (cs->count == 0)
- return class_check(hdl, cs->ctrl_class);
+ return class_check(hdl, V4L2_CTRL_ID2CLASS(cs->ctrl_class));
if (cs->count > ARRAY_SIZE(helper)) {
helpers = kmalloc_array(cs->count, sizeof(helper[0]),
@@ -2855,8 +2916,8 @@ static int try_set_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
first since those will become the new manual values (which
may be overwritten by explicit new values from this set
of controls). */
- if (master->is_auto && master->has_volatiles &&
- !is_cur_manual(master)) {
+ if (store == master->cur_store && master->is_auto &&
+ master->has_volatiles && !is_cur_manual(master)) {
/* Pick an initial non-manual value */
s32 new_auto_val = master->manual_mode_value + 1;
u32 tmp_idx = idx;
@@ -2868,6 +2929,7 @@ static int try_set_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
new_auto_val = cs->controls[tmp_idx].value;
tmp_idx = helpers[tmp_idx].next;
} while (tmp_idx);
+
/* If the new value == the manual value, then copy
the current volatile values. */
if (new_auto_val == master->manual_mode_value)
@@ -2882,14 +2944,16 @@ static int try_set_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
} while (!ret && idx);
if (!ret)
- ret = try_or_set_cluster(fh, master, set, 0);
+ ret = try_or_set_cluster(fh, master,
+ store ? store : master->cur_store,
+ set, 0);
/* Copy the new values back to userspace. */
if (!ret) {
idx = i;
do {
- ret = new_to_user(cs->controls + idx,
- helpers[idx].ctrl);
+ ret = store_to_user(cs->controls + idx,
+ helpers[idx].ctrl, store);
idx = helpers[idx].next;
} while (!ret && idx);
}
@@ -2941,9 +3005,12 @@ static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl,
return -EINVAL;
/* Reset the 'is_new' flags of the cluster */
- for (i = 0; i < master->ncontrols; i++)
- if (master->cluster[i])
- master->cluster[i]->is_new = 0;
+ for (i = 0; i < master->ncontrols; i++) {
+ if (master->cluster[i] == NULL)
+ continue;
+ master->cluster[i]->is_new = 0;
+ master->cluster[i]->store = master->cur_store;
+ }
/* For autoclusters with volatiles that are switched from auto to
manual mode we have to update the current volatile values since
@@ -2953,7 +3020,7 @@ static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl,
update_from_auto_cluster(master);
user_to_new(c, ctrl);
- return try_or_set_cluster(fh, master, true, ch_flags);
+ return try_or_set_cluster(fh, master, master->cur_store, true, ch_flags);
}
/* Helper function for VIDIOC_S_CTRL compatibility */
diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
index b889778..911b22a 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -92,6 +92,9 @@ typedef void (*v4l2_ctrl_notify_fnc)(struct v4l2_ctrl *ctrl, void *priv);
* @handler: The handler that owns the control.
* @cluster: Point to start of cluster array.
* @ncontrols: Number of controls in cluster array.
+ * @nstores: Number of configuration stores for this control.
+ * @store: The configuration store that the control op operates on.
+ * @cur_store: The configuration store used for the current value.
* @done: Internal flag: set for each processed control.
* @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
@@ -155,7 +158,10 @@ struct v4l2_ctrl {
struct list_head ev_subs;
struct v4l2_ctrl_handler *handler;
struct v4l2_ctrl **cluster;
- unsigned ncontrols;
+ u16 ncontrols;
+ u16 nstores;
+ u16 store;
+ u16 cur_store;
unsigned int done:1;
unsigned int is_new:1;
@@ -263,6 +269,8 @@ struct v4l2_ctrl_handler {
* @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.
+ * @nstores: The number of configuration stores.
+ * @initial_store: The configuration store used as the initial current value.
* @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,
@@ -289,6 +297,7 @@ struct v4l2_ctrl_config {
u64 step;
s64 def;
u32 elem_size;
+ u32 nstores, initial_store;
u32 flags;
u64 menu_skip_mask;
const char * const *qmenu;
--
1.8.5.2
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [RFCv1 PATCH 13/27] v4l2-ctrls: add function to apply a configuration store.
2014-01-06 14:20 [RFCv1 PATCH 00/27] Add property & configuration store support Hans Verkuil
` (11 preceding siblings ...)
2014-01-06 14:21 ` [RFCv1 PATCH 12/27] v4l2-ctrls: add initial support for configuration stores Hans Verkuil
@ 2014-01-06 14:21 ` Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 14/27] v4l2-ctrls: compare values only once Hans Verkuil
` (14 subsequent siblings)
27 siblings, 0 replies; 29+ messages in thread
From: Hans Verkuil @ 2014-01-06 14:21 UTC (permalink / raw)
To: linux-media; +Cc: Hans Verkuil
From: Hans Verkuil <hans.verkuil@cisco.com>
Drivers need to be able to select a specific store. Add a new function that can
be used to apply a given store.
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
drivers/media/v4l2-core/v4l2-ctrls.c | 67 ++++++++++++++++++++++++++++++++++++
include/media/v4l2-ctrls.h | 2 ++
2 files changed, 69 insertions(+)
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 3e32e21..66724b7 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1423,6 +1423,15 @@ static void cur_to_new(struct v4l2_ctrl *ctrl)
ptr_to_ptr(ctrl, ctrl->stores[0], ctrl->new);
}
+static void store_to_new(struct v4l2_ctrl *ctrl, unsigned store)
+{
+ if (ctrl == NULL)
+ return;
+ ptr_to_ptr(ctrl, ctrl->stores[store ? store : ctrl->cur_store],
+ ctrl->new);
+ ctrl->is_new = true;
+}
+
/* Return non-zero if one or more of the controls in the cluster has a new
value that differs from the current value. */
static int cluster_changed(struct v4l2_ctrl *master)
@@ -3087,6 +3096,64 @@ int v4l2_ctrl_s_ctrl_int64(struct v4l2_ctrl *ctrl, s64 val)
}
EXPORT_SYMBOL(v4l2_ctrl_s_ctrl_int64);
+int v4l2_ctrl_apply_store(struct v4l2_ctrl_handler *hdl, unsigned store)
+{
+ struct v4l2_ctrl_ref *ref;
+ bool found_store = false;
+ unsigned i;
+
+ if (hdl == NULL || store == 0)
+ return -EINVAL;
+
+ mutex_lock(hdl->lock);
+
+ list_for_each_entry(ref, &hdl->ctrl_refs, node) {
+ struct v4l2_ctrl *master;
+
+ if (store > ref->ctrl->nstores)
+ continue;
+ found_store = true;
+ if (ref->ctrl->cur_store) {
+ if (ref->ctrl->cur_store == store)
+ continue;
+ ref->ctrl->cur_store = store;
+ ref->ctrl->stores[0] = ref->ctrl->stores[store];
+ send_event(NULL, ref->ctrl, V4L2_EVENT_CTRL_CH_VALUE);
+ continue;
+ }
+ master = ref->ctrl->cluster[0];
+ if (ref->ctrl != master)
+ continue;
+ if (master->handler != hdl)
+ v4l2_ctrl_lock(master);
+ for (i = 0; i < master->ncontrols; i++)
+ store_to_new(master->cluster[i], store);
+
+ /* For volatile autoclusters that are currently in auto mode
+ we need to discover if it will be set to manual mode.
+ If so, then we have to copy the current volatile values
+ first since those will become the new manual values (which
+ may be overwritten by explicit new values from this set
+ of controls). */
+ if (master->is_auto && master->has_volatiles &&
+ !is_cur_manual(master)) {
+ s32 new_auto_val = *master->stores[store].p_s32;
+
+ /* If the new value == the manual value, then copy
+ the current volatile values. */
+ if (new_auto_val == master->manual_mode_value)
+ update_from_auto_cluster(master);
+ }
+
+ try_or_set_cluster(NULL, master, 0, true, 0);
+ if (master->handler != hdl)
+ v4l2_ctrl_unlock(master);
+ }
+ mutex_unlock(hdl->lock);
+ return found_store ? 0 : -EINVAL;
+}
+EXPORT_SYMBOL(v4l2_ctrl_apply_store);
+
void v4l2_ctrl_notify(struct v4l2_ctrl *ctrl, v4l2_ctrl_notify_fnc notify, void *priv)
{
if (ctrl == NULL)
diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
index 911b22a..2b9b2da 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -704,6 +704,8 @@ s64 v4l2_ctrl_g_ctrl_int64(struct v4l2_ctrl *ctrl);
*/
int v4l2_ctrl_s_ctrl_int64(struct v4l2_ctrl *ctrl, s64 val);
+int v4l2_ctrl_apply_store(struct v4l2_ctrl_handler *hdl, unsigned store);
+
/* Internal helper functions that deal with control events. */
extern const struct v4l2_subscribed_event_ops v4l2_ctrl_sub_ev_ops;
void v4l2_ctrl_replace(struct v4l2_event *old, const struct v4l2_event *new);
--
1.8.5.2
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [RFCv1 PATCH 14/27] v4l2-ctrls: compare values only once.
2014-01-06 14:20 [RFCv1 PATCH 00/27] Add property & configuration store support Hans Verkuil
` (12 preceding siblings ...)
2014-01-06 14:21 ` [RFCv1 PATCH 13/27] v4l2-ctrls: add function to apply a configuration store Hans Verkuil
@ 2014-01-06 14:21 ` Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 15/27] v4l2-ctrls: prepare for matrix support: add cols & rows fields Hans Verkuil
` (13 subsequent siblings)
27 siblings, 0 replies; 29+ messages in thread
From: Hans Verkuil @ 2014-01-06 14:21 UTC (permalink / raw)
To: linux-media; +Cc: 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_store(), 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_store() instead of having to do
another compare.
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
drivers/media/v4l2-core/v4l2-ctrls.c | 16 ++++++++++------
include/media/v4l2-ctrls.h | 3 +++
2 files changed, 13 insertions(+), 6 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 66724b7..a1c5e3e 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1389,8 +1389,10 @@ static void new_to_store(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flag
if (ctrl == NULL)
return;
- changed = !ctrl->type_ops->equal(ctrl, store, ctrl->new);
- ptr_to_ptr(ctrl, ctrl->new, store);
+
+ changed = ctrl->has_changed;
+ if (changed)
+ ptr_to_ptr(ctrl, ctrl->new, store);
if (ch_flags & V4L2_EVENT_CTRL_CH_FLAGS) {
/* Note: CH_FLAGS is only set for auto clusters. */
@@ -1436,17 +1438,19 @@ static void store_to_new(struct v4l2_ctrl *ctrl, unsigned store)
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 2b9b2da..9ce740d 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -99,6 +99,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.
@@ -165,6 +167,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] 29+ messages in thread
* [RFCv1 PATCH 15/27] v4l2-ctrls: prepare for matrix support: add cols & rows fields.
2014-01-06 14:20 [RFCv1 PATCH 00/27] Add property & configuration store support Hans Verkuil
` (13 preceding siblings ...)
2014-01-06 14:21 ` [RFCv1 PATCH 14/27] v4l2-ctrls: compare values only once Hans Verkuil
@ 2014-01-06 14:21 ` Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 16/27] v4l2-ctrls: replace cur by a union v4l2_ctrl_ptr Hans Verkuil
` (12 subsequent siblings)
27 siblings, 0 replies; 29+ messages in thread
From: Hans Verkuil @ 2014-01-06 14:21 UTC (permalink / raw)
To: linux-media; +Cc: 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>
---
drivers/media/v4l2-core/v4l2-ctrls.c | 24 ++++++++++++++++--------
include/media/v4l2-ctrls.h | 6 ++++++
2 files changed, 22 insertions(+), 8 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index a1c5e3e..8ed8a70 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1729,7 +1729,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 nstores, u32 initial_store,
u32 flags, const char * const *qmenu,
const s64 *qmenu_int, void *priv)
@@ -1743,6 +1743,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)
@@ -1823,6 +1828,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_PROP_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;
ctrl->nstores = nstores;
ctrl->cur_store = initial_store;
@@ -1893,8 +1900,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,
cfg->nstores, cfg->initial_store,
flags, qmenu, qmenu_int, priv);
if (ctrl)
@@ -1921,7 +1928,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, 0, 0,
+ min, max, step, def, 0, 0, 0, 0, 0,
flags, NULL, NULL, NULL);
}
EXPORT_SYMBOL(v4l2_ctrl_new_std);
@@ -1955,7 +1962,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, 0,
+ 0, max, mask, def, 0, 0, 0, 0, 0,
flags, qmenu, qmenu_int, NULL);
}
EXPORT_SYMBOL(v4l2_ctrl_new_std_menu);
@@ -1988,7 +1995,7 @@ 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, 0, 0,
+ 0, max, mask, def, 0, 0, 0, 0, 0,
flags, qmenu, NULL, NULL);
}
@@ -2014,7 +2021,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl,
return NULL;
}
return v4l2_ctrl_new(hdl, ops, NULL, id, name, unit, type,
- 0, max, 0, def, 0, 0, 0,
+ 0, max, 0, def, 0, 0, 0, 0, 0,
flags, NULL, qmenu_int, NULL);
}
EXPORT_SYMBOL(v4l2_ctrl_new_int_menu);
@@ -2358,7 +2365,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 9ce740d..ad62b71 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -132,6 +132,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
@@ -184,6 +186,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;
@@ -271,6 +274,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.
* @nstores: The number of configuration stores.
* @initial_store: The configuration store used as the initial current value.
@@ -299,6 +304,7 @@ struct v4l2_ctrl_config {
s64 max;
u64 step;
s64 def;
+ u32 rows, cols;
u32 elem_size;
u32 nstores, initial_store;
u32 flags;
--
1.8.5.2
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [RFCv1 PATCH 16/27] v4l2-ctrls: replace cur by a union v4l2_ctrl_ptr.
2014-01-06 14:20 [RFCv1 PATCH 00/27] Add property & configuration store support Hans Verkuil
` (14 preceding siblings ...)
2014-01-06 14:21 ` [RFCv1 PATCH 15/27] v4l2-ctrls: prepare for matrix support: add cols & rows fields Hans Verkuil
@ 2014-01-06 14:21 ` Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 17/27] v4l2-ctrls: new strings and props must be accessed through the new field Hans Verkuil
` (11 subsequent siblings)
27 siblings, 0 replies; 29+ messages in thread
From: Hans Verkuil @ 2014-01-06 14:21 UTC (permalink / raw)
To: linux-media; +Cc: 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 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.
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 | 19 +++++++++---------
include/media/v4l2-ctrls.h | 9 ++-------
22 files changed, 84 insertions(+), 90 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 1c2303d..26079a2 100644
--- a/drivers/media/i2c/mt9p031.c
+++ b/drivers/media/i2c/mt9p031.c
@@ -666,12 +666,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 7964634..c446079 100644
--- a/drivers/media/i2c/mt9t001.c
+++ b/drivers/media/i2c/mt9t001.c
@@ -443,7 +443,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++;
}
@@ -457,7 +457,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 fbd48f0..909479ce 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 2d4e73b..2ec8511 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 8ed8a70..e7effc8 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
@@ -1092,7 +1092,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
@@ -1794,7 +1794,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
if (nstores)
flags |= V4L2_CTRL_FLAG_CAN_STORE;
- sz_extra = (1 + nstores) * sizeof(union v4l2_ctrl_ptr);
+ sz_extra = nstores * sizeof(union v4l2_ctrl_ptr);
if (type == V4L2_CTRL_TYPE_BUTTON)
flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
@@ -1803,7 +1803,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
else if (type == V4L2_CTRL_TYPE_STRING || type >= V4L2_PROP_TYPES)
sz_extra += (2 + nstores) * elem_size;
else
- sz_extra += nstores * elem_size;
+ sz_extra += (1 + nstores) * elem_size;
ctrl = kzalloc(sizeof(*ctrl) + sz_extra, GFP_KERNEL);
if (ctrl == NULL) {
@@ -1838,7 +1838,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;
props = &ctrl->stores[1 + nstores];
if (ctrl->is_ptr) {
@@ -1847,9 +1847,8 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
ctrl->stores[s].p = props + (s + 1) * elem_size;
} else {
ctrl->new.p = &ctrl->val;
- ctrl->stores[0].p = &ctrl->cur.val;
- for (s = 1; s <= nstores; s++)
- ctrl->stores[s].p = props + (s - 1) * elem_size;
+ for (s = 0; s <= nstores; s++)
+ ctrl->stores[s].p = props + s * elem_size;
}
for (s = -1; s <= (int)nstores; s++)
ctrl->type_ops->init(ctrl, ctrl->stores[s]);
@@ -3206,10 +3205,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 ad62b71..3bfd9a6 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -204,14 +204,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] 29+ messages in thread
* [RFCv1 PATCH 17/27] v4l2-ctrls: new strings and props must be accessed through the new field.
2014-01-06 14:20 [RFCv1 PATCH 00/27] Add property & configuration store support Hans Verkuil
` (15 preceding siblings ...)
2014-01-06 14:21 ` [RFCv1 PATCH 16/27] v4l2-ctrls: replace cur by a union v4l2_ctrl_ptr Hans Verkuil
@ 2014-01-06 14:21 ` Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 18/27] v4l2-ctrls: prepare for matrix support Hans Verkuil
` (10 subsequent siblings)
27 siblings, 0 replies; 29+ messages in thread
From: Hans Verkuil @ 2014-01-06 14:21 UTC (permalink / raw)
To: linux-media; +Cc: 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>
---
drivers/media/radio/si4713/si4713.c | 4 ++--
drivers/media/v4l2-core/v4l2-ctrls.c | 3 +--
drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c | 2 +-
include/media/v4l2-ctrls.h | 2 --
4 files changed, 4 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 e7effc8..bb7f4ccb 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1842,8 +1842,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
props = &ctrl->stores[1 + nstores];
if (ctrl->is_ptr) {
- ctrl->p = ctrl->new.p = props;
- for (s = 0; s <= nstores; s++)
+ for (s = -1; s <= (int)nstores; s++)
ctrl->stores[s].p = props + (s + 1) * elem_size;
} else {
ctrl->new.p = &ctrl->val;
diff --git a/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c b/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
index d582c5b..a4a6bee 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 3bfd9a6..b735b5c 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -201,8 +201,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] 29+ messages in thread
* [RFCv1 PATCH 18/27] v4l2-ctrls: prepare for matrix support.
2014-01-06 14:20 [RFCv1 PATCH 00/27] Add property & configuration store support Hans Verkuil
` (16 preceding siblings ...)
2014-01-06 14:21 ` [RFCv1 PATCH 17/27] v4l2-ctrls: new strings and props must be accessed through the new field Hans Verkuil
@ 2014-01-06 14:21 ` Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 19/27] v4l2-ctrls: type_ops can handle matrix elements Hans Verkuil
` (9 subsequent siblings)
27 siblings, 0 replies; 29+ messages in thread
From: Hans Verkuil @ 2014-01-06 14:21 UTC (permalink / raw)
To: linux-media; +Cc: 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 | 57 +++++++++++++++++++++++-------------
include/media/v4l2-ctrls.h | 8 +++--
2 files changed, 41 insertions(+), 24 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index bb7f4ccb..b6edd81 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1118,7 +1118,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)
{
@@ -1137,7 +1137,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) {
@@ -1164,6 +1164,9 @@ static void std_log(const struct v4l2_ctrl *ctrl)
{
union v4l2_ctrl_ptr ptr = ctrl->stores[ctrl->cur_store];
+ 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);
@@ -1206,7 +1209,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;
@@ -1446,7 +1449,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;
}
@@ -1504,15 +1507,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);
}
}
@@ -1735,7 +1738,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_prop_size;
void *props;
int err;
int s;
@@ -1747,6 +1751,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);
@@ -1754,10 +1759,11 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
elem_size = max + 1;
else if (type < V4L2_PROP_TYPES)
elem_size = sizeof(s32);
+ tot_prop_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);
@@ -1772,7 +1778,8 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
handler_set_err(hdl, -EINVAL);
return NULL;
}
- if (!(flags & V4L2_CTRL_FLAG_PROPERTY) && type >= V4L2_PROP_TYPES) {
+ if (!(flags & V4L2_CTRL_FLAG_PROPERTY) &&
+ (is_matrix || type >= V4L2_PROP_TYPES)) {
handler_set_err(hdl, -EINVAL);
return NULL;
}
@@ -1791,6 +1798,12 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
handler_set_err(hdl, -EINVAL);
return NULL;
}
+ if (is_matrix &&
+ (type == V4L2_CTRL_TYPE_BUTTON ||
+ type == V4L2_CTRL_TYPE_CTRL_CLASS)) {
+ handler_set_err(hdl, -EINVAL);
+ return NULL;
+ }
if (nstores)
flags |= V4L2_CTRL_FLAG_CAN_STORE;
@@ -1800,10 +1813,11 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
else if (type == V4L2_CTRL_TYPE_CTRL_CLASS)
flags |= V4L2_CTRL_FLAG_READ_ONLY;
- else if (type == V4L2_CTRL_TYPE_STRING || type >= V4L2_PROP_TYPES)
- sz_extra += (2 + nstores) * elem_size;
+ else if (type == V4L2_CTRL_TYPE_STRING ||
+ type >= V4L2_PROP_TYPES || is_matrix)
+ sz_extra += (2 + nstores) * tot_prop_size;
else
- sz_extra += (1 + nstores) * elem_size;
+ sz_extra += (1 + nstores) * tot_prop_size;
ctrl = kzalloc(sizeof(*ctrl) + sz_extra, GFP_KERNEL);
if (ctrl == NULL) {
@@ -1825,9 +1839,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_PROP_TYPES || ctrl->is_string;
+ ctrl->is_string = !is_matrix && type == V4L2_CTRL_TYPE_STRING;
+ ctrl->is_ptr = is_matrix || type >= V4L2_PROP_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;
@@ -1843,14 +1858,14 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
if (ctrl->is_ptr) {
for (s = -1; s <= (int)nstores; s++)
- ctrl->stores[s].p = props + (s + 1) * elem_size;
+ ctrl->stores[s].p = props + (s + 1) * tot_prop_size;
} else {
ctrl->new.p = &ctrl->val;
for (s = 0; s <= nstores; s++)
- ctrl->stores[s].p = props + s * elem_size;
+ ctrl->stores[s].p = props + s * tot_prop_size;
}
for (s = -1; s <= (int)nstores; 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);
@@ -2775,7 +2790,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;
@@ -3100,7 +3115,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 b735b5c..514c427 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);
};
@@ -114,6 +114,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_PROP_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
@@ -175,6 +176,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] 29+ messages in thread
* [RFCv1 PATCH 19/27] v4l2-ctrls: type_ops can handle matrix elements.
2014-01-06 14:20 [RFCv1 PATCH 00/27] Add property & configuration store support Hans Verkuil
` (17 preceding siblings ...)
2014-01-06 14:21 ` [RFCv1 PATCH 18/27] v4l2-ctrls: prepare for matrix support Hans Verkuil
@ 2014-01-06 14:21 ` Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 20/27] v4l2-ctrls: add matrix support Hans Verkuil
` (8 subsequent siblings)
27 siblings, 0 replies; 29+ messages in thread
From: Hans Verkuil @ 2014-01-06 14:21 UTC (permalink / raw)
To: linux-media; +Cc: 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 b6edd81..3655b51 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1126,14 +1126,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);
}
}
@@ -1142,18 +1144,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;
@@ -1216,36 +1219,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] 29+ messages in thread
* [RFCv1 PATCH 20/27] v4l2-ctrls: add matrix support.
2014-01-06 14:20 [RFCv1 PATCH 00/27] Add property & configuration store support Hans Verkuil
` (18 preceding siblings ...)
2014-01-06 14:21 ` [RFCv1 PATCH 19/27] v4l2-ctrls: type_ops can handle matrix elements Hans Verkuil
@ 2014-01-06 14:21 ` Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 21/27] videodev2.h: rename reserved2 to config_store in v4l2_buffer Hans Verkuil
` (7 subsequent siblings)
27 siblings, 0 replies; 29+ messages in thread
From: Hans Verkuil @ 2014-01-06 14:21 UTC (permalink / raw)
To: linux-media; +Cc: 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 | 106 ++++++++++++++++++++---------------
1 file changed, 61 insertions(+), 45 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 3655b51..8d6711e 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1159,6 +1159,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;
}
}
@@ -1276,7 +1278,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:
@@ -1327,8 +1329,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:
@@ -1371,21 +1382,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. */
@@ -1446,15 +1443,19 @@ static void store_to_new(struct v4l2_ctrl *ctrl, unsigned store)
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;
@@ -1501,26 +1502,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)
@@ -1744,6 +1751,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
struct v4l2_ctrl *ctrl;
bool is_matrix;
unsigned sz_extra, tot_prop_size;
+ unsigned idx;
void *props;
int err;
int s;
@@ -1869,7 +1877,8 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
ctrl->stores[s].p = props + s * tot_prop_size;
}
for (s = -1; s <= (int)nstores; 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);
@@ -2566,12 +2575,16 @@ 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) {
+ if (c->size == 0 || c->size % ctrl->elem_size) {
+ if (get) {
+ c->size = ctrl->rows * ctrl->cols * ctrl->elem_size;
+ return -ENOSPC;
+ }
+ return -EFAULT;
}
- return -EFAULT;
+ if (c->size > ctrl->rows * ctrl->cols * ctrl->elem_size)
+ c->size = ctrl->rows * ctrl->cols * ctrl->elem_size;
}
/* Store the ref to the master control of the cluster */
h->mref = ref;
@@ -3202,7 +3215,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) {
@@ -3212,6 +3225,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] 29+ messages in thread
* [RFCv1 PATCH 21/27] videodev2.h: rename reserved2 to config_store in v4l2_buffer.
2014-01-06 14:20 [RFCv1 PATCH 00/27] Add property & configuration store support Hans Verkuil
` (19 preceding siblings ...)
2014-01-06 14:21 ` [RFCv1 PATCH 20/27] v4l2-ctrls: add matrix support Hans Verkuil
@ 2014-01-06 14:21 ` Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 22/27] v4l2-ctrls: add ctrl64 event Hans Verkuil
` (6 subsequent siblings)
27 siblings, 0 replies; 29+ messages in thread
From: Hans Verkuil @ 2014-01-06 14:21 UTC (permalink / raw)
To: linux-media; +Cc: Hans Verkuil
From: Hans Verkuil <hans.verkuil@cisco.com>
When queuing buffers allow for passing the configuration store ID that
should be associated with this buffer. Use the 'reserved2' field for this.
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
drivers/media/usb/cpia2/cpia2_v4l.c | 2 +-
drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 4 ++--
drivers/media/v4l2-core/videobuf2-core.c | 2 +-
include/uapi/linux/videodev2.h | 4 ++--
4 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/media/usb/cpia2/cpia2_v4l.c b/drivers/media/usb/cpia2/cpia2_v4l.c
index d5d42b6..51b7759 100644
--- a/drivers/media/usb/cpia2/cpia2_v4l.c
+++ b/drivers/media/usb/cpia2/cpia2_v4l.c
@@ -952,7 +952,7 @@ static int cpia2_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
buf->sequence = cam->buffers[buf->index].seq;
buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer;
buf->length = cam->frame_size;
- buf->reserved2 = 0;
+ buf->config_store = 0;
buf->reserved = 0;
memset(&buf->timecode, 0, sizeof(buf->timecode));
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
index 0d9b97e..a381c92 100644
--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
@@ -322,7 +322,7 @@ struct v4l2_buffer32 {
__s32 fd;
} m;
__u32 length;
- __u32 reserved2;
+ __u32 config_store;
__u32 reserved;
};
@@ -487,7 +487,7 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) ||
copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)) ||
put_user(kp->sequence, &up->sequence) ||
- put_user(kp->reserved2, &up->reserved2) ||
+ put_user(kp->config_store, &up->config_store) ||
put_user(kp->reserved, &up->reserved))
return -EFAULT;
diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c
index 12df9fd..5f35e1d 100644
--- a/drivers/media/v4l2-core/videobuf2-core.c
+++ b/drivers/media/v4l2-core/videobuf2-core.c
@@ -435,7 +435,7 @@ static void __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b)
/* Copy back data such as timestamp, flags, etc. */
memcpy(b, &vb->v4l2_buf, offsetof(struct v4l2_buffer, m));
- b->reserved2 = vb->v4l2_buf.reserved2;
+ b->config_store = vb->v4l2_buf.config_store;
b->reserved = vb->v4l2_buf.reserved;
if (V4L2_TYPE_IS_MULTIPLANAR(q->type)) {
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 789f876..78aba44 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -640,7 +640,7 @@ struct v4l2_plane {
* @length: size in bytes of the buffer (NOT its payload) for single-plane
* buffers (when type != *_MPLANE); number of elements in the
* planes array for multi-plane buffers
- * @input: input number from which the video data has has been captured
+ * @config_store: this buffer should use this configuration store
*
* Contains data exchanged by application and driver using one of the Streaming
* I/O methods.
@@ -664,7 +664,7 @@ struct v4l2_buffer {
__s32 fd;
} m;
__u32 length;
- __u32 reserved2;
+ __u32 config_store;
__u32 reserved;
};
--
1.8.5.2
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [RFCv1 PATCH 22/27] v4l2-ctrls: add ctrl64 event.
2014-01-06 14:20 [RFCv1 PATCH 00/27] Add property & configuration store support Hans Verkuil
` (20 preceding siblings ...)
2014-01-06 14:21 ` [RFCv1 PATCH 21/27] videodev2.h: rename reserved2 to config_store in v4l2_buffer Hans Verkuil
@ 2014-01-06 14:21 ` Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 23/27] videodev2.h: add new property types Hans Verkuil
` (5 subsequent siblings)
27 siblings, 0 replies; 29+ messages in thread
From: Hans Verkuil @ 2014-01-06 14:21 UTC (permalink / raw)
To: linux-media; +Cc: Hans Verkuil
From: Hans Verkuil <hans.verkuil@cisco.com>
The current control event is not able to handle the 64-bit ranges or the
config_store. Add a new extended event that is able to handle this.
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
drivers/media/v4l2-core/v4l2-ctrls.c | 61 ++++++++++++++++++++++++++++++------
include/uapi/linux/videodev2.h | 19 ++++++++++-
2 files changed, 69 insertions(+), 11 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 8d6711e..0014324 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1091,8 +1091,10 @@ static void fill_event(struct v4l2_event *ev, struct v4l2_ctrl *ctrl, u32 change
ev->u.ctrl.flags = ctrl->flags;
if (ctrl->is_ptr)
ev->u.ctrl.value64 = 0;
- else
+ else if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64)
ev->u.ctrl.value64 = *ctrl->cur.p_s64;
+ else
+ ev->u.ctrl.value = *ctrl->cur.p_s32;
ev->u.ctrl.minimum = ctrl->minimum;
ev->u.ctrl.maximum = ctrl->maximum;
if (ctrl->type == V4L2_CTRL_TYPE_MENU
@@ -1103,19 +1105,48 @@ static void fill_event(struct v4l2_event *ev, struct v4l2_ctrl *ctrl, u32 change
ev->u.ctrl.default_value = ctrl->default_value;
}
+static void fill_event64(struct v4l2_event *ev, struct v4l2_ctrl *ctrl, u32 changes)
+{
+ memset(ev->reserved, 0, sizeof(ev->reserved));
+ ev->type = V4L2_EVENT_CTRL64;
+ ev->id = ctrl->id;
+ ev->u.ctrl64.changes = changes;
+ ev->u.ctrl64.type = ctrl->type;
+ ev->u.ctrl64.config_store = ctrl->cur_store;
+ ev->u.ctrl64.flags = ctrl->flags;
+ if (ctrl->is_ptr)
+ ev->u.ctrl64.value64 = 0;
+ else if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64)
+ ev->u.ctrl64.value64 = *ctrl->cur.p_s64;
+ else
+ ev->u.ctrl64.value = *ctrl->cur.p_s32;
+ ev->u.ctrl64.minimum = ctrl->minimum;
+ ev->u.ctrl64.maximum = ctrl->maximum;
+ if (ctrl->type == V4L2_CTRL_TYPE_MENU
+ || ctrl->type == V4L2_CTRL_TYPE_INTEGER_MENU)
+ ev->u.ctrl64.step = 1;
+ else
+ ev->u.ctrl64.step = ctrl->step;
+ ev->u.ctrl64.default_value = ctrl->default_value;
+}
+
static void send_event(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 changes)
{
struct v4l2_event ev;
+ struct v4l2_event ev64;
struct v4l2_subscribed_event *sev;
if (list_empty(&ctrl->ev_subs))
return;
fill_event(&ev, ctrl, changes);
+ fill_event64(&ev64, ctrl, changes);
list_for_each_entry(sev, &ctrl->ev_subs, node)
if (sev->fh != fh ||
- (sev->flags & V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK))
+ (sev->flags & V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK)) {
v4l2_event_queue_fh(sev->fh, &ev);
+ v4l2_event_queue_fh(sev->fh, &ev64);
+ }
}
static bool std_equal(const struct v4l2_ctrl *ctrl, u32 idx,
@@ -3239,13 +3270,23 @@ int v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl,
ctrl->maximum = max;
ctrl->step = step;
ctrl->default_value = def;
- c.value = *ctrl->cur.p_s32;
- if (validate_new(ctrl, &c))
- c.value = def;
- 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);
+ if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64) {
+ c.value64 = *ctrl->cur.p_s64;
+ if (validate_new(ctrl, &c))
+ c.value64 = def;
+ if (c.value64 != *ctrl->cur.p_s64)
+ ret = set_ctrl(NULL, ctrl, &c, V4L2_EVENT_CTRL_CH_RANGE);
+ else
+ send_event(NULL, ctrl, V4L2_EVENT_CTRL_CH_RANGE);
+ } else {
+ c.value = *ctrl->cur.p_s32;
+ if (validate_new(ctrl, &c))
+ c.value = def;
+ 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);
+ }
v4l2_ctrl_unlock(ctrl);
return ret;
}
@@ -3324,7 +3365,7 @@ EXPORT_SYMBOL(v4l2_ctrl_log_status);
int v4l2_ctrl_subscribe_event(struct v4l2_fh *fh,
const struct v4l2_event_subscription *sub)
{
- if (sub->type == V4L2_EVENT_CTRL)
+ if (sub->type == V4L2_EVENT_CTRL || sub->type == V4L2_EVENT_CTRL64)
return v4l2_event_subscribe(fh, sub, 0, &v4l2_ctrl_sub_ev_ops);
return -EINVAL;
}
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 78aba44..afa335d 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_CTRL64 5
#define V4L2_EVENT_PRIVATE_START 0x08000000
/* Payload for V4L2_EVENT_VSYNC */
@@ -1781,7 +1782,7 @@ struct v4l2_event_vsync {
__u8 field;
} __attribute__ ((packed));
-/* Payload for V4L2_EVENT_CTRL */
+/* Payload for V4L2_EVENT_CTRL/V4L2_EVENT_CTRL64 */
#define V4L2_EVENT_CTRL_CH_VALUE (1 << 0)
#define V4L2_EVENT_CTRL_CH_FLAGS (1 << 1)
#define V4L2_EVENT_CTRL_CH_RANGE (1 << 2)
@@ -1800,6 +1801,21 @@ struct v4l2_event_ctrl {
__s32 default_value;
};
+struct v4l2_event_ctrl64 {
+ __u32 changes;
+ __u32 type;
+ union {
+ __s32 value;
+ __s64 value64;
+ };
+ __u32 flags;
+ __u32 config_store;
+ __s64 minimum;
+ __s64 maximum;
+ __u64 step;
+ __s64 default_value;
+};
+
struct v4l2_event_frame_sync {
__u32 frame_sequence;
};
@@ -1809,6 +1825,7 @@ struct v4l2_event {
union {
struct v4l2_event_vsync vsync;
struct v4l2_event_ctrl ctrl;
+ struct v4l2_event_ctrl64 ctrl64;
struct v4l2_event_frame_sync frame_sync;
__u8 data[64];
} u;
--
1.8.5.2
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [RFCv1 PATCH 23/27] videodev2.h: add new property types.
2014-01-06 14:20 [RFCv1 PATCH 00/27] Add property & configuration store support Hans Verkuil
` (21 preceding siblings ...)
2014-01-06 14:21 ` [RFCv1 PATCH 22/27] v4l2-ctrls: add ctrl64 event Hans Verkuil
@ 2014-01-06 14:21 ` Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 24/27] v4l2-controls.h: add new property class and new properties Hans Verkuil
` (4 subsequent siblings)
27 siblings, 0 replies; 29+ messages in thread
From: Hans Verkuil @ 2014-01-06 14:21 UTC (permalink / raw)
To: linux-media; +Cc: Hans Verkuil
From: Hans Verkuil <hans.verkuil@cisco.com>
Add support for a selection property and for u8 and u16 matrices.
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
include/uapi/linux/videodev2.h | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index afa335d..1ceaed1 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -1220,6 +1220,13 @@ struct v4l2_control {
__s32 value;
};
+/* Property types */
+struct v4l2_prop_selection {
+ __u32 flags;
+ struct v4l2_rect r;
+ __u32 reserved[9];
+};
+
struct v4l2_ext_control {
__u32 id;
__u32 size;
@@ -1228,6 +1235,9 @@ struct v4l2_ext_control {
__s32 value;
__s64 value64;
char *string;
+ __u8 *p_u8;
+ __u16 *p_u16;
+ struct v4l2_prop_selection *p_sel;
void *p;
};
} __attribute__ ((packed));
@@ -1260,6 +1270,9 @@ enum v4l2_ctrl_type {
/* Property types are >= 0x0100 */
V4L2_PROP_TYPES = 0x0100,
+ V4L2_PROP_TYPE_U8 = 0x0100,
+ V4L2_PROP_TYPE_U16 = 0x0101,
+ V4L2_PROP_TYPE_SELECTION = 0x0102,
};
/* Used in the VIDIOC_QUERYCTRL ioctl for querying controls */
--
1.8.5.2
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [RFCv1 PATCH 24/27] v4l2-controls.h: add new property class and new properties.
2014-01-06 14:20 [RFCv1 PATCH 00/27] Add property & configuration store support Hans Verkuil
` (22 preceding siblings ...)
2014-01-06 14:21 ` [RFCv1 PATCH 23/27] videodev2.h: add new property types Hans Verkuil
@ 2014-01-06 14:21 ` Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 25/27] v4l2-ctrls: add support for u8, u16 and prop_selection types Hans Verkuil
` (3 subsequent siblings)
27 siblings, 0 replies; 29+ messages in thread
From: Hans Verkuil @ 2014-01-06 14:21 UTC (permalink / raw)
To: linux-media; +Cc: Hans Verkuil
From: Hans Verkuil <hans.verkuil@cisco.com>
Add a class for properties (for demonstration purposes only, will need to be
renamed) and capture/output crop/compose and motion detection matrix
properties.
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
drivers/media/v4l2-core/v4l2-ctrls.c | 3 +++
include/uapi/linux/v4l2-controls.h | 16 ++++++++++++++++
2 files changed, 19 insertions(+)
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 0014324..2191451 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -852,6 +852,8 @@ 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";
+
+ case V4L2_CID_PROPS_CLASS: return "Properties";
default:
return NULL;
}
@@ -987,6 +989,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_PROPS_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;
diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
index 1666aab..6c3616e 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_PROPS 0x00a20000 /* Properties */
/* User-class control IDs */
@@ -886,4 +887,19 @@ enum v4l2_deemphasis {
#define V4L2_CID_RDS_RECEPTION (V4L2_CID_FM_RX_CLASS_BASE + 2)
+
+/* Properties */
+
+#define V4L2_CID_PROPS_CLASS_BASE (V4L2_CTRL_CLASS_PROPS | 0x900)
+#define V4L2_CID_PROPS_CLASS (V4L2_CTRL_CLASS_PROPS | 1)
+
+#define V4L2_CID_CAPTURE_CROP (V4L2_CID_PROPS_CLASS_BASE + 0)
+#define V4L2_CID_CAPTURE_COMPOSE (V4L2_CID_PROPS_CLASS_BASE + 1)
+#define V4L2_CID_OUTPUT_CROP (V4L2_CID_PROPS_CLASS_BASE + 2)
+#define V4L2_CID_OUTPUT_COMPOSE (V4L2_CID_PROPS_CLASS_BASE + 3)
+
+/* TODO: use a Motion Detection property class */
+#define V4L2_CID_MD_REGION (V4L2_CID_PROPS_CLASS_BASE + 4)
+#define V4L2_CID_MD_THRESHOLD (V4L2_CID_PROPS_CLASS_BASE + 5)
+
#endif
--
1.8.5.2
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [RFCv1 PATCH 25/27] v4l2-ctrls: add support for u8, u16 and prop_selection types.
2014-01-06 14:20 [RFCv1 PATCH 00/27] Add property & configuration store support Hans Verkuil
` (23 preceding siblings ...)
2014-01-06 14:21 ` [RFCv1 PATCH 24/27] v4l2-controls.h: add new property class and new properties Hans Verkuil
@ 2014-01-06 14:21 ` Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 26/27] v4l2-common.h: add new target Hans Verkuil
` (2 subsequent siblings)
27 siblings, 0 replies; 29+ messages in thread
From: Hans Verkuil @ 2014-01-06 14:21 UTC (permalink / raw)
To: linux-media; +Cc: Hans Verkuil
From: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
drivers/media/v4l2-core/v4l2-ctrls.c | 30 ++++++++++++++++++++++++++++++
include/media/v4l2-ctrls.h | 3 +++
2 files changed, 33 insertions(+)
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 2191451..6c7640b 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1165,6 +1165,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_PROP_TYPE_U8:
+ return ptr1.p_u8[idx] == ptr2.p_u8[idx];
+ case V4L2_PROP_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];
@@ -1192,6 +1196,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_PROP_TYPE_U8:
+ ptr.p_u8[idx] = ctrl->default_value;
+ break;
+ case V4L2_PROP_TYPE_U16:
+ ptr.p_u16[idx] = ctrl->default_value;
+ break;
default:
idx *= ctrl->elem_size;
memset(ptr.p + idx, 0, ctrl->elem_size);
@@ -1228,6 +1238,18 @@ static void std_log(const struct v4l2_ctrl *ctrl)
case V4L2_CTRL_TYPE_STRING:
pr_cont("%s", ptr.p_char);
break;
+ case V4L2_PROP_TYPE_U8:
+ pr_cont("%u", (unsigned)*ptr.p_u8);
+ break;
+ case V4L2_PROP_TYPE_U16:
+ pr_cont("%u", (unsigned)*ptr.p_u16);
+ break;
+ case V4L2_PROP_TYPE_SELECTION:
+ pr_cont("%ux%u@%dx%d (0x%x)",
+ ptr.p_sel->r.width, ptr.p_sel->r.height,
+ ptr.p_sel->r.left, ptr.p_sel->r.top,
+ ptr.p_sel->flags);
+ break;
default:
pr_cont("unknown type %d", ctrl->type);
break;
@@ -1258,6 +1280,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_PROP_TYPE_U8:
+ return ROUND_TO_RANGE(ptr.p_u8[idx], u8, ctrl);
+ case V4L2_PROP_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];
@@ -1504,6 +1530,8 @@ static int check_range(enum v4l2_ctrl_type type,
if (step != 1 || max > 1 || min < 0)
return -ERANGE;
/* fall through */
+ case V4L2_PROP_TYPE_U8:
+ case V4L2_PROP_TYPE_U16:
case V4L2_CTRL_TYPE_INTEGER:
case V4L2_CTRL_TYPE_INTEGER64:
if (step == 0 || min > max || def < min || def > max)
@@ -3259,6 +3287,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_PROP_TYPE_U8:
+ case V4L2_PROP_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 514c427..09257e4 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -45,7 +45,10 @@ struct poll_table_struct;
union v4l2_ctrl_ptr {
s32 *p_s32;
s64 *p_s64;
+ u8 *p_u8;
+ u16 *p_u16;
char *p_char;
+ struct v4l2_prop_selection *p_sel;
void *p;
};
--
1.8.5.2
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [RFCv1 PATCH 26/27] v4l2-common.h: add new target
2014-01-06 14:20 [RFCv1 PATCH 00/27] Add property & configuration store support Hans Verkuil
` (24 preceding siblings ...)
2014-01-06 14:21 ` [RFCv1 PATCH 25/27] v4l2-ctrls: add support for u8, u16 and prop_selection types Hans Verkuil
@ 2014-01-06 14:21 ` Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 27/27] vivi: add matrix and selection test code Hans Verkuil
2014-01-06 14:22 ` [RFCv1 PATCH 00/27] Add property & configuration store support Hans Verkuil
27 siblings, 0 replies; 29+ messages in thread
From: Hans Verkuil @ 2014-01-06 14:21 UTC (permalink / raw)
To: linux-media; +Cc: Hans Verkuil
From: Hans Verkuil <hans.verkuil@cisco.com>
This target can be used to set the frame size for devices that do not
support S_STD or S_DV_TIMINGS.
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
include/uapi/linux/v4l2-common.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/include/uapi/linux/v4l2-common.h b/include/uapi/linux/v4l2-common.h
index 4f0667e..88c9f89 100644
--- a/include/uapi/linux/v4l2-common.h
+++ b/include/uapi/linux/v4l2-common.h
@@ -50,6 +50,8 @@
/* Current composing area plus all padding pixels */
#define V4L2_SEL_TGT_COMPOSE_PADDED 0x0103
+#define V4L2_SEL_TGT_FRAME_SIZE 0x0200
+
/* Backward compatibility target definitions --- to be removed. */
#define V4L2_SEL_TGT_CROP_ACTIVE V4L2_SEL_TGT_CROP
#define V4L2_SEL_TGT_COMPOSE_ACTIVE V4L2_SEL_TGT_COMPOSE
--
1.8.5.2
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [RFCv1 PATCH 27/27] vivi: add matrix and selection test code.
2014-01-06 14:20 [RFCv1 PATCH 00/27] Add property & configuration store support Hans Verkuil
` (25 preceding siblings ...)
2014-01-06 14:21 ` [RFCv1 PATCH 26/27] v4l2-common.h: add new target Hans Verkuil
@ 2014-01-06 14:21 ` Hans Verkuil
2014-01-06 14:22 ` [RFCv1 PATCH 00/27] Add property & configuration store support Hans Verkuil
27 siblings, 0 replies; 29+ messages in thread
From: Hans Verkuil @ 2014-01-06 14:21 UTC (permalink / raw)
To: linux-media; +Cc: Hans Verkuil
From: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
drivers/media/platform/vivi.c | 312 ++++++++++++++++++++++++++++++++++++++----
1 file changed, 286 insertions(+), 26 deletions(-)
diff --git a/drivers/media/platform/vivi.c b/drivers/media/platform/vivi.c
index 2ec8511..0532d2b 100644
--- a/drivers/media/platform/vivi.c
+++ b/drivers/media/platform/vivi.c
@@ -48,8 +48,9 @@
*/
#define FPS_MAX 1000
-#define MAX_WIDTH 1920
-#define MAX_HEIGHT 1200
+#define MAX_ZOOM 4
+#define MAX_WIDTH (1920 * MAX_ZOOM)
+#define MAX_HEIGHT (1200 * MAX_ZOOM)
#define VIVI_VERSION "0.8.1"
@@ -86,6 +87,9 @@ static const struct v4l2_fract
#define dprintk(dev, level, fmt, arg...) \
v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ## arg)
+#define VIVI_CID_CUSTOM_BASE (V4L2_CID_USER_BASE | 0xf000)
+#define VIVI_PID_CUSTOM_BASE (V4L2_CID_PROPS_CLASS_BASE | 0xf000)
+
/* ------------------------------------------------------------------
Basic structures
------------------------------------------------------------------*/
@@ -207,6 +211,8 @@ struct vivi_dmaqueue {
static LIST_HEAD(vivi_devlist);
+#define VIVI_UNSET (-1000)
+
struct vivi_dev {
struct list_head vivi_devlist;
struct v4l2_device v4l2_dev;
@@ -233,6 +239,16 @@ struct vivi_dev {
struct v4l2_ctrl *string;
struct v4l2_ctrl *bitmask;
struct v4l2_ctrl *int_menu;
+ struct v4l2_ctrl *store;
+ struct v4l2_ctrl *prop1;
+ struct v4l2_ctrl *prop2;
+ struct v4l2_ctrl *prop3;
+ struct { /* crop/compose selection cluster */
+ struct v4l2_ctrl *crop;
+ struct v4l2_ctrl *compose;
+ };
+ struct v4l2_prop_selection *crop_sel;
+ struct v4l2_prop_selection *compose_sel;
spinlock_t slock;
struct mutex mutex;
@@ -253,6 +269,7 @@ struct vivi_dev {
const struct vivi_fmt *fmt;
struct v4l2_fract timeperframe;
unsigned int width, height;
+ unsigned int canvas_width, canvas_height;
struct vb2_queue vb_vidq;
unsigned int field_count;
@@ -314,6 +331,7 @@ static const struct bar_std bars[] = {
};
#define NUM_INPUTS ARRAY_SIZE(bars)
+#define NUM_STORES NUM_INPUTS
#define TO_Y(r, g, b) \
(((16829 * r + 33039 * g + 6416 * b + 32768) >> 16) + 16)
@@ -535,19 +553,26 @@ static void precalculate_line(struct vivi_dev *dev)
unsigned pixsize = dev->pixelsize;
unsigned pixsize2 = 2*pixsize;
int colorpos;
- u8 *pos;
+ unsigned width = dev->canvas_width * dev->compose_sel->r.width / dev->crop_sel->r.width;
+ u8 *pos = dev->line;
for (colorpos = 0; colorpos < 16; ++colorpos) {
u8 pix[8];
- int wstart = colorpos * dev->width / 8;
- int wend = (colorpos+1) * dev->width / 8;
+ int wstart = (colorpos) * width / 8;
+ int wend = ((colorpos+1)) * width / 8;
int w;
+ wstart = wstart & ~1;
+ wend = wend & ~1;
+ if (colorpos == 15)
+ wend = MAX_WIDTH * MAX_ZOOM;
gen_twopix(dev, &pix[0], colorpos % 8, 0);
gen_twopix(dev, &pix[pixsize], colorpos % 8, 1);
- for (w = wstart/2*2, pos = dev->line + w*pixsize; w < wend; w += 2, pos += pixsize2)
+ for (w = wstart; w < wend; w += 2) {
memcpy(pos, pix, pixsize2);
+ pos += pixsize2;
+ }
}
}
@@ -605,21 +630,26 @@ static void gen_text(struct vivi_dev *dev, char *basep,
static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
{
int stride = dev->width * dev->pixelsize;
- int hmax = dev->height;
+ int hmax = dev->compose_sel->r.height;
void *vbuf = vb2_plane_vaddr(&buf->vb, 0);
+ u8 *matrix = dev->prop3->cur.p_u8;
unsigned ms;
char str[100];
int h, line = 1;
+ unsigned start;
u8 *linestart;
s32 gain;
if (!vbuf)
return;
- linestart = dev->line + (dev->mv_count % dev->width) * dev->pixelsize;
+ start = (dev->mv_count + dev->crop_sel->r.left) % dev->canvas_width;
+ start = (start * dev->compose_sel->r.width) / dev->crop_sel->r.width;
+ start &= ~1;
+ linestart = dev->line + start * dev->pixelsize;
for (h = 0; h < hmax; h++)
- memcpy(vbuf + h * stride, linestart, stride);
+ memcpy(vbuf + h * stride, linestart, dev->compose_sel->r.width * dev->pixelsize);
/* Updates stream time */
@@ -636,7 +666,7 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
ms % 1000);
gen_text(dev, vbuf, line++ * 16, 16, str);
snprintf(str, sizeof(str), " %dx%d, input %d ",
- dev->width, dev->height, dev->input);
+ dev->canvas_width, dev->canvas_height, dev->input);
gen_text(dev, vbuf, line++ * 16, 16, str);
gain = v4l2_ctrl_g_ctrl(dev->gain);
@@ -665,6 +695,12 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
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);
+ snprintf(str, sizeof(str), " matrix %3d %3d ",
+ matrix[0], matrix[1]);
+ gen_text(dev, vbuf, line++ * 16, 16, str);
+ snprintf(str, sizeof(str), " %3d %3d ",
+ matrix[2], matrix[3]);
+ gen_text(dev, vbuf, line++ * 16, 16, str);
mutex_unlock(dev->ctrl_handler.lock);
if (dev->button_pressed) {
dev->button_pressed--;
@@ -858,7 +894,7 @@ static int buffer_prepare(struct vb2_buffer *vb)
BUG_ON(NULL == dev->fmt);
/*
- * Theses properties only change when queue is idle, see s_fmt.
+ * These properties only change when queue is idle, see s_fmt.
* The below checks should not be performed here, on each
* buffer_prepare (i.e. on each qbuf). Most of the code in this function
* should thus be moved to buffer_init and s_fmt.
@@ -1038,6 +1074,8 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
dev->pixelsize = dev->fmt->depth / 8;
dev->width = f->fmt.pix.width;
dev->height = f->fmt.pix.height;
+ dev->crop_sel->r.width = dev->compose_sel->r.width = dev->width;
+ dev->crop_sel->r.height = dev->compose_sel->r.height = dev->height;
return 0;
}
@@ -1063,6 +1101,62 @@ static int vidioc_enum_framesizes(struct file *file, void *fh,
return 0;
}
+static int adjust_sel(unsigned flags, struct v4l2_rect *r)
+{
+ unsigned w = r->width;
+ unsigned h = r->height;
+
+ if (!(flags & V4L2_SEL_FLAG_LE)) {
+ w++;
+ h++;
+ if (r->width < 2)
+ r->width = 2;
+ if (r->height < 2)
+ r->height = 2;
+ }
+ if (!(flags & V4L2_SEL_FLAG_GE)) {
+ if (r->width > MAX_WIDTH)
+ r->width = MAX_WIDTH;
+ if (r->height > MAX_HEIGHT)
+ r->height = MAX_HEIGHT;
+ }
+ w = w & ~1;
+ h = h & ~1;
+ r->left = r->top = 0;
+ if (r->width < 2 || r->height < 2)
+ return -ERANGE;
+ if (r->width > MAX_WIDTH || r->height > MAX_HEIGHT)
+ return -ERANGE;
+ if ((flags & (V4L2_SEL_FLAG_GE | V4L2_SEL_FLAG_LE)) ==
+ (V4L2_SEL_FLAG_GE | V4L2_SEL_FLAG_LE) &&
+ (r->width != w || r->height != h))
+ return -ERANGE;
+ r->width = w;
+ r->height = h;
+ return 0;
+}
+
+static int vidioc_s_selection(struct file *file, void *fh, struct v4l2_selection *s)
+{
+ struct vivi_dev *dev = video_drvdata(file);
+ int ret;
+
+ if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (s->target != V4L2_SEL_TGT_FRAME_SIZE)
+ return -EINVAL;
+ ret = adjust_sel(s->flags, &s->r);
+ if (ret)
+ return ret;
+ dev->canvas_width = s->r.width;
+ dev->canvas_height = s->r.height;
+ /* TODO: event handling when changing properties */
+ /* Question: should prop events be optional? */
+ dev->crop_sel->r.width = dev->compose_sel->r.width = dev->canvas_width;
+ dev->crop_sel->r.height = dev->compose_sel->r.height = dev->canvas_height;
+ return 0;
+}
+
/* only one input in this sample driver */
static int vidioc_enum_input(struct file *file, void *priv,
struct v4l2_input *inp)
@@ -1095,16 +1189,18 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
dev->input = i;
/*
- * Modify the brightness range depending on the input.
+ * Modify the volume range depending on the input.
* This makes it easy to use vivi to test if applications can
* handle control range modifications and is also how this is
* typically used in practice as different inputs may be hooked
* up to different receivers with different control ranges.
*/
- v4l2_ctrl_modify_range(dev->brightness,
- 128 * i, 255 + 128 * i, 1, 127 + 128 * i);
+ v4l2_ctrl_modify_range(dev->volume,
+ 128 * i, 255 + 128 * i, 1, 200 + 128 * i);
precalculate_bars(dev);
precalculate_line(dev);
+ v4l2_ctrl_apply_store(&dev->ctrl_handler, i + 1);
+ *dev->store->stores[i + 1].p_s32 = i + 1;
return 0;
}
@@ -1183,6 +1279,34 @@ static int vivi_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
return 0;
}
+static int vivi_try_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct vivi_dev *dev = container_of(ctrl->handler, struct vivi_dev, ctrl_handler);
+ struct v4l2_prop_selection *crop, *compose;
+ int ret;
+
+ switch (ctrl->id) {
+ case V4L2_CID_CAPTURE_CROP:
+ crop = dev->crop->new.p_sel;
+ ret = adjust_sel(crop->flags, &crop->r);
+ if (ret)
+ return ret;
+ compose = dev->compose->new.p_sel;
+ ret = adjust_sel(compose->flags, &compose->r);
+ if (ret)
+ return ret;
+ if (compose->r.width > crop->r.width * MAX_ZOOM)
+ crop->r.width = compose->r.width / MAX_ZOOM;
+ if (compose->r.height > crop->r.height * MAX_ZOOM)
+ crop->r.height = compose->r.height / MAX_ZOOM;
+ ret = adjust_sel(crop->flags, &crop->r);
+ if (ret)
+ return ret;
+ break;
+ }
+ return 0;
+}
+
static int vivi_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct vivi_dev *dev = container_of(ctrl->handler, struct vivi_dev, ctrl_handler);
@@ -1191,6 +1315,13 @@ static int vivi_s_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_ALPHA_COMPONENT:
dev->alpha_component = ctrl->val;
break;
+ case V4L2_CID_CAPTURE_CROP:
+ if (dev->crop->is_new)
+ *dev->crop_sel = *dev->crop->new.p_sel;
+ if (dev->compose->is_new)
+ *dev->compose_sel = *dev->compose->new.p_sel;
+ precalculate_line(dev);
+ break;
default:
if (ctrl == dev->button)
dev->button_pressed = 30;
@@ -1205,10 +1336,50 @@ static int vivi_s_ctrl(struct v4l2_ctrl *ctrl)
static const struct v4l2_ctrl_ops vivi_ctrl_ops = {
.g_volatile_ctrl = vivi_g_volatile_ctrl,
+ .try_ctrl = vivi_try_ctrl,
.s_ctrl = vivi_s_ctrl,
};
-#define VIVI_CID_CUSTOM_BASE (V4L2_CID_USER_BASE | 0xf000)
+static const struct v4l2_ctrl_config vivi_ctrl_brightness = {
+ .ops = &vivi_ctrl_ops,
+ .id = V4L2_CID_BRIGHTNESS,
+ .nstores = NUM_STORES,
+ .initial_store = 1,
+ .max = 255,
+ .step = 1,
+ .def = 127,
+};
+
+static const struct v4l2_ctrl_config vivi_ctrl_contrast = {
+ .ops = &vivi_ctrl_ops,
+ .id = V4L2_CID_CONTRAST,
+ .nstores = NUM_STORES,
+ .initial_store = 1,
+ .max = 255,
+ .step = 1,
+ .def = 16,
+};
+
+static const struct v4l2_ctrl_config vivi_ctrl_saturation = {
+ .ops = &vivi_ctrl_ops,
+ .id = V4L2_CID_SATURATION,
+ .nstores = NUM_STORES,
+ .initial_store = 1,
+ .max = 255,
+ .step = 1,
+ .def = 127,
+};
+
+static const struct v4l2_ctrl_config vivi_ctrl_hue = {
+ .ops = &vivi_ctrl_ops,
+ .id = V4L2_CID_HUE,
+ .nstores = NUM_STORES,
+ .initial_store = 1,
+ .min = -128,
+ .max = 127,
+ .step = 1,
+ .def = 0,
+};
static const struct v4l2_ctrl_config vivi_ctrl_button = {
.ops = &vivi_ctrl_ops,
@@ -1226,14 +1397,16 @@ static const struct v4l2_ctrl_config vivi_ctrl_boolean = {
.max = 1,
.step = 1,
.def = 1,
+ .flags = V4L2_CTRL_FLAG_CAN_STORE,
};
static const struct v4l2_ctrl_config vivi_ctrl_int32 = {
.ops = &vivi_ctrl_ops,
.id = VIVI_CID_CUSTOM_BASE + 2,
.name = "Integer 32 Bits",
+ .unit = "km/s",
.type = V4L2_CTRL_TYPE_INTEGER,
- .min = 0x80000000,
+ .min = 0xffffffff80000000,
.max = 0x7fffffff,
.step = 1,
};
@@ -1242,6 +1415,9 @@ static const struct v4l2_ctrl_config vivi_ctrl_int64 = {
.ops = &vivi_ctrl_ops,
.id = VIVI_CID_CUSTOM_BASE + 3,
.name = "Integer 64 Bits",
+ .min = -999999999999LL,
+ .max = 999999999999LL,
+ .step = 1,
.type = V4L2_CTRL_TYPE_INTEGER64,
};
@@ -1304,6 +1480,82 @@ static const struct v4l2_ctrl_config vivi_ctrl_int_menu = {
.qmenu_int = vivi_ctrl_int_menu_values,
};
+static const struct v4l2_ctrl_config vivi_ctrl_store = {
+ .ops = &vivi_ctrl_ops,
+ .id = VIVI_CID_CUSTOM_BASE + 8,
+ .name = "Config Store",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 1,
+ .max = NUM_STORES,
+ .def = 1,
+ .step = 1,
+ .flags = V4L2_CTRL_FLAG_READ_ONLY,
+ .nstores = NUM_STORES,
+ .initial_store = 1,
+};
+
+static const struct v4l2_ctrl_config vivi_prop_int = {
+ .ops = &vivi_ctrl_ops,
+ .id = VIVI_PID_CUSTOM_BASE + 0,
+ .name = "Property1",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .flags = V4L2_CTRL_FLAG_PROPERTY,
+ .def = 0x80,
+ .min = 0,
+ .max = 0xff,
+ .step = 1,
+};
+
+static const struct v4l2_ctrl_config vivi_prop_bool = {
+ .ops = &vivi_ctrl_ops,
+ .id = VIVI_PID_CUSTOM_BASE + 1,
+ .name = "Property2",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .flags = V4L2_CTRL_FLAG_PROPERTY,
+ .def = 1,
+ .min = 0,
+ .max = 1,
+ .step = 1,
+};
+
+static const struct v4l2_ctrl_config vivi_prop_matrix_u8 = {
+ .ops = &vivi_ctrl_ops,
+ .id = VIVI_PID_CUSTOM_BASE + 2,
+ .name = "Property3",
+ .type = V4L2_PROP_TYPE_U8,
+ .flags = V4L2_CTRL_FLAG_PROPERTY,
+ .def = 0x80,
+ .min = 0,
+ .max = 0xff,
+ .step = 1,
+ .cols = 2,
+ .rows = 2,
+ .elem_size = 1,
+ .nstores = NUM_STORES,
+};
+
+static const struct v4l2_ctrl_config vivi_prop_cap_crop = {
+ .ops = &vivi_ctrl_ops,
+ .id = V4L2_CID_CAPTURE_CROP,
+ .name = "Capture Crop",
+ .type = V4L2_PROP_TYPE_SELECTION,
+ .flags = V4L2_CTRL_FLAG_PROPERTY,
+ .cols = 1,
+ .rows = 1,
+ .elem_size = sizeof(struct v4l2_prop_selection),
+};
+
+static const struct v4l2_ctrl_config vivi_prop_cap_compose = {
+ .ops = &vivi_ctrl_ops,
+ .id = V4L2_CID_CAPTURE_COMPOSE,
+ .name = "Capture Compose",
+ .type = V4L2_PROP_TYPE_SELECTION,
+ .flags = V4L2_CTRL_FLAG_PROPERTY,
+ .cols = 1,
+ .rows = 1,
+ .elem_size = sizeof(struct v4l2_prop_selection),
+};
+
static const struct v4l2_file_operations vivi_fops = {
.owner = THIS_MODULE,
.open = v4l2_fh_open,
@@ -1333,6 +1585,7 @@ static const struct v4l2_ioctl_ops vivi_ioctl_ops = {
.vidioc_enum_frameintervals = vidioc_enum_frameintervals,
.vidioc_g_parm = vidioc_g_parm,
.vidioc_s_parm = vidioc_s_parm,
+ .vidioc_s_selection = vidioc_s_selection,
.vidioc_streamon = vb2_ioctl_streamon,
.vidioc_streamoff = vb2_ioctl_streamoff,
.vidioc_log_status = v4l2_ctrl_log_status,
@@ -1392,21 +1645,17 @@ static int __init vivi_create_instance(int inst)
dev->fmt = &formats[0];
dev->timeperframe = tpf_default;
- dev->width = 640;
- dev->height = 480;
+ dev->width = dev->canvas_width = 640;
+ dev->height = dev->canvas_height = 480;
dev->pixelsize = dev->fmt->depth / 8;
hdl = &dev->ctrl_handler;
v4l2_ctrl_handler_init(hdl, 11);
dev->volume = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
V4L2_CID_AUDIO_VOLUME, 0, 255, 1, 200);
- dev->brightness = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
- V4L2_CID_BRIGHTNESS, 0, 255, 1, 127);
- dev->contrast = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
- V4L2_CID_CONTRAST, 0, 255, 1, 16);
- dev->saturation = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
- V4L2_CID_SATURATION, 0, 255, 1, 127);
- dev->hue = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
- V4L2_CID_HUE, -128, 127, 1, 0);
+ dev->brightness = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_brightness, NULL);
+ dev->contrast = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_contrast, NULL);
+ dev->saturation = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_saturation, NULL);
+ dev->hue = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_hue, NULL);
dev->autogain = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
dev->gain = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
@@ -1421,11 +1670,22 @@ static int __init vivi_create_instance(int inst)
dev->string = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_string, NULL);
dev->bitmask = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_bitmask, NULL);
dev->int_menu = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int_menu, NULL);
+ dev->store = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_store, NULL);
+ dev->prop1 = v4l2_ctrl_new_custom(hdl, &vivi_prop_int, NULL);
+ dev->prop2 = v4l2_ctrl_new_custom(hdl, &vivi_prop_bool, NULL);
+ dev->prop3 = v4l2_ctrl_new_custom(hdl, &vivi_prop_matrix_u8, NULL);
+ dev->crop = v4l2_ctrl_new_custom(hdl, &vivi_prop_cap_crop, NULL);
+ dev->compose = v4l2_ctrl_new_custom(hdl, &vivi_prop_cap_compose, NULL);
if (hdl->error) {
ret = hdl->error;
goto unreg_dev;
}
v4l2_ctrl_auto_cluster(2, &dev->autogain, 0, true);
+ v4l2_ctrl_cluster(2, &dev->crop);
+ dev->crop_sel = dev->crop->cur.p_sel;
+ dev->compose_sel = dev->compose->cur.p_sel;
+ dev->crop_sel->r.width = dev->compose_sel->r.width = dev->width;
+ dev->crop_sel->r.height = dev->compose_sel->r.height = dev->height;
dev->v4l2_dev.ctrl_handler = hdl;
/* initialize locks */
--
1.8.5.2
^ permalink raw reply related [flat|nested] 29+ messages in thread
* Re: [RFCv1 PATCH 00/27] Add property & configuration store support
2014-01-06 14:20 [RFCv1 PATCH 00/27] Add property & configuration store support Hans Verkuil
` (26 preceding siblings ...)
2014-01-06 14:21 ` [RFCv1 PATCH 27/27] vivi: add matrix and selection test code Hans Verkuil
@ 2014-01-06 14:22 ` Hans Verkuil
27 siblings, 0 replies; 29+ messages in thread
From: Hans Verkuil @ 2014-01-06 14:22 UTC (permalink / raw)
To: linux-media
Oops, forgot to mention that the git tree containing these patches can be found
here:
http://git.linuxtv.org/hverkuil/media_tree.git/shortlog/refs/heads/propapi6
Regards,
Hans
On 01/06/2014 03:20 PM, Hans Verkuil wrote:
> This patch series adds support for properties, matrices and configuration
> stores to the control framework.
>
> See this RFCv2 for a more detailed discussion:
>
> http://permalink.gmane.org/gmane.linux.drivers.video-input-infrastructure/71822
>
> Changes since that RFCv2 are:
>
> - I dropped the 'property' bit in the control ID, instead a new flag is
> added: V4L2_CTRL_FLAG_PROPERTY.
> - A V4L2_CTRL_FLAG_IS_PTR flag is added to simplify applications: if set, then
> applications need to use the 'p' field instead of 'val' or 'val64'. This can
> be deduced from various other fields as well, but that leads to ugly code.
> This flag is cheap to set and very helpful in applications.
> - Matrix types have been dropped. If cols or rows are > 1, then you have a
> matrix, so there is no need for specific matrix types.
> - As a result it is no longer possible to set just a sub-rectangle of a
> matrix. It is however possible to just set the first X elements of
> a matrix/array. It became too complex to deal with the sub-rectangle,
> both in the framework, for drivers and for applications, and there are
> not enough benefits to warrant that effort.
>
> Other than those changes this patch series implements all the ideas described
> in RFCv2.
>
> The first 21 patches are pretty definitive and the only thing missing are
> the DocBook patches and a v4l2-controls.txt patch.
>
> Before I write those I would like to get feedback for this API enhancement.
> The actual API changes are surprisingly small, and most of the work done in
> the patches has more to do with data structure changes needed to simplify
> handling the more complex control types than with actual new code.
>
> Patch 22 adds a new event that can deal with the new 64-bit ranges and that
> adds a config_store field. However, I am not yet convinced that this is
> really needed. Feedback would be welcome.
>
> Patches 23-27 add test code for vivi to test matrices and to test the new
> selection properties. This code needs more work, particularly with regards
> to naming.
>
> A working v4l2-ctl that can handle the new stuff is available here:
>
> http://git.linuxtv.org/hverkuil/v4l-utils.git/shortlog/refs/heads/propapi
>
> Regards,
>
> Hans
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-media" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply [flat|nested] 29+ messages in thread
end of thread, other threads:[~2014-01-06 14:22 UTC | newest]
Thread overview: 29+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-01-06 14:20 [RFCv1 PATCH 00/27] Add property & configuration store support Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 01/27] v4l2-ctrls: increase internal min/max/step/def to 64 bit Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 02/27] v4l2-ctrls: add unit string Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 03/27] v4l2-ctrls: use pr_info/cont instead of printk Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 04/27] videodev2.h: add initial support for properties Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 05/27] videodev2.h: add struct v4l2_query_ext_ctrl and VIDIOC_QUERY_EXT_CTRL Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 06/27] v4l2-ctrls: add support for properties Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 07/27] v4l2: integrate support for VIDIOC_QUERY_EXT_CTRL Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 08/27] videodev2.h: add V4L2_CTRL_FLAG_CAN_STORE Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 09/27] videodev2.h: add config_store to v4l2_ext_controls Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 10/27] v4l2-ctrls: create type_ops Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 11/27] v4l2-ctrls: rewrite copy routines to operate on union v4l2_ctrl_ptr Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 12/27] v4l2-ctrls: add initial support for configuration stores Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 13/27] v4l2-ctrls: add function to apply a configuration store Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 14/27] v4l2-ctrls: compare values only once Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 15/27] v4l2-ctrls: prepare for matrix support: add cols & rows fields Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 16/27] v4l2-ctrls: replace cur by a union v4l2_ctrl_ptr Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 17/27] v4l2-ctrls: new strings and props must be accessed through the new field Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 18/27] v4l2-ctrls: prepare for matrix support Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 19/27] v4l2-ctrls: type_ops can handle matrix elements Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 20/27] v4l2-ctrls: add matrix support Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 21/27] videodev2.h: rename reserved2 to config_store in v4l2_buffer Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 22/27] v4l2-ctrls: add ctrl64 event Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 23/27] videodev2.h: add new property types Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 24/27] v4l2-controls.h: add new property class and new properties Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 25/27] v4l2-ctrls: add support for u8, u16 and prop_selection types Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 26/27] v4l2-common.h: add new target Hans Verkuil
2014-01-06 14:21 ` [RFCv1 PATCH 27/27] vivi: add matrix and selection test code Hans Verkuil
2014-01-06 14:22 ` [RFCv1 PATCH 00/27] Add property & configuration store support Hans Verkuil
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.