]> Pileus Git - ~andy/linux/commitdiff
[media] v4l2-ctrls: Add v4l2_ctrl_[gs]_ctrl_int64()
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Mon, 23 Jul 2012 12:15:21 +0000 (09:15 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Thu, 13 Sep 2012 19:23:36 +0000 (16:23 -0300)
These helper functions get and set a 64-bit control's value from within
a driver. They are similar to v4l2_ctrl_[gs]_ctrl() but operate on
64-bit integer controls instead of 32-bit controls.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
Acked-by: Sakari Ailus <sakari.ailus@iki.fi>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/v4l2-core/v4l2-ctrls.c
include/media/v4l2-ctrls.h

index 6a34c30fff5b8334049d5aa790106497bf35b69e..ab287f2368014fe8cf045a3a0c33ca840dd8e916 100644 (file)
@@ -1213,76 +1213,53 @@ static int cluster_changed(struct v4l2_ctrl *master)
        return diff;
 }
 
-/* Validate integer-type control */
-static int validate_new_int(const struct v4l2_ctrl *ctrl, s32 *pval)
+/* Validate a new control */
+static int validate_new(const struct v4l2_ctrl *ctrl,
+                       struct v4l2_ext_control *c)
 {
-       s32 val = *pval;
+       size_t len;
        u32 offset;
+       s32 val;
 
        switch (ctrl->type) {
        case V4L2_CTRL_TYPE_INTEGER:
                /* Round towards the closest legal value */
-               val += ctrl->step / 2;
-               if (val < ctrl->minimum)
-                       val = ctrl->minimum;
-               if (val > ctrl->maximum)
-                       val = ctrl->maximum;
+               val = c->value + ctrl->step / 2;
+               val = clamp(val, ctrl->minimum, ctrl->maximum);
                offset = val - ctrl->minimum;
                offset = ctrl->step * (offset / ctrl->step);
-               val = ctrl->minimum + offset;
-               *pval = val;
+               c->value = ctrl->minimum + offset;
                return 0;
 
        case V4L2_CTRL_TYPE_BOOLEAN:
-               *pval = !!val;
+               c->value = !!c->value;
                return 0;
 
        case V4L2_CTRL_TYPE_MENU:
        case V4L2_CTRL_TYPE_INTEGER_MENU:
-               if (val < ctrl->minimum || val > ctrl->maximum)
+               if (c->value < ctrl->minimum || c->value > ctrl->maximum)
                        return -ERANGE;
-               if (ctrl->menu_skip_mask & (1 << val))
+               if (ctrl->menu_skip_mask & (1 << c->value))
                        return -EINVAL;
                if (ctrl->type == V4L2_CTRL_TYPE_MENU &&
-                   ctrl->qmenu[val][0] == '\0')
+                   ctrl->qmenu[c->value][0] == '\0')
                        return -EINVAL;
                return 0;
 
        case V4L2_CTRL_TYPE_BITMASK:
-               *pval &= ctrl->maximum;
+               c->value &= ctrl->maximum;
                return 0;
 
        case V4L2_CTRL_TYPE_BUTTON:
        case V4L2_CTRL_TYPE_CTRL_CLASS:
-               *pval = 0;
+               c->value = 0;
                return 0;
 
-       default:
-               return -EINVAL;
-       }
-}
-
-/* Validate a new control */
-static int validate_new(const struct v4l2_ctrl *ctrl, struct v4l2_ext_control *c)
-{
-       char *s = c->string;
-       size_t len;
-
-       switch (ctrl->type) {
-       case V4L2_CTRL_TYPE_INTEGER:
-       case V4L2_CTRL_TYPE_BOOLEAN:
-       case V4L2_CTRL_TYPE_MENU:
-       case V4L2_CTRL_TYPE_INTEGER_MENU:
-       case V4L2_CTRL_TYPE_BITMASK:
-       case V4L2_CTRL_TYPE_BUTTON:
-       case V4L2_CTRL_TYPE_CTRL_CLASS:
-               return validate_new_int(ctrl, &c->value);
-
        case V4L2_CTRL_TYPE_INTEGER64:
                return 0;
 
        case V4L2_CTRL_TYPE_STRING:
-               len = strlen(s);
+               len = strlen(c->string);
                if (len < ctrl->minimum)
                        return -ERANGE;
                if ((len - ctrl->minimum) % ctrl->step)
@@ -2274,12 +2251,19 @@ int v4l2_subdev_g_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *cs
 EXPORT_SYMBOL(v4l2_subdev_g_ext_ctrls);
 
 /* Helper function to get a single control */
-static int get_ctrl(struct v4l2_ctrl *ctrl, s32 *val)
+static int get_ctrl(struct v4l2_ctrl *ctrl, struct v4l2_ext_control *c)
 {
        struct v4l2_ctrl *master = ctrl->cluster[0];
        int ret = 0;
        int i;
 
+       /* String controls are not supported. The new_to_user() and
+        * cur_to_user() calls below would need to be modified not to access
+        * userspace memory when called from get_ctrl().
+        */
+       if (ctrl->type == V4L2_CTRL_TYPE_STRING)
+               return -EINVAL;
+
        if (ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY)
                return -EACCES;
 
@@ -2289,9 +2273,9 @@ static int get_ctrl(struct v4l2_ctrl *ctrl, s32 *val)
                for (i = 0; i < master->ncontrols; i++)
                        cur_to_new(master->cluster[i]);
                ret = call_op(master, g_volatile_ctrl);
-               *val = ctrl->val;
+               new_to_user(c, ctrl);
        } else {
-               *val = ctrl->cur.val;
+               cur_to_user(c, ctrl);
        }
        v4l2_ctrl_unlock(master);
        return ret;
@@ -2300,10 +2284,14 @@ static int get_ctrl(struct v4l2_ctrl *ctrl, s32 *val)
 int v4l2_g_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_control *control)
 {
        struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, control->id);
+       struct v4l2_ext_control c;
+       int ret;
 
        if (ctrl == NULL || !type_is_int(ctrl))
                return -EINVAL;
-       return get_ctrl(ctrl, &control->value);
+       ret = get_ctrl(ctrl, &c);
+       control->value = c.value;
+       return ret;
 }
 EXPORT_SYMBOL(v4l2_g_ctrl);
 
