From: Marius Vlad <marius.vl...@gmail.com>

Signed-off-by: Marius Vlad <marius.vl...@gmail.com>
Signed-off-by: Marius-Adrian Negreanu <gro...@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

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to