Re: [PATCH] RFC: v4l2-ctrls: Inmplement v4l2_ctrl_new_std_compound()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 9/20/19 12:33 PM, Ricardo Ribalda Delgado wrote:
> Hello Hans
> 
> Thanks for your review!  I will implement the changes and resend, just
> one comment.
> 
> 
> On Fri, Sep 20, 2019 at 12:07 PM Hans Verkuil <hverkuil@xxxxxxxxx> wrote:
>>
>> On 9/17/19 6:21 PM, Ricardo Ribalda Delgado wrote:
>>> Hi Hans
>>>
>>> Is this something close to what you were having in mind? Right now it
>>> sits on https://github.com/ribalda/linux/commit/de21dbc2f57b58b22f5d73bc314dd8e59dff5c7d
>>> but I will make it as the beginning of my patchset if you think that I
>>> am on the right track.
>>>
>>> Thanks!
>>>
>>> On Tue, Sep 17, 2019 at 6:19 PM Ricardo Ribalda Delgado
>>> <ribalda@xxxxxxxxxx> wrote:
>>>>
>>>> Implement v4l2_ctrl_new_std_compound. This is just a discussion patch,
>>>> do not merge as is, and be gentle with the author ;P.
>>>>
>>>> Signed-off-by: Ricardo Ribalda Delgado <ribalda@xxxxxxxxxx>
>>>> ---
>>>>  drivers/media/i2c/imx214.c           | 13 +++--
>>>>  drivers/media/v4l2-core/v4l2-ctrls.c | 79 +++++++++++++++++-----------
>>>>  include/media/v4l2-ctrls.h           | 25 +++++++++
>>>>  3 files changed, 81 insertions(+), 36 deletions(-)
>>>>
>>>> diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c
>>>> index 625617d4c81a..e18fed9f31f1 100644
>>>> --- a/drivers/media/i2c/imx214.c
>>>> +++ b/drivers/media/i2c/imx214.c
>>>> @@ -953,6 +953,9 @@ static int imx214_probe(struct i2c_client *client)
>>>>                 .width = 1120,
>>>>                 .height = 1120,
>>>>         };
>>>> +       union v4l2_ctrl_ptr p_def = {
>>>> +               .p_area = &unit_size,
>>>> +       };
>>>>         int ret;
>>>>
>>>>         ret = imx214_parse_fwnode(dev);
>>>> @@ -1034,11 +1037,11 @@ static int imx214_probe(struct i2c_client *client)
>>>>                                              V4L2_CID_EXPOSURE,
>>>>                                              0, 3184, 1, 0x0c70);
>>>>
>>>> -       imx214->unit_size = v4l2_ctrl_new_area(&imx214->ctrls,
>>>> -                                              &imx214_ctrl_ops,
>>>> -                                              V4L2_CID_UNIT_CELL_SIZE,
>>>> -                                              &unit_size);
>>>> -
>>>> +       imx214->unit_size = v4l2_ctrl_new_std_compound(&imx214->ctrls,
>>>> +                                                      NULL,
>>>> +                                                      V4L2_CID_UNIT_CELL_SIZE,
>>>> +                                                      0, 0x7ffffff, 1, 0,
>>>> +                                                      p_def);
>>>>         ret = imx214->ctrls.error;
>>>>         if (ret) {
>>>>                 dev_err(&client->dev, "%s control init failed (%d)\n",
>>>> diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
>>>> index 3d2fa1868982..04813ba2262b 100644
>>>> --- a/drivers/media/v4l2-core/v4l2-ctrls.c
>>>> +++ b/drivers/media/v4l2-core/v4l2-ctrls.c
>>>> @@ -1555,6 +1555,10 @@ static void std_init_compound(const struct v4l2_ctrl *ctrl, u32 idx,
>>>>                 p_mpeg2_slice_params->picture.picture_coding_type =
>>>>                                         V4L2_MPEG2_PICTURE_CODING_TYPE_I;
>>>>                 break;
>>>> +       default:
>>>> +               if (ctrl->has_p_def)
>>>> +                       memcpy(p, ctrl->p_def.p, ctrl->elem_size);
>>>> +               break;
>>
>> It makes more sense to do this at the beginning of this function:
>>
>>         if (ctrl->p_def.p)
>>                 memcpy(p, ctrl->p_def.p, ctrl->elem_size);
>>         else
>>                 memset(p, 0, ctrl->elem_size);
>>
>> and then enter the switch.
>>
>> This avoids calling memset followed by a memcpy.
>>
>>>>         }
>>>>  }
>>>>
>>>> @@ -2369,7 +2373,8 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
>>>>                         s64 min, s64 max, u64 step, s64 def,
>>>>                         const u32 dims[V4L2_CTRL_MAX_DIMS], u32 elem_size,
>>>>                         u32 flags, const char * const *qmenu,
>>>> -                       const s64 *qmenu_int, void *priv)
>>>> +                       const s64 *qmenu_int, const union v4l2_ctrl_ptr p_def,
>>>> +                       void *priv)
>>>>  {
>>>>         struct v4l2_ctrl *ctrl;
>>>>         unsigned sz_extra;
>>>> @@ -2478,6 +2483,9 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
>>>>                  is_array)
>>>>                 sz_extra += 2 * tot_ctrl_size;
>>>>
>>>> +       if (type >= V4L2_CTRL_COMPOUND_TYPES && p_def.p)
>>>> +               sz_extra += elem_size;
>>>> +
>>>>         ctrl = kvzalloc(sizeof(*ctrl) + sz_extra, GFP_KERNEL);
>>>>         if (ctrl == NULL) {
>>>>                 handler_set_err(hdl, -ENOMEM);
>>>> @@ -2521,6 +2529,13 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
>>>>                 ctrl->p_new.p = &ctrl->val;
>>>>                 ctrl->p_cur.p = &ctrl->cur.val;
>>>>         }
>>>> +
>>>> +       if (type >= V4L2_CTRL_COMPOUND_TYPES && p_def.p) {
>>>> +               ctrl->p_def.p = ctrl->p_cur.p + tot_ctrl_size;
>>>> +               memcpy(ctrl->p_def.p, p_def.p, elem_size);
>>>> +               ctrl->has_p_def = true;
>>
>> Is this needed? ctrl->p_def.p would be NULL if there is no p_def.
>>
>>>> +       }
>>>> +
>>>>         for (idx = 0; idx < elems; idx++) {
>>>>                 ctrl->type_ops->init(ctrl, idx, ctrl->p_cur);
>>>>                 ctrl->type_ops->init(ctrl, idx, ctrl->p_new);
>>>> @@ -2550,6 +2565,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl,
>>>>         s64 max = cfg->max;
>>>>         u64 step = cfg->step;
>>>>         s64 def = cfg->def;
>>>> +       const union v4l2_ctrl_ptr p_def = {};
>>
>> I think it is cleaner to have a 'static const union v4l2_ctrl_ptr ptr_null;'
>> at the start of the source and just use that.
>>
>>>>
>>>>         if (name == NULL)
>>>>                 v4l2_ctrl_fill(cfg->id, &name, &type, &min, &max, &step,
>>>> @@ -2572,7 +2588,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl,
>>>>                         type, min, max,
>>>>                         is_menu ? cfg->menu_skip_mask : step, def,
>>>>                         cfg->dims, cfg->elem_size,
>>>> -                       flags, qmenu, qmenu_int, priv);
>>>> +                       flags, qmenu, qmenu_int, p_def, priv);
>>>>         if (ctrl)
>>>>                 ctrl->is_private = cfg->is_private;
>>>>         return ctrl;
>>>> @@ -2587,6 +2603,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl,
>>>>         const char *name;
>>>>         enum v4l2_ctrl_type type;
>>>>         u32 flags;
>>>> +       const union v4l2_ctrl_ptr p_def = {};
>>>>
>>>>         v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
>>>>         if (type == V4L2_CTRL_TYPE_MENU ||
>>>> @@ -2597,7 +2614,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl,
>>>>         }
>>>>         return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
>>>>                              min, max, step, def, NULL, 0,
>>>> -                            flags, NULL, NULL, NULL);
>>>> +                            flags, NULL, NULL, p_def, NULL);
>>>>  }
>>>>  EXPORT_SYMBOL(v4l2_ctrl_new_std);
>>>>
>>>> @@ -2616,6 +2633,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl,
>>>>         s64 def = _def;
>>>>         u64 step;
>>>>         u32 flags;
>>>> +       const union v4l2_ctrl_ptr p_def = {};
>>>>
>>>>         v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
>>>>
>>>> @@ -2630,7 +2648,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl,
>>>>         }
>>>>         return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
>>>>                              0, max, mask, def, NULL, 0,
>>>> -                            flags, qmenu, qmenu_int, NULL);
>>>> +                            flags, qmenu, qmenu_int, p_def, NULL);
>>>>  }
>>>>  EXPORT_SYMBOL(v4l2_ctrl_new_std_menu);
>>>>
>>>> @@ -2646,6 +2664,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu_items(struct v4l2_ctrl_handler *hdl,
>>>>         s64 min;
>>>>         s64 max = _max;
>>>>         s64 def = _def;
>>>> +       const union v4l2_ctrl_ptr p_def = {};
>>>>
>>>>         /* v4l2_ctrl_new_std_menu_items() should only be called for
>>>>          * standard controls without a standard menu.
>>>> @@ -2662,11 +2681,33 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu_items(struct v4l2_ctrl_handler *hdl,
>>>>         }
>>>>         return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
>>>>                              0, max, mask, def, NULL, 0,
>>>> -                            flags, qmenu, NULL, NULL);
>>>> +                            flags, qmenu, NULL, p_def, NULL);
>>>>
>>>>  }
>>>>  EXPORT_SYMBOL(v4l2_ctrl_new_std_menu_items);
>>>>
>>>> +/* Helper function for standard compound controls */
>>>> +struct v4l2_ctrl *v4l2_ctrl_new_std_compound(struct v4l2_ctrl_handler *hdl,
>>>> +                       const struct v4l2_ctrl_ops *ops,
>>>> +                       u32 id, s64 min, s64 max, u64 step, s64 def,
>>
>> The def arg makes no sense, since that's superseded by p_def.
>>
> 
> If def does not make sense, then for the same reason min, max and step
> should not make any sense (because they are not a pointer but a
> integer).
> What about removing them completely from the function prototype and
> add them later if we change our mind, it is a internal API.

I've been going back and forth about whether or not min/max/step is useful
for e.g. this AREA control as it would still help in validating a range
for the width and height. But I think you are right, and it is better to
just drop this and mark min/max/step/def as N/A in the documentation for
these compound controls.

We DO need basic validation for AREA (i.e. the width/height shall be > 0),
but that's easy enough.

Regards,

	Hans

> 
>>>> +                       const union v4l2_ctrl_ptr p_def)
>>>> +{
>>>> +       const char *name;
>>>> +       enum v4l2_ctrl_type type;
>>>> +       u32 flags;
>>
>> Add:
>>
>>         s64 def = min;
>>
>> It will be discarded anyway.
>>
>>>> +
>>>> +       v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
>>>> +       if (type == V4L2_CTRL_TYPE_MENU ||
>>>> +           type == V4L2_CTRL_TYPE_INTEGER_MENU) {
>>>> +               handler_set_err(hdl, -EINVAL);
>>>> +               return NULL;
>>>> +       }
>>
>> This makes no sense. It should just check that the type is a compound type and
>> return an error if it isn't.
>>
>>>> +       return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
>>>> +                            min, max, step, def, NULL, 0,
>>>> +                            flags, NULL, NULL, p_def, NULL);
>>>> +}
>>>> +EXPORT_SYMBOL(v4l2_ctrl_new_std_compound);
>>>> +
>>>>  /* Helper function for standard integer menu controls */
>>>>  struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl,
>>>>                         const struct v4l2_ctrl_ops *ops,
>>>> @@ -2679,6 +2720,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl,
>>>>         s64 max = _max;
>>>>         s64 def = _def;
>>>>         u32 flags;
>>>> +       const union v4l2_ctrl_ptr p_def = {};
>>>>
>>>>         v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
>>>>         if (type != V4L2_CTRL_TYPE_INTEGER_MENU) {
>>>> @@ -2687,7 +2729,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl,
>>>>         }
>>>>         return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
>>>>                              0, max, 0, def, NULL, 0,
>>>> -                            flags, NULL, qmenu_int, NULL);
>>>> +                            flags, NULL, qmenu_int, p_def, NULL);
>>>>  }
>>>>  EXPORT_SYMBOL(v4l2_ctrl_new_int_menu);
>>>>
>>>> @@ -4030,31 +4072,6 @@ static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags)
>>>>         return try_or_set_cluster(fh, master, true, ch_flags);
>>>>  }
>>>>
>>>> -/* Helper function for area controls */
>>>> -struct v4l2_ctrl *v4l2_ctrl_new_area(struct v4l2_ctrl_handler *hdl,
>>>> -                                    const struct v4l2_ctrl_ops *ops,
>>>> -                                    u32 id, const struct v4l2_area *area)
>>>> -{
>>>> -       static struct v4l2_ctrl_config ctrl = {};
>>>> -       struct v4l2_ctrl *c;
>>>> -       int ret;
>>>> -
>>>> -       ctrl.id = id;
>>>> -       c = v4l2_ctrl_new_custom(hdl, &ctrl, (void *)area);
>>>> -       if (!c)
>>>> -               return NULL;
>>>> -
>>>> -       memcpy(c->p_new.p_area, area, sizeof(*area));
>>>> -       ret = set_ctrl(NULL, c, 0);
>>>> -       if (ret){
>>>> -               hdl->error = ret;
>>>> -               return NULL;
>>>> -       }
>>>> -
>>>> -       return c;
>>>> -}
>>>> -EXPORT_SYMBOL(v4l2_ctrl_new_area);
>>>> -
>>>>  /* Helper function for VIDIOC_S_CTRL compatibility */
>>>>  static int set_ctrl_lock(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl,
>>>>                          struct v4l2_ext_control *c)
>>>> diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
>>>> index b5b42777a756..8dc7e9827056 100644
>>>> --- a/include/media/v4l2-ctrls.h
>>>> +++ b/include/media/v4l2-ctrls.h
>>>> @@ -164,6 +164,7 @@ 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.
>>>> + * @has_p_def:  If set, the p_def field points to the default value of the control.
>>>>   * @ops:       The control ops.
>>>>   * @type_ops:  The control type ops.
>>>>   * @id:        The control ID.
>>>> @@ -230,6 +231,7 @@ struct v4l2_ctrl {
>>>>         unsigned int has_volatiles:1;
>>>>         unsigned int call_notify:1;
>>>>         unsigned int manual_mode_value:8;
>>>> +       unsigned int has_p_def:1;
>>>>
>>>>         const struct v4l2_ctrl_ops *ops;
>>>>         const struct v4l2_ctrl_type_ops *type_ops;
>>>> @@ -256,6 +258,7 @@ struct v4l2_ctrl {
>>>>                 s32 val;
>>>>         } cur;
>>>>
>>>> +       union v4l2_ctrl_ptr p_def;
>>>>         union v4l2_ctrl_ptr p_new;
>>>>         union v4l2_ctrl_ptr p_cur;
>>>>  };
>>>> @@ -647,6 +650,28 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu_items(struct v4l2_ctrl_handler *hdl,
>>>>                                                u32 id, u8 max,
>>>>                                                u64 mask, u8 def,
>>>>                                                const char * const *qmenu);
>>>> +/**
>>>> + * v4l2_ctrl_new_std_compound() - Allocate and initialize a new standard V4L2
>>>> + *      compound control.
>>>> + *
>>>> + * @hdl:       The control handler.
>>>> + * @ops:       The control ops.
>>>> + * @id:                The control ID.
>>>> + * @min:       The control's minimum value.
>>>> + * @max:       The control's maximum value.
>>>> + * @step:      The control's step value
>>>> + * @def:       The control's default value.
>>>> + * @p_def:     The control's p_def value.
>>>> + *
>>>> + * Sames as v4l2_ctrl_new_std(), but with support to compound controls, thanks to
>>>> + * the @p_def field.
>>>> + *
>>>> + */
>>>> +struct v4l2_ctrl *v4l2_ctrl_new_std_compound(struct v4l2_ctrl_handler *hdl,
>>>> +                                   const struct v4l2_ctrl_ops *ops,
>>>> +                                   u32 id, s64 min, s64 max, u64 step,
>>>> +                                   s64 def, const union v4l2_ctrl_ptr p_def);
>>>> +
>>>>
>>>>  /**
>>>>   * v4l2_ctrl_new_int_menu() - Create a new standard V4L2 integer menu control.
>>>> --
>>>> 2.23.0
>>>>
>>
>> So other than these fairly minor points, this is indeed what I was looking for.
>>
>> Regards,
>>
>>         Hans




[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux