From: Hans Verkuil <hans.verk...@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.verk...@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

--
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