Re: [RFC PATCH 04/11] v4l2-ctrls: add config store support

2015-12-02 Thread Enric Balletbo Serra
2015-12-02 13:33 GMT+01:00 Hans Verkuil :
> On 12/02/15 13:03, Enric Balletbo Serra wrote:
>> Dear Hans,
>>
>> We've a driver that uses your confstore stuff and we'd like to push
>> upstream. I'm wondering if there is any plan to upstream the confstore
>> patches or if this was abandoned for some reason. Thanks
>
> Ouch, that's really old code you're using.
>
> The latest version is here:
>
> http://git.linuxtv.org/hverkuil/media_tree.git/log/?h=requests
>
> But that too won't be the final version.
>
> There is still work going on in this area (specifically by Laurent Pinchart)
> since we really need this functionality. But we need to make sure that the
> API is good enough to handle complex hardware before it can be upstreamed.
>
> I suspect that once Laurent has it working for his non-trivial use-case we
> can start looking at upstreaming it.
>
> I recommend rebasing to at least the version in my git tree as that will
> be much closer to the final version. I'll try to rebase that branch to
> the latest kernel, but that's a bit difficult and takes more time than I
> have at the moment.
>

Thanks to point me in the right direction.

Regards,
Enric

> Regards,
>
> Hans
--
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


Re: [RFC PATCH 04/11] v4l2-ctrls: add config store support

2015-12-02 Thread Hans Verkuil
On 12/02/15 13:03, Enric Balletbo Serra wrote:
> Dear Hans,
> 
> We've a driver that uses your confstore stuff and we'd like to push
> upstream. I'm wondering if there is any plan to upstream the confstore
> patches or if this was abandoned for some reason. Thanks

Ouch, that's really old code you're using.

The latest version is here:

http://git.linuxtv.org/hverkuil/media_tree.git/log/?h=requests

But that too won't be the final version.

There is still work going on in this area (specifically by Laurent Pinchart)
since we really need this functionality. But we need to make sure that the
API is good enough to handle complex hardware before it can be upstreamed.

I suspect that once Laurent has it working for his non-trivial use-case we
can start looking at upstreaming it.

I recommend rebasing to at least the version in my git tree as that will
be much closer to the final version. I'll try to rebase that branch to
the latest kernel, but that's a bit difficult and takes more time than I
have at the moment.

Regards,

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


Re: [RFC PATCH 04/11] v4l2-ctrls: add config store support

2015-12-02 Thread Enric Balletbo Serra
Dear Hans,

