[RFCv2 PATCH 05/15] v4l2-ctrls: add request support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Hans Verkuil <hans.verkuil@xxxxxxxxx>

Signed-off-by: Hans Verkuil <hans.verkuil@xxxxxxxxx>
---
 drivers/media/v4l2-core/v4l2-ctrls.c | 228 ++++++++++++++++++++++++++++++-----
 drivers/media/v4l2-core/v4l2-ioctl.c |   8 ++
 include/media/v4l2-ctrls.h           |  20 +++
 3 files changed, 228 insertions(+), 28 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index e3a3468..d28035c 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1235,6 +1235,96 @@ static void send_event(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 changes)
 			v4l2_event_queue_fh(sev->fh, &ev);
 }
 
+static int alloc_requests(struct v4l2_ctrl *ctrl)
+{
+	unsigned i;
+
+	ctrl->request_lists = kmalloc_array(VIDEO_MAX_FRAME,
+					sizeof(struct list_head), GFP_KERNEL);
+	if (ctrl->request_lists == NULL)
+		return -ENOMEM;
+	for (i = 0; i < VIDEO_MAX_FRAME; i++)
+		INIT_LIST_HEAD(ctrl->request_lists + i);
+	return 0;
+}
+
+static struct v4l2_ctrl_req *get_request(struct v4l2_ctrl *ctrl, unsigned request)
+{
+	struct v4l2_ctrl_req *req;
+	struct list_head *head;
+
+	if (ctrl->request_lists == NULL)
+		return NULL;
+	head = ctrl->request_lists + (request % VIDEO_MAX_FRAME);
+	list_for_each_entry(req, head, node)
+		if (req->request == request)
+			return req;
+	return NULL;
+}
+
+static int add_request(struct v4l2_ctrl *ctrl, unsigned request,
+		       struct v4l2_ctrl_req **p_req)
+{
+	struct v4l2_ctrl_req *req;
+	struct list_head *head;
+	unsigned idx;
+	int ret;
+
+	if (ctrl->nr_of_requests == ctrl->max_reqs)
+		return -ENOSPC;
+
+	if (ctrl->request_lists == NULL) {
+		ret = alloc_requests(ctrl);
+		if (ret)
+			return ret;
+	}
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (req == NULL)
+		return -ENOMEM;
+	req->ptr.p = kcalloc(ctrl->elems, ctrl->elem_size, GFP_KERNEL);
+	req->request = request;
+	if (req->ptr.p == NULL) {
+		kfree(req);
+		return -ENOMEM;
+	}
+	head = ctrl->request_lists + (request % VIDEO_MAX_FRAME);
+	for (idx = 0; idx < ctrl->elems; idx++)
+		ctrl->type_ops->init(ctrl, idx, req->ptr);
+	ctrl->nr_of_requests++;
+	list_add(&req->node, head);
+	if (p_req)
+		*p_req = req;
+	return 0;
+}
+
+static void del_request(struct v4l2_ctrl *ctrl, struct v4l2_ctrl_req *req)
+{
+	list_del(&req->node);
+	ctrl->nr_of_requests--;
+	kfree(req->ptr.p);
+	kfree(req);
+}
+
+static void free_requests(struct v4l2_ctrl *ctrl)
+{
+	unsigned idx;
+
+	if (!ctrl->request_lists)
+		return;
+
+	for (idx = 0; idx < VIDEO_MAX_FRAME; idx++) {
+		struct list_head *head = ctrl->request_lists + idx;
+
+		while (!list_empty(head)) {
+			struct v4l2_ctrl_req *req =
+				list_first_entry(head, struct v4l2_ctrl_req, node);
+			del_request(ctrl, req);
+		}
+	}
+	kfree(ctrl->request_lists);
+	ctrl->request_lists = NULL;
+}
+
 static bool std_equal(const struct v4l2_ctrl *ctrl, u32 idx,
 		      union v4l2_ctrl_ptr ptr1,
 		      union v4l2_ctrl_ptr ptr2)
