diff options
-rw-r--r-- | libdrm/xf86drm.c | 12 | ||||
-rw-r--r-- | linux-core/drmP.h | 14 | ||||
-rw-r--r-- | linux-core/drm_drv.c | 243 | ||||
-rw-r--r-- | linux-core/i810_drv.c | 3 | ||||
-rw-r--r-- | linux-core/mga_drv.c | 3 | ||||
-rw-r--r-- | linux-core/r128_drv.c | 3 | ||||
-rw-r--r-- | linux-core/radeon_drv.c | 3 | ||||
-rw-r--r-- | linux-core/sis_drv.c | 4 | ||||
-rw-r--r-- | linux-core/tdfx_drv.c | 3 | ||||
-rw-r--r-- | linux/drm.h | 1 | ||||
-rw-r--r-- | linux/drmP.h | 14 | ||||
-rw-r--r-- | linux/drm_drv.h | 243 | ||||
-rw-r--r-- | linux/gamma_drv.c | 3 | ||||
-rw-r--r-- | linux/i810_drv.c | 3 | ||||
-rw-r--r-- | linux/mga_drv.c | 3 | ||||
-rw-r--r-- | linux/r128_drv.c | 3 | ||||
-rw-r--r-- | linux/radeon_drv.c | 3 | ||||
-rw-r--r-- | linux/sis_drv.c | 4 | ||||
-rw-r--r-- | linux/tdfx_drv.c | 3 | ||||
-rw-r--r-- | shared-core/drm.h | 1 | ||||
-rw-r--r-- | shared/drm.h | 1 |
21 files changed, 294 insertions, 276 deletions
diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index a04cf7ae..17026b76 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -433,6 +433,18 @@ drmVersionPtr drmGetVersion(int fd) return retval; } +int drmSetVersion(int fd, int major, int minor, int patch) +{ + drm_version_t version; + + memset(&version, 0, sizeof(version)); + version.version_major = major; + version.version_minor = minor; + version.version_patchlevel = patch; + if (ioctl(fd, DRM_IOCTL_SET_VERSION, &version)) return -errno; + return 0; +} + void drmFreeBusid(const char *busid) { drmFree((void *)busid); diff --git a/linux-core/drmP.h b/linux-core/drmP.h index a6d36a64..1ba62e2d 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -725,8 +725,20 @@ typedef struct drm_device { void *dev_private; drm_sigdata_t sigdata; /* For block_all_signals */ sigset_t sigmask; + + /* Support for version setting */ + int major_version; + int minor_version; + int patch_version; + struct file_operations *file_ops; } drm_device_t; +typedef struct drm_version_table { + int major_version; + int minor_version; + int patch_version; + struct file_operations *file_ops; +} drm_version_table_t; /* ================================================================ * Internal function definitions @@ -740,6 +752,8 @@ extern int DRM(cpu_valid)( void ); /* Driver support (drm_drv.h) */ extern int DRM(version)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); +extern int DRM(set_version)(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); extern int DRM(open)(struct inode *inode, struct file *filp); extern int DRM(release)(struct inode *inode, struct file *filp); extern int DRM(ioctl)(struct inode *inode, struct file *filp, diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 43186632..7a00b75d 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -43,7 +43,6 @@ * #define DRIVER_MINOR 0 * #define DRIVER_PATCHLEVEL 2 * - * #define DRIVER_IOCTL_COUNT DRM_ARRAY_SIZE( mga_ioctls ) * * #define DRM(x) mga_##x */ @@ -109,9 +108,20 @@ #ifndef DRIVER_POSTSETUP #define DRIVER_POSTSETUP() #endif -#ifndef DRIVER_IOCTLS -#define DRIVER_IOCTLS + +/* + * The default number of instances (minor numbers) to initialize. + */ +#ifndef DRIVER_NUM_CARDS +#define DRIVER_NUM_CARDS 1 #endif + +/* + * defining file operations is the responsibility of the driver writer + * if there are multiple versions. + */ + +#ifndef DRIVER_VERSION_TABLE #ifndef DRIVER_FOPS #define DRIVER_FOPS \ static struct file_operations DRM(fops) = { \ @@ -127,91 +137,20 @@ static struct file_operations DRM(fops) = { \ } #endif - -/* - * The default number of instances (minor numbers) to initialize. - */ -#ifndef DRIVER_NUM_CARDS -#define DRIVER_NUM_CARDS 1 -#endif - -static drm_device_t *DRM(device); -static int *DRM(minor); -static int DRM(numdevs) = 0; - DRIVER_FOPS; -static drm_ioctl_desc_t DRM(ioctls)[] = { - [DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = { DRM(version), 0, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)] = { DRM(getunique), 0, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)] = { DRM(getmagic), 0, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)] = { DRM(irq_busid), 0, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_GET_MAP)] = { DRM(getmap), 0, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_GET_CLIENT)] = { DRM(getclient), 0, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_GET_STATS)] = { DRM(getstats), 0, 0 }, - - [DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)] = { DRM(setunique), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_BLOCK)] = { DRM(block), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)] = { DRM(unblock), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)] = { DRM(authmagic), 1, 1 }, - - [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)] = { DRM(addmap), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_RM_MAP)] = { DRM(rmmap), 1, 0 }, - -#if __HAVE_CTX_BITMAP - [DRM_IOCTL_NR(DRM_IOCTL_SET_SAREA_CTX)] = { DRM(setsareactx), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_GET_SAREA_CTX)] = { DRM(getsareactx), 1, 0 }, -#endif - - [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = { DRM(addctx), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = { DRM(rmctx), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = { DRM(modctx), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = { DRM(getctx), 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { DRM(switchctx), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = { DRM(newctx), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = { DRM(resctx), 1, 0 }, - - [DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)] = { DRM(adddraw), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)] = { DRM(rmdraw), 1, 1 }, - - [DRM_IOCTL_NR(DRM_IOCTL_LOCK)] = { DRM(lock), 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)] = { DRM(unlock), 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = { DRM(finish), 1, 0 }, - -#if __HAVE_DMA - [DRM_IOCTL_NR(DRM_IOCTL_ADD_BUFS)] = { DRM(addbufs), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)] = { DRM(markbufs), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)] = { DRM(infobufs), 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)] = { DRM(mapbufs), 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)] = { DRM(freebufs), 1, 0 }, - - /* The DRM_IOCTL_DMA ioctl should be defined by the driver. - */ -#if __HAVE_DMA_IRQ - [DRM_IOCTL_NR(DRM_IOCTL_CONTROL)] = { DRM(control), 1, 1 }, -#endif -#endif - -#if __REALLY_HAVE_AGP - [DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)] = { DRM(agp_acquire), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)] = { DRM(agp_release), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)] = { DRM(agp_enable), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO)] = { DRM(agp_info), 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC)] = { DRM(agp_alloc), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)] = { DRM(agp_free), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)] = { DRM(agp_bind), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = { DRM(agp_unbind), 1, 1 }, -#endif - -#if __HAVE_SG - [DRM_IOCTL_NR(DRM_IOCTL_SG_ALLOC)] = { DRM(sg_alloc), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_SG_FREE)] = { DRM(sg_free), 1, 1 }, -#endif - - DRIVER_IOCTLS -}; +#define DRIVER_VERSION_TABLE \ +static drm_version_table_t DRM(version_table)[] = \ +{ \ + { DRIVER_MAJOR, DRIVER_MINOR, DRIVER_PATCHLEVEL, &DRM(fops) }, \ + { 0, 0, 0, NULL } \ +} +#endif /* DRIVER_VERSION_TABLE */ -#define DRIVER_IOCTL_COUNT DRM_ARRAY_SIZE( DRM(ioctls) ) +static drm_device_t *DRM(device); +static int *DRM(minor); +static int DRM(numdevs) = 0; +DRIVER_VERSION_TABLE; #ifdef MODULE static char *drm_opts = NULL; @@ -480,6 +419,16 @@ static int DRM(takedown)( drm_device_t *dev ) dev->lock.pid = 0; wake_up_interruptible( &dev->lock.lock_queue ); } + + /* Always default to the first file operations on recycle. */ + memcpy(dev->file_ops, + DRM(version_table)[0].file_ops, + sizeof(*dev->file_ops)); + + dev->major_version = DRM(version_table)[0].major_version; + dev->minor_version = DRM(version_table)[0].minor_version; + dev->patch_version = DRM(version_table)[0].patch_version; + up( &dev->struct_sem ); return 0; @@ -559,11 +508,27 @@ static int __init drm_init( void ) for (i = 0; i < DRM(numdevs); i++) { dev = &(DRM(device)[i]); memset( (void *)dev, 0, sizeof(*dev) ); + dev->file_ops = kmalloc(sizeof(*dev->file_ops), GFP_KERNEL); + if (!dev->file_ops) return -ENOMEM; + + /* Always default to the first file operations */ + memcpy(dev->file_ops, + DRM(version_table)[0].file_ops, + sizeof(*dev->file_ops)); + + dev->major_version = DRM(version_table)[0].major_version; + dev->minor_version = DRM(version_table)[0].minor_version; + dev->patch_version = DRM(version_table)[0].patch_version; + dev->count_lock = SPIN_LOCK_UNLOCKED; sema_init( &dev->struct_sem, 1 ); - if ((DRM(minor)[i] = DRM(stub_register)(DRIVER_NAME, &DRM(fops),dev)) < 0) + if ((DRM(minor)[i] = DRM(stub_register)(DRIVER_NAME, + dev->file_ops, + dev)) < 0) { + DRM(takedown)( dev ); return -EPERM; + } dev->device = MKDEV(DRM_MAJOR, DRM(minor)[i] ); dev->name = DRIVER_NAME; @@ -651,6 +616,7 @@ static void __exit drm_cleanup( void ) dev->agp = NULL; } #endif + if(dev->file_ops) kfree(dev->file_ops); } DRIVER_POSTCLEANUP(); kfree(DRM(minor)); @@ -662,9 +628,20 @@ module_init( drm_init ); module_exit( drm_cleanup ); +#define DRM_COPY( name, value ) \ + len = strlen( value ); \ + if ( len > name##_len ) len = name##_len; \ + name##_len = strlen( value ); \ + if ( len && name ) { \ + if ( copy_to_user( name, value, len ) ) \ + return -EFAULT; \ + } + int DRM(version)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ) { + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; drm_version_t version; int len; @@ -673,18 +650,11 @@ int DRM(version)( struct inode *inode, struct file *filp, sizeof(version) ) ) return -EFAULT; -#define DRM_COPY( name, value ) \ - len = strlen( value ); \ - if ( len > name##_len ) len = name##_len; \ - name##_len = strlen( value ); \ - if ( len && name ) { \ - if ( copy_to_user( name, value, len ) ) \ - return -EFAULT; \ - } - - version.version_major = DRIVER_MAJOR; - version.version_minor = DRIVER_MINOR; - version.version_patchlevel = DRIVER_PATCHLEVEL; + down( &dev->struct_sem ); + version.version_major = dev->major_version; + version.version_minor = dev->minor_version; + version.version_patchlevel = dev->patch_version; + up( &dev->struct_sem ); DRM_COPY( version.name, DRIVER_NAME ); DRM_COPY( version.date, DRIVER_DATE ); @@ -697,6 +667,43 @@ int DRM(version)( struct inode *inode, struct file *filp, return 0; } +int DRM(set_version)( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_version_t version; + drm_version_table_t *table; + struct file_operations *file_ops = NULL; + int i; + + if ( copy_from_user( &version, + (drm_version_t *)arg, + sizeof(version) ) ) + return -EFAULT; + + i = 0; + do { + table = &DRM(version_table)[i]; + if (table->major_version == version.version_major && + table->minor_version >= version.version_minor) { + file_ops = table->file_ops; + break; + } + i++; + } while (table->file_ops != NULL); + if (!file_ops) return -EINVAL; + + down( &dev->struct_sem ); + dev->major_version = table->major_version; + dev->minor_version = table->minor_version; + dev->patch_version = table->patch_version; + memcpy(dev->file_ops, file_ops, sizeof(*file_ops)); + up( &dev->struct_sem ); + + return 0; +} + int DRM(open)( struct inode *inode, struct file *filp ) { drm_device_t *dev = NULL; @@ -856,46 +863,6 @@ int DRM(release)( struct inode *inode, struct file *filp ) return retcode; } -/* DRM(ioctl) is called whenever a process performs an ioctl on /dev/drm. - */ -int DRM(ioctl)( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) -{ - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - drm_ioctl_desc_t *ioctl; - drm_ioctl_t *func; - int nr = DRM_IOCTL_NR(cmd); - int retcode = 0; - - atomic_inc( &dev->ioctl_count ); - atomic_inc( &dev->counts[_DRM_STAT_IOCTLS] ); - ++priv->ioctl_count; - - DRM_DEBUG( "pid=%d, cmd=0x%02x, nr=0x%02x, dev 0x%x, auth=%d\n", - current->pid, cmd, nr, dev->device, priv->authenticated ); - - if ( nr >= DRIVER_IOCTL_COUNT ) { - retcode = -EINVAL; - } else { - ioctl = &DRM(ioctls)[nr]; - func = ioctl->func; - - if ( !func ) { - DRM_DEBUG( "no function\n" ); - retcode = -EINVAL; - } else if ( ( ioctl->root_only && !capable( CAP_SYS_ADMIN ) )|| - ( ioctl->auth_needed && !priv->authenticated ) ) { - retcode = -EACCES; - } else { - retcode = func( inode, filp, cmd, arg ); - } - } - - atomic_dec( &dev->ioctl_count ); - return retcode; -} - int DRM(lock)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ) { diff --git a/linux-core/i810_drv.c b/linux-core/i810_drv.c index e6ed2769..b407ef5e 100644 --- a/linux-core/i810_drv.c +++ b/linux-core/i810_drv.c @@ -55,6 +55,8 @@ [DRM_IOCTL_NR(DRM_IOCTL_I810_SWAP)] = { i810_swap_bufs, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_I810_DOCOPY)] = { i810_docopy, 1, 0 }, +#define IOCTL_TABLE_NAME DRM(ioctls) +#define IOCTL_FUNC_NAME DRM(ioctl) #define __HAVE_COUNTERS 4 #define __HAVE_COUNTER6 _DRM_STAT_IRQ @@ -69,6 +71,7 @@ #include "drm_context.h" #include "drm_dma.h" #include "drm_drawable.h" +#include "drm_ioctl_table.h" #include "drm_drv.h" #ifndef MODULE diff --git a/linux-core/mga_drv.c b/linux-core/mga_drv.c index 4200f9ef..5fcb950d 100644 --- a/linux-core/mga_drv.c +++ b/linux-core/mga_drv.c @@ -56,6 +56,8 @@ [DRM_IOCTL_NR(DRM_IOCTL_MGA_ILOAD)] = { mga_dma_iload, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_MGA_BLIT)] = { mga_dma_blit, 1, 0 }, +#define IOCTL_TABLE_NAME DRM(ioctls) +#define IOCTL_FUNC_NAME DRM(ioctl) #define __HAVE_COUNTERS 3 #define __HAVE_COUNTER6 _DRM_STAT_IRQ @@ -69,6 +71,7 @@ #include "drm_context.h" #include "drm_dma.h" #include "drm_drawable.h" +#include "drm_ioctl_table.h" #include "drm_drv.h" #ifndef MODULE diff --git a/linux-core/r128_drv.c b/linux-core/r128_drv.c index 53217870..270c2c08 100644 --- a/linux-core/r128_drv.c +++ b/linux-core/r128_drv.c @@ -63,6 +63,8 @@ [DRM_IOCTL_NR(DRM_IOCTL_R128_STIPPLE)] = { r128_cce_stipple, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_R128_INDIRECT)] = { r128_cce_indirect, 1, 1 }, +#define IOCTL_TABLE_NAME DRM(ioctls) +#define IOCTL_FUNC_NAME DRM(ioctl) #if 0 /* GH: Count data sent to card via ring or vertex/indirect buffers. @@ -80,6 +82,7 @@ #include "drm_context.h" #include "drm_dma.h" #include "drm_drawable.h" +#include "drm_ioctl_table.h" #include "drm_drv.h" #ifndef MODULE diff --git a/linux-core/radeon_drv.c b/linux-core/radeon_drv.c index d4faa4d3..f54fc67c 100644 --- a/linux-core/radeon_drv.c +++ b/linux-core/radeon_drv.c @@ -59,6 +59,8 @@ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_STIPPLE)] = { radeon_cp_stipple, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_INDIRECT)] = { radeon_cp_indirect, 1, 1 }, +#define IOCTL_TABLE_NAME DRM(ioctls) +#define IOCTL_FUNC_NAME DRM(ioctl) #if 0 /* GH: Count data sent to card via ring or vertex/indirect buffers. @@ -76,6 +78,7 @@ #include "drm_context.h" #include "drm_dma.h" #include "drm_drawable.h" +#include "drm_ioctl_table.h" #include "drm_drv.h" #ifndef MODULE diff --git a/linux-core/sis_drv.c b/linux-core/sis_drv.c index 50bac103..6ea9d871 100644 --- a/linux-core/sis_drv.c +++ b/linux-core/sis_drv.c @@ -54,6 +54,9 @@ [DRM_IOCTL_NR(SIS_IOCTL_FLIP_FINAL)] = { sis_flip_final, 1, 1 } #endif +#define IOCTL_TABLE_NAME DRM(ioctls) +#define IOCTL_FUNC_NAME DRM(ioctl) + #define __HAVE_COUNTERS 5 #include "drm_auth.h" @@ -62,6 +65,7 @@ #include "drm_context.h" #include "drm_dma.h" #include "drm_drawable.h" +#include "drm_ioctl_table.h" #include "drm_drv.h" #include "drm_fops.h" #include "drm_init.h" diff --git a/linux-core/tdfx_drv.c b/linux-core/tdfx_drv.c index 91499077..aeb66366 100644 --- a/linux-core/tdfx_drv.c +++ b/linux-core/tdfx_drv.c @@ -74,12 +74,15 @@ static drm_pci_list_t DRM(idlist)[] = { #define DRIVER_CARD_LIST DRM(idlist) +#define IOCTL_TABLE_NAME DRM(ioctls) +#define IOCTL_FUNC_NAME DRM(ioctl) #include "drm_auth.h" #include "drm_bufs.h" #include "drm_context.h" #include "drm_dma.h" #include "drm_drawable.h" +#include "drm_ioctl_table.h" #include "drm_drv.h" #ifndef MODULE diff --git a/linux/drm.h b/linux/drm.h index 42cbb14c..3ad96e8c 100644 --- a/linux/drm.h +++ b/linux/drm.h @@ -385,6 +385,7 @@ typedef struct drm_scatter_gather { #define DRM_IOCTL_GET_MAP DRM_IOWR(0x04, drm_map_t) #define DRM_IOCTL_GET_CLIENT DRM_IOWR(0x05, drm_client_t) #define DRM_IOCTL_GET_STATS DRM_IOR( 0x06, drm_stats_t) +#define DRM_IOCTL_SET_VERSION DRM_IOW( 0x07, drm_version_t) #define DRM_IOCTL_SET_UNIQUE DRM_IOW( 0x10, drm_unique_t) #define DRM_IOCTL_AUTH_MAGIC DRM_IOW( 0x11, drm_auth_t) diff --git a/linux/drmP.h b/linux/drmP.h index a6d36a64..1ba62e2d 100644 --- a/linux/drmP.h +++ b/linux/drmP.h @@ -725,8 +725,20 @@ typedef struct drm_device { void *dev_private; drm_sigdata_t sigdata; /* For block_all_signals */ sigset_t sigmask; + + /* Support for version setting */ + int major_version; + int minor_version; + int patch_version; + struct file_operations *file_ops; } drm_device_t; +typedef struct drm_version_table { + int major_version; + int minor_version; + int patch_version; + struct file_operations *file_ops; +} drm_version_table_t; /* ================================================================ * Internal function definitions @@ -740,6 +752,8 @@ extern int DRM(cpu_valid)( void ); /* Driver support (drm_drv.h) */ extern int DRM(version)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); +extern int DRM(set_version)(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); extern int DRM(open)(struct inode *inode, struct file *filp); extern int DRM(release)(struct inode *inode, struct file *filp); extern int DRM(ioctl)(struct inode *inode, struct file *filp, diff --git a/linux/drm_drv.h b/linux/drm_drv.h index 43186632..7a00b75d 100644 --- a/linux/drm_drv.h +++ b/linux/drm_drv.h @@ -43,7 +43,6 @@ * #define DRIVER_MINOR 0 * #define DRIVER_PATCHLEVEL 2 * - * #define DRIVER_IOCTL_COUNT DRM_ARRAY_SIZE( mga_ioctls ) * * #define DRM(x) mga_##x */ @@ -109,9 +108,20 @@ #ifndef DRIVER_POSTSETUP #define DRIVER_POSTSETUP() #endif -#ifndef DRIVER_IOCTLS -#define DRIVER_IOCTLS + +/* + * The default number of instances (minor numbers) to initialize. + */ +#ifndef DRIVER_NUM_CARDS +#define DRIVER_NUM_CARDS 1 #endif + +/* + * defining file operations is the responsibility of the driver writer + * if there are multiple versions. + */ + +#ifndef DRIVER_VERSION_TABLE #ifndef DRIVER_FOPS #define DRIVER_FOPS \ static struct file_operations DRM(fops) = { \ @@ -127,91 +137,20 @@ static struct file_operations DRM(fops) = { \ } #endif - -/* - * The default number of instances (minor numbers) to initialize. - */ -#ifndef DRIVER_NUM_CARDS -#define DRIVER_NUM_CARDS 1 -#endif - -static drm_device_t *DRM(device); -static int *DRM(minor); -static int DRM(numdevs) = 0; - DRIVER_FOPS; -static drm_ioctl_desc_t DRM(ioctls)[] = { - [DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = { DRM(version), 0, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)] = { DRM(getunique), 0, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)] = { DRM(getmagic), 0, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)] = { DRM(irq_busid), 0, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_GET_MAP)] = { DRM(getmap), 0, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_GET_CLIENT)] = { DRM(getclient), 0, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_GET_STATS)] = { DRM(getstats), 0, 0 }, - - [DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)] = { DRM(setunique), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_BLOCK)] = { DRM(block), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)] = { DRM(unblock), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)] = { DRM(authmagic), 1, 1 }, - - [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)] = { DRM(addmap), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_RM_MAP)] = { DRM(rmmap), 1, 0 }, - -#if __HAVE_CTX_BITMAP - [DRM_IOCTL_NR(DRM_IOCTL_SET_SAREA_CTX)] = { DRM(setsareactx), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_GET_SAREA_CTX)] = { DRM(getsareactx), 1, 0 }, -#endif - - [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = { DRM(addctx), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = { DRM(rmctx), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = { DRM(modctx), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = { DRM(getctx), 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { DRM(switchctx), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = { DRM(newctx), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = { DRM(resctx), 1, 0 }, - - [DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)] = { DRM(adddraw), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)] = { DRM(rmdraw), 1, 1 }, - - [DRM_IOCTL_NR(DRM_IOCTL_LOCK)] = { DRM(lock), 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)] = { DRM(unlock), 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = { DRM(finish), 1, 0 }, - -#if __HAVE_DMA - [DRM_IOCTL_NR(DRM_IOCTL_ADD_BUFS)] = { DRM(addbufs), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)] = { DRM(markbufs), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)] = { DRM(infobufs), 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)] = { DRM(mapbufs), 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)] = { DRM(freebufs), 1, 0 }, - - /* The DRM_IOCTL_DMA ioctl should be defined by the driver. - */ -#if __HAVE_DMA_IRQ - [DRM_IOCTL_NR(DRM_IOCTL_CONTROL)] = { DRM(control), 1, 1 }, -#endif -#endif - -#if __REALLY_HAVE_AGP - [DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)] = { DRM(agp_acquire), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)] = { DRM(agp_release), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)] = { DRM(agp_enable), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO)] = { DRM(agp_info), 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC)] = { DRM(agp_alloc), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)] = { DRM(agp_free), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)] = { DRM(agp_bind), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = { DRM(agp_unbind), 1, 1 }, -#endif - -#if __HAVE_SG - [DRM_IOCTL_NR(DRM_IOCTL_SG_ALLOC)] = { DRM(sg_alloc), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_SG_FREE)] = { DRM(sg_free), 1, 1 }, -#endif - - DRIVER_IOCTLS -}; +#define DRIVER_VERSION_TABLE \ +static drm_version_table_t DRM(version_table)[] = \ +{ \ + { DRIVER_MAJOR, DRIVER_MINOR, DRIVER_PATCHLEVEL, &DRM(fops) }, \ + { 0, 0, 0, NULL } \ +} +#endif /* DRIVER_VERSION_TABLE */ -#define DRIVER_IOCTL_COUNT DRM_ARRAY_SIZE( DRM(ioctls) ) +static drm_device_t *DRM(device); +static int *DRM(minor); +static int DRM(numdevs) = 0; +DRIVER_VERSION_TABLE; #ifdef MODULE static char *drm_opts = NULL; @@ -480,6 +419,16 @@ static int DRM(takedown)( drm_device_t *dev ) dev->lock.pid = 0; wake_up_interruptible( &dev->lock.lock_queue ); } + + /* Always default to the first file operations on recycle. */ + memcpy(dev->file_ops, + DRM(version_table)[0].file_ops, + sizeof(*dev->file_ops)); + + dev->major_version = DRM(version_table)[0].major_version; + dev->minor_version = DRM(version_table)[0].minor_version; + dev->patch_version = DRM(version_table)[0].patch_version; + up( &dev->struct_sem ); return 0; @@ -559,11 +508,27 @@ static int __init drm_init( void ) for (i = 0; i < DRM(numdevs); i++) { dev = &(DRM(device)[i]); memset( (void *)dev, 0, sizeof(*dev) ); + dev->file_ops = kmalloc(sizeof(*dev->file_ops), GFP_KERNEL); + if (!dev->file_ops) return -ENOMEM; + + /* Always default to the first file operations */ + memcpy(dev->file_ops, + DRM(version_table)[0].file_ops, + sizeof(*dev->file_ops)); + + dev->major_version = DRM(version_table)[0].major_version; + dev->minor_version = DRM(version_table)[0].minor_version; + dev->patch_version = DRM(version_table)[0].patch_version; + dev->count_lock = SPIN_LOCK_UNLOCKED; sema_init( &dev->struct_sem, 1 ); - if ((DRM(minor)[i] = DRM(stub_register)(DRIVER_NAME, &DRM(fops),dev)) < 0) + if ((DRM(minor)[i] = DRM(stub_register)(DRIVER_NAME, + dev->file_ops, + dev)) < 0) { + DRM(takedown)( dev ); return -EPERM; + } dev->device = MKDEV(DRM_MAJOR, DRM(minor)[i] ); dev->name = DRIVER_NAME; @@ -651,6 +616,7 @@ static void __exit drm_cleanup( void ) dev->agp = NULL; } #endif + if(dev->file_ops) kfree(dev->file_ops); } DRIVER_POSTCLEANUP(); kfree(DRM(minor)); @@ -662,9 +628,20 @@ module_init( drm_init ); module_exit( drm_cleanup ); +#define DRM_COPY( name, value ) \ + len = strlen( value ); \ + if ( len > name##_len ) len = name##_len; \ + name##_len = strlen( value ); \ + if ( len && name ) { \ + if ( copy_to_user( name, value, len ) ) \ + return -EFAULT; \ + } + int DRM(version)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ) { + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; drm_version_t version; int len; @@ -673,18 +650,11 @@ int DRM(version)( struct inode *inode, struct file *filp, sizeof(version) ) ) return -EFAULT; -#define DRM_COPY( name, value ) \ - len = strlen( value ); \ - if ( len > name##_len ) len = name##_len; \ - name##_len = strlen( value ); \ - if ( len && name ) { \ - if ( copy_to_user( name, value, len ) ) \ - return -EFAULT; \ - } - - version.version_major = DRIVER_MAJOR; - version.version_minor = DRIVER_MINOR; - version.version_patchlevel = DRIVER_PATCHLEVEL; + down( &dev->struct_sem ); + version.version_major = dev->major_version; + version.version_minor = dev->minor_version; + version.version_patchlevel = dev->patch_version; + up( &dev->struct_sem ); DRM_COPY( version.name, DRIVER_NAME ); DRM_COPY( version.date, DRIVER_DATE ); @@ -697,6 +667,43 @@ int DRM(version)( struct inode *inode, struct file *filp, return 0; } +int DRM(set_version)( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_version_t version; + drm_version_table_t *table; + struct file_operations *file_ops = NULL; + int i; + + if ( copy_from_user( &version, + (drm_version_t *)arg, + sizeof(version) ) ) + return -EFAULT; + + i = 0; + do { + table = &DRM(version_table)[i]; + if (table->major_version == version.version_major && + table->minor_version >= version.version_minor) { + file_ops = table->file_ops; + break; + } + i++; + } while (table->file_ops != NULL); + if (!file_ops) return -EINVAL; + + down( &dev->struct_sem ); + dev->major_version = table->major_version; + dev->minor_version = table->minor_version; + dev->patch_version = table->patch_version; + memcpy(dev->file_ops, file_ops, sizeof(*file_ops)); + up( &dev->struct_sem ); + + return 0; +} + int DRM(open)( struct inode *inode, struct file *filp ) { drm_device_t *dev = NULL; @@ -856,46 +863,6 @@ int DRM(release)( struct inode *inode, struct file *filp ) return retcode; } -/* DRM(ioctl) is called whenever a process performs an ioctl on /dev/drm. - */ -int DRM(ioctl)( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) -{ - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - drm_ioctl_desc_t *ioctl; - drm_ioctl_t *func; - int nr = DRM_IOCTL_NR(cmd); - int retcode = 0; - - atomic_inc( &dev->ioctl_count ); - atomic_inc( &dev->counts[_DRM_STAT_IOCTLS] ); - ++priv->ioctl_count; - - DRM_DEBUG( "pid=%d, cmd=0x%02x, nr=0x%02x, dev 0x%x, auth=%d\n", - current->pid, cmd, nr, dev->device, priv->authenticated ); - - if ( nr >= DRIVER_IOCTL_COUNT ) { - retcode = -EINVAL; - } else { - ioctl = &DRM(ioctls)[nr]; - func = ioctl->func; - - if ( !func ) { - DRM_DEBUG( "no function\n" ); - retcode = -EINVAL; - } else if ( ( ioctl->root_only && !capable( CAP_SYS_ADMIN ) )|| - ( ioctl->auth_needed && !priv->authenticated ) ) { - retcode = -EACCES; - } else { - retcode = func( inode, filp, cmd, arg ); - } - } - - atomic_dec( &dev->ioctl_count ); - return retcode; -} - int DRM(lock)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ) { diff --git a/linux/gamma_drv.c b/linux/gamma_drv.c index 8db10728..5519bb07 100644 --- a/linux/gamma_drv.c +++ b/linux/gamma_drv.c @@ -49,6 +49,8 @@ [DRM_IOCTL_NR(DRM_IOCTL_GAMMA_INIT)] = { gamma_dma_init, 1, 1 }, \ [DRM_IOCTL_NR(DRM_IOCTL_GAMMA_COPY)] = { gamma_dma_copy, 1, 1 } +#define IOCTL_TABLE_NAME DRM(ioctls) +#define IOCTL_FUNC_NAME DRM(ioctl) #define __HAVE_COUNTERS 5 #define __HAVE_COUNTER6 _DRM_STAT_IRQ @@ -64,6 +66,7 @@ #include "drm_context.h" #include "drm_dma.h" #include "drm_drawable.h" +#include "drm_ioctl_table.h" #include "drm_drv.h" #ifndef MODULE diff --git a/linux/i810_drv.c b/linux/i810_drv.c index e6ed2769..b407ef5e 100644 --- a/linux/i810_drv.c +++ b/linux/i810_drv.c @@ -55,6 +55,8 @@ [DRM_IOCTL_NR(DRM_IOCTL_I810_SWAP)] = { i810_swap_bufs, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_I810_DOCOPY)] = { i810_docopy, 1, 0 }, +#define IOCTL_TABLE_NAME DRM(ioctls) +#define IOCTL_FUNC_NAME DRM(ioctl) #define __HAVE_COUNTERS 4 #define __HAVE_COUNTER6 _DRM_STAT_IRQ @@ -69,6 +71,7 @@ #include "drm_context.h" #include "drm_dma.h" #include "drm_drawable.h" +#include "drm_ioctl_table.h" #include "drm_drv.h" #ifndef MODULE diff --git a/linux/mga_drv.c b/linux/mga_drv.c index 4200f9ef..5fcb950d 100644 --- a/linux/mga_drv.c +++ b/linux/mga_drv.c @@ -56,6 +56,8 @@ [DRM_IOCTL_NR(DRM_IOCTL_MGA_ILOAD)] = { mga_dma_iload, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_MGA_BLIT)] = { mga_dma_blit, 1, 0 }, +#define IOCTL_TABLE_NAME DRM(ioctls) +#define IOCTL_FUNC_NAME DRM(ioctl) #define __HAVE_COUNTERS 3 #define __HAVE_COUNTER6 _DRM_STAT_IRQ @@ -69,6 +71,7 @@ #include "drm_context.h" #include "drm_dma.h" #include "drm_drawable.h" +#include "drm_ioctl_table.h" #include "drm_drv.h" #ifndef MODULE diff --git a/linux/r128_drv.c b/linux/r128_drv.c index 53217870..270c2c08 100644 --- a/linux/r128_drv.c +++ b/linux/r128_drv.c @@ -63,6 +63,8 @@ [DRM_IOCTL_NR(DRM_IOCTL_R128_STIPPLE)] = { r128_cce_stipple, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_R128_INDIRECT)] = { r128_cce_indirect, 1, 1 }, +#define IOCTL_TABLE_NAME DRM(ioctls) +#define IOCTL_FUNC_NAME DRM(ioctl) #if 0 /* GH: Count data sent to card via ring or vertex/indirect buffers. @@ -80,6 +82,7 @@ #include "drm_context.h" #include "drm_dma.h" #include "drm_drawable.h" +#include "drm_ioctl_table.h" #include "drm_drv.h" #ifndef MODULE diff --git a/linux/radeon_drv.c b/linux/radeon_drv.c index d4faa4d3..f54fc67c 100644 --- a/linux/radeon_drv.c +++ b/linux/radeon_drv.c @@ -59,6 +59,8 @@ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_STIPPLE)] = { radeon_cp_stipple, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_INDIRECT)] = { radeon_cp_indirect, 1, 1 }, +#define IOCTL_TABLE_NAME DRM(ioctls) +#define IOCTL_FUNC_NAME DRM(ioctl) #if 0 /* GH: Count data sent to card via ring or vertex/indirect buffers. @@ -76,6 +78,7 @@ #include "drm_context.h" #include "drm_dma.h" #include "drm_drawable.h" +#include "drm_ioctl_table.h" #include "drm_drv.h" #ifndef MODULE diff --git a/linux/sis_drv.c b/linux/sis_drv.c index 50bac103..6ea9d871 100644 --- a/linux/sis_drv.c +++ b/linux/sis_drv.c @@ -54,6 +54,9 @@ [DRM_IOCTL_NR(SIS_IOCTL_FLIP_FINAL)] = { sis_flip_final, 1, 1 } #endif +#define IOCTL_TABLE_NAME DRM(ioctls) +#define IOCTL_FUNC_NAME DRM(ioctl) + #define __HAVE_COUNTERS 5 #include "drm_auth.h" @@ -62,6 +65,7 @@ #include "drm_context.h" #include "drm_dma.h" #include "drm_drawable.h" +#include "drm_ioctl_table.h" #include "drm_drv.h" #include "drm_fops.h" #include "drm_init.h" diff --git a/linux/tdfx_drv.c b/linux/tdfx_drv.c index 91499077..aeb66366 100644 --- a/linux/tdfx_drv.c +++ b/linux/tdfx_drv.c @@ -74,12 +74,15 @@ static drm_pci_list_t DRM(idlist)[] = { #define DRIVER_CARD_LIST DRM(idlist) +#define IOCTL_TABLE_NAME DRM(ioctls) +#define IOCTL_FUNC_NAME DRM(ioctl) #include "drm_auth.h" #include "drm_bufs.h" #include "drm_context.h" #include "drm_dma.h" #include "drm_drawable.h" +#include "drm_ioctl_table.h" #include "drm_drv.h" #ifndef MODULE diff --git a/shared-core/drm.h b/shared-core/drm.h index 42cbb14c..3ad96e8c 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -385,6 +385,7 @@ typedef struct drm_scatter_gather { #define DRM_IOCTL_GET_MAP DRM_IOWR(0x04, drm_map_t) #define DRM_IOCTL_GET_CLIENT DRM_IOWR(0x05, drm_client_t) #define DRM_IOCTL_GET_STATS DRM_IOR( 0x06, drm_stats_t) +#define DRM_IOCTL_SET_VERSION DRM_IOW( 0x07, drm_version_t) #define DRM_IOCTL_SET_UNIQUE DRM_IOW( 0x10, drm_unique_t) #define DRM_IOCTL_AUTH_MAGIC DRM_IOW( 0x11, drm_auth_t) diff --git a/shared/drm.h b/shared/drm.h index 42cbb14c..3ad96e8c 100644 --- a/shared/drm.h +++ b/shared/drm.h @@ -385,6 +385,7 @@ typedef struct drm_scatter_gather { #define DRM_IOCTL_GET_MAP DRM_IOWR(0x04, drm_map_t) #define DRM_IOCTL_GET_CLIENT DRM_IOWR(0x05, drm_client_t) #define DRM_IOCTL_GET_STATS DRM_IOR( 0x06, drm_stats_t) +#define DRM_IOCTL_SET_VERSION DRM_IOW( 0x07, drm_version_t) #define DRM_IOCTL_SET_UNIQUE DRM_IOW( 0x10, drm_unique_t) #define DRM_IOCTL_AUTH_MAGIC DRM_IOW( 0x11, drm_auth_t) |