From: Marius Vlad <marius.vlad0@xxxxxxxxx> Signed-off-by: Marius Vlad <marius.vlad0@xxxxxxxxx> Signed-off-by: Marius-Adrian Negreanu <groleo@xxxxxxxxx> --- 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@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx