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

[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
...@@ -1202,6 +1202,8 @@ static void std_init(const struct v4l2_ctrl *ctrl, u32 idx, ...@@ -1202,6 +1202,8 @@ static void std_init(const struct v4l2_ctrl *ctrl, u32 idx,
ptr.p_s32[idx] = ctrl->default_value; ptr.p_s32[idx] = ctrl->default_value;
break; break;
default: default:
idx *= ctrl->elem_size;
memset(ptr.p + idx, 0, ctrl->elem_size);
break; break;
} }
} }
...@@ -1324,7 +1326,7 @@ static int ptr_to_user(struct v4l2_ext_control *c, ...@@ -1324,7 +1326,7 @@ static int ptr_to_user(struct v4l2_ext_control *c,
u32 len; u32 len;
if (ctrl->is_ptr && !ctrl->is_string) 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) { switch (ctrl->type) {
case V4L2_CTRL_TYPE_STRING: case V4L2_CTRL_TYPE_STRING:
...@@ -1368,8 +1370,16 @@ static int user_to_ptr(struct v4l2_ext_control *c, ...@@ -1368,8 +1370,16 @@ static int user_to_ptr(struct v4l2_ext_control *c,
u32 size; u32 size;
ctrl->is_new = 1; ctrl->is_new = 1;
if (ctrl->is_ptr && !ctrl->is_string) if (ctrl->is_ptr && !ctrl->is_string) {
return copy_from_user(ptr.p, c->ptr, ctrl->elem_size); 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) { switch (ctrl->type) {
case V4L2_CTRL_TYPE_INTEGER64: case V4L2_CTRL_TYPE_INTEGER64:
...@@ -1412,21 +1422,7 @@ static void ptr_to_ptr(struct v4l2_ctrl *ctrl, ...@@ -1412,21 +1422,7 @@ static void ptr_to_ptr(struct v4l2_ctrl *ctrl,
{ {
if (ctrl == NULL) if (ctrl == NULL)
return; return;
switch (ctrl->type) { memcpy(to.p, from.p, ctrl->elems * ctrl->elem_size);
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;
}
} }
/* Copy the new value to the current value. */ /* Copy the new value to the current value. */
...@@ -1478,15 +1474,19 @@ static void cur_to_new(struct v4l2_ctrl *ctrl) ...@@ -1478,15 +1474,19 @@ static void cur_to_new(struct v4l2_ctrl *ctrl)
static int cluster_changed(struct v4l2_ctrl *master) static int cluster_changed(struct v4l2_ctrl *master)
{ {
bool changed = false; bool changed = false;
unsigned idx;
int i; int i;
for (i = 0; i < master->ncontrols; i++) { for (i = 0; i < master->ncontrols; i++) {
struct v4l2_ctrl *ctrl = master->cluster[i]; struct v4l2_ctrl *ctrl = master->cluster[i];
bool ctrl_changed = false;
if (ctrl == NULL) if (ctrl == NULL)
continue; 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->p_cur, ctrl->p_new);
ctrl->has_changed = ctrl_changed;
changed |= ctrl->has_changed; changed |= ctrl->has_changed;
} }
return changed; return changed;
...@@ -1533,7 +1533,10 @@ static int validate_new(const struct v4l2_ctrl *ctrl, ...@@ -1533,7 +1533,10 @@ static int validate_new(const struct v4l2_ctrl *ctrl,
struct v4l2_ext_control *c) struct v4l2_ext_control *c)
{ {
union v4l2_ctrl_ptr ptr; union v4l2_ctrl_ptr ptr;
unsigned idx;
int err = 0;
if (!ctrl->is_ptr) {
switch (ctrl->type) { switch (ctrl->type) {
case V4L2_CTRL_TYPE_INTEGER: case V4L2_CTRL_TYPE_INTEGER:
case V4L2_CTRL_TYPE_INTEGER_MENU: case V4L2_CTRL_TYPE_INTEGER_MENU:
...@@ -1548,11 +1551,14 @@ static int validate_new(const struct v4l2_ctrl *ctrl, ...@@ -1548,11 +1551,14 @@ static int validate_new(const struct v4l2_ctrl *ctrl,
case V4L2_CTRL_TYPE_INTEGER64: case V4L2_CTRL_TYPE_INTEGER64:
ptr.p_s64 = &c->value64; ptr.p_s64 = &c->value64;
return ctrl->type_ops->validate(ctrl, 0, ptr); return ctrl->type_ops->validate(ctrl, 0, ptr);
default: default:
ptr.p = c->ptr; break;
return ctrl->type_ops->validate(ctrl, 0, ptr); }
} }
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) static inline u32 node2id(struct list_head *node)
...@@ -1781,6 +1787,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, ...@@ -1781,6 +1787,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
unsigned elems = 1; unsigned elems = 1;
bool is_array; bool is_array;
unsigned tot_ctrl_size; unsigned tot_ctrl_size;
unsigned idx;
void *data; void *data;
int err; int err;
...@@ -1881,8 +1888,10 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, ...@@ -1881,8 +1888,10 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
ctrl->p_new.p = &ctrl->val; ctrl->p_new.p = &ctrl->val;
ctrl->p_cur.p = &ctrl->cur.val; ctrl->p_cur.p = &ctrl->cur.val;
} }
ctrl->type_ops->init(ctrl, 0, ctrl->p_cur); for (idx = 0; idx < elems; idx++) {
ctrl->type_ops->init(ctrl, 0, ctrl->p_new); ctrl->type_ops->init(ctrl, idx, ctrl->p_cur);
ctrl->type_ops->init(ctrl, idx, ctrl->p_new);
}
if (handler_new_ref(hdl, ctrl)) { if (handler_new_ref(hdl, ctrl)) {
kfree(ctrl); kfree(ctrl);
...@@ -2578,13 +2587,18 @@ static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl, ...@@ -2578,13 +2587,18 @@ static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl,
have_clusters = true; have_clusters = true;
if (ctrl->cluster[0] != ctrl) if (ctrl->cluster[0] != ctrl)
ref = find_ref_lock(hdl, ctrl->cluster[0]->id); 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) { if (get) {
c->size = ctrl->elem_size; c->size = tot_size;
return -ENOSPC; return -ENOSPC;
} }
return -EFAULT; return -EFAULT;
} }
c->size = tot_size;
}
/* Store the ref to the master control of the cluster */ /* Store the ref to the master control of the cluster */
h->mref = ref; h->mref = ref;
h->ctrl = ctrl; h->ctrl = ctrl;
...@@ -3123,7 +3137,7 @@ EXPORT_SYMBOL(v4l2_ctrl_notify); ...@@ -3123,7 +3137,7 @@ EXPORT_SYMBOL(v4l2_ctrl_notify);
int v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl, int v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl,
s64 min, s64 max, u64 step, s64 def) 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; struct v4l2_ext_control c;
switch (ctrl->type) { switch (ctrl->type) {
...@@ -3133,6 +3147,9 @@ int v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl, ...@@ -3133,6 +3147,9 @@ int v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl,
case V4L2_CTRL_TYPE_MENU: case V4L2_CTRL_TYPE_MENU:
case V4L2_CTRL_TYPE_INTEGER_MENU: case V4L2_CTRL_TYPE_INTEGER_MENU:
case V4L2_CTRL_TYPE_BITMASK: case V4L2_CTRL_TYPE_BITMASK:
if (ctrl->is_array)
return -EINVAL;
ret = check_range(ctrl->type, min, max, step, def);
if (ret) if (ret)
return ret; return ret;
break; break;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment