summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libdrm/xf86drm.c12
-rw-r--r--linux-core/drmP.h14
-rw-r--r--linux-core/drm_drv.c243
-rw-r--r--linux-core/i810_drv.c3
-rw-r--r--linux-core/mga_drv.c3
-rw-r--r--linux-core/r128_drv.c3
-rw-r--r--linux-core/radeon_drv.c3
-rw-r--r--linux-core/sis_drv.c4
-rw-r--r--linux-core/tdfx_drv.c3
-rw-r--r--linux/drm.h1
-rw-r--r--linux/drmP.h14
-rw-r--r--linux/drm_drv.h243
-rw-r--r--linux/gamma_drv.c3
-rw-r--r--linux/i810_drv.c3
-rw-r--r--linux/mga_drv.c3
-rw-r--r--linux/r128_drv.c3
-rw-r--r--linux/radeon_drv.c3
-rw-r--r--linux/sis_drv.c4
-rw-r--r--linux/tdfx_drv.c3
-rw-r--r--shared-core/drm.h1
-rw-r--r--shared/drm.h1
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)