2014-11-17 9:46 GMT+01:00 Hans Verkuil :
> On 11/14/2014 04:44 PM, Sakari Ailus wrote:
>> Hi Hans,
>>
>> Some comments below.
>>
>> On Sun, Sep 21, 2014 at 04:48:22PM +0200, Hans Verkuil wrote:
>>> From: Hans Verkuil 
>>>
>>> Signed-off-by: Hans Verkuil 
>>> ---
>>>  drivers/media/v4l2-core/v4l2-ctrls.c | 150 
>>> +--
>>>  drivers/media/v4l2-core/v4l2-ioctl.c |   4 +-
>>>  include/media/v4l2-ctrls.h   |  14 
>>>  3 files changed, 141 insertions(+), 27 deletions(-)
>>>
>>> diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c 
>>> b/drivers/media/v4l2-core/v4l2-ctrls.c
>>> index 35d1f3d..df0f3ee 100644
>>> --- a/drivers/media/v4l2-core/v4l2-ctrls.c
>>> +++ b/drivers/media/v4l2-core/v4l2-ctrls.c
>>> @@ -1478,6 +1478,15 @@ static int cur_to_user(struct v4l2_ext_control *c,
>>>  return ptr_to_user(c, ctrl, ctrl->p_cur);
>>>  }
>>>
>>> +/* Helper function: copy the store's control value back to the caller */
>>> +static int store_to_user(struct v4l2_ext_control *c,
>>> +   struct v4l2_ctrl *ctrl, unsigned store)
>>> +{
>>> +if (store == 0)
>>> +return ptr_to_user(c, ctrl, ctrl->p_new);
>>> +return ptr_to_user(c, ctrl, ctrl->p_stores[store - 1]);
>>> +}
>>> +
>>>  /* Helper function: copy the new control value back to the caller */
>>>  static int new_to_user(struct v4l2_ext_control *c,
>>> struct v4l2_ctrl *ctrl)
>>> @@ -1585,6 +1594,14 @@ static void new_to_cur(struct v4l2_fh *fh, struct 
>>> v4l2_ctrl *ctrl, u32 ch_flags)
>>>  }
>>>  }
>>>
>>> +/* Helper function: copy the new control value to the store */
>>> +static void new_to_store(struct v4l2_ctrl *ctrl)
>>> +{
>>> +/* has_changed is set by cluster_changed */
>>> +if (ctrl && ctrl->has_changed)
>>> +ptr_to_ptr(ctrl, ctrl->p_new, ctrl->p_stores[ctrl->store - 1]);
>>> +}
>>> +
>>>  /* Copy the current value to the new value */
>>>  static void cur_to_new(struct v4l2_ctrl *ctrl)
>>>  {
>>> @@ -1603,13 +1620,18 @@ static int cluster_changed(struct v4l2_ctrl *master)
>>>
>>>  for (i = 0; i < master->ncontrols; i++) {
>>>  struct v4l2_ctrl *ctrl = master->cluster[i];
>>> +union v4l2_ctrl_ptr ptr;
>>>  bool ctrl_changed = false;
>>>
>>>  if (ctrl == NULL)
>>>  continue;
>>> +if (ctrl->store)
>>> +ptr = ctrl->p_stores[ctrl->store - 1];
>>> +else
>>> +ptr = ctrl->p_cur;
>>>  for (idx = 0; !ctrl_changed && idx < ctrl->elems; idx++)
>>>  ctrl_changed = !ctrl->type_ops->equal(ctrl, idx,
>>> -ctrl->p_cur, ctrl->p_new);
>>> +ptr, ctrl->p_new);
>>>  ctrl->has_changed = ctrl_changed;
>>>  changed |= ctrl->has_changed;
>>>  }
>>> @@ -1740,6 +1762,13 @@ void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler 
>>> *hdl)
>>>  list_del(&ctrl->node);
>>>  list_for_each_entry_safe(sev, next_sev, &ctrl->ev_subs, node)
>>>  list_del(&sev->node);
>>> +if (ctrl->p_stores) {
>>> +unsigned s;
>>> +
>>> +for (s = 0; s < ctrl->nr_of_stores; s++)
>>> +kfree(ctrl->p_stores[s].p);
>>> +}
>>> +kfree(ctrl->p_stores);
>>>  kfree(ctrl);
>>>  }
>>>  kfree(hdl->buckets);
>>> @@ -1970,7 +1999,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct 
>>> v4l2_ctrl_handler *hdl,
>>>  handler_set_err(hdl, -ERANGE);
>>>  return NULL;
>>>  }
>>> -if (is_array &&
>>> +if ((is_array || (flags & V4L2_CTRL_FLAG_CAN_STORE)) &&
>>>  (type == V4L2_CTRL_TYPE_BUTTON ||
>>>   type == V4L2_CTRL_TYPE_CTRL_CLASS)) {
>>>  handler_set_err(hdl, -EINVAL);
>>> @@ -2084,8 +2113,10 @@ struct v4l2_ctrl *v4l2_ctrl_new_custom(struct 
>>> v4l2_ctrl_handler *hdl,
>>>  is_menu ? cfg->menu_skip_mask : step, def,
>>>  cfg->dims, cfg->elem_size,
>>>  flags, qmenu, qmenu_int, priv);
>>> -if (ctrl)
>>> +if (ctrl) {
>>
>> I think it'd be cleaner to return NULL here if ctrl == NULL. Up to you.
>
> Agreed.
>
>>
>>>  ctrl->is_private = cfg->is_private;
>>> +ctrl->can_store = cfg->can_store;
>>> +}
>>>  return ctrl;
>>>  }
>>>  EXPORT_SYMBOL(v4l2_ctrl_new_custom);
>>> @@ -2452,6 +2483,7 @@ int v4l2_ctrl_handler_setup(struct v4l2_ctrl_handler 
>>> *hdl)
>>>  cur_to_new(master->cluster[i]);
>>>  master->cluster[i]->is_new = 1;
>>>  master->cluster[i]->done = true;
>>> +master->cluster[i]->store = 0;
>>>  }
>>>  }
>>>  ret = call_op(master, s_ctrl);
>>> @@ -2539,6 +2571,8 @@ int v4l2_que

Re: [RFC PATCH 04/11] v4l2-ctrls: add config store support

