[PATCH] v4l2-ctrls: add v4l2_ctrl_del_handler()

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

 



If a sub-device is unbound, then it should also remove its controls from
other control handlers that it was added to using v4l2_ctrl_add_handler().

So create a v4l2_ctrl_del_handler() function that removes the controls that
were earlier added with v4l2_ctrl_add_handler().

Signed-off-by: Hans Verkuil <hansverk@xxxxxxxxx>
---
I'm not sure if this should be merged. It is necessary to safely unbind
subdevs, but since we don't do that yet anyway it is debatable if this
should be merged without anyone using it. But at least it will be archived
in patchwork so it isn't lost.

This function is used in our out-of-tree driver when we unconfigure an
FPGA where we do exactly this type of unbinding.

Regards,

	Hans
---
 drivers/media/v4l2-core/v4l2-ctrls.c | 39 ++++++++++++++++++++++++++++
 include/media/v4l2-ctrls.h           | 12 +++++++++
 2 files changed, 51 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 599c1cbff3b9..b40cea8ec436 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -2421,6 +2421,45 @@ int v4l2_ctrl_add_handler(struct v4l2_ctrl_handler *hdl,
 }
 EXPORT_SYMBOL(v4l2_ctrl_add_handler);

+void v4l2_ctrl_del_handler(struct v4l2_ctrl_handler *hdl,
+			  struct v4l2_ctrl_handler *del)
+{
+	struct v4l2_ctrl_ref *ref, *ref_safe;
+
+	/* Do nothing if either handler is NULL or if they are the same */
+	if (!hdl || !del || hdl == del)
+		return;
+
+	mutex_lock(hdl->lock);
+	list_for_each_entry_safe(ref, ref_safe, &hdl->ctrl_refs, node) {
+		struct v4l2_ctrl *ctrl = ref->ctrl;
+		struct v4l2_ctrl_ref *bucket_ref;
+		int bucket;
+
+		if (ctrl->handler != del)
+			continue;
+
+		bucket = ctrl->id % hdl->nr_of_buckets;	/* which bucket to use */
+		bucket_ref = hdl->buckets[bucket];
+
+		list_del(&ref->node);
+		if (bucket_ref == ref)
+			hdl->buckets[bucket] = ref->next;
+		else {
+			while (bucket_ref->next && bucket_ref->next != ref)
+				bucket_ref = bucket_ref->next;
+			if (bucket_ref)
+				bucket_ref->next = ref->next;
+			else
+				pr_err("could not find ctrl '%s'\n", ctrl->name);
+		}
+		kfree(ref);
+	}
+	hdl->cached = NULL;
+	mutex_unlock(hdl->lock);
+}
+EXPORT_SYMBOL(v4l2_ctrl_del_handler);
+
 bool v4l2_ctrl_radio_filter(const struct v4l2_ctrl *ctrl)
 {
 	if (V4L2_CTRL_ID2WHICH(ctrl->id) == V4L2_CTRL_CLASS_FM_TX)
diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
index f615ba1b29dd..c32d3500db54 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -644,6 +644,18 @@ int v4l2_ctrl_add_handler(struct v4l2_ctrl_handler *hdl,
 			  struct v4l2_ctrl_handler *add,
 			  v4l2_ctrl_filter filter);

+/**
+ * v4l2_ctrl_del_handler() - Remove all controls in handler @del from
+ * handler @hdl.
+ * @hdl:	The control handler.
+ * @del:	The control handler whose controls you want to delete from
+ *		the @hdl control handler.
+ *
+ * Does nothing if either of the two handlers is a NULL pointer.
+ */
+void v4l2_ctrl_del_handler(struct v4l2_ctrl_handler *hdl,
+			   struct v4l2_ctrl_handler *del);
+
 /**
  * v4l2_ctrl_radio_filter() - Standard filter for radio controls.
  *
-- 
2.18.0




[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