Integer controls provide a way to get their default/initial value, but
any other control (p_u32, p_u8.....) provide no other way to get the
initial value than unloading the module and loading it back.

*What is the actual problem?
I have a custom control with WIDTH integer values. Every value
represents the calibrated FPN (fixed pattern noise) correction value for that 
column
-Application A changes the FPN correction value
-Application B wants to restore the calibrated value but it cant :(

*What is the proposed solution?
-Add a new ioctl VIDIOC_INITIAL_EXT_CTRLS, with the same API as
G_EXT_CTRLS, but that returns the initial value of a given control

*This code is not splited in different patches and there is no doc!
Yes, at this point I want your feedback about the ioctl, and an initial
piece of code could help the disscussion. Of course, once we agreed I
will provide the documentation and a properly build patchset.

So, shoot me: What do you think?

THANKS!

Signed-off-by: Ricardo Ribalda Delgado <[email protected]>
---
 drivers/media/v4l2-core/v4l2-compat-ioctl32.c |  4 ++
 drivers/media/v4l2-core/v4l2-ctrls.c          | 65 ++++++++++++++++++++++++---
 drivers/media/v4l2-core/v4l2-ioctl.c          | 20 +++++++++
 drivers/media/v4l2-core/v4l2-subdev.c         |  3 ++
 include/media/v4l2-ctrls.h                    |  2 +
 include/media/v4l2-ioctl.h                    |  2 +
 include/uapi/linux/videodev2.h                |  4 +-
 7 files changed, 92 insertions(+), 8 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c 
b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
index af635430524e..1e3272e28b2d 100644
--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
@@ -817,6 +817,7 @@ static int put_v4l2_edid32(struct v4l2_edid *kp, struct 
v4l2_edid32 __user *up)
 #define        VIDIOC_DQEVENT32        _IOR ('V', 89, struct v4l2_event32)
 #define VIDIOC_CREATE_BUFS32   _IOWR('V', 92, struct v4l2_create_buffers32)
 #define VIDIOC_PREPARE_BUF32   _IOWR('V', 93, struct v4l2_buffer32)
+#define VIDIOC_INITIAL_EXT_CTRLS32    _IOWR('V', 104, struct 
v4l2_ext_controls32)
 
 #define VIDIOC_OVERLAY32       _IOW ('V', 14, s32)
 #define VIDIOC_STREAMON32      _IOW ('V', 18, s32)
@@ -859,6 +860,7 @@ static long do_video_ioctl(struct file *file, unsigned int 
cmd, unsigned long ar
        case VIDIOC_TRY_FMT32: cmd = VIDIOC_TRY_FMT; break;
        case VIDIOC_G_EXT_CTRLS32: cmd = VIDIOC_G_EXT_CTRLS; break;
        case VIDIOC_S_EXT_CTRLS32: cmd = VIDIOC_S_EXT_CTRLS; break;
+       case VIDIOC_INITIAL_EXT_CTRLS32: cmd = VIDIOC_INITIAL_EXT_CTRLS; break;
        case VIDIOC_TRY_EXT_CTRLS32: cmd = VIDIOC_TRY_EXT_CTRLS; break;
        case VIDIOC_DQEVENT32: cmd = VIDIOC_DQEVENT; break;
        case VIDIOC_OVERLAY32: cmd = VIDIOC_OVERLAY; break;
@@ -937,6 +939,7 @@ static long do_video_ioctl(struct file *file, unsigned int 
cmd, unsigned long ar
        case VIDIOC_G_EXT_CTRLS:
        case VIDIOC_S_EXT_CTRLS:
        case VIDIOC_TRY_EXT_CTRLS:
+       case VIDIOC_INITIAL_EXT_CTRLS:
                err = get_v4l2_ext_controls32(&karg.v2ecs, up);
                compatible_arg = 0;
                break;
@@ -964,6 +967,7 @@ static long do_video_ioctl(struct file *file, unsigned int 
cmd, unsigned long ar
        case VIDIOC_G_EXT_CTRLS:
        case VIDIOC_S_EXT_CTRLS:
        case VIDIOC_TRY_EXT_CTRLS:
+       case VIDIOC_INITIAL_EXT_CTRLS:
                if (put_v4l2_ext_controls32(&karg.v2ecs, up))
                        err = -EFAULT;
                break;
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c 
b/drivers/media/v4l2-core/v4l2-ctrls.c
index b462165a7f0c..465f73acc644 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1449,6 +1449,40 @@ static const struct v4l2_ctrl_type_ops std_type_ops = {
        .validate = std_validate,
 };
 
+/* Helper function: copy the initial value back to the caller */
+static int init_to_user(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl)
+{
+       int idx;
+       int ret;
+       long size;
+       union v4l2_ctrl_ptr ptr;
+
+       if (!ctrl->is_ptr){
+               ptr.p = &c->value;
+               ctrl->type_ops->init(ctrl, 0, ptr);
+               return 0;
+       }
+
+       size = ctrl->elem_size * ctrl->elems;
+       if (c->size < size){
+               c->size = size;
+               return -ENOSPC;
+       }
+
+       ptr.p = kzalloc(size, GFP_KERNEL);
+       if (!ptr.p)
+               return -ENOMEM;
+
+       for (idx=0; idx<ctrl->elems; idx++)
+               ctrl->type_ops->init(ctrl, idx, ptr);
+
+       ret = copy_to_user(c->ptr, ptr.p, size);
+
+       kfree(ptr.p);
+
+       return ret ? -EFAULT : 0;
+}
+
 /* 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,
@@ -2806,10 +2840,10 @@ static int class_check(struct v4l2_ctrl_handler *hdl, 
u32 ctrl_class)
        return find_ref_lock(hdl, ctrl_class | 1) ? 0 : -EINVAL;
 }
 
-
-
 /* Get extended controls. Allocates the helpers array if needed. */
-int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls 
*cs)
+static int v4l2_g_ext_ctrls_initial(struct v4l2_ctrl_handler *hdl,
+                                   struct v4l2_ext_controls *cs,
+                                   bool initial_value)
 {
        struct v4l2_ctrl_helper helper[4];
        struct v4l2_ctrl_helper *helpers = helper;
@@ -2840,10 +2874,11 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, 
struct v4l2_ext_controls *cs
                        ret = -EACCES;
 
        for (i = 0; !ret && i < cs->count; i++) {
-               int (*ctrl_to_user)(struct v4l2_ext_control *c,
-                                   struct v4l2_ctrl *ctrl) = cur_to_user;
+               int (*ctrl_to_user)(struct v4l2_ext_control *c, struct 
v4l2_ctrl *ctrl);
                struct v4l2_ctrl *master;
 
+               ctrl_to_user =  initial_value ? init_to_user : cur_to_user;
+
                if (helpers[i].mref == NULL)
                        continue;
 
@@ -2853,8 +2888,9 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, 
struct v4l2_ext_controls *cs
                v4l2_ctrl_lock(master);
 
                /* g_volatile_ctrl will update the new control values */
-               if ((master->flags & V4L2_CTRL_FLAG_VOLATILE) ||
-                       (master->has_volatiles && !is_cur_manual(master))) {
+               if ((!(master->flags & V4L2_CTRL_FLAG_VOLATILE) ||
+                    (master->has_volatiles && !is_cur_manual(master))) &&
+                    !initial_value) {
                        for (j = 0; j < master->ncontrols; j++)
                                cur_to_new(master->cluster[j]);
                        ret = call_op(master, g_volatile_ctrl);
@@ -2879,6 +2915,10 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, 
struct v4l2_ext_controls *cs
                kfree(helpers);
        return ret;
 }
+
+int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls 
*cs){
+       return v4l2_g_ext_ctrls_initial(hdl, cs, false);
+}
 EXPORT_SYMBOL(v4l2_g_ext_ctrls);
 
 int v4l2_subdev_g_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls 
*cs)
@@ -2887,6 +2927,17 @@ int v4l2_subdev_g_ext_ctrls(struct v4l2_subdev *sd, 
struct v4l2_ext_controls *cs
 }
 EXPORT_SYMBOL(v4l2_subdev_g_ext_ctrls);
 
+int v4l2_initial_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct 
v4l2_ext_controls *cs){
+       return v4l2_g_ext_ctrls_initial(hdl, cs, true);
+}
+EXPORT_SYMBOL(v4l2_initial_ext_ctrls);
+
+int v4l2_subdev_initial_ext_ctrls(struct v4l2_subdev *sd, struct 
v4l2_ext_controls *cs)
+{
+       return v4l2_initial_ext_ctrls(sd->ctrl_handler, cs);
+}
+EXPORT_SYMBOL(v4l2_subdev_initial_ext_ctrls);
+
 /* Helper function to get a single control */
 static int get_ctrl(struct v4l2_ctrl *ctrl, struct v4l2_ext_control *c)
 {
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c 
b/drivers/media/v4l2-core/v4l2-ioctl.c
index 8712168a3b0a..e68d9ec8832a 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -1812,6 +1812,25 @@ static int v4l_g_ext_ctrls(const struct v4l2_ioctl_ops 
*ops,
                                        -EINVAL;
 }
 
+static int v4l_initial_ext_ctrls(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       struct video_device *vfd = video_devdata(file);
+       struct v4l2_ext_controls *p = arg;
+       struct v4l2_fh *vfh =
+               test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) ? fh : NULL;
+
+       p->error_idx = p->count;
+       if (vfh && vfh->ctrl_handler)
+               return v4l2_initial_ext_ctrls(vfh->ctrl_handler, p);
+       if (vfd->ctrl_handler)
+               return v4l2_initial_ext_ctrls(vfd->ctrl_handler, p);
+       if (ops->vidioc_initial_ext_ctrls == NULL)
+               return -ENOTTY;
+       return check_ext_ctrls(p, 0) ? ops->vidioc_initial_ext_ctrls(file, fh, 
p) :
+                                       -EINVAL;
+}
+
 static int v4l_s_ext_ctrls(const struct v4l2_ioctl_ops *ops,
                                struct file *file, void *fh, void *arg)
 {
@@ -2285,6 +2304,7 @@ static struct v4l2_ioctl_info v4l2_ioctls[] = {
        IOCTL_INFO_FNC(VIDIOC_G_SLICED_VBI_CAP, v4l_g_sliced_vbi_cap, 
v4l_print_sliced_vbi_cap, INFO_FL_CLEAR(v4l2_sliced_vbi_cap, type)),
        IOCTL_INFO_FNC(VIDIOC_LOG_STATUS, v4l_log_status, v4l_print_newline, 0),
        IOCTL_INFO_FNC(VIDIOC_G_EXT_CTRLS, v4l_g_ext_ctrls, 
v4l_print_ext_controls, INFO_FL_CTRL),
+       IOCTL_INFO_FNC(VIDIOC_INITIAL_EXT_CTRLS, v4l_initial_ext_ctrls, 
v4l_print_ext_controls, INFO_FL_CTRL),
        IOCTL_INFO_FNC(VIDIOC_S_EXT_CTRLS, v4l_s_ext_ctrls, 
v4l_print_ext_controls, INFO_FL_PRIO | INFO_FL_CTRL),
        IOCTL_INFO_FNC(VIDIOC_TRY_EXT_CTRLS, v4l_try_ext_ctrls, 
v4l_print_ext_controls, INFO_FL_CTRL),
        IOCTL_INFO_STD(VIDIOC_ENUM_FRAMESIZES, vidioc_enum_framesizes, 
v4l_print_frmsizeenum, INFO_FL_CLEAR(v4l2_frmsizeenum, pixel_format)),
diff --git a/drivers/media/v4l2-core/v4l2-subdev.c 
b/drivers/media/v4l2-core/v4l2-subdev.c
index 19a034e79be4..6ed308df9d2f 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -206,6 +206,9 @@ static long subdev_do_ioctl(struct file *file, unsigned int 
cmd, void *arg)
        case VIDIOC_G_EXT_CTRLS:
                return v4l2_g_ext_ctrls(vfh->ctrl_handler, arg);
 
+       case VIDIOC_INITIAL_EXT_CTRLS:
+               return v4l2_initial_ext_ctrls(vfh->ctrl_handler, arg);
+
        case VIDIOC_S_EXT_CTRLS:
                return v4l2_s_ext_ctrls(vfh, vfh->ctrl_handler, arg);
 
diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
index ec63d8c44f4e..6521f54718ca 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -815,6 +815,7 @@ int v4l2_g_ctrl(struct v4l2_ctrl_handler *hdl, struct 
v4l2_control *ctrl);
 int v4l2_s_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
                                                struct v4l2_control *ctrl);
 int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls 
*c);
+int v4l2_initial_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct 
v4l2_ext_controls *c);
 int v4l2_try_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls 
*c);
 int v4l2_s_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
                                                struct v4l2_ext_controls *c);
