From: Hans Verkuil <hans.verkuil@xxxxxxxxx> Experimental: I am still not certain whether this is desired or not. Signed-off-by: Hans Verkuil <hans.verkuil@xxxxxxxxx> --- drivers/media/v4l2-core/v4l2-ctrls.c | 28 ++++++++++++++++++++-------- drivers/media/v4l2-core/v4l2-ioctl.c | 9 ++++++++- drivers/media/v4l2-core/v4l2-subdev.c | 11 ++++++++++- include/media/v4l2-ctrls.h | 3 +++ include/media/v4l2-fh.h | 3 +++ include/uapi/linux/videodev2.h | 4 ++++ 6 files changed, 48 insertions(+), 10 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index d262e2e..480bdb6 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -2693,6 +2693,8 @@ int v4l2_query_ext_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_query_ext_ctr if (req) { if (ctrl_req->applied) qc->flags |= V4L2_CTRL_FLAG_REQ_APPLIED; + if (ctrl_req->keep) + qc->flags |= V4L2_CTRL_FLAG_REQ_KEEP; } qc->max_reqs = ctrl->max_reqs; qc->type = ctrl->type; @@ -3148,7 +3150,7 @@ EXPORT_SYMBOL(v4l2_ctrl_g_ctrl_int64); copied to the current value on a set. Must be called with ctrl->handler->lock held. */ static int try_or_set_cluster(struct v4l2_fh *fh, struct v4l2_ctrl *master, - u16 request, bool set, u32 ch_flags) + u16 request, bool keep, bool set, u32 ch_flags) { bool update_flag; int ret; @@ -3172,6 +3174,8 @@ static int try_or_set_cluster(struct v4l2_fh *fh, struct v4l2_ctrl *master, if (ret) return ret; } + if (set) + req->keep = keep; } ctrl->request = req; if (!ctrl->is_new) { @@ -3272,14 +3276,17 @@ static int try_set_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl, struct v4l2_ctrl_helper helper[4]; struct v4l2_ctrl_helper *helpers = helper; unsigned request = 0; + bool keep = false; unsigned i, j; int ret; cs->error_idx = cs->count; - if (V4L2_CTRL_ID2CLASS(cs->ctrl_class)) + if (V4L2_CTRL_ID2CLASS(cs->ctrl_class)) { cs->ctrl_class = V4L2_CTRL_ID2CLASS(cs->ctrl_class); - else + } else { request = cs->request; + keep = set && (cs->request & V4L2_CTRL_REQ_FL_KEEP); + } if (hdl == NULL || request > USHRT_MAX) return -EINVAL; @@ -3351,7 +3358,8 @@ static int try_set_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl, } while (!ret && idx); if (!ret) - ret = try_or_set_cluster(fh, master, request, set, 0); + ret = try_or_set_cluster(fh, master, request, + keep, set, 0); /* Copy the new values back to userspace. */ if (!ret) { @@ -3423,7 +3431,7 @@ static int set_ctrl(struct v4l2_fh *fh, unsigned request, update_from_auto_cluster(master); ctrl->is_new = 1; - return try_or_set_cluster(fh, master, request, true, ch_flags); + return try_or_set_cluster(fh, master, request, false, true, ch_flags); } /* Helper function for VIDIOC_S_CTRL compatibility */ @@ -3517,6 +3525,7 @@ int v4l2_ctrl_apply_request(struct v4l2_ctrl_handler *hdl, unsigned request) list_for_each_entry(ref, &hdl->ctrl_refs, node) { struct v4l2_ctrl *master; bool apply_request = false; + bool keep = false; if (ref->ctrl->max_reqs == 0) continue; @@ -3535,9 +3544,11 @@ int v4l2_ctrl_apply_request(struct v4l2_ctrl_handler *hdl, unsigned request) if (ctrl->request == NULL) continue; found_request = true; - if (!ctrl->request->applied) { + if (ctrl->request->keep || !ctrl->request->applied) { request_to_new(master->cluster[i]); apply_request = true; + if (ctrl->request->keep) + keep = true; ctrl->request->applied = 1; } } @@ -3548,7 +3559,8 @@ int v4l2_ctrl_apply_request(struct v4l2_ctrl_handler *hdl, unsigned request) } /* - * Skip if it is a request that has already been applied. + * Skip if it is a one-off request that has already been + * applied. */ if (!apply_request) goto unlock; @@ -3569,7 +3581,7 @@ int v4l2_ctrl_apply_request(struct v4l2_ctrl_handler *hdl, unsigned request) update_from_auto_cluster(master); } - try_or_set_cluster(NULL, master, 0, true, 0); + try_or_set_cluster(NULL, master, 0, keep, true, 0); unlock: if (master->handler != hdl) diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 44c33f3..503354a 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1833,8 +1833,11 @@ static int v4l_s_ext_ctrls(const struct v4l2_ioctl_ops *ops, p->error_idx = p->count; if (vfh && vfh->ctrl_handler) { - if (vfh->request && p->request == 0) + if (vfh->request && p->request == 0) { p->request = vfh->request; + if (vfh->flags & V4L2_FH_FL_KEEP) + p->request |= V4L2_CTRL_REQ_FL_KEEP; + } return v4l2_s_ext_ctrls(vfh, vfh->ctrl_handler, p); } if (vfd->ctrl_handler) @@ -1988,6 +1991,10 @@ static int v4l_request_cmd(const struct v4l2_ioctl_ops *ops, if (p->request == 0) return -EINVAL; vfh->request = p->request; + if (p->flags & V4L2_REQ_CMD_BEGIN_FL_KEEP) + vfh->flags |= V4L2_FH_FL_KEEP; + else + vfh->flags &= ~V4L2_FH_FL_KEEP; break; case V4L2_REQ_CMD_END: vfh->request = 0; diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index 7113b95..5fe41c9 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -212,14 +212,19 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) if (vfh->request && p->request == 0) p->request = vfh->request; + else if (p->request > USHRT_MAX) + return -EINVAL; return v4l2_g_ext_ctrls(vfh->ctrl_handler, arg); } case VIDIOC_S_EXT_CTRLS: { struct v4l2_ext_controls *p = arg; - if (vfh->request && p->request == 0) + if (vfh->request && p->request == 0) { p->request = vfh->request; + if (vfh->flags & V4L2_FH_FL_KEEP) + p->request |= V4L2_CTRL_REQ_FL_KEEP; + } return v4l2_s_ext_ctrls(vfh, vfh->ctrl_handler, arg); } @@ -256,6 +261,10 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) if (p->request == 0) return -EINVAL; vfh->request = p->request; + if (p->flags & V4L2_REQ_CMD_BEGIN_FL_KEEP) + vfh->flags |= V4L2_FH_FL_KEEP; + else + vfh->flags &= ~V4L2_FH_FL_KEEP; break; case V4L2_REQ_CMD_END: vfh->request = 0; diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h index efba887..7a028e0 100644 --- a/include/media/v4l2-ctrls.h +++ b/include/media/v4l2-ctrls.h @@ -36,6 +36,8 @@ struct v4l2_subscribed_event; struct v4l2_fh; struct poll_table_struct; +#define V4L2_CTRL_REQ_FL_KEEP (1UL << 31) + /** union v4l2_ctrl_ptr - A pointer to a control value. * @p_s32: Pointer to a 32-bit signed value. * @p_s64: Pointer to a 64-bit signed value. @@ -95,6 +97,7 @@ typedef void (*v4l2_ctrl_notify_fnc)(struct v4l2_ctrl *ctrl, void *priv); struct v4l2_ctrl_req { struct list_head node; u32 request; + unsigned keep:1; unsigned applied:1; union v4l2_ctrl_ptr ptr; }; diff --git a/include/media/v4l2-fh.h b/include/media/v4l2-fh.h index 652202f..bee0754 100644 --- a/include/media/v4l2-fh.h +++ b/include/media/v4l2-fh.h @@ -33,6 +33,8 @@ struct video_device; struct v4l2_ctrl_handler; +#define V4L2_FH_FL_KEEP (1 << 0) + struct v4l2_fh { struct list_head list; struct video_device *vdev; @@ -46,6 +48,7 @@ struct v4l2_fh { unsigned int navailable; u32 sequence; u16 request; + u16 flags; #if IS_ENABLED(CONFIG_V4L2_MEM2MEM_DEV) struct v4l2_m2m_ctx *m2m_ctx; diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index f3164f6..b2cbf3f 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -1472,6 +1472,7 @@ struct v4l2_querymenu { #define V4L2_CTRL_FLAG_HAS_PAYLOAD 0x0100 #define V4L2_CTRL_FLAG_EXECUTE_ON_WRITE 0x0200 #define V4L2_CTRL_FLAG_REQ_APPLIED 0x0400 +#define V4L2_CTRL_FLAG_REQ_KEEP 0x0800 /* Query flags, to be ORed with the control ID */ #define V4L2_CTRL_FLAG_NEXT_CTRL 0x80000000 @@ -2091,6 +2092,9 @@ struct v4l2_create_buffers { #define V4L2_REQ_CMD_APPLY (3) #define V4L2_REQ_CMD_QUEUE (4) +/* Flag for V4L2_REQ_CMD_BEGIN */ +#define V4L2_REQ_CMD_BEGIN_FL_KEEP (1 << 0) + struct v4l2_request_cmd { __u32 cmd; __u16 request; -- 2.1.4 -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html