@@ -1482,6 +1572,15 @@ static int cur_to_user(struct v4l2_ext_control *c,
 	return ptr_to_user(c, ctrl, ctrl->p_cur);
 }
 
+/* Helper function: copy the request's control value back to the caller */
+static int request_to_user(struct v4l2_ext_control *c,
+		       struct v4l2_ctrl *ctrl)
+{
+	if (ctrl->request == NULL)
+		return ptr_to_user(c, ctrl, ctrl->p_new);
+	return ptr_to_user(c, ctrl, ctrl->request->ptr);
+}
+
 /* 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)
@@ -1589,6 +1688,13 @@ static void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags)
 	}
 }
 
+/* Helper function: copy the new control value to the request */
+static void new_to_request(struct v4l2_ctrl *ctrl)
+{
+	if (ctrl)
+		ptr_to_ptr(ctrl, ctrl->p_new, ctrl->request->ptr);
+}
+
 /* Copy the current value to the new value */
 static void cur_to_new(struct v4l2_ctrl *ctrl)
 {
@@ -1750,6 +1856,7 @@ void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl)
 		list_del(&ctrl->node);
 		list_for_each_entry_safe(sev, next_sev, &ctrl->ev_subs, node)
 			list_del(&sev->node);
+		free_requests(ctrl);
 		kfree(ctrl);
 	}
 	kfree(hdl->buckets);
@@ -2095,8 +2202,10 @@ struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl,
 			is_menu ? cfg->menu_skip_mask : step, def,
 			cfg->dims, cfg->elem_size,
 			flags, qmenu, qmenu_int, priv);
-	if (ctrl)
+	if (ctrl) {
 		ctrl->is_private = cfg->is_private;
+		ctrl->max_reqs = cfg->max_reqs;
+	}
 	return ctrl;
 }
 EXPORT_SYMBOL(v4l2_ctrl_new_custom);
@@ -2289,18 +2398,26 @@ EXPORT_SYMBOL(v4l2_ctrl_radio_filter);
 void v4l2_ctrl_cluster(unsigned ncontrols, struct v4l2_ctrl **controls)
 {
 	bool has_volatiles = false;
+	unsigned max_reqs;
 	int i;
 
 	/* The first control is the master control and it must not be NULL */
 	if (WARN_ON(ncontrols == 0 || controls[0] == NULL))
 		return;
 
+	max_reqs = controls[0]->max_reqs;
 	for (i = 0; i < ncontrols; i++) {
 		if (controls[i]) {
 			controls[i]->cluster = controls;
 			controls[i]->ncontrols = ncontrols;
 			if (controls[i]->flags & V4L2_CTRL_FLAG_VOLATILE)
 				has_volatiles = true;
+			/*
+			 * The max_reqs value should be the same for all
+			 * controls inside the cluster.
+			 */
+			if (WARN_ON(controls[i]->max_reqs != max_reqs))
+				controls[i]->max_reqs = max_reqs;
 		}
 	}
 	controls[0]->has_volatiles = has_volatiles;
@@ -2463,6 +2580,7 @@ int v4l2_ctrl_handler_setup(struct v4l2_ctrl_handler *hdl)
 				cur_to_new(master->cluster[i]);
 				master->cluster[i]->is_new = 1;
 				master->cluster[i]->done = true;
+				master->cluster[i]->request = NULL;
 			}
 		}
 		ret = call_op(master, s_ctrl);
@@ -2479,10 +2597,11 @@ int v4l2_query_ext_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_query_ext_ctr
 {
 	const unsigned next_flags = V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND;
 	u32 id = qc->id & V4L2_CTRL_ID_MASK;
+	u32 req = qc->request;
 	struct v4l2_ctrl_ref *ref;
 	struct v4l2_ctrl *ctrl;
 
-	if (hdl == NULL)
+	if (hdl == NULL || req > USHRT_MAX)
 		return -EINVAL;
 
 	mutex_lock(hdl->lock);
@@ -2516,6 +2635,7 @@ int v4l2_query_ext_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_query_ext_ctr
 				is_compound =
 					ref->ctrl->type >= V4L2_CTRL_COMPOUND_TYPES;
 				if (id < ref->ctrl->id &&
+				    (!req || get_request(ref->ctrl, req)) &&
 				    (is_compound & mask) == match)
 					break;
 			}
