1 From 613b860fe9c37b96d9706b02fe77933f086f9896 Mon Sep 17 00:00:00 2001
2 From: Hans Verkuil <hverkuil-cisco@xs4all.nl>
3 Date: Thu, 15 Apr 2021 13:56:53 +0200
4 Subject: [PATCH] v4l2-ctrls: add support for dynamically allocated
7 Implement support for dynamically allocated arrays.
9 Most of the changes concern keeping track of the number of elements
10 of the array and the number of elements allocated for the array and
11 reallocating memory if needed.
13 Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
14 (cherry picked from commit fd5d45e6561f6f8c406b81aeddecaa11f0bd15af)
16 drivers/media/v4l2-core/v4l2-ctrls-api.c | 103 ++++++++---
17 drivers/media/v4l2-core/v4l2-ctrls-core.c | 182 +++++++++++++++----
18 drivers/media/v4l2-core/v4l2-ctrls-priv.h | 3 +-
19 drivers/media/v4l2-core/v4l2-ctrls-request.c | 13 +-
20 include/media/v4l2-ctrls.h | 42 ++++-
21 5 files changed, 272 insertions(+), 71 deletions(-)
23 --- a/drivers/media/v4l2-core/v4l2-ctrls-api.c
24 +++ b/drivers/media/v4l2-core/v4l2-ctrls-api.c
25 @@ -97,29 +97,47 @@ static int def_to_user(struct v4l2_ext_c
26 return ptr_to_user(c, ctrl, ctrl->p_new);
29 -/* Helper function: copy the caller-provider value to the given control value */
30 -static int user_to_ptr(struct v4l2_ext_control *c,
31 - struct v4l2_ctrl *ctrl,
32 - union v4l2_ctrl_ptr ptr)
33 +/* Helper function: copy the caller-provider value as the new control value */
34 +static int user_to_new(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl)
41 + if (ctrl->is_dyn_array &&
42 + c->size > ctrl->p_dyn_alloc_elems * ctrl->elem_size) {
43 + void *old = ctrl->p_dyn;
44 + void *tmp = kvzalloc(2 * c->size, GFP_KERNEL);
48 + memcpy(tmp, ctrl->p_new.p, ctrl->elems * ctrl->elem_size);
49 + memcpy(tmp + c->size, ctrl->p_cur.p, ctrl->elems * ctrl->elem_size);
50 + ctrl->p_new.p = tmp;
51 + ctrl->p_cur.p = tmp + c->size;
53 + ctrl->p_dyn_alloc_elems = c->size / ctrl->elem_size;
57 if (ctrl->is_ptr && !ctrl->is_string) {
58 + unsigned int elems = c->size / ctrl->elem_size;
61 - ret = copy_from_user(ptr.p, c->ptr, c->size) ? -EFAULT : 0;
62 - if (ret || !ctrl->is_array)
64 - for (idx = c->size / ctrl->elem_size; idx < ctrl->elems; idx++)
65 - ctrl->type_ops->init(ctrl, idx, ptr);
66 + if (copy_from_user(ctrl->p_new.p, c->ptr, c->size))
69 + if (ctrl->is_dyn_array)
70 + ctrl->new_elems = elems;
71 + else if (ctrl->is_array)
72 + for (idx = elems; idx < ctrl->elems; idx++)
73 + ctrl->type_ops->init(ctrl, idx, ctrl->p_new);
78 case V4L2_CTRL_TYPE_INTEGER64:
79 - *ptr.p_s64 = c->value64;
80 + *ctrl->p_new.p_s64 = c->value64;
82 case V4L2_CTRL_TYPE_STRING:
84 @@ -127,32 +145,27 @@ static int user_to_ptr(struct v4l2_ext_c
86 if (size > ctrl->maximum + 1)
87 size = ctrl->maximum + 1;
88 - ret = copy_from_user(ptr.p_char, c->string, size) ? -EFAULT : 0;
89 + ret = copy_from_user(ctrl->p_new.p_char, c->string, size) ? -EFAULT : 0;
91 - char last = ptr.p_char[size - 1];
92 + char last = ctrl->p_new.p_char[size - 1];
94 - ptr.p_char[size - 1] = 0;
95 + ctrl->p_new.p_char[size - 1] = 0;
97 * If the string was longer than ctrl->maximum,
98 * then return an error.
100 - if (strlen(ptr.p_char) == ctrl->maximum && last)
101 + if (strlen(ctrl->p_new.p_char) == ctrl->maximum && last)
106 - *ptr.p_s32 = c->value;
107 + *ctrl->p_new.p_s32 = c->value;
114 -/* Helper function: copy the caller-provider value as the new control value */
115 -static int user_to_new(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl)
117 - return user_to_ptr(c, ctrl, ctrl->p_new);
121 * VIDIOC_G/TRY/S_EXT_CTRLS implementation
123 @@ -254,7 +267,31 @@ static int prepare_ext_ctrls(struct v4l2
124 have_clusters = true;
125 if (ctrl->cluster[0] != ctrl)
126 ref = find_ref_lock(hdl, ctrl->cluster[0]->id);
127 - if (ctrl->is_ptr && !ctrl->is_string) {
128 + if (ctrl->is_dyn_array) {
129 + unsigned int max_size = ctrl->dims[0] * ctrl->elem_size;
130 + unsigned int tot_size = ctrl->elem_size;
132 + if (cs->which == V4L2_CTRL_WHICH_REQUEST_VAL)
133 + tot_size *= ref->p_req_elems;
135 + tot_size *= ctrl->elems;
137 + c->size = ctrl->elem_size * (c->size / ctrl->elem_size);
139 + if (c->size < tot_size) {
140 + c->size = tot_size;
143 + c->size = tot_size;
145 + if (c->size > max_size) {
146 + c->size = max_size;
152 + } else if (ctrl->is_ptr && !ctrl->is_string) {
153 unsigned int tot_size = ctrl->elems * ctrl->elem_size;
155 if (c->size < tot_size) {
156 @@ -346,7 +383,7 @@ static int class_check(struct v4l2_ctrl_
158 * Note that v4l2_g_ext_ctrls_common() with 'which' set to
159 * V4L2_CTRL_WHICH_REQUEST_VAL is only called if the request was
160 - * completed, and in that case valid_p_req is true for all controls.
161 + * completed, and in that case p_req_valid is true for all controls.
163 int v4l2_g_ext_ctrls_common(struct v4l2_ctrl_handler *hdl,
164 struct v4l2_ext_controls *cs,
165 @@ -430,7 +467,9 @@ int v4l2_g_ext_ctrls_common(struct v4l2_
168 ret = def_to_user(cs->controls + idx, ref->ctrl);
169 - else if (is_request && ref->valid_p_req)
170 + else if (is_request && ref->p_req_dyn_enomem)
172 + else if (is_request && ref->p_req_valid)
173 ret = req_to_user(cs->controls + idx, ref);
174 else if (is_volatile)
175 ret = new_to_user(cs->controls + idx, ref->ctrl);
176 @@ -457,6 +496,17 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_ha
178 EXPORT_SYMBOL(v4l2_g_ext_ctrls);
180 +/* Validate a new control */
181 +static int validate_new(const struct v4l2_ctrl *ctrl, union v4l2_ctrl_ptr p_new)
186 + for (idx = 0; !err && idx < ctrl->new_elems; idx++)
187 + err = ctrl->type_ops->validate(ctrl, idx, p_new);
191 /* Validate controls. */
192 static int validate_ctrls(struct v4l2_ext_controls *cs,
193 struct v4l2_ctrl_helper *helpers,
194 @@ -872,6 +922,9 @@ int __v4l2_ctrl_s_ctrl_compound(struct v
195 /* It's a driver bug if this happens. */
196 if (WARN_ON(ctrl->type != type))
198 + /* Setting dynamic arrays is not (yet?) supported. */
199 + if (WARN_ON(ctrl->is_dyn_array))
201 memcpy(ctrl->p_new.p, p, ctrl->elems * ctrl->elem_size);
202 return set_ctrl(NULL, ctrl, 0);
204 --- a/drivers/media/v4l2-core/v4l2-ctrls-core.c
205 +++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c
206 @@ -809,11 +809,12 @@ EXPORT_SYMBOL(v4l2_ctrl_notify);
208 /* Copy the one value to another. */
209 static void ptr_to_ptr(struct v4l2_ctrl *ctrl,
210 - union v4l2_ctrl_ptr from, union v4l2_ctrl_ptr to)
211 + union v4l2_ctrl_ptr from, union v4l2_ctrl_ptr to,
212 + unsigned int elems)
216 - memcpy(to.p, from.p_const, ctrl->elems * ctrl->elem_size);
217 + memcpy(to.p, from.p_const, elems * ctrl->elem_size);
220 /* Copy the new value to the current value. */
221 @@ -826,8 +827,11 @@ void new_to_cur(struct v4l2_fh *fh, stru
223 /* has_changed is set by cluster_changed */
224 changed = ctrl->has_changed;
226 - ptr_to_ptr(ctrl, ctrl->p_new, ctrl->p_cur);
228 + if (ctrl->is_dyn_array)
229 + ctrl->elems = ctrl->new_elems;
230 + ptr_to_ptr(ctrl, ctrl->p_new, ctrl->p_cur, ctrl->elems);
233 if (ch_flags & V4L2_EVENT_CTRL_CH_FLAGS) {
234 /* Note: CH_FLAGS is only set for auto clusters. */
235 @@ -857,36 +861,122 @@ void cur_to_new(struct v4l2_ctrl *ctrl)
239 - ptr_to_ptr(ctrl, ctrl->p_cur, ctrl->p_new);
240 + if (ctrl->is_dyn_array)
241 + ctrl->new_elems = ctrl->elems;
242 + ptr_to_ptr(ctrl, ctrl->p_cur, ctrl->p_new, ctrl->new_elems);
245 +static bool req_alloc_dyn_array(struct v4l2_ctrl_ref *ref, u32 elems)
249 + if (elems < ref->p_req_dyn_alloc_elems)
252 + tmp = kvmalloc(elems * ref->ctrl->elem_size, GFP_KERNEL);
255 + ref->p_req_dyn_enomem = true;
258 + ref->p_req_dyn_enomem = false;
259 + kvfree(ref->p_req.p);
260 + ref->p_req.p = tmp;
261 + ref->p_req_dyn_alloc_elems = elems;
265 /* Copy the new value to the request value */
266 void new_to_req(struct v4l2_ctrl_ref *ref)
268 + struct v4l2_ctrl *ctrl;
272 - ptr_to_ptr(ref->ctrl, ref->ctrl->p_new, ref->p_req);
273 - ref->valid_p_req = true;
276 + if (ctrl->is_dyn_array && !req_alloc_dyn_array(ref, ctrl->new_elems))
279 + ref->p_req_elems = ctrl->new_elems;
280 + ptr_to_ptr(ctrl, ctrl->p_new, ref->p_req, ref->p_req_elems);
281 + ref->p_req_valid = true;
284 /* Copy the current value to the request value */
285 void cur_to_req(struct v4l2_ctrl_ref *ref)
287 + struct v4l2_ctrl *ctrl;
291 - ptr_to_ptr(ref->ctrl, ref->ctrl->p_cur, ref->p_req);
292 - ref->valid_p_req = true;
295 + if (ctrl->is_dyn_array && !req_alloc_dyn_array(ref, ctrl->elems))
298 + ref->p_req_elems = ctrl->elems;
299 + ptr_to_ptr(ctrl, ctrl->p_cur, ref->p_req, ctrl->elems);
300 + ref->p_req_valid = true;
303 /* Copy the request value to the new value */
304 -void req_to_new(struct v4l2_ctrl_ref *ref)
305 +int req_to_new(struct v4l2_ctrl_ref *ref)
307 + struct v4l2_ctrl *ctrl;
311 - if (ref->valid_p_req)
312 - ptr_to_ptr(ref->ctrl, ref->p_req, ref->ctrl->p_new);
314 - ptr_to_ptr(ref->ctrl, ref->ctrl->p_cur, ref->ctrl->p_new);
320 + * This control was never set in the request, so just use the current
323 + if (!ref->p_req_valid) {
324 + if (ctrl->is_dyn_array)
325 + ctrl->new_elems = ctrl->elems;
326 + ptr_to_ptr(ctrl, ctrl->p_cur, ctrl->p_new, ctrl->new_elems);
330 + /* Not a dynamic array, so just copy the request value */
331 + if (!ctrl->is_dyn_array) {
332 + ptr_to_ptr(ctrl, ref->p_req, ctrl->p_new, ctrl->new_elems);
336 + /* Sanity check, should never happen */
337 + if (WARN_ON(!ref->p_req_dyn_alloc_elems))
341 + * Check if the number of elements in the request is more than the
342 + * elements in ctrl->p_dyn. If so, attempt to realloc ctrl->p_dyn.
343 + * Note that p_dyn is allocated with twice the number of elements
344 + * in the dynamic array since it has to store both the current and
345 + * new value of such a control.
347 + if (ref->p_req_elems > ctrl->p_dyn_alloc_elems) {
348 + unsigned int sz = ref->p_req_elems * ctrl->elem_size;
349 + void *old = ctrl->p_dyn;
350 + void *tmp = kvzalloc(2 * sz, GFP_KERNEL);
354 + memcpy(tmp, ctrl->p_new.p, ctrl->elems * ctrl->elem_size);
355 + memcpy(tmp + sz, ctrl->p_cur.p, ctrl->elems * ctrl->elem_size);
356 + ctrl->p_new.p = tmp;
357 + ctrl->p_cur.p = tmp + sz;
359 + ctrl->p_dyn_alloc_elems = ref->p_req_elems;
363 + ctrl->new_elems = ref->p_req_elems;
364 + ptr_to_ptr(ctrl, ref->p_req, ctrl->p_new, ctrl->new_elems);
368 /* Control range checking */
369 @@ -928,17 +1018,6 @@ int check_range(enum v4l2_ctrl_type type
373 -/* Validate a new control */
374 -int validate_new(const struct v4l2_ctrl *ctrl, union v4l2_ctrl_ptr p_new)
379 - for (idx = 0; !err && idx < ctrl->elems; idx++)
380 - err = ctrl->type_ops->validate(ctrl, idx, p_new);
384 /* Set the handler's error code if it wasn't set earlier already */
385 static inline int handler_set_err(struct v4l2_ctrl_handler *hdl, int err)
387 @@ -983,6 +1062,8 @@ void v4l2_ctrl_handler_free(struct v4l2_
389 list_for_each_entry_safe(ref, next_ref, &hdl->ctrl_refs, node) {
390 list_del(&ref->node);
391 + if (ref->p_req_dyn_alloc_elems)
392 + kvfree(ref->p_req.p);
395 /* Free all controls owned by the handler */
396 @@ -990,6 +1071,7 @@ void v4l2_ctrl_handler_free(struct v4l2_
397 list_del(&ctrl->node);
398 list_for_each_entry_safe(sev, next_sev, &ctrl->ev_subs, node)
399 list_del(&sev->node);
400 + kvfree(ctrl->p_dyn);
403 kvfree(hdl->buckets);
404 @@ -1105,7 +1187,7 @@ int handler_new_ref(struct v4l2_ctrl_han
409 + if (allocate_req && !ctrl->is_dyn_array)
410 size_extra_req = ctrl->elems * ctrl->elem_size;
411 new_ref = kzalloc(sizeof(*new_ref) + size_extra_req, GFP_KERNEL);
413 @@ -1273,7 +1355,6 @@ static struct v4l2_ctrl *v4l2_ctrl_new(s
414 elem_size = sizeof(s32);
417 - tot_ctrl_size = elem_size * elems;
420 if (id == 0 || name == NULL || !elem_size ||
421 @@ -1294,17 +1375,33 @@ static struct v4l2_ctrl *v4l2_ctrl_new(s
422 handler_set_err(hdl, -EINVAL);
425 + if (flags & V4L2_CTRL_FLAG_DYNAMIC_ARRAY) {
427 + * For now only support this for one-dimensional arrays only.
429 + * This can be relaxed in the future, but this will
430 + * require more effort.
432 + if (nr_of_dims != 1) {
433 + handler_set_err(hdl, -EINVAL);
436 + /* Start with just 1 element */
440 + tot_ctrl_size = elem_size * elems;
442 if (type == V4L2_CTRL_TYPE_BUTTON)
443 flags |= V4L2_CTRL_FLAG_WRITE_ONLY |
444 V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
445 else if (type == V4L2_CTRL_TYPE_CTRL_CLASS)
446 flags |= V4L2_CTRL_FLAG_READ_ONLY;
447 - else if (type == V4L2_CTRL_TYPE_INTEGER64 ||
448 - type == V4L2_CTRL_TYPE_STRING ||
449 - type >= V4L2_CTRL_COMPOUND_TYPES ||
451 + else if (!(flags & V4L2_CTRL_FLAG_DYNAMIC_ARRAY) &&
452 + (type == V4L2_CTRL_TYPE_INTEGER64 ||
453 + type == V4L2_CTRL_TYPE_STRING ||
454 + type >= V4L2_CTRL_COMPOUND_TYPES ||
456 sz_extra += 2 * tot_ctrl_size;
458 if (type >= V4L2_CTRL_COMPOUND_TYPES && p_def.p_const)
459 @@ -1333,7 +1430,9 @@ static struct v4l2_ctrl *v4l2_ctrl_new(s
460 ctrl->is_ptr = is_array || type >= V4L2_CTRL_COMPOUND_TYPES || ctrl->is_string;
461 ctrl->is_int = !ctrl->is_ptr && type != V4L2_CTRL_TYPE_INTEGER64;
462 ctrl->is_array = is_array;
463 + ctrl->is_dyn_array = !!(flags & V4L2_CTRL_FLAG_DYNAMIC_ARRAY);
465 + ctrl->new_elems = elems;
466 ctrl->nr_of_dims = nr_of_dims;
468 memcpy(ctrl->dims, dims, nr_of_dims * sizeof(dims[0]));
469 @@ -1346,6 +1445,16 @@ static struct v4l2_ctrl *v4l2_ctrl_new(s
470 ctrl->cur.val = ctrl->val = def;
473 + if (ctrl->is_dyn_array) {
474 + ctrl->p_dyn_alloc_elems = elems;
475 + ctrl->p_dyn = kvzalloc(2 * elems * elem_size, GFP_KERNEL);
476 + if (!ctrl->p_dyn) {
480 + data = ctrl->p_dyn;
484 ctrl->p_new.p = data;
485 ctrl->p_cur.p = data + tot_ctrl_size;
486 @@ -1355,7 +1464,10 @@ static struct v4l2_ctrl *v4l2_ctrl_new(s
489 if (type >= V4L2_CTRL_COMPOUND_TYPES && p_def.p_const) {
490 - ctrl->p_def.p = ctrl->p_cur.p + tot_ctrl_size;
491 + if (ctrl->is_dyn_array)
492 + ctrl->p_def.p = &ctrl[1];
494 + ctrl->p_def.p = ctrl->p_cur.p + tot_ctrl_size;
495 memcpy(ctrl->p_def.p, p_def.p_const, elem_size);
498 @@ -1365,6 +1477,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(s
501 if (handler_new_ref(hdl, ctrl, NULL, false, false)) {
502 + kvfree(ctrl->p_dyn);
506 @@ -1702,6 +1815,9 @@ static int cluster_changed(struct v4l2_c
510 + if (ctrl->elems != ctrl->new_elems)
511 + ctrl_changed = true;
513 for (idx = 0; !ctrl_changed && idx < ctrl->elems; idx++)
514 ctrl_changed = !ctrl->type_ops->equal(ctrl, idx,
515 ctrl->p_cur, ctrl->p_new);
516 --- a/drivers/media/v4l2-core/v4l2-ctrls-priv.h
517 +++ b/drivers/media/v4l2-core/v4l2-ctrls-priv.h
518 @@ -57,10 +57,9 @@ void cur_to_new(struct v4l2_ctrl *ctrl);
519 void cur_to_req(struct v4l2_ctrl_ref *ref);
520 void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags);
521 void new_to_req(struct v4l2_ctrl_ref *ref);
522 -void req_to_new(struct v4l2_ctrl_ref *ref);
523 +int req_to_new(struct v4l2_ctrl_ref *ref);
524 void send_initial_event(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl);
525 void send_event(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 changes);
526 -int validate_new(const struct v4l2_ctrl *ctrl, union v4l2_ctrl_ptr p_new);
527 int handler_new_ref(struct v4l2_ctrl_handler *hdl,
528 struct v4l2_ctrl *ctrl,
529 struct v4l2_ctrl_ref **ctrl_ref,
530 --- a/drivers/media/v4l2-core/v4l2-ctrls-request.c
531 +++ b/drivers/media/v4l2-core/v4l2-ctrls-request.c
532 @@ -143,7 +143,7 @@ v4l2_ctrl_request_hdl_ctrl_find(struct v
534 struct v4l2_ctrl_ref *ref = find_ref_lock(hdl, id);
536 - return (ref && ref->valid_p_req) ? ref->ctrl : NULL;
537 + return (ref && ref->p_req_valid) ? ref->ctrl : NULL;
539 EXPORT_SYMBOL_GPL(v4l2_ctrl_request_hdl_ctrl_find);
541 @@ -373,7 +373,7 @@ void v4l2_ctrl_request_complete(struct m
542 v4l2_ctrl_unlock(master);
545 - if (ref->valid_p_req)
546 + if (ref->p_req_valid)
549 /* Copy the current control value into the request */
550 @@ -442,7 +442,7 @@ int v4l2_ctrl_request_setup(struct media
551 struct v4l2_ctrl_ref *r =
552 find_ref(hdl, master->cluster[i]->id);
554 - if (r->valid_p_req) {
555 + if (r->p_req_valid) {
556 have_new_data = true;
559 @@ -458,7 +458,11 @@ int v4l2_ctrl_request_setup(struct media
560 struct v4l2_ctrl_ref *r =
561 find_ref(hdl, master->cluster[i]->id);
564 + ret = req_to_new(r);
566 + v4l2_ctrl_unlock(master);
569 master->cluster[i]->is_new = 1;
572 @@ -490,6 +494,7 @@ int v4l2_ctrl_request_setup(struct media
577 media_request_object_put(obj);
580 --- a/include/media/v4l2-ctrls.h
581 +++ b/include/media/v4l2-ctrls.h
582 @@ -181,6 +181,8 @@ typedef void (*v4l2_ctrl_notify_fnc)(str
583 * and/or has type %V4L2_CTRL_TYPE_STRING. In other words, &struct
584 * v4l2_ext_control uses field p to point to the data.
585 * @is_array: If set, then this control contains an N-dimensional array.
586 + * @is_dyn_array: If set, then this control contains a dynamically sized 1-dimensional array.
587 + * If this is set, then @is_array is also set.
588 * @has_volatiles: If set, then one or more members of the cluster are volatile.
589 * Drivers should never touch this flag.
590 * @call_notify: If set, then call the handler's notify function whenever the
591 @@ -201,6 +203,9 @@ typedef void (*v4l2_ctrl_notify_fnc)(str
592 * @step: The control's step value for non-menu controls.
593 * @elems: The number of elements in the N-dimensional array.
594 * @elem_size: The size in bytes of the control.
595 + * @new_elems: The number of elements in p_new. This is the same as @elems,
596 + * except for dynamic arrays. In that case it is in the range of
597 + * 1 to @p_dyn_alloc_elems.
598 * @dims: The size of each dimension.
599 * @nr_of_dims:The number of dimensions in @dims.
600 * @menu_skip_mask: The control's skip mask for menu controls. This makes it
601 @@ -219,15 +224,21 @@ typedef void (*v4l2_ctrl_notify_fnc)(str
602 * :math:`ceil(\frac{maximum - minimum}{step}) + 1`.
603 * Used only if the @type is %V4L2_CTRL_TYPE_INTEGER_MENU.
604 * @flags: The control's flags.
605 - * @cur: Structure to store the current value.
606 - * @cur.val: The control's current value, if the @type is represented via
607 - * a u32 integer (see &enum v4l2_ctrl_type).
608 - * @val: The control's new s32 value.
609 * @priv: The control's private pointer. For use by the driver. It is
610 * untouched by the control framework. Note that this pointer is
611 * not freed when the control is deleted. Should this be needed
612 * then a new internal bitfield can be added to tell the framework
613 * to free this pointer.
614 + * @p_dyn: Pointer to the dynamically allocated array. Only valid if
615 + * @is_dyn_array is true.
616 + * @p_dyn_alloc_elems: The number of elements in the dynamically allocated
617 + * array for both the cur and new values. So @p_dyn is actually
618 + * sized for 2 * @p_dyn_alloc_elems * @elem_size. Only valid if
619 + * @is_dyn_array is true.
620 + * @cur: Structure to store the current value.
621 + * @cur.val: The control's current value, if the @type is represented via
622 + * a u32 integer (see &enum v4l2_ctrl_type).
623 + * @val: The control's new s32 value.
624 * @p_def: The control's default value represented via a union which
625 * provides a standard way of accessing control types
626 * through a pointer (for compound controls only).
627 @@ -256,6 +267,7 @@ struct v4l2_ctrl {
628 unsigned int is_string:1;
629 unsigned int is_ptr:1;
630 unsigned int is_array:1;
631 + unsigned int is_dyn_array:1;
632 unsigned int has_volatiles:1;
633 unsigned int call_notify:1;
634 unsigned int manual_mode_value:8;
635 @@ -268,6 +280,7 @@ struct v4l2_ctrl {
636 s64 minimum, maximum, default_value;
640 u32 dims[V4L2_CTRL_MAX_DIMS];
643 @@ -280,6 +293,8 @@ struct v4l2_ctrl {
648 + u32 p_dyn_alloc_elems;
652 @@ -305,12 +320,22 @@ struct v4l2_ctrl {
653 * the control has been applied. This prevents applying controls
654 * from a cluster with multiple controls twice (when the first
655 * control of a cluster is applied, they all are).
656 - * @valid_p_req: If set, then p_req contains the control value for the request.
657 + * @p_req_valid: If set, then p_req contains the control value for the request.
658 + * @p_req_dyn_enomem: If set, then p_req is invalid since allocating space for
659 + * a dynamic array failed. Attempting to read this value shall
660 + * result in ENOMEM. Only valid if ctrl->is_dyn_array is true.
661 + * @p_req_dyn_alloc_elems: The number of elements allocated for the dynamic
662 + * array. Only valid if @p_req_valid and ctrl->is_dyn_array are
664 + * @p_req_elems: The number of elements in @p_req. This is the same as
665 + * ctrl->elems, except for dynamic arrays. In that case it is in
666 + * the range of 1 to @p_req_dyn_alloc_elems. Only valid if
667 + * @p_req_valid is true.
668 * @p_req: If the control handler containing this control reference
669 * is bound to a media request, then this points to the
670 * value of the control that must be applied when the request
671 * is executed, or to the value of the control at the time
672 - * that the request was completed. If @valid_p_req is false,
673 + * that the request was completed. If @p_req_valid is false,
674 * then this control was never set for this request and the
675 * control will not be updated when this request is applied.
677 @@ -325,7 +350,10 @@ struct v4l2_ctrl_ref {
678 struct v4l2_ctrl_helper *helper;
683 + bool p_req_dyn_enomem;
684 + u32 p_req_dyn_alloc_elems;
686 union v4l2_ctrl_ptr p_req;