@@ -2315,15 +2303,28 @@ EXPORT_SYMBOL(v4l2_subdev_g_ctrl);
 
 s32 v4l2_ctrl_g_ctrl(struct v4l2_ctrl *ctrl)
 {
-       s32 val = 0;
+       struct v4l2_ext_control c;
 
        /* It's a driver bug if this happens. */
        WARN_ON(!type_is_int(ctrl));
-       get_ctrl(ctrl, &val);
-       return val;
+       c.value = 0;
+       get_ctrl(ctrl, &c);
+       return c.value;
 }
 EXPORT_SYMBOL(v4l2_ctrl_g_ctrl);
 
+s64 v4l2_ctrl_g_ctrl_int64(struct v4l2_ctrl *ctrl)
+{
+       struct v4l2_ext_control c;
+
+       /* It's a driver bug if this happens. */
+       WARN_ON(ctrl->type != V4L2_CTRL_TYPE_INTEGER64);
+       c.value = 0;
+       get_ctrl(ctrl, &c);
+       return c.value;
+}
+EXPORT_SYMBOL(v4l2_ctrl_g_ctrl_int64);
+
 
 /* Core function that calls try/s_ctrl and ensures that the new value is
    copied to the current value on a set.
@@ -2539,13 +2540,21 @@ int v4l2_subdev_s_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *cs
 EXPORT_SYMBOL(v4l2_subdev_s_ext_ctrls);
 
 /* Helper function for VIDIOC_S_CTRL compatibility */
-static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, s32 *val)
+static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl,
+                   struct v4l2_ext_control *c)
 {
        struct v4l2_ctrl *master = ctrl->cluster[0];
        int ret;
        int i;
 
-       ret = validate_new_int(ctrl, val);
+       /* String controls are not supported. The user_to_new() and
+        * cur_to_user() calls below would need to be modified not to access
+        * userspace memory when called from set_ctrl().
+        */
+       if (ctrl->type == V4L2_CTRL_TYPE_STRING)
+               return -EINVAL;
+
+       ret = validate_new(ctrl, c);
        if (ret)
                return ret;
 
@@ -2560,12 +2569,13 @@ static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, s32 *val)
           manual mode we have to update the current volatile values since
           those will become the initial manual values after such a switch. */
        if (master->is_auto && master->has_volatiles && ctrl == master &&
-           !is_cur_manual(master) && *val == master->manual_mode_value)
+           !is_cur_manual(master) && c->value == master->manual_mode_value)
                update_from_auto_cluster(master);