@@ -2530,6 +2650,7 @@ int v4l2_query_ext_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_query_ext_ctr
 				is_compound =
 					ref->ctrl->type >= V4L2_CTRL_COMPOUND_TYPES;
 				if (id < ref->ctrl->id &&
+				    (!req || get_request(ref->ctrl, req)) &&
 				    (is_compound & mask) == match)
 					break;
 			}
@@ -2541,6 +2662,8 @@ int v4l2_query_ext_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_query_ext_ctr
 
 	if (!ref)
 		return -EINVAL;
+	if (req && get_request(ref->ctrl, req) == NULL)
+		return -EINVAL;
 
 	ctrl = ref->ctrl;
 	memset(qc, 0, sizeof(*qc));
@@ -2550,6 +2673,7 @@ int v4l2_query_ext_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_query_ext_ctr
 		qc->id = ctrl->id;
 	strlcpy(qc->name, ctrl->name, sizeof(qc->name));
 	qc->flags = ctrl->flags;
+	qc->max_reqs = ctrl->max_reqs;
 	qc->type = ctrl->type;
 	if (ctrl->is_ptr)
 		qc->flags |= V4L2_CTRL_FLAG_HAS_PAYLOAD;
@@ -2711,6 +2835,8 @@ static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl,
 			     struct v4l2_ctrl_helper *helpers,
 			     bool get)
 {
+	u32 ctrl_class = V4L2_CTRL_ID2CLASS(cs->ctrl_class);
+	unsigned request = cs->request & 0xffff;
 	struct v4l2_ctrl_helper *h;
 	bool have_clusters = false;
 	u32 i;
@@ -2723,7 +2849,7 @@ static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl,
 
 		cs->error_idx = i;
 
-		if (cs->ctrl_class && V4L2_CTRL_ID2CLASS(id) != cs->ctrl_class)
+		if (ctrl_class && V4L2_CTRL_ID2CLASS(id) != ctrl_class)
 			return -EINVAL;
 
 		/* Old-style private controls are not allowed for
@@ -2736,6 +2862,8 @@ static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl,
 		ctrl = ref->ctrl;
 		if (ctrl->flags & V4L2_CTRL_FLAG_DISABLED)
 			return -EINVAL;
+		if (request && !ctrl->max_reqs)
+			return -EINVAL;
 
 		if (ctrl->cluster[0]->ncontrols > 1)
 			have_clusters = true;
@@ -2807,24 +2935,26 @@ 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)
 {
 	struct v4l2_ctrl_helper helper[4];
 	struct v4l2_ctrl_helper *helpers = helper;
+	unsigned request = 0;
 	int ret;
 	int i, j;
 
 	cs->error_idx = cs->count;
-	cs->ctrl_class = V4L2_CTRL_ID2CLASS(cs->ctrl_class);
+	if (V4L2_CTRL_ID2CLASS(cs->ctrl_class))
+		cs->ctrl_class = V4L2_CTRL_ID2CLASS(cs->ctrl_class);
+	else
+		request = cs->request;
 
-	if (hdl == NULL)
+	if (hdl == NULL || request > USHRT_MAX)
 		return -EINVAL;
 
 	if (cs->count == 0)
-		return class_check(hdl, cs->ctrl_class);
+		return class_check(hdl, V4L2_CTRL_ID2CLASS(cs->ctrl_class));
 
 	if (cs->count > ARRAY_SIZE(helper)) {
 		helpers = kmalloc_array(cs->count, sizeof(helper[0]),
@@ -2854,13 +2984,27 @@ 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 (request == 0 &&
+		    ((master->flags & V4L2_CTRL_FLAG_VOLATILE) ||
+		     (master->has_volatiles && !is_cur_manual(master)))) {
 			for (j = 0; j < master->ncontrols; j++)
 				cur_to_new(master->cluster[j]);
 			ret = call_op(master, g_volatile_ctrl);
 			ctrl_to_user = new_to_user;
 		}
+		if (request) {
+			for (j = 0; !ret && j < master->ncontrols; j++) {
+				struct v4l2_ctrl *ctrl = master->cluster[j];
+
+				if (!ctrl)
+					continue;
+				ctrl->request = get_request(ctrl, request);
+				if (ctrl->request)
+					continue;
+				ret = add_request(ctrl, request, &ctrl->request);
+			}
+		}
+
 		/* If OK, then copy the current (for non-volatile controls)
 		   or the new (for volatile controls) control values to the
 		   caller */
@@ -2868,7 +3012,11 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs
 			u32 idx = i;
 
 			do {
-				ret = ctrl_to_user(cs->controls + idx,
+				if (request)
+					ret = request_to_user(cs->controls + idx,
+						   helpers[idx].ctrl);
+				else
+					ret = ctrl_to_user(cs->controls + idx,
 						   helpers[idx].ctrl);
 				idx = helpers[idx].next;
 			} while (!ret && idx);
@@ -2963,12 +3111,11 @@ s64 v4l2_ctrl_g_ctrl_int64(struct v4l2_ctrl *ctrl)
 }
 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.
    Must be called with ctrl->handler->lock held. */
 static int try_or_set_cluster(struct v4l2_fh *fh, struct v4l2_ctrl *master,
-			      bool set, u32 ch_flags)
+			      u16 request, bool set, u32 ch_flags)
 {
 	bool update_flag;
 	int ret;
@@ -2980,10 +3127,20 @@ static int try_or_set_cluster(struct v4l2_fh *fh, struct v4l2_ctrl *master,
 	   called. */
 	for (i = 0; i < master->ncontrols; i++) {
 		struct v4l2_ctrl *ctrl = master->cluster[i];
+		struct v4l2_ctrl_req *req = NULL;
 
 		if (ctrl == NULL)
 			continue;
 
+		if (request) {
+			req = get_request(ctrl, request);
+			if (!req) {
+				ret = add_request(ctrl, request, &req);
+				if (ret)
+					return ret;
+			}
+		}
+		ctrl->request = req;
 		if (!ctrl->is_new) {
 			cur_to_new(ctrl);
 			continue;
@@ -2997,7 +3154,7 @@ static int try_or_set_cluster(struct v4l2_fh *fh, struct v4l2_ctrl *master,
 	ret = call_op(master, try_ctrl);
 
 	/* Don't set if there is no change */
-	if (ret || !set || !cluster_changed(master))
+	if (ret || !set || (!request && !cluster_changed(master)))
 		return ret;
 	ret = call_op(master, s_ctrl);
 	if (ret)
@@ -3005,9 +3162,13 @@ static int try_or_set_cluster(struct v4l2_fh *fh, struct v4l2_ctrl *master,
 
 	/* If OK, then make the new values permanent. */
 	update_flag = is_cur_manual(master) != is_new_manual(master);
-	for (i = 0; i < master->ncontrols; i++)
-		new_to_cur(fh, master->cluster[i], ch_flags |
-			((update_flag && i > 0) ? V4L2_EVENT_CTRL_CH_FLAGS : 0));
+	for (i = 0; i < master->ncontrols; i++) {
+		if (request)
+			new_to_request(master->cluster[i]);
+		else
+			new_to_cur(fh, master->cluster[i], ch_flags |
+				((update_flag && i > 0) ? V4L2_EVENT_CTRL_CH_FLAGS : 0));
+	}
 	return 0;
 }
 
@@ -3058,8 +3219,12 @@ static void update_from_auto_cluster(struct v4l2_ctrl *master)
 {
 	int i;
 
-	for (i = 0; i < master->ncontrols; i++)
+	for (i = 0; i < master->ncontrols; i++) {
+		if (master->cluster[i] == NULL)
+			continue;
 		cur_to_new(master->cluster[i]);
+		master->cluster[i]->request = 0;
+	}
 	if (!call_op(master, g_volatile_ctrl))
 		for (i = 1; i < master->ncontrols; i++)
 			if (master->cluster[i])
@@ -3073,17 +3238,21 @@ 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;
 	unsigned i, j;
 	int ret;
 
 	cs->error_idx = cs->count;
-	cs->ctrl_class = V4L2_CTRL_ID2CLASS(cs->ctrl_class);
+	if (V4L2_CTRL_ID2CLASS(cs->ctrl_class))
+		cs->ctrl_class = V4L2_CTRL_ID2CLASS(cs->ctrl_class);
+	else
+		request = cs->request;
 
-	if (hdl == NULL)
+	if (hdl == NULL || request > USHRT_MAX)
 		return -EINVAL;
 
 	if (cs->count == 0)
-		return class_check(hdl, cs->ctrl_class);
+		return class_check(hdl, V4L2_CTRL_ID2CLASS(cs->ctrl_class));
 
 	if (cs->count > ARRAY_SIZE(helper)) {
 		helpers = kmalloc_array(cs->count, sizeof(helper[0]),
@@ -3118,7 +3287,7 @@ static int try_set_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
 		   first since those will become the new manual values (which
 		   may be overwritten by explicit new values from this set
 		   of controls). */
-		if (master->is_auto && master->has_volatiles &&
+		if (!request && master->is_auto && master->has_volatiles &&
 						!is_cur_manual(master)) {
 			/* Pick an initial non-manual value */
 			s32 new_auto_val = master->manual_mode_value + 1;
@@ -3149,13 +3318,13 @@ 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, set, 0);
+			ret = try_or_set_cluster(fh, master, request, set, 0);
 
 		/* Copy the new values back to userspace. */
 		if (!ret) {
 			idx = i;
 			do {
-				ret = new_to_user(cs->controls + idx,
+				ret = request_to_user(cs->controls + idx,
 						helpers[idx].ctrl);
 				idx = helpers[idx].next;
 			} while (!ret && idx);
@@ -3201,9 +3370,12 @@ static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags)
 	int i;
 
 	/* Reset the 'is_new' flags of the cluster */
-	for (i = 0; i < master->ncontrols; i++)
-		if (master->cluster[i])
-			master->cluster[i]->is_new = 0;
+	for (i = 0; i < master->ncontrols; i++) {
+		if (master->cluster[i] == NULL)
+			continue;
+		master->cluster[i]->is_new = 0;
+		master->cluster[i]->request = NULL;
+	}
 
 	ret = validate_new(ctrl, ctrl->p_new);
 	if (ret)
@@ -3217,7 +3389,7 @@ static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags)
 		update_from_auto_cluster(master);
 
 	ctrl->is_new = 1;
-	return try_or_set_cluster(fh, master, true, ch_flags);
+	return try_or_set_cluster(fh, master, 0, true, ch_flags);
 }
 
 /* Helper function for VIDIOC_S_CTRL compatibility */
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index d2d1fb1..a16af7f 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -1701,6 +1701,8 @@ static int v4l_query_ext_ctrl(const struct v4l2_ioctl_ops *ops,
 		return v4l2_query_ext_ctrl(vfh->ctrl_handler, p);
 	if (vfd->ctrl_handler)
 		return v4l2_query_ext_ctrl(vfd->ctrl_handler, p);
+	if (p->request)
+		return -EINVAL;
 	if (ops->vidioc_query_ext_ctrl)
 		return ops->vidioc_query_ext_ctrl(file, fh, p);
 	return -ENOTTY;
@@ -1801,6 +1803,8 @@ static int v4l_g_ext_ctrls(const struct v4l2_ioctl_ops *ops,
 		return v4l2_g_ext_ctrls(vfd->ctrl_handler, p);
 	if (ops->vidioc_g_ext_ctrls == NULL)
 		return -ENOTTY;
+	if (p->request)
+		return -EINVAL;
 	return check_ext_ctrls(p, 0) ? ops->vidioc_g_ext_ctrls(file, fh, p) :
 					-EINVAL;
 }
@@ -1820,6 +1824,8 @@ static int v4l_s_ext_ctrls(const struct v4l2_ioctl_ops *ops,
 		return v4l2_s_ext_ctrls(NULL, vfd->ctrl_handler, p);
 	if (ops->vidioc_s_ext_ctrls == NULL)
 		return -ENOTTY;
+	if (p->request)
+		return -EINVAL;
 	return check_ext_ctrls(p, 0) ? ops->vidioc_s_ext_ctrls(file, fh, p) :
 					-EINVAL;
 }
@@ -1839,6 +1845,8 @@ static int v4l_try_ext_ctrls(const struct v4l2_ioctl_ops *ops,
 		return v4l2_try_ext_ctrls(vfd->ctrl_handler, p);
 	if (ops->vidioc_try_ext_ctrls == NULL)
 		return -ENOTTY;
+	if (p->request)
+		return -EINVAL;
 	return check_ext_ctrls(p, 0) ? ops->vidioc_try_ext_ctrls(file, fh, p) :
 					-EINVAL;
 }
diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
index 911f3e5..abc5eb3 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -92,6 +92,12 @@ struct v4l2_ctrl_type_ops {
 
 typedef void (*v4l2_ctrl_notify_fnc)(struct v4l2_ctrl *ctrl, void *priv);
 
+struct v4l2_ctrl_req {
+	struct list_head node;
+	u32 request;
+	union v4l2_ctrl_ptr ptr;
+};
+
 /** struct v4l2_ctrl - The control structure.
   * @node:	The list node.
   * @ev_subs:	The list of control event subscriptions.
@@ -140,6 +146,9 @@ typedef void (*v4l2_ctrl_notify_fnc)(struct v4l2_ctrl *ctrl, void *priv);
   * @elem_size:	The size in bytes of the control.
   * @dims:	The size of each dimension.
   * @nr_of_dims:The number of dimensions in @dims.
+  * @nr_of_requests: The number of allocated requests of this control.
+  * @max_reqs:	The maximum number of requests supported by this control.
+  * @request:	The request that the control op operates on.
   * @menu_skip_mask: The control's skip mask for menu controls. This makes it
   *		easy to skip menu items that are not valid. If bit X is set,
   *		then menu item X is skipped. Of course, this only works for
@@ -191,6 +200,9 @@ struct v4l2_ctrl {
 	u32 elem_size;
 	u32 dims[V4L2_CTRL_MAX_DIMS];
 	u32 nr_of_dims;
+	u16 nr_of_requests;
+	u16 max_reqs;
+	struct v4l2_ctrl_req *request;
 	union {
 		u64 step;
 		u64 menu_skip_mask;
@@ -208,6 +220,7 @@ struct v4l2_ctrl {
 
 	union v4l2_ctrl_ptr p_new;
 	union v4l2_ctrl_ptr p_cur;
+	struct list_head *request_lists;
 };
 
 /** struct v4l2_ctrl_ref - The control reference.
@@ -284,6 +297,7 @@ struct v4l2_ctrl_handler {
   *		must be NULL.
   * @is_private: If set, then this control is private to its handler and it
   *		will not be added to any other handlers.
+  * @max_reqs:	The maximum number of requests supported by this control.
   */
 struct v4l2_ctrl_config {
 	const struct v4l2_ctrl_ops *ops;
@@ -302,6 +316,7 @@ struct v4l2_ctrl_config {
 	const char * const *qmenu;
 	const s64 *qmenu_int;
 	unsigned int is_private:1;
+	u16 max_reqs;
 };
 
 /** v4l2_ctrl_fill() - Fill in the control fields based on the control ID.
@@ -788,6 +803,11 @@ static inline int v4l2_ctrl_s_ctrl_string(struct v4l2_ctrl *ctrl, const char *s)
 	return rval;
 }
 
+static inline void v4l2_ctrl_s_max_reqs(struct v4l2_ctrl *ctrl, u16 max_reqs)
+{
+	ctrl->max_reqs = max_reqs;
+}
+
 /* 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);
-- 
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




[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux