aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Verkuil <hans.verkuil@cisco.com>2013-02-16 22:19:00 +0100
committerHans Verkuil <hans.verkuil@cisco.com>2013-02-16 22:19:00 +0100
commit10ab2beb37c14a0446fdddb3caf070bbf4955f3b (patch)
tree794b0cc022b7c3d8cb709a3553f83a48ad28030f
parented72d37a33fdf43dc47787fe220532cdec9da528 (diff)
v4l2-ctrls: must be able to enable/disable controlsctrl-enable
Controls can be dependent on the chosen input/output. So it has to be possible to enable or disable groups of controls, preventing them from being seen in the application. We need to allow duplicate controls as well so that two control handlers that both have the same control will still work. The first enabled control will win. And duplicate controls are always sorted based on when they were added (so the sorted list and the hash are both stable lists/hashes). Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
-rw-r--r--drivers/media/v4l2-core/v4l2-ctrls.c93
-rw-r--r--include/media/v4l2-ctrls.h34
2 files changed, 97 insertions, 30 deletions
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 6b28b5800500..99d3dae18fc4 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1425,7 +1425,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_enabled || !type_is_int(ref->ctrl))
continue;
if (id == 0)
return ref;
@@ -1454,7 +1454,7 @@ static struct v4l2_ctrl_ref *find_ref(struct v4l2_ctrl_handler *hdl, u32 id)
/* Not in cache, search the hash */
ref = hdl->buckets ? hdl->buckets[bucket] : NULL;
- while (ref && ref->ctrl->id != id)
+ while (ref && ref->ctrl->id != id && ref->ctrl->is_enabled)
ref = ref->next;
if (ref)
@@ -1531,23 +1531,28 @@ static int handler_new_ref(struct v4l2_ctrl_handler *hdl,
/* Find insert position in sorted list */
list_for_each_entry(ref, &hdl->ctrl_refs, node) {
- if (ref->ctrl->id < id)
- continue;
- /* Don't add duplicates */
- if (ref->ctrl->id == id) {
- kfree(new_ref);
- goto unlock;
+ /* If there are multiple elements with the same ID, then
+ add the new element at the end. */
+ if (ref->ctrl->id > id) {
+ list_add(&new_ref->node, ref->node.prev);
+ break;
}
- list_add(&new_ref->node, ref->node.prev);
- break;
}
insert_in_hash:
- /* Insert the control node in the hash */
- new_ref->next = hdl->buckets[bucket];
- hdl->buckets[bucket] = new_ref;
+ /* Append the control ref to the hash */
+ if (hdl->buckets[bucket] == NULL) {
+ hdl->buckets[bucket] = new_ref;
+ } else {
+ for (ref = hdl->buckets[bucket]; ref->next; ref = ref->next)
+ ; /* empty */
+ ref->next = new_ref;
+ }
+ /* Note regarding the hdl->cached control ref: since new control refs
+ are always appended after any existing controls they will never
+ invalidate the cached control ref. So there is no need to set the
+ hdl->cached pointer to NULL. */
-unlock:
mutex_unlock(hdl->lock);
return 0;
}
@@ -1569,6 +1574,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
/* Sanity checks */
if (id == 0 || name == NULL || id >= V4L2_CID_PRIVATE_BASE ||
+ (flags & V4L2_CTRL_FLAG_DISABLED) ||
(type == V4L2_CTRL_TYPE_MENU && qmenu == NULL) ||
(type == V4L2_CTRL_TYPE_INTEGER_MENU && qmenu_int == NULL)) {
handler_set_err(hdl, -ERANGE);
@@ -1613,6 +1619,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->is_enabled = 1;
ctrl->cur.val = ctrl->val = ctrl->default_value = def;
if (ctrl->type == V4L2_CTRL_TYPE_STRING) {
@@ -1931,11 +1938,39 @@ void v4l2_ctrl_grab(struct v4l2_ctrl *ctrl, bool grabbed)
}
EXPORT_SYMBOL(v4l2_ctrl_grab);
+/* Enable/disable a control.
+ Usually used if controls can be enabled/disabled when changing to a
+ different input or output.
+
+ When a control is disabled, then it will no longer show up in the
+ application. */
+void v4l2_ctrl_enable(struct v4l2_ctrl *ctrl, bool enabled)
+{
+ if (ctrl == NULL)
+ return;
+
+ ctrl->is_enabled = enabled;
+}
+EXPORT_SYMBOL(v4l2_ctrl_enable);
+
+void v4l2_ctrl_handler_enable(struct v4l2_ctrl_handler *hdl, bool enabled)
+{
+ struct v4l2_ctrl *ctrl;
+
+ if (hdl == NULL)
+ return;
+ mutex_lock(hdl->lock);
+ list_for_each_entry(ctrl, &hdl->ctrls, node)
+ ctrl->is_enabled = enabled;
+ mutex_unlock(hdl->lock);
+}
+EXPORT_SYMBOL(v4l2_ctrl_handler_enable);
+
/* Log the control name and value */
static void log_ctrl(const struct v4l2_ctrl *ctrl,
const char *prefix, const char *colon)
{
- if (ctrl->flags & (V4L2_CTRL_FLAG_DISABLED | V4L2_CTRL_FLAG_WRITE_ONLY))
+ if (ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY)
return;
if (ctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS)
return;
@@ -1962,7 +1997,7 @@ static void log_ctrl(const struct v4l2_ctrl *ctrl,
printk(KERN_CONT "%lld", ctrl->cur.val64);
break;
case V4L2_CTRL_TYPE_STRING:
- printk(KERN_CONT "%s", ctrl->cur.string);
+ printk(KERN_CONT "\"%s\"", ctrl->cur.string);
break;
default:
printk(KERN_CONT "unknown type %d", ctrl->type);
@@ -1970,6 +2005,7 @@ static void log_ctrl(const struct v4l2_ctrl *ctrl,
}
if (ctrl->flags & (V4L2_CTRL_FLAG_INACTIVE |
V4L2_CTRL_FLAG_GRABBED |
+ V4L2_CTRL_FLAG_DISABLED |
V4L2_CTRL_FLAG_VOLATILE)) {
if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
printk(KERN_CONT " inactive");
@@ -1977,6 +2013,8 @@ static void log_ctrl(const struct v4l2_ctrl *ctrl,
printk(KERN_CONT " grabbed");
if (ctrl->flags & V4L2_CTRL_FLAG_VOLATILE)
printk(KERN_CONT " volatile");
+ if (ctrl->flags & V4L2_CTRL_FLAG_DISABLED)
+ printk(KERN_CONT " disabled");
}
printk(KERN_CONT "\n");
}
@@ -1998,8 +2036,7 @@ void v4l2_ctrl_handler_log_status(struct v4l2_ctrl_handler *hdl,
colon = ": ";
mutex_lock(hdl->lock);
list_for_each_entry(ctrl, &hdl->ctrls, node)
- if (!(ctrl->flags & V4L2_CTRL_FLAG_DISABLED))
- log_ctrl(ctrl, prefix, colon);
+ log_ctrl(ctrl, prefix, colon);
mutex_unlock(hdl->lock);
}
EXPORT_SYMBOL(v4l2_ctrl_handler_log_status);
@@ -2070,17 +2107,15 @@ int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc)
/* Did we reach the end of the control list? */
if (id >= node2id(hdl->ctrl_refs.prev)) {
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);
} 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 no ref was found, then start searching from the
+ beginning of the ctrl_refs list. */
+ if (ref == NULL)
+ ref = list_entry(hdl->ctrl_refs.next,
+ typeof(*ref), node);
+ /* Search for the next largest ID. */
+ list_for_each_entry_from(ref, &hdl->ctrl_refs, node)
+ if (ref->ctrl->is_enabled && id < ref->ctrl->id)
break;
}
}
@@ -2236,8 +2271,6 @@ static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl,
if (ref == NULL)
return -EINVAL;
ctrl = ref->ctrl;
- if (ctrl->flags & V4L2_CTRL_FLAG_DISABLED)
- return -EINVAL;
if (ctrl->cluster[0]->ncontrols > 1)
have_clusters = true;
diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
index f00d42bc01a6..d8f5aab21d4a 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -81,6 +81,8 @@ typedef void (*v4l2_ctrl_notify_fnc)(struct v4l2_ctrl *ctrl, void *priv);
* manual mode. So if the value of the auto control equals this
* value, then the whole cluster is in manual mode. Drivers should
* never set this flag directly.
+ * @is_enabled: If 0, then this control is disabled and will be hidden for
+ * applications. Controls are always enabled by default.
* @ops: The control ops.
* @id: The control ID.
* @name: The control name.
@@ -122,6 +124,7 @@ struct v4l2_ctrl {
unsigned int is_new:1;
unsigned int is_private:1;
unsigned int is_auto:1;
+ unsigned int is_enabled:1;
unsigned int has_volatiles:1;
unsigned int call_notify:1;
unsigned int manual_mode_value:8;
@@ -538,6 +541,37 @@ void v4l2_ctrl_grab(struct v4l2_ctrl *ctrl, bool grabbed);
int v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl,
s32 min, s32 max, u32 step, s32 def);
+/** v4l2_ctrl_enable() - Mark the control as enabled or disabled.
+ * @ctrl: The control to en/disable.
+ * @enabled: True if the control should become enabled.
+ *
+ * Enable/disable a control.
+ * Does nothing if @ctrl == NULL.
+ * Usually called if controls are to be enabled or disabled when changing
+ * to a different input or output.
+ *
+ * When a control is disabled, then it will no longer show up in the
+ * application.
+ *
+ * This function can be called regardless of whether the control handler
+ * is locked or not.
+ */
+void v4l2_ctrl_enable(struct v4l2_ctrl *ctrl, bool enabled);
+
+/** v4l2_ctrl_handler_enable() - Mark the controls in the handler as enabled or disabled.
+ * @hdl: The control handler.
+ * @enabled: True if the controls should become enabled.
+ *
+ * Enable/disable the controls owned by the handler.
+ * Does nothing if @hdl == NULL.
+ * Usually called if controls are to be enabled or disabled when changing
+ * to a different input or output.
+ *
+ * When a control is disabled, then it will no longer show up in the
+ * application.
+ */
+void v4l2_ctrl_handler_enable(struct v4l2_ctrl_handler *hdl, bool enabled);
+
/** v4l2_ctrl_lock() - Helper function to lock the handler
* associated with the control.
* @ctrl: The control to lock.

Privacy Policy