-       ctrl->val = *val;
-       ctrl->is_new = 1;
+
+       user_to_new(c, ctrl);
        ret = try_or_set_cluster(fh, master, true);
-       *val = ctrl->cur.val;
+       cur_to_user(c, ctrl);
+
        v4l2_ctrl_unlock(ctrl);
        return ret;
 }
@@ -2574,6 +2584,8 @@ int v4l2_s_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
                                        struct v4l2_control *control)
 {
        struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, control->id);
+       struct v4l2_ext_control c;
+       int ret;
 
        if (ctrl == NULL || !type_is_int(ctrl))
                return -EINVAL;
@@ -2581,7 +2593,10 @@ int v4l2_s_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
        if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY)
                return -EACCES;
 
-       return set_ctrl(fh, ctrl, &control->value);
+       c.value = control->value;
+       ret = set_ctrl(fh, ctrl, &c);
+       control->value = c.value;
+       return ret;
 }
 EXPORT_SYMBOL(v4l2_s_ctrl);
 
@@ -2593,12 +2608,26 @@ EXPORT_SYMBOL(v4l2_subdev_s_ctrl);
 
 int v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val)
 {
+       struct v4l2_ext_control c;
+
        /* It's a driver bug if this happens. */
        WARN_ON(!type_is_int(ctrl));
-       return set_ctrl(NULL, ctrl, &val);
+       c.value = val;
+       return set_ctrl(NULL, ctrl, &c);
 }
 EXPORT_SYMBOL(v4l2_ctrl_s_ctrl);
 
+int v4l2_ctrl_s_ctrl_int64(struct v4l2_ctrl *ctrl, s64 val)
+{
+       struct v4l2_ext_control c;
+
+       /* It's a driver bug if this happens. */
+       WARN_ON(ctrl->type != V4L2_CTRL_TYPE_INTEGER64);
+       c.value64 = val;
+       return set_ctrl(NULL, ctrl, &c);
+}
+EXPORT_SYMBOL(v4l2_ctrl_s_ctrl_int64);
+
 static int v4l2_ctrl_add_event(struct v4l2_subscribed_event *sev, unsigned elems)
 {
        struct v4l2_ctrl *ctrl = v4l2_ctrl_find(sev->fh->ctrl_handler, sev->id);
index 776605f1cbe269514b1f5cc757e9a7176e92022e..7ef6b27d450fcb2f6674b0d902e2a87cfaae21a0 100644 (file)
@@ -511,6 +511,29 @@ s32 v4l2_ctrl_g_ctrl(struct v4l2_ctrl *ctrl);
   */
 int v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val);
 
+/** v4l2_ctrl_g_ctrl_int64() - Helper function to get a 64-bit control's value from within a driver.
+  * @ctrl:     The control.
+  *
+  * This returns the control's value safely by going through the control
+  * framework. This function will lock the control's handler, so it cannot be
+  * used from within the &v4l2_ctrl_ops functions.
+  *
+  * This function is for 64-bit integer type controls only.
+  */
+s64 v4l2_ctrl_g_ctrl_int64(struct v4l2_ctrl *ctrl);
+
+/** v4l2_ctrl_s_ctrl_int64() - Helper function to set a 64-bit control's value from within a driver.
+  * @ctrl:     The control.
+  * @val:      The new value.
+  *
+  * This set the control's new value safely by going through the control
+  * framework. This function will lock the control's handler, so it cannot be
+  * used from within the &v4l2_ctrl_ops functions.
+  *
+  * This function is for 64-bit integer type controls only.
+  */
+int v4l2_ctrl_s_ctrl_int64(struct v4l2_ctrl *ctrl, s64 val);
+
 /* Internal helper functions that deal with control events. */
 extern const struct v4l2_subscribed_event_ops v4l2_ctrl_sub_ev_ops;
 void v4l2_ctrl_replace(struct v4l2_event *old, const struct v4l2_event *new);