From: Hans Verkuil <hans.verk...@cisco.com>

Rather than always having to use a v4l2_ext_control struct to set
a control value from within a driver, switch to just setting the
new value. This is faster and it makes it possible to set more
complex types such as a string control.

Signed-off-by: Hans Verkuil <hans.verk...@cisco.com>
---
 drivers/media/v4l2-core/v4l2-ctrls.c | 46 ++++++++++++++++++++++++------------
 include/media/v4l2-ctrls.h           | 12 ++++++++++
 2 files changed, 43 insertions(+), 15 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c 
b/drivers/media/v4l2-core/v4l2-ctrls.c
index 7c138b5..2aad5c6 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -2786,26 +2786,22 @@ 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
-        * 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)
-               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;
 
+       if (c)
+               user_to_new(c, ctrl);
+
        /* For autoclusters with volatiles that are switched from auto to
           manual mode we have to update the current volatile values since
           those will become the initial manual values after such a switch. */
        if (master->is_auto && master->has_volatiles && ctrl == master &&
-           !is_cur_manual(master) && c->value == master->manual_mode_value)
+           !is_cur_manual(master) && ctrl->val == master->manual_mode_value)
                update_from_auto_cluster(master);
 
-       user_to_new(c, ctrl);
+       ctrl->is_new = 1;
        return try_or_set_cluster(fh, master, true, ch_flags);
 }
 
@@ -2853,26 +2849,46 @@ EXPORT_SYMBOL(v4l2_subdev_s_ctrl);
 
 int v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val)
 {
-       struct v4l2_ext_control c;
+       int ret;
 
        /* It's a driver bug if this happens. */
        WARN_ON(!type_is_int(ctrl));
-       c.value = val;
-       return set_ctrl_lock(NULL, ctrl, &c);
+       v4l2_ctrl_lock(ctrl);
+       ctrl->val = val;
+       ret = set_ctrl(NULL, ctrl, NULL, 0);
+       v4l2_ctrl_unlock(ctrl);
+       return ret;
 }
 EXPORT_SYMBOL(v4l2_ctrl_s_ctrl);
 
 int v4l2_ctrl_s_ctrl_int64(struct v4l2_ctrl *ctrl, s64 val)
 {
-       struct v4l2_ext_control c;
+       int ret;
 
        /* It's a driver bug if this happens. */
        WARN_ON(ctrl->type != V4L2_CTRL_TYPE_INTEGER64);
-       c.value64 = val;
-       return set_ctrl_lock(NULL, ctrl, &c);
+       v4l2_ctrl_lock(ctrl);
+       ctrl->val64 = val;
+       ret = set_ctrl(NULL, ctrl, NULL, 0);
+       v4l2_ctrl_unlock(ctrl);
+       return ret;
 }
 EXPORT_SYMBOL(v4l2_ctrl_s_ctrl_int64);
 
+int v4l2_ctrl_s_ctrl_string(struct v4l2_ctrl *ctrl, const char *s)
+{
+       int ret;
+
+       /* It's a driver bug if this happens. */
+       WARN_ON(ctrl->type != V4L2_CTRL_TYPE_STRING);
+       v4l2_ctrl_lock(ctrl);
+       strlcpy(ctrl->string, s, ctrl->maximum + 1);
+       ret = set_ctrl(NULL, ctrl, NULL, 0);
+       v4l2_ctrl_unlock(ctrl);
+       return ret;
+}
+EXPORT_SYMBOL(v4l2_ctrl_s_ctrl_string);
+
 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 16f7f26..ee00f11 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -640,6 +640,18 @@ s64 v4l2_ctrl_g_ctrl_int64(struct v4l2_ctrl *ctrl);
   */
 int v4l2_ctrl_s_ctrl_int64(struct v4l2_ctrl *ctrl, s64 val);
 
+/** v4l2_ctrl_s_ctrl_string() - Helper function to set a control's string 
value from within a driver.
+  * @ctrl:     The control.
+  * @s:                The new string.
+  *
+  * This set the control's new string safely by going through the control
+  * framework. This function will lock the control's handler, so it cannot be
+  * used from within the &v4l2_ctrl_ops functions.
+  *
+  * This function is for string type controls only.
+  */
+int v4l2_ctrl_s_ctrl_string(struct v4l2_ctrl *ctrl, const char *s);
+
 /* 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

--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to