2014-11-17 Thread Hans Verkuil
On 11/14/2014 04:44 PM, Sakari Ailus wrote:
> Hi Hans,
> 
> Some comments below.
> 
> On Sun, Sep 21, 2014 at 04:48:22PM +0200, Hans Verkuil wrote:
>> From: Hans Verkuil 
>>
>> Signed-off-by: Hans Verkuil 
>> ---
>>  drivers/media/v4l2-core/v4l2-ctrls.c | 150 
>> +--
>>  drivers/media/v4l2-core/v4l2-ioctl.c |   4 +-
>>  include/media/v4l2-ctrls.h   |  14 
>>  3 files changed, 141 insertions(+), 27 deletions(-)
>>
>> diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c 
>> b/drivers/media/v4l2-core/v4l2-ctrls.c
>> index 35d1f3d..df0f3ee 100644
>> --- a/drivers/media/v4l2-core/v4l2-ctrls.c
>> +++ b/drivers/media/v4l2-core/v4l2-ctrls.c
>> @@ -1478,6 +1478,15 @@ static int cur_to_user(struct v4l2_ext_control *c,
>>  return ptr_to_user(c, ctrl, ctrl->p_cur);
>>  }
>>  
>> +/* Helper function: copy the store's control value back to the caller */
>> +static int store_to_user(struct v4l2_ext_control *c,
>> +   struct v4l2_ctrl *ctrl, unsigned store)
>> +{
>> +if (store == 0)
>> +return ptr_to_user(c, ctrl, ctrl->p_new);
>> +return ptr_to_user(c, ctrl, ctrl->p_stores[store - 1]);
>> +}
>> +
>>  /* Helper function: copy the new control value back to the caller */
>>  static int new_to_user(struct v4l2_ext_control *c,
>> struct v4l2_ctrl *ctrl)
>> @@ -1585,6 +1594,14 @@ static void new_to_cur(struct v4l2_fh *fh, struct 
>> v4l2_ctrl *ctrl, u32 ch_flags)
>>  }
>>  }
>>  
>> +/* Helper function: copy the new control value to the store */
>> +static void new_to_store(struct v4l2_ctrl *ctrl)
>> +{
>> +/* has_changed is set by cluster_changed */
>> +if (ctrl && ctrl->has_changed)
>> +ptr_to_ptr(ctrl, ctrl->p_new, ctrl->p_stores[ctrl->store - 1]);
>> +}
>> +
>>  /* Copy the current value to the new value */
>>  static void cur_to_new(struct v4l2_ctrl *ctrl)
>>  {
>> @@ -1603,13 +1620,18 @@ static int cluster_changed(struct v4l2_ctrl *master)
>>  
>>  for (i = 0; i < master->ncontrols; i++) {
>>  struct v4l2_ctrl *ctrl = master->cluster[i];
>> +union v4l2_ctrl_ptr ptr;
>>  bool ctrl_changed = false;
>>  
>>  if (ctrl == NULL)
>>  continue;
>> +if (ctrl->store)
>> +ptr = ctrl->p_stores[ctrl->store - 1];
>> +else
>> +ptr = ctrl->p_cur;
>>  for (idx = 0; !ctrl_changed && idx < ctrl->elems; idx++)
>>  ctrl_changed = !ctrl->type_ops->equal(ctrl, idx,
>> -ctrl->p_cur, ctrl->p_new);
>> +ptr, ctrl->p_new);
>>  ctrl->has_changed = ctrl_changed;
>>  changed |= ctrl->has_changed;
>>  }
>> @@ -1740,6 +1762,13 @@ void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler 
>> *hdl)
>>  list_del(&ctrl->node);
>>  list_for_each_entry_safe(sev, next_sev, &ctrl->ev_subs, node)
>>  list_del(&sev->node);
>> +if (ctrl->p_stores) {
>> +unsigned s;
>> +
>> +for (s = 0; s < ctrl->nr_of_stores; s++)
>> +kfree(ctrl->p_stores[s].p);
>> +}
>> +kfree(ctrl->p_stores);
>>  kfree(ctrl);
>>  }
>>  kfree(hdl->buckets);
>> @@ -1970,7 +1999,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct 
>> v4l2_ctrl_handler *hdl,
>>  handler_set_err(hdl, -ERANGE);
>>  return NULL;
>>  }
>> -if (is_array &&
>> +if ((is_array || (flags & V4L2_CTRL_FLAG_CAN_STORE)) &&
>>  (type == V4L2_CTRL_TYPE_BUTTON ||
>>   type == V4L2_CTRL_TYPE_CTRL_CLASS)) {
>>  handler_set_err(hdl, -EINVAL);
>> @@ -2084,8 +2113,10 @@ struct v4l2_ctrl *v4l2_ctrl_new_custom(struct 
>> v4l2_ctrl_handler *hdl,
>>  is_menu ? cfg->menu_skip_mask : step, def,
>>  cfg->dims, cfg->elem_size,
>>  flags, qmenu, qmenu_int, priv);
>> -if (ctrl)
>> +if (ctrl) {
> 
> I think it'd be cleaner to return NULL here if ctrl == NULL. Up to you.

Agreed.

> 
>>  ctrl->is_private = cfg->is_private;
>> +ctrl->can_store = cfg->can_store;
>> +}
>>  return ctrl;
>>  }
>>  EXPORT_SYMBOL(v4l2_ctrl_new_custom);
>> @@ -2452,6 +2483,7 @@ int v4l2_ctrl_handler_setup(struct v4l2_ctrl_handler 
>> *hdl)
>>  cur_to_new(master->cluster[i]);
>>  master->cluster[i]->is_new = 1;
>>  master->cluster[i]->done = true;
>> +master->cluster[i]->store = 0;
>>  }
>>  }
>>  ret = call_op(master, s_ctrl);
>> @@ -2539,6 +2571,8 @@ int v4l2_query_ext_ctrl(struct v4l2_ctrl_handler *hdl, 
>> struct v4l2_query_ext_ctr
>>  qc->id = ctrl->id;
>>  strlcpy(qc->name, ctrl->name, sizeof(qc->name));
>>   

Re: [RFC PATCH 04/11] v4l2-ctrls: add config store support

2014-11-14 Thread Sakari Ailus
Hi Hans,

Some comments below.

On Sun, Sep 21, 2014 at 04:48:22PM +0200, Hans Verkuil wrote:
> From: Hans Verkuil 
> 
> Signed-off-by: Hans Verkuil 
> ---
>  drivers/media/v4l2-core/v4l2-ctrls.c | 150 
> +--
>  drivers/media/v4l2-core/v4l2-ioctl.c |   4 +-
>  include/media/v4l2-ctrls.h   |  14 
>  3 files changed, 141 insertions(+), 27 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c 
> b/drivers/media/v4l2-core/v4l2-ctrls.c
> index 35d1f3d..df0f3ee 100644
> --- a/drivers/media/v4l2-core/v4l2-ctrls.c
> +++ b/drivers/media/v4l2-core/v4l2-ctrls.c
> @@ -1478,6 +1478,15 @@ static int cur_to_user(struct v4l2_ext_control *c,
>   return ptr_to_user(c, ctrl, ctrl->p_cur);
>  }
>  
> +/* Helper function: copy the store's control value back to the caller */
> +static int store_to_user(struct v4l2_ext_control *c,
> +struct v4l2_ctrl *ctrl, unsigned store)
> +{
> + if (store == 0)
> + return ptr_to_user(c, ctrl, ctrl->p_new);
> + return ptr_to_user(c, ctrl, ctrl->p_stores[store - 1]);
> +}
> +
>  /* Helper function: copy the new control value back to the caller */
>  static int new_to_user(struct v4l2_ext_control *c,
>  struct v4l2_ctrl *ctrl)
> @@ -1585,6 +1594,14 @@ static void new_to_cur(struct v4l2_fh *fh, struct 
> v4l2_ctrl *ctrl, u32 ch_flags)
>   }
>  }
>  
> +/* Helper function: copy the new control value to the store */
> +static void new_to_store(struct v4l2_ctrl *ctrl)
> +{
> + /* has_changed is set by cluster_changed */
> + if (ctrl && ctrl->has_changed)
> + ptr_to_ptr(ctrl, ctrl->p_new, ctrl->p_stores[ctrl->store - 1]);
> +}
> +
>  /* Copy the current value to the new value */
>  static void cur_to_new(struct v4l2_ctrl *ctrl)
>  {
> @@ -1603,13 +1620,18 @@ static int cluster_changed(struct v4l2_ctrl *master)
>  
>   for (i = 0; i < master->ncontrols; i++) {
>   struct v4l2_ctrl *ctrl = master->cluster[i];
> + union v4l2_ctrl_ptr ptr;
>   bool ctrl_changed = false;
>  
>   if (ctrl == NULL)
>   continue;
> + if (ctrl->store)
> + ptr = ctrl->p_stores[ctrl->store - 1];
> + else
> + ptr = ctrl->p_cur;
>   for (idx = 0; !ctrl_changed && idx < ctrl->elems; idx++)
>   ctrl_changed = !ctrl->type_ops->equal(ctrl, idx,
> - ctrl->p_cur, ctrl->p_new);
> + ptr, ctrl->p_new);
>   ctrl->has_changed = ctrl_changed;
>   changed |= ctrl->has_changed;
>   }
> @@ -1740,6 +1762,13 @@ void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler 
> *hdl)
>   list_del(&ctrl->node);
>   list_for_each_entry_safe(sev, next_sev, &ctrl->ev_subs, node)
>   list_del(&sev->node);
> + if (ctrl->p_stores) {
> + unsigned s;
> +
> + for (s = 0; s < ctrl->nr_of_stores; s++)
> + kfree(ctrl->p_stores[s].p);
> + }
> + kfree(ctrl->p_stores);
>   kfree(ctrl);
>   }
>   kfree(hdl->buckets);
> @@ -1970,7 +1999,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct 
> v4l2_ctrl_handler *hdl,
>   handler_set_err(hdl, -ERANGE);
>   return NULL;
>   }
> - if (is_array &&
> + if ((is_array || (flags & V4L2_CTRL_FLAG_CAN_STORE)) &&
>   (type == V4L2_CTRL_TYPE_BUTTON ||
>type == V4L2_CTRL_TYPE_CTRL_CLASS)) {
>   handler_set_err(hdl, -EINVAL);
> @@ -2084,8 +2113,10 @@ struct v4l2_ctrl *v4l2_ctrl_new_custom(struct 
> v4l2_ctrl_handler *hdl,
>   is_menu ? cfg->menu_skip_mask : step, def,
>   cfg->dims, cfg->elem_size,
>   flags, qmenu, qmenu_int, priv);
> - if (ctrl)
> + if (ctrl) {

I think it'd be cleaner to return NULL here if ctrl == NULL. Up to you.

>   ctrl->is_private = cfg->is_private;
> + ctrl->can_store = cfg->can_store;
> + }
>   return ctrl;
>  }
>  EXPORT_SYMBOL(v4l2_ctrl_new_custom);
> @@ -2452,6 +2483,7 @@ int v4l2_ctrl_handler_setup(struct v4l2_ctrl_handler 
> *hdl)
>   cur_to_new(master->cluster[i]);
>   master->cluster[i]->is_new = 1;
>   master->cluster[i]->done = true;
> + master->cluster[i]->store = 0;
>   }
>   }
>   ret = call_op(master, s_ctrl);
> @@ -2539,6 +2571,8 @@ int v4l2_query_ext_ctrl(struct v4l2_ctrl_handler *hdl, 
> struct v4l2_query_ext_ctr
>   qc->id = ctrl->id;
>   strlcpy(qc->name, ctrl->name, sizeof(qc->name));
>   qc->flags = ctrl->flags;
> + if (ctrl->can_store)
> + qc->flags |= V4L2_CTRL_FLAG_CAN_STORE;
>   q

[RFC PATCH 04/11] v4l2-ctrls: add config store support

2014-09-21 Thread Hans Verkuil
From: Hans Verkuil 

Signed-off-by: Hans Verkuil 
---
 drivers/media/v4l2-core/v4l2-ctrls.c | 150 +--
 drivers/media/v4l2-core/v4l2-ioctl.c |   4 +-
 include/media/v4l2-ctrls.h   |  14 
 3 files changed, 141 insertions(+), 27 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c 
b/drivers/media/v4l2-core/v4l2-ctrls.c
index 35d1f3d..df0f3ee 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1478,6 +1478,15 @@ static int cur_to_user(struct v4l2_ext_control *c,
return ptr_to_user(c, ctrl, ctrl->p_cur);
 }
 
+/* Helper function: copy the store's control value back to the caller */
+static int store_to_user(struct v4l2_ext_control *c,
+  struct v4l2_ctrl *ctrl, unsigned store)
+{
+   if (store == 0)
+   return ptr_to_user(c, ctrl, ctrl->p_new);
+   return ptr_to_user(c, ctrl, ctrl->p_stores[store - 1]);
+}
+
 /* Helper function: copy the new control value back to the caller */
 static int new_to_user(struct v4l2_ext_control *c,
   struct v4l2_ctrl *ctrl)
@@ -1585,6 +1594,14 @@ static void new_to_cur(struct v4l2_fh *fh, struct 
v4l2_ctrl *ctrl, u32 ch_flags)
}
 }
 
