summaryrefslogtreecommitdiff
path: root/drivers/media/v4l2-core
diff options
context:
space:
mode:
authorHans Verkuil <hans.verkuil@cisco.com>2014-04-27 10:26:30 +0400
committerMauro Carvalho Chehab <m.chehab@samsung.com>2014-07-17 18:56:48 +0400
commit000e4f9a5bcf86fb52914c445ce5634b65e910a2 (patch)
tree88e6df0acadda540020be1d364fcdde2ab8cac91 /drivers/media/v4l2-core
parent0176077a813933a547b7a913377a87d615b7c108 (diff)
downloadlinux-000e4f9a5bcf86fb52914c445ce5634b65e910a2.tar.xz
[media] v4l2-ctrls: rewrite copy routines to operate on union v4l2_ctrl_ptr
In order to implement array support and (for the future) configuration stores we need to have more generic copy routines that all operate on the v4l2_ctrl_ptr union. So instead of e.g. using ctrl->cur.string it uses ptr.p_char. This makes e.g. cur_to_user generic so it can be used to copy any v4l2_ctrl_ptr value to userspace, not just the (hardcoded) current value. Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
Diffstat (limited to 'drivers/media/v4l2-core')
-rw-r--r--drivers/media/v4l2-core/v4l2-ctrls.c129
1 files changed, 56 insertions, 73 deletions
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 09e2c3a2c5c2..e7e0beab7048 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1304,48 +1304,64 @@ static const struct v4l2_ctrl_type_ops std_type_ops = {
.validate = std_validate,
};
-/* Helper function: copy the current control value back to the caller */
-static int cur_to_user(struct v4l2_ext_control *c,
- struct v4l2_ctrl *ctrl)
+/* Helper function: copy the given control value back to the caller */
+static int ptr_to_user(struct v4l2_ext_control *c,
+ struct v4l2_ctrl *ctrl,
+ union v4l2_ctrl_ptr ptr)
{
u32 len;
if (ctrl->is_ptr && !ctrl->is_string)
- return copy_to_user(c->ptr, ctrl->cur.p, ctrl->elem_size);
+ return copy_to_user(c->ptr, ptr.p, ctrl->elem_size);
switch (ctrl->type) {
case V4L2_CTRL_TYPE_STRING:
- len = strlen(ctrl->cur.string);
+ len = strlen(ptr.p_char);
if (c->size < len + 1) {
c->size = len + 1;
return -ENOSPC;
}
- return copy_to_user(c->string, ctrl->cur.string,
- len + 1) ? -EFAULT : 0;
+ return copy_to_user(c->string, ptr.p_char, len + 1) ?
+ -EFAULT : 0;
case V4L2_CTRL_TYPE_INTEGER64:
- c->value64 = ctrl->cur.val64;
+ c->value64 = *ptr.p_s64;
break;
default:
- c->value = ctrl->cur.val;
+ c->value = *ptr.p_s32;
break;
}
return 0;
}
-/* Helper function: copy the caller-provider value as the new control value */
-static int user_to_new(struct v4l2_ext_control *c,
+/* Helper function: copy the current control value back to the caller */
+static int cur_to_user(struct v4l2_ext_control *c,
struct v4l2_ctrl *ctrl)
{
+ return ptr_to_user(c, ctrl, ctrl->p_cur);
+}
+
+/* Helper function: copy the new control value back to the caller */
+static int new_to_user(struct v4l2_ext_control *c,
+ struct v4l2_ctrl *ctrl)
+{
+ return ptr_to_user(c, ctrl, ctrl->p_new);
+}
+
+/* Helper function: copy the caller-provider value to the given control value */
+static int user_to_ptr(struct v4l2_ext_control *c,
+ struct v4l2_ctrl *ctrl,
+ union v4l2_ctrl_ptr ptr)
+{
int ret;
u32 size;
ctrl->is_new = 1;
if (ctrl->is_ptr && !ctrl->is_string)
- return copy_from_user(ctrl->p, c->ptr, ctrl->elem_size);
+ return copy_from_user(ptr.p, c->ptr, ctrl->elem_size);
switch (ctrl->type) {
case V4L2_CTRL_TYPE_INTEGER64:
- ctrl->val64 = c->value64;
+ *ptr.p_s64 = c->value64;
break;
case V4L2_CTRL_TYPE_STRING:
size = c->size;
@@ -1353,83 +1369,64 @@ static int user_to_new(struct v4l2_ext_control *c,
return -ERANGE;
if (size > ctrl->maximum + 1)
size = ctrl->maximum + 1;
- ret = copy_from_user(ctrl->string, c->string, size);
+ ret = copy_from_user(ptr.p_char, c->string, size);
if (!ret) {
- char last = ctrl->string[size - 1];
+ char last = ptr.p_char[size - 1];
- ctrl->string[size - 1] = 0;
+ ptr.p_char[size - 1] = 0;
/* If the string was longer than ctrl->maximum,
then return an error. */
- if (strlen(ctrl->string) == ctrl->maximum && last)
+ if (strlen(ptr.p_char) == ctrl->maximum && last)
return -ERANGE;
}
return ret ? -EFAULT : 0;
default:
- ctrl->val = c->value;
+ *ptr.p_s32 = c->value;
break;
}
return 0;
}
-/* Helper function: copy the new control value back to the caller */
-static int new_to_user(struct v4l2_ext_control *c,
+/* Helper function: copy the caller-provider value as the new control value */
+static int user_to_new(struct v4l2_ext_control *c,
struct v4l2_ctrl *ctrl)
{
- u32 len;
-
- if (ctrl->is_ptr && !ctrl->is_string)
- return copy_to_user(c->ptr, ctrl->p, ctrl->elem_size);
+ return user_to_ptr(c, ctrl, ctrl->p_new);
+}
+/* Copy the one value to another. */
+static void ptr_to_ptr(struct v4l2_ctrl *ctrl,
+ union v4l2_ctrl_ptr from, union v4l2_ctrl_ptr to)
+{
+ if (ctrl == NULL)
+ return;
switch (ctrl->type) {
case V4L2_CTRL_TYPE_STRING:
- len = strlen(ctrl->string);
- if (c->size < len + 1) {
- c->size = ctrl->maximum + 1;
- return -ENOSPC;
- }
- return copy_to_user(c->string, ctrl->string,
- len + 1) ? -EFAULT : 0;
+ /* strings are always 0-terminated */
+ strcpy(to.p_char, from.p_char);
+ break;
case V4L2_CTRL_TYPE_INTEGER64:
- c->value64 = ctrl->val64;
+ *to.p_s64 = *from.p_s64;
break;
default:
- c->value = ctrl->val;
+ if (ctrl->is_ptr)
+ memcpy(to.p, from.p, ctrl->elem_size);
+ else
+ *to.p_s32 = *from.p_s32;
break;
}
- return 0;
}
/* Copy the new value to the current value. */
static void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags)
{
- bool changed = false;
+ bool changed;
if (ctrl == NULL)
return;
+ changed = !ctrl->type_ops->equal(ctrl, ctrl->p_cur, ctrl->p_new);
+ ptr_to_ptr(ctrl, ctrl->p_new, ctrl->p_cur);
- switch (ctrl->type) {
- case V4L2_CTRL_TYPE_BUTTON:
- changed = true;
- break;
- case V4L2_CTRL_TYPE_STRING:
- /* strings are always 0-terminated */
- changed = strcmp(ctrl->string, ctrl->cur.string);
- strcpy(ctrl->cur.string, ctrl->string);
- break;
- case V4L2_CTRL_TYPE_INTEGER64:
- changed = ctrl->val64 != ctrl->cur.val64;
- ctrl->cur.val64 = ctrl->val64;
- break;
- default:
- if (ctrl->is_ptr) {
- changed = memcmp(ctrl->p, ctrl->cur.p, ctrl->elem_size);
- memcpy(ctrl->cur.p, ctrl->p, ctrl->elem_size);
- } else {
- changed = ctrl->val != ctrl->cur.val;
- ctrl->cur.val = ctrl->val;
- }
- break;
- }
if (ch_flags & V4L2_EVENT_CTRL_CH_FLAGS) {
/* Note: CH_FLAGS is only set for auto clusters. */
ctrl->flags &=
@@ -1458,21 +1455,7 @@ static void cur_to_new(struct v4l2_ctrl *ctrl)
{
if (ctrl == NULL)
return;
- switch (ctrl->type) {
- case V4L2_CTRL_TYPE_STRING:
- /* strings are always 0-terminated */
- strcpy(ctrl->string, ctrl->cur.string);
- break;
- case V4L2_CTRL_TYPE_INTEGER64:
- ctrl->val64 = ctrl->cur.val64;
- break;
- default:
- if (ctrl->is_ptr)
- memcpy(ctrl->p, ctrl->cur.p, ctrl->elem_size);
- else
- ctrl->val = ctrl->cur.val;
- break;
- }
+ ptr_to_ptr(ctrl, ctrl->p_cur, ctrl->p_new);
}
/* Return non-zero if one or more of the controls in the cluster has a new