aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media
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 /drivers/media
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>
Diffstat (limited to 'drivers/media')
-rw-r--r--drivers/media/v4l2-core/v4l2-ctrls.c93
1 files changed, 63 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;

Privacy Policy