[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