@@ -824,6 +825,7 @@ int v4l2_s_ext_ctrls(struct v4l2_fh *fh, struct 
v4l2_ctrl_handler *hdl,
 int v4l2_subdev_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc);
 int v4l2_subdev_querymenu(struct v4l2_subdev *sd, struct v4l2_querymenu *qm);
 int v4l2_subdev_g_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls 
*cs);
+int v4l2_subdev_initial_ext_ctrls(struct v4l2_subdev *sd, struct 
v4l2_ext_controls *cs);
 int v4l2_subdev_try_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls 
*cs);
 int v4l2_subdev_s_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls 
*cs);
 int v4l2_subdev_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl);
diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h
index 8537983b9b22..16a289bc46b1 100644
--- a/include/media/v4l2-ioctl.h
+++ b/include/media/v4l2-ioctl.h
@@ -166,6 +166,8 @@ struct v4l2_ioctl_ops {
                                        struct v4l2_control *a);
        int (*vidioc_g_ext_ctrls)      (struct file *file, void *fh,
                                        struct v4l2_ext_controls *a);
+       int (*vidioc_initial_ext_ctrls)(struct file *file, void *fh,
+                                       struct v4l2_ext_controls *a);
        int (*vidioc_s_ext_ctrls)      (struct file *file, void *fh,
                                        struct v4l2_ext_controls *a);
        int (*vidioc_try_ext_ctrls)    (struct file *file, void *fh,
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 2b26d23f9b04..9b84f1755d5f 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -2204,8 +2204,10 @@ struct v4l2_create_buffers {
 
 #define VIDIOC_QUERY_EXT_CTRL  _IOWR('V', 103, struct v4l2_query_ext_ctrl)
 
+#define VIDIOC_INITIAL_EXT_CTRLS       _IOWR('V', 104, struct 
v4l2_ext_controls)
+
 /* Reminder: when adding new ioctls please add support for them to
-   drivers/media/video/v4l2-compat-ioctl32.c as well! */
+   drivers/media/v4l2-core/v4l2-compat-ioctl32.c as well! */
 
 #define BASE_VIDIOC_PRIVATE    192             /* 192-255 are private */
 
-- 
2.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to