Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 302ab7ce authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab
Browse files

[media] v4l2-ctrls: add array support



Finish the userspace-facing array support.

Signed-off-by: default avatarHans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: default avatarMauro Carvalho Chehab <m.chehab@samsung.com>
parent 265c7f8a
Loading
Loading
Loading
Loading
+63 −46
Original line number Diff line number Diff line
@@ -1202,6 +1202,8 @@ static void std_init(const struct v4l2_ctrl *ctrl, u32 idx,
		ptr.p_s32[idx] = ctrl->default_value;
		break;
	default:
		idx *= ctrl->elem_size;
		memset(ptr.p + idx, 0, ctrl->elem_size);
		break;
	}
}
@@ -1324,7 +1326,7 @@ static int ptr_to_user(struct v4l2_ext_control *c,
	u32 len;

	if (ctrl->is_ptr && !ctrl->is_string)
		return copy_to_user(c->ptr, ptr.p, ctrl->elem_size);
		return copy_to_user(c->ptr, ptr.p, c->size);

	switch (ctrl->type) {
	case V4L2_CTRL_TYPE_STRING:
@@ -1368,8 +1370,16 @@ static int user_to_ptr(struct v4l2_ext_control *c,
	u32 size;

	ctrl->is_new = 1;
	if (ctrl->is_ptr && !ctrl->is_string)
		return copy_from_user(ptr.p, c->ptr, ctrl->elem_size);
	if (ctrl->is_ptr && !ctrl->is_string) {
		unsigned idx;

		ret = copy_from_user(ptr.p, c->ptr, c->size);
		if (ret || !ctrl->is_array)
			return ret;
		for (idx = c->size / ctrl->elem_size; idx < ctrl->elems; idx++)
			ctrl->type_ops->init(ctrl, idx, ptr);
		return 0;
	}

	switch (ctrl->type) {
	case V4L2_CTRL_TYPE_INTEGER64:
@@ -1412,21 +1422,7 @@ static void ptr_to_ptr(struct v4l2_ctrl *ctrl,
{
	if (ctrl == NULL)
		return;
	switch (ctrl->type) {
	case V4L2_CTRL_TYPE_STRING:
		/* strings are always 0-terminated */
		strcpy(to.p_char, from.p_char);
		break;
	case V4L2_CTRL_TYPE_INTEGER64:
		*to.p_s64 = *from.p_s64;
		break;
	default:
		if (ctrl->is_ptr)
			memcpy(to.p, from.p, ctrl->elem_size);
		else
			*to.p_s32 = *from.p_s32;
		break;
	}
	memcpy(to.p, from.p, ctrl->elems * ctrl->elem_size);
}

/* Copy the new value to the current value. */
@@ -1478,15 +1474,19 @@ static void cur_to_new(struct v4l2_ctrl *ctrl)
static int cluster_changed(struct v4l2_ctrl *master)
{
	bool changed = false;
	unsigned idx;
	int i;

	for (i = 0; i < master->ncontrols; i++) {
		struct v4l2_ctrl *ctrl = master->cluster[i];
		bool ctrl_changed = false;

		if (ctrl == NULL)
			continue;
		ctrl->has_changed = !ctrl->type_ops->equal(ctrl, 0,
		for (idx = 0; !ctrl_changed && idx < ctrl->elems; idx++)
			ctrl_changed = !ctrl->type_ops->equal(ctrl, idx,
				ctrl->p_cur, ctrl->p_new);
		ctrl->has_changed = ctrl_changed;
		changed |= ctrl->has_changed;
	}
	return changed;
@@ -1533,7 +1533,10 @@ static int validate_new(const struct v4l2_ctrl *ctrl,
			struct v4l2_ext_control *c)
{
	union v4l2_ctrl_ptr ptr;
	unsigned idx;
	int err = 0;

	if (!ctrl->is_ptr) {
		switch (ctrl->type) {
		case V4L2_CTRL_TYPE_INTEGER:
		case V4L2_CTRL_TYPE_INTEGER_MENU:
@@ -1548,11 +1551,14 @@ static int validate_new(const struct v4l2_ctrl *ctrl,
		case V4L2_CTRL_TYPE_INTEGER64:
			ptr.p_s64 = &c->value64;
			return ctrl->type_ops->validate(ctrl, 0, ptr);

		default:
		ptr.p = c->ptr;
		return ctrl->type_ops->validate(ctrl, 0, ptr);
			break;
		}
	}
	ptr.p = c->ptr;
	for (idx = 0; !err && idx < c->size / ctrl->elem_size; idx++)
		err = ctrl->type_ops->validate(ctrl, idx, ptr);
	return err;
}

static inline u32 node2id(struct list_head *node)
@@ -1781,6 +1787,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
	unsigned elems = 1;
	bool is_array;
	unsigned tot_ctrl_size;
	unsigned idx;
	void *data;
	int err;

@@ -1881,8 +1888,10 @@ 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;
	}
	ctrl->type_ops->init(ctrl, 0, ctrl->p_cur);
	ctrl->type_ops->init(ctrl, 0, ctrl->p_new);
	for (idx = 0; idx < elems; idx++) {
		ctrl->type_ops->init(ctrl, idx, ctrl->p_cur);
		ctrl->type_ops->init(ctrl, idx, ctrl->p_new);
	}

	if (handler_new_ref(hdl, ctrl)) {
		kfree(ctrl);
@@ -2578,13 +2587,18 @@ static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl,
			have_clusters = true;
		if (ctrl->cluster[0] != ctrl)
			ref = find_ref_lock(hdl, ctrl->cluster[0]->id);
		if (ctrl->is_ptr && !ctrl->is_string && c->size < ctrl->elem_size) {
		if (ctrl->is_ptr && !ctrl->is_string) {
			unsigned tot_size = ctrl->elems * ctrl->elem_size;

			if (c->size < tot_size) {
				if (get) {
				c->size = ctrl->elem_size;
					c->size = tot_size;
					return -ENOSPC;
				}
				return -EFAULT;
			}
			c->size = tot_size;
		}
		/* Store the ref to the master control of the cluster */
		h->mref = ref;
		h->ctrl = ctrl;
@@ -3123,7 +3137,7 @@ EXPORT_SYMBOL(v4l2_ctrl_notify);
int v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl,
			s64 min, s64 max, u64 step, s64 def)
{
	int ret = check_range(ctrl->type, min, max, step, def);
	int ret;
	struct v4l2_ext_control c;

	switch (ctrl->type) {
@@ -3133,6 +3147,9 @@ int v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl,
	case V4L2_CTRL_TYPE_MENU:
	case V4L2_CTRL_TYPE_INTEGER_MENU:
	case V4L2_CTRL_TYPE_BITMASK:
		if (ctrl->is_array)
			return -EINVAL;
		ret = check_range(ctrl->type, min, max, step, def);
		if (ret)
			return ret;
		break;