[media] v4l2-ctrls: add array support
authorHans Verkuil <hans.verkuil@cisco.com>
Tue, 10 Jun 2014 10:06:50 +0000 (07:06 -0300)
committerMauro Carvalho Chehab <m.chehab@samsung.com>
Thu, 17 Jul 2014 14:57:19 +0000 (11:57 -0300)
Finish the userspace-facing array support.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
drivers/media/v4l2-core/v4l2-ctrls.c

index f6ac9271d29214e2860195de7b09ecbb3740a7fc..b3ab8a974afaa1895409a7f1247564e774fe88aa 100644 (file)
@@ -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,26 +1533,32 @@ static int validate_new(const struct v4l2_ctrl *ctrl,
                        struct v4l2_ext_control *c)
 {
        union v4l2_ctrl_ptr ptr;
-
-       switch (ctrl->type) {
-       case V4L2_CTRL_TYPE_INTEGER:
-       case V4L2_CTRL_TYPE_INTEGER_MENU:
-       case V4L2_CTRL_TYPE_MENU:
-       case V4L2_CTRL_TYPE_BITMASK:
-       case V4L2_CTRL_TYPE_BOOLEAN:
-       case V4L2_CTRL_TYPE_BUTTON:
-       case V4L2_CTRL_TYPE_CTRL_CLASS:
-               ptr.p_s32 = &c->value;
-               return ctrl->type_ops->validate(ctrl, 0, ptr);
-
-       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);
+       unsigned idx;
+       int err = 0;
+
+       if (!ctrl->is_ptr) {
+               switch (ctrl->type) {
+               case V4L2_CTRL_TYPE_INTEGER:
+               case V4L2_CTRL_TYPE_INTEGER_MENU:
+               case V4L2_CTRL_TYPE_MENU:
+               case V4L2_CTRL_TYPE_BITMASK:
+               case V4L2_CTRL_TYPE_BOOLEAN:
+               case V4L2_CTRL_TYPE_BUTTON:
+               case V4L2_CTRL_TYPE_CTRL_CLASS:
+                       ptr.p_s32 = &c->value;
+                       return ctrl->type_ops->validate(ctrl, 0, ptr);
+
+               case V4L2_CTRL_TYPE_INTEGER64:
+                       ptr.p_s64 = &c->value64;
+                       return ctrl->type_ops->validate(ctrl, 0, ptr);
+               default:
+                       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,12 +2587,17 @@ 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 (get) {
-                               c->size = ctrl->elem_size;
-                               return -ENOSPC;
+               if (ctrl->is_ptr && !ctrl->is_string) {
+                       unsigned tot_size = ctrl->elems * ctrl->elem_size;
+
+                       if (c->size < tot_size) {
+                               if (get) {
+                                       c->size = tot_size;
+                                       return -ENOSPC;
+                               }
+                               return -EFAULT;
                        }
-                       return -EFAULT;
+                       c->size = tot_size;
                }
                /* Store the ref to the master control of the cluster */
                h->mref = ref;
@@ -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;