> > This adds support for the fraction_bits field, used with integer controls. > This allows fixed point formats to be described. > > The fraction_bits field is only exposed through VIDIOC_QUERY_EXT_CTRL. > > For a given signed two's complement Qf fixed point value 'f' equals > fraction_bits. > > Signed-off-by: Hans Verkuil <hverkuil-cisco@xxxxxxxxx> Tested-by: Shengjiu Wang <shengjiu.wang@xxxxxxx> Best regards Wang Shengjiu > --- > Changes in v2: use div64_s64 > > This is the cleaned up version of my earlier RFC patch. > > Shengjiu, for your next patch series just use this patch. > > Note that I dropped the inline helpers in videodev2.h, but I am not sure if > there shouldn't still be a helper added to include/media/v4l2-ctrls.h in order > to fill in a fixed point value. > > Regards, > > Hans > --- > .../media/v4l/vidioc-queryctrl.rst | 11 ++- > drivers/media/v4l2-core/v4l2-ctrls-api.c | 1 + > drivers/media/v4l2-core/v4l2-ctrls-core.c | 93 +++++++++++++++---- > include/media/v4l2-ctrls.h | 7 +- > include/uapi/linux/videodev2.h | 3 +- > 5 files changed, 95 insertions(+), 20 deletions(-) > > diff --git a/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst > b/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst > index 4d38acafe8e1..e65c7e5d78ec 100644 > --- a/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst > +++ b/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst > @@ -267,7 +267,16 @@ See also the examples in :ref:`control`. > - The size of each dimension. The first ``nr_of_dims`` elements of > this array must be non-zero, all remaining elements must be zero. > * - __u32 > - - ``reserved``\ [32] > + - ``fraction_bits`` > + - The number of least significant bits of the control value that > + form the fraction of the fixed point value. This is 0 if the value > + is a regular integer. This can be used with all integer control types > + (``INTEGER``, ``INTEGER64``, ``U8``, ``U16`` and ``U32``). > + For the signed types the signed two's complement representation is > used. > + This field applies to the control value as well as the ``minimum``, > + ``maximum``, ``step`` and ``default_value`` fields. > + * - __u32 > + - ``reserved``\ [31] > - Reserved for future extensions. Applications and drivers must set > the array to zero. > > diff --git a/drivers/media/v4l2-core/v4l2-ctrls-api.c b/drivers/media/v4l2- > core/v4l2-ctrls-api.c > index 002ea6588edf..3132df315b17 100644 > --- a/drivers/media/v4l2-core/v4l2-ctrls-api.c > +++ b/drivers/media/v4l2-core/v4l2-ctrls-api.c > @@ -1101,6 +1101,7 @@ int v4l2_query_ext_ctrl(struct v4l2_ctrl_handler > *hdl, struct v4l2_query_ext_ctr > qc->elems = ctrl->elems; > qc->nr_of_dims = ctrl->nr_of_dims; > memcpy(qc->dims, ctrl->dims, qc->nr_of_dims * sizeof(qc->dims[0])); > + qc->fraction_bits = ctrl->fraction_bits; > qc->minimum = ctrl->minimum; > qc->maximum = ctrl->maximum; > qc->default_value = ctrl->default_value; diff --git a/drivers/media/v4l2- > core/v4l2-ctrls-core.c b/drivers/media/v4l2-core/v4l2-ctrls-core.c > index a662fb60f73f..b86ceaaacbd7 100644 > --- a/drivers/media/v4l2-core/v4l2-ctrls-core.c > +++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c > @@ -252,12 +252,61 @@ void v4l2_ctrl_type_op_init(const struct v4l2_ctrl > *ctrl, u32 from_idx, } EXPORT_SYMBOL(v4l2_ctrl_type_op_init); > > +static void v4l2_ctrl_log_fp(s64 v, unsigned int fraction_bits) { > + s64 i, f, mask; > + > + if (!fraction_bits) { > + pr_cont("%lld", v); > + return; > + } > + > + mask = (1ULL << fraction_bits) - 1; > + > + /* > + * Note: this function does not support fixed point u64 with > + * fraction_bits set to 64. At the moment there is no U64 > + * control type, but if that is added, then this code will have > + * to add support for it. > + */ > + if (fraction_bits >= 63) > + i = v < 0 ? -1 : 0; > + else > + i = div64_s64(v, 1LL << fraction_bits); > + > + f = v < 0 ? -((-v) & mask) : (v & mask); > + > + if (!f) { > + pr_cont("%lld", i); > + } else if (fraction_bits < 20) { > + u64 div = 1ULL << fraction_bits; > + > + if (!i && f < 0) > + pr_cont("-%lld/%llu", -f, div); > + else if (!i) > + pr_cont("%lld/%llu", f, div); > + else if (i < 0 || f < 0) > + pr_cont("-%lld-%llu/%llu", -i, -f, div); > + else > + pr_cont("%lld+%llu/%llu", i, f, div); > + } else { > + if (!i && f < 0) > + pr_cont("-%lld/(2^%u)", -f, fraction_bits); > + else if (!i) > + pr_cont("%lld/(2^%u)", f, fraction_bits); > + else if (i < 0 || f < 0) > + pr_cont("-%lld-%llu/(2^%u)", -i, -f, fraction_bits); > + else > + pr_cont("%lld+%llu/(2^%u)", i, f, fraction_bits); > + } > +} > + > void v4l2_ctrl_type_op_log(const struct v4l2_ctrl *ctrl) { > union v4l2_ctrl_ptr ptr = ctrl->p_cur; > > if (ctrl->is_array) { > - unsigned i; > + unsigned int i; > > for (i = 0; i < ctrl->nr_of_dims; i++) > pr_cont("[%u]", ctrl->dims[i]); @@ -266,7 +315,7 @@ void > v4l2_ctrl_type_op_log(const struct v4l2_ctrl *ctrl) > > switch (ctrl->type) { > case V4L2_CTRL_TYPE_INTEGER: > - pr_cont("%d", *ptr.p_s32); > + v4l2_ctrl_log_fp(*ptr.p_s32, ctrl->fraction_bits); > break; > case V4L2_CTRL_TYPE_BOOLEAN: > pr_cont("%s", *ptr.p_s32 ? "true" : "false"); @@ -281,19 +330,19 > @@ void v4l2_ctrl_type_op_log(const struct v4l2_ctrl *ctrl) > pr_cont("0x%08x", *ptr.p_s32); > break; > case V4L2_CTRL_TYPE_INTEGER64: > - pr_cont("%lld", *ptr.p_s64); > + v4l2_ctrl_log_fp(*ptr.p_s64, ctrl->fraction_bits); > break; > case V4L2_CTRL_TYPE_STRING: > pr_cont("%s", ptr.p_char); > break; > case V4L2_CTRL_TYPE_U8: > - pr_cont("%u", (unsigned)*ptr.p_u8); > + v4l2_ctrl_log_fp(*ptr.p_u8, ctrl->fraction_bits); > break; > case V4L2_CTRL_TYPE_U16: > - pr_cont("%u", (unsigned)*ptr.p_u16); > + v4l2_ctrl_log_fp(*ptr.p_u16, ctrl->fraction_bits); > break; > case V4L2_CTRL_TYPE_U32: > - pr_cont("%u", (unsigned)*ptr.p_u32); > + v4l2_ctrl_log_fp(*ptr.p_u32, ctrl->fraction_bits); > break; > case V4L2_CTRL_TYPE_H264_SPS: > pr_cont("H264_SPS"); > @@ -1752,11 +1801,12 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct > v4l2_ctrl_handler *hdl, > u32 id, const char *name, enum v4l2_ctrl_type type, > s64 min, s64 max, u64 step, s64 def, > const u32 dims[V4L2_CTRL_MAX_DIMS], u32 elem_size, > - u32 flags, const char * const *qmenu, > + u32 fraction_bits, u32 flags, const char * const > + *qmenu, > const s64 *qmenu_int, const union v4l2_ctrl_ptr p_def, > void *priv) > { > struct v4l2_ctrl *ctrl; > + unsigned int max_fraction_bits = 0; > unsigned sz_extra; > unsigned nr_of_dims = 0; > unsigned elems = 1; > @@ -1778,20 +1828,28 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct > v4l2_ctrl_handler *hdl, > > /* Prefill elem_size for all types handled by std_type_ops */ > switch ((u32)type) { > + case V4L2_CTRL_TYPE_INTEGER: > + elem_size = sizeof(s32); > + max_fraction_bits = 31; > + break; > case V4L2_CTRL_TYPE_INTEGER64: > elem_size = sizeof(s64); > + max_fraction_bits = 63; > break; > case V4L2_CTRL_TYPE_STRING: > elem_size = max + 1; > break; > case V4L2_CTRL_TYPE_U8: > elem_size = sizeof(u8); > + max_fraction_bits = 8; > break; > case V4L2_CTRL_TYPE_U16: > elem_size = sizeof(u16); > + max_fraction_bits = 16; > break; > case V4L2_CTRL_TYPE_U32: > elem_size = sizeof(u32); > + max_fraction_bits = 32; > break; > case V4L2_CTRL_TYPE_MPEG2_SEQUENCE: > elem_size = sizeof(struct v4l2_ctrl_mpeg2_sequence); @@ -1875,10 > +1933,10 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler > *hdl, > } > > /* Sanity checks */ > - if (id == 0 || name == NULL || !elem_size || > - id >= V4L2_CID_PRIVATE_BASE || > - (type == V4L2_CTRL_TYPE_MENU && qmenu == NULL) || > - (type == V4L2_CTRL_TYPE_INTEGER_MENU && qmenu_int == NULL)) { > + if (id == 0 || !name || !elem_size || > + fraction_bits > max_fraction_bits || id >= V4L2_CID_PRIVATE_BASE || > + (type == V4L2_CTRL_TYPE_MENU && !qmenu) || > + (type == V4L2_CTRL_TYPE_INTEGER_MENU && !qmenu_int)) { > handler_set_err(hdl, -ERANGE); > return NULL; > } > @@ -1939,6 +1997,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct > v4l2_ctrl_handler *hdl, > ctrl->name = name; > ctrl->type = type; > ctrl->flags = flags; > + ctrl->fraction_bits = fraction_bits; > ctrl->minimum = min; > ctrl->maximum = max; > ctrl->step = step; > @@ -2037,7 +2096,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_custom(struct > v4l2_ctrl_handler *hdl, > ctrl = v4l2_ctrl_new(hdl, cfg->ops, cfg->type_ops, cfg->id, name, > type, min, max, > is_menu ? cfg->menu_skip_mask : step, def, > - cfg->dims, cfg->elem_size, > + cfg->dims, cfg->elem_size, cfg->fraction_bits, > flags, qmenu, qmenu_int, cfg->p_def, priv); > if (ctrl) > ctrl->is_private = cfg->is_private; @@ -2062,7 +2121,7 @@ struct > v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl, > return NULL; > } > return v4l2_ctrl_new(hdl, ops, NULL, id, name, type, > - min, max, step, def, NULL, 0, > + min, max, step, def, NULL, 0, 0, > flags, NULL, NULL, ptr_null, NULL); } > EXPORT_SYMBOL(v4l2_ctrl_new_std); @@ -2095,7 +2154,7 @@ struct > v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl, > return NULL; > } > return v4l2_ctrl_new(hdl, ops, NULL, id, name, type, > - 0, max, mask, def, NULL, 0, > + 0, max, mask, def, NULL, 0, 0, > flags, qmenu, qmenu_int, ptr_null, NULL); } > EXPORT_SYMBOL(v4l2_ctrl_new_std_menu); > @@ -2127,7 +2186,7 @@ struct v4l2_ctrl > *v4l2_ctrl_new_std_menu_items(struct v4l2_ctrl_handler *hdl, > return NULL; > } > return v4l2_ctrl_new(hdl, ops, NULL, id, name, type, > - 0, max, mask, def, NULL, 0, > + 0, max, mask, def, NULL, 0, 0, > flags, qmenu, NULL, ptr_null, NULL); > > } > @@ -2149,7 +2208,7 @@ struct v4l2_ctrl > *v4l2_ctrl_new_std_compound(struct v4l2_ctrl_handler *hdl, > return NULL; > } > return v4l2_ctrl_new(hdl, ops, NULL, id, name, type, > - min, max, step, def, NULL, 0, > + min, max, step, def, NULL, 0, 0, > flags, NULL, NULL, p_def, NULL); } > EXPORT_SYMBOL(v4l2_ctrl_new_std_compound); > @@ -2173,7 +2232,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct > v4l2_ctrl_handler *hdl, > return NULL; > } > return v4l2_ctrl_new(hdl, ops, NULL, id, name, type, > - 0, max, 0, def, NULL, 0, > + 0, max, 0, def, NULL, 0, 0, > flags, NULL, qmenu_int, ptr_null, NULL); } > EXPORT_SYMBOL(v4l2_ctrl_new_int_menu); > diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h index > 59679a42b3e7..c35514c5bf88 100644 > --- a/include/media/v4l2-ctrls.h > +++ b/include/media/v4l2-ctrls.h > @@ -211,7 +211,8 @@ typedef void (*v4l2_ctrl_notify_fnc)(struct v4l2_ctrl > *ctrl, void *priv); > * except for dynamic arrays. In that case it is in the range of > * 1 to @p_array_alloc_elems. > * @dims: The size of each dimension. > - * @nr_of_dims:The number of dimensions in @dims. > + * @nr_of_dims: The number of dimensions in @dims. > + * @fraction_bits: The number of fraction bits for fixed point values. > * @menu_skip_mask: The control's skip mask for menu controls. This > makes it > * easy to skip menu items that are not valid. If bit X is set, > * then menu item X is skipped. Of course, this only works for > @@ -228,6 +229,7 @@ typedef void (*v4l2_ctrl_notify_fnc)(struct v4l2_ctrl > *ctrl, void *priv); > * :math:`ceil(\frac{maximum - minimum}{step}) + 1`. > * Used only if the @type is %V4L2_CTRL_TYPE_INTEGER_MENU. > * @flags: The control's flags. > + * @fraction_bits: The number of fraction bits for fixed point values. > * @priv: The control's private pointer. For use by the driver. It is > * untouched by the control framework. Note that this pointer is > * not freed when the control is deleted. Should this be needed > @@ -286,6 +288,7 @@ struct v4l2_ctrl { > u32 new_elems; > u32 dims[V4L2_CTRL_MAX_DIMS]; > u32 nr_of_dims; > + u32 fraction_bits; > union { > u64 step; > u64 menu_skip_mask; > @@ -426,6 +429,7 @@ struct v4l2_ctrl_handler { > * @dims: The size of each dimension. > * @elem_size: The size in bytes of the control. > * @flags: The control's flags. > + * @fraction_bits: The number of fraction bits for fixed point values. > * @menu_skip_mask: The control's skip mask for menu controls. This > makes it > * easy to skip menu items that are not valid. If bit X is set, > * then menu item X is skipped. Of course, this only works for > @@ -455,6 +459,7 @@ struct v4l2_ctrl_config { > u32 dims[V4L2_CTRL_MAX_DIMS]; > u32 elem_size; > u32 flags; > + u32 fraction_bits; > u64 menu_skip_mask; > const char * const *qmenu; > const s64 *qmenu_int; > diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h > index c3d4e490ce7c..3813212a5cd3 100644 > --- a/include/uapi/linux/videodev2.h > +++ b/include/uapi/linux/videodev2.h > @@ -1944,7 +1944,8 @@ struct v4l2_query_ext_ctrl { > __u32 elems; > __u32 nr_of_dims; > __u32 dims[V4L2_CTRL_MAX_DIMS]; > - __u32 reserved[32]; > + __u32 fraction_bits; > + __u32 reserved[31]; > }; > > /* Used in the VIDIOC_QUERYMENU ioctl for querying menu items */ > -- > 2.42.0