aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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