[PATCHv2] media: v4l2-ctrls: add support for fraction_bits
Commit Message
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@xs4all.nl>
---
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(-)
Comments
>
> 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@xs4all.nl>
Tested-by: Shengjiu Wang <shengjiu.wang@nxp.com>
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
@@ -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.
@@ -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;
@@ -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);
@@ -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;
@@ -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 */