Commit 7392d87a authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab
Browse files

media: v4l2-ctrls: alloc arrays in ctrl_ref



Also allocate space for arrays in struct ctrl_ref.

This is in preparation for allowing to change the array size from
a driver.

Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
Reviewed-by: default avatarLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@kernel.org>
parent 5f2c5c69
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -467,7 +467,7 @@ int v4l2_g_ext_ctrls_common(struct v4l2_ctrl_handler *hdl,

			if (is_default)
				ret = def_to_user(cs->controls + idx, ref->ctrl);
			else if (is_request && ref->p_req_dyn_enomem)
			else if (is_request && ref->p_req_array_enomem)
				ret = -ENOMEM;
			else if (is_request && ref->p_req_valid)
				ret = req_to_user(cs->controls + idx, ref);
+19 −12
Original line number Diff line number Diff line
@@ -1048,23 +1048,26 @@ void cur_to_new(struct v4l2_ctrl *ctrl)
	ptr_to_ptr(ctrl, ctrl->p_cur, ctrl->p_new, ctrl->new_elems);
}

static bool req_alloc_dyn_array(struct v4l2_ctrl_ref *ref, u32 elems)
static bool req_alloc_array(struct v4l2_ctrl_ref *ref, u32 elems)
{
	void *tmp;

	if (elems < ref->p_req_dyn_alloc_elems)
	if (elems == ref->p_req_array_alloc_elems)
		return true;
	if (ref->ctrl->is_dyn_array &&
	    elems < ref->p_req_array_alloc_elems)
		return true;

	tmp = kvmalloc(elems * ref->ctrl->elem_size, GFP_KERNEL);

	if (!tmp) {
		ref->p_req_dyn_enomem = true;
		ref->p_req_array_enomem = true;
		return false;
	}
	ref->p_req_dyn_enomem = false;
	ref->p_req_array_enomem = false;
	kvfree(ref->p_req.p);
	ref->p_req.p = tmp;
	ref->p_req_dyn_alloc_elems = elems;
	ref->p_req_array_alloc_elems = elems;
	return true;
}

@@ -1077,7 +1080,7 @@ void new_to_req(struct v4l2_ctrl_ref *ref)
		return;

	ctrl = ref->ctrl;
	if (ctrl->is_dyn_array && !req_alloc_dyn_array(ref, ctrl->new_elems))
	if (ctrl->is_array && !req_alloc_array(ref, ctrl->new_elems))
		return;

	ref->p_req_elems = ctrl->new_elems;
@@ -1094,7 +1097,7 @@ void cur_to_req(struct v4l2_ctrl_ref *ref)
		return;

	ctrl = ref->ctrl;
	if (ctrl->is_dyn_array && !req_alloc_dyn_array(ref, ctrl->elems))
	if (ctrl->is_array && !req_alloc_array(ref, ctrl->elems))
		return;

	ref->p_req_elems = ctrl->elems;
@@ -1123,14 +1126,18 @@ int req_to_new(struct v4l2_ctrl_ref *ref)
		return 0;
	}

	/* Not a dynamic array, so just copy the request value */
	if (!ctrl->is_dyn_array) {
	/* Not an array, so just copy the request value */
	if (!ctrl->is_array) {
		ptr_to_ptr(ctrl, ref->p_req, ctrl->p_new, ctrl->new_elems);
		return 0;
	}

	/* Sanity check, should never happen */
	if (WARN_ON(!ref->p_req_dyn_alloc_elems))
	if (WARN_ON(!ref->p_req_array_alloc_elems))
		return -ENOMEM;

	if (!ctrl->is_dyn_array &&
	    ref->p_req_elems != ctrl->p_array_alloc_elems)
		return -ENOMEM;

	/*
@@ -1243,7 +1250,7 @@ void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl)
	/* Free all nodes */
	list_for_each_entry_safe(ref, next_ref, &hdl->ctrl_refs, node) {
		list_del(&ref->node);
		if (ref->p_req_dyn_alloc_elems)
		if (ref->p_req_array_alloc_elems)
			kvfree(ref->p_req.p);
		kfree(ref);
	}
@@ -1368,7 +1375,7 @@ int handler_new_ref(struct v4l2_ctrl_handler *hdl,
	if (hdl->error)
		return hdl->error;

	if (allocate_req && !ctrl->is_dyn_array)
	if (allocate_req && !ctrl->is_array)
		size_extra_req = ctrl->elems * ctrl->elem_size;
	new_ref = kzalloc(sizeof(*new_ref) + size_extra_req, GFP_KERNEL);
	if (!new_ref)
+8 −8
Original line number Diff line number Diff line
@@ -318,15 +318,15 @@ struct v4l2_ctrl {
 *		from a cluster with multiple controls twice (when the first
 *		control of a cluster is applied, they all are).
 * @p_req_valid: If set, then p_req contains the control value for the request.
 * @p_req_dyn_enomem: If set, then p_req is invalid since allocating space for
 *		a dynamic array failed. Attempting to read this value shall
 *		result in ENOMEM. Only valid if ctrl->is_dyn_array is true.
 * @p_req_dyn_alloc_elems: The number of elements allocated for the dynamic
 *		array. Only valid if @p_req_valid and ctrl->is_dyn_array are
 * @p_req_array_enomem: If set, then p_req is invalid since allocating space for
 *		an array failed. Attempting to read this value shall
 *		result in ENOMEM. Only valid if ctrl->is_array is true.
 * @p_req_array_alloc_elems: The number of elements allocated for the
 *		array. Only valid if @p_req_valid and ctrl->is_array are
 *		true.
 * @p_req_elems: The number of elements in @p_req. This is the same as
 *		ctrl->elems, except for dynamic arrays. In that case it is in
 *		the range of 1 to @p_req_dyn_alloc_elems. Only valid if
 *		the range of 1 to @p_req_array_alloc_elems. Only valid if
 *		@p_req_valid is true.
 * @p_req:	If the control handler containing this control reference
 *		is bound to a media request, then this points to the
@@ -348,8 +348,8 @@ struct v4l2_ctrl_ref {
	bool from_other_dev;
	bool req_done;
	bool p_req_valid;
	bool p_req_dyn_enomem;
	u32 p_req_dyn_alloc_elems;
	bool p_req_array_enomem;
	u32 p_req_array_alloc_elems;
	u32 p_req_elems;
	union v4l2_ctrl_ptr p_req;
};