[PATCH 1/4] drm/: Support registering driver-specific ioctls dynamically

Marius Vlad marius-cristian.vlad at nxp.com
Mon Sep 4 15:16:42 UTC 2017


From: Marius Vlad <marius.vlad0 at gmail.com>


Signed-off-by: Marius Vlad <marius.vlad0 at gmail.com>
Signed-off-by: Marius-Adrian Negreanu <groleo at gmail.com>
---
 drivers/gpu/drm/drm_drv.c   |  1 +
 drivers/gpu/drm/drm_ioctl.c | 99 +++++++++++++++++++++++++++++++++++++++++++--
 include/drm/drm_drv.h       | 34 ++++++++++++++++
 include/drm/drm_ioctl.h     |  6 +++
 4 files changed, 136 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index be38ac7..7727662 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -513,6 +513,7 @@ int drm_dev_init(struct drm_device *dev,
 	INIT_LIST_HEAD(&dev->vmalist);
 	INIT_LIST_HEAD(&dev->maplist);
 	INIT_LIST_HEAD(&dev->vblank_event_list);
+	INIT_LIST_HEAD(&dev->driver->registered_ioctls);
 
 	spin_lock_init(&dev->buf_lock);
 	spin_lock_init(&dev->event_lock);
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
index a9ae6dd..03868d8 100644
--- a/drivers/gpu/drm/drm_ioctl.c
+++ b/drivers/gpu/drm/drm_ioctl.c
@@ -777,10 +777,18 @@ long drm_ioctl(struct file *filp,
 	is_driver_ioctl = nr >= DRM_COMMAND_BASE && nr < DRM_COMMAND_END;
 
 	if (is_driver_ioctl) {
-		/* driver ioctl */
-		if (nr - DRM_COMMAND_BASE >= dev->driver->num_ioctls)
-			goto err_i1;
-		ioctl = &dev->driver->ioctls[nr - DRM_COMMAND_BASE];
+		/* check first if the driver has registered dynamically ioctls */
+		if (dev->driver->ioctl_register && dev->driver->ioctl_deregister) {
+			struct drm_ioctl_desc *pos = drm_ioctl_get_ioctl(dev, nr);
+			if (!pos)
+				goto err_i1;
+			ioctl = pos;
+		} else {
+			/* driver ioctl */
+			if (nr - DRM_COMMAND_BASE >= dev->driver->num_ioctls)
+				goto err_i1;
+			ioctl = &dev->driver->ioctls[nr - DRM_COMMAND_BASE];
+		}
 	} else {
 		/* core ioctl */
 		if (nr >= DRM_CORE_IOCTL_COUNT)
@@ -871,3 +879,86 @@ bool drm_ioctl_flags(unsigned int nr, unsigned int *flags)
 	return true;
 }
 EXPORT_SYMBOL(drm_ioctl_flags);
+
+/**
+ * drm_ioctl_register - registers a driver-specific ioctl
+ * @drm: the drm device
+ * @ioctl: the ioctl to register
+ *
+ * This method can be used to dynamically register a driver-specific
+ * ioctl, without the need to have an array of drm_ioctl_desc declared
+ * in DRM core driver.
+ */
+void drm_ioctl_register(struct drm_device *drm, struct drm_ioctl_desc *ioctl)
+{
+	mutex_lock(&drm_global_mutex);
+	list_add_tail(&ioctl->next, &drm->driver->registered_ioctls);
+	mutex_unlock(&drm_global_mutex);
+}
+EXPORT_SYMBOL_GPL(drm_ioctl_register);
+
+/**
+ * drm_ioctl_deregister - removes the ioctl previously registered
+ * @drm: the drm device
+ * @ioctl: the ioctl to be removed
+ *
+ * Use this method to remove previously registered ioctls.
+ */
+void drm_ioctl_deregister(struct drm_device *drm, struct drm_ioctl_desc *ioctl)
+{
+	struct drm_ioctl_desc *pos, *ppos;
+	struct list_head *head = &drm->driver->registered_ioctls;
+
+	mutex_lock(&drm_global_mutex);
+	list_for_each_entry_safe(pos, ppos, head, next) {
+		if (DRM_IOCTL_NR(pos->cmd) == DRM_IOCTL_NR(ioctl->cmd)) {
+			list_del(&pos->next);
+			break;
+		}
+	}
+	mutex_unlock(&drm_global_mutex);
+}
+EXPORT_SYMBOL_GPL(drm_ioctl_deregister);
+
+/**
+ * drm_ioctl_get_ioctl - retrieve a ioctl based on its IOCTL nr
+ * @drm: the drm device
+ * @nr: ioctl number
+ *
+ * Returns: a pointer to struct drm_ioctl_desc or NULL otherwise
+ */
+struct drm_ioctl_desc *drm_ioctl_get_ioctl(struct drm_device *drm, unsigned int nr)
+{
+	struct drm_ioctl_desc *pos, *found;
+	struct list_head *head = &drm->driver->registered_ioctls;
+
+	found = NULL;
+
+	mutex_lock(&drm_global_mutex);
+	list_for_each_entry(pos, head, next) {
+		if (DRM_IOCTL_NR(pos->cmd) == nr) {
+			found = pos;
+			break;
+		}
+	}
+	mutex_unlock(&drm_global_mutex);
+	return found;
+}
+
+/**
+ * drm_ioctl_get_registered - retrieve the number of ioctls registered so far
+ * @drm: the drm device
+ */
+size_t drm_ioctl_get_registered(struct drm_device *drm)
+{
+	size_t cnt = 0;
+	struct list_head *pos;
+
+	mutex_lock(&drm_global_mutex);
+	list_for_each(pos, &drm->driver->registered_ioctls)
+		cnt++;
+	mutex_unlock(&drm_global_mutex);
+
+	return cnt;
+}
+EXPORT_SYMBOL_GPL(drm_ioctl_get_registered);
diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h
index 71bbaae..9e43152 100644
--- a/include/drm/drm_drv.h
+++ b/include/drm/drm_drv.h
@@ -31,6 +31,7 @@
 #include <linux/irqreturn.h>
 
 #include <drm/drm_device.h>
+#include <drm/drm_ioctl.h>
 
 struct drm_file;
 struct drm_gem_object;
@@ -537,6 +538,28 @@ struct drm_driver {
 			    struct drm_device *dev,
 			    uint32_t handle);
 
+
+	/**
+	 * @ioctl_register:
+	 *
+	 * Registers an ioctl.
+	 */
+	void (*ioctl_register)(struct drm_device *drm, struct drm_ioctl_desc *ioctl);
+
+	/**
+	 * @ioctl_deregister:
+	 *
+	 * Removes a previously registered ioctl.
+	 */
+	void (*ioctl_deregister)(struct drm_device *drm, struct drm_ioctl_desc *ioctl);
+
+	/**
+	 * @ioctl_get_registered:
+	 *
+	 * Return the number of ioctls currently registered.
+	 */
+	size_t (*ioctl_get_registered)(struct drm_device *drm);
+
 	/**
 	 * @gem_vm_ops: Driver private ops for this object
 	 */
@@ -571,6 +594,17 @@ struct drm_driver {
 	int num_ioctls;
 
 	/**
+	 * @registered_ioctls:
+	 *
+	 * A list holding dynamically registered ioctls, as an alternative way of
+	 * having a static array of drm_ioctl_desc.
+	 *
+	 * Drivers must initialize ioctl_register and ioctl_deregister (or use
+	 * the already provided drm_ioctl_register/drm_ioctl_deregister).
+	 */
+	struct list_head registered_ioctls;
+
+	/**
 	 * @fops:
 	 *
 	 * File operations for the DRM device node. See the discussion in
diff --git a/include/drm/drm_ioctl.h b/include/drm/drm_ioctl.h
index add4280..ae96e39 100644
--- a/include/drm/drm_ioctl.h
+++ b/include/drm/drm_ioctl.h
@@ -150,6 +150,7 @@ struct drm_ioctl_desc {
 	enum drm_ioctl_flags flags;
 	drm_ioctl_t *func;
 	const char *name;
+	struct list_head next;
 };
 
 /**
@@ -181,6 +182,11 @@ long drm_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
 #endif
 bool drm_ioctl_flags(unsigned int nr, unsigned int *flags);
 
+void drm_ioctl_register(struct drm_device *drm, struct drm_ioctl_desc *ioctl);
+void drm_ioctl_deregister(struct drm_device *drm, struct drm_ioctl_desc *ioctl);
+struct drm_ioctl_desc *drm_ioctl_get_ioctl(struct drm_device *drm, unsigned int nr);
+size_t drm_ioctl_get_registered(struct drm_device *drm);
+
 int drm_noop(struct drm_device *dev, void *data,
 	     struct drm_file *file_priv);
 int drm_invalid_op(struct drm_device *dev, void *data,
-- 
2.9.3



More information about the dri-devel mailing list