+/* Helper function: copy the new control value to the store */
+static void new_to_store(struct v4l2_ctrl *ctrl)
+{
+   /* has_changed is set by cluster_changed */
+   if (ctrl && ctrl->has_changed)
+   ptr_to_ptr(ctrl, ctrl->p_new, ctrl->p_stores[ctrl->store - 1]);
+}
+
 /* Copy the current value to the new value */
 static void cur_to_new(struct v4l2_ctrl *ctrl)
 {
@@ -1603,13 +1620,18 @@ static int cluster_changed(struct v4l2_ctrl *master)
 
for (i = 0; i < master->ncontrols; i++) {
struct v4l2_ctrl *ctrl = master->cluster[i];
+   union v4l2_ctrl_ptr ptr;
bool ctrl_changed = false;
 
if (ctrl == NULL)
continue;
+   if (ctrl->store)
+   ptr = ctrl->p_stores[ctrl->store - 1];
+   else
+   ptr = ctrl->p_cur;
for (idx = 0; !ctrl_changed && idx < ctrl->elems; idx++)
ctrl_changed = !ctrl->type_ops->equal(ctrl, idx,
-   ctrl->p_cur, ctrl->p_new);
+   ptr, ctrl->p_new);
ctrl->has_changed = ctrl_changed;
changed |= ctrl->has_changed;
}
@@ -1740,6 +1762,13 @@ void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler 
*hdl)
list_del(&ctrl->node);
list_for_each_entry_safe(sev, next_sev, &ctrl->ev_subs, node)
list_del(&sev->node);
+   if (ctrl->p_stores) {
+   unsigned s;
+
+   for (s = 0; s < ctrl->nr_of_stores; s++)
+   kfree(ctrl->p_stores[s].p);
+   }
+   kfree(ctrl->p_stores);
kfree(ctrl);
}
kfree(hdl->buckets);
@@ -1970,7 +1999,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct 
v4l2_ctrl_handler *hdl,
handler_set_err(hdl, -ERANGE);
return NULL;
}
-   if (is_array &&
+   if ((is_array || (flags & V4L2_CTRL_FLAG_CAN_STORE)) &&
(type == V4L2_CTRL_TYPE_BUTTON ||
 type == V4L2_CTRL_TYPE_CTRL_CLASS)) {
handler_set_err(hdl, -EINVAL);
@@ -2084,8 +2113,10 @@ struct v4l2_ctrl *v4l2_ctrl_new_custom(struct 
v4l2_ctrl_handler *hdl,
is_menu ? cfg->menu_skip_mask : step, def,
cfg->dims, cfg->elem_size,
flags, qmenu, qmenu_int, priv);
-   if (ctrl)
+   if (ctrl) {
ctrl->is_private = cfg->is_private;
+   ctrl->can_store = cfg->can_store;
+   }
return ctrl;
 }
 EXPORT_SYMBOL(v4l2_ctrl_new_custom);
@@ -2452,6 +2483,7 @@ int v4l2_ctrl_handler_setup(struct v4l2_ctrl_handler *hdl)
cur_to_new(master->cluster[i]);
master->cluster[i]->is_new = 1;
master->cluster[i]->done = true;
+   master->cluster[i]->store = 0;
}
}
ret = call_op(master, s_ctrl);
@@ -2539,6 +2571,8 @@ int v4l2_query_ext_ctrl(struct v4l2_ctrl_handler *hdl, 
struct v4l2_query_ext_ctr
qc->id = ctrl->id;
strlcpy(qc->name, ctrl->name, sizeof(qc->name));
qc->flags = ctrl->flags;
+   if (ctrl->can_store)
+   qc->flags |= V4L2_CTRL_FLAG_CAN_STORE;
qc->type = ctrl->type;
if (ctrl->is_ptr)
qc->flags |= V4L2_CTRL_FLAG_HAS_PAYLOAD;
@@ -2700,6 +2734,8 @@ static int prepare_ext_ctrls(struct v4l2_ctrl_handler 
*hdl,
 struct v4l2_ctrl_helper *helpers,