diff --git a/drivers/char/drm/i810.h b/drivers/char/drm/i810.h
index ba40892f5d8a611fb6cbacb336403f35ba3ca711..a5d300a246fa2a6d78a40c8a11846a90a62eb781 100644
--- a/drivers/char/drm/i810.h
+++ b/drivers/char/drm/i810.h
@@ -55,9 +55,10 @@
  * 1.2.1 - Disable copying code (leave stub ioctls for backwards compatibility)
  *       - Remove requirement for interrupt (leave stubs again)
  * 1.3   - Add page flipping.
+ * 1.4   - fix DRM interface
  */
 #define DRIVER_MAJOR		1
-#define DRIVER_MINOR		3
+#define DRIVER_MINOR		4
 #define DRIVER_PATCHLEVEL	0
 
 #define DRIVER_IOCTLS							    \
diff --git a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c
index c21fc1c8ef2757e5896a8184f957ac8182b8be6e..7f65b110fce7d56b7daf71a2a6c64b138179e909 100644
--- a/drivers/char/drm/i810_dma.c
+++ b/drivers/char/drm/i810_dma.c
@@ -443,6 +443,49 @@ static int i810_dma_initialize(drm_device_t *dev,
    	return 0;
 }
 
+/* i810 DRM version 1.1 used a smaller init structure with different
+ * ordering of values than is currently used (drm >= 1.2). There is
+ * no defined way to detect the XFree version to correct this problem,
+ * however by checking using this procedure we can detect the correct
+ * thing to do.
+ *
+ * #1 Read the Smaller init structure from user-space
+ * #2 Verify the overlay_physical is a valid physical address, or NULL
+ *    If it isn't then we have a v1.1 client. Fix up params.
+ *    If it is, then we have a 1.2 client... get the rest of the data.
+ */
+int i810_dma_init_compat(drm_i810_init_t *init, unsigned long arg)
+{
+
+	/* Get v1.1 init data */
+	if (copy_from_user(init, (drm_i810_pre12_init_t *)arg,
+			  sizeof(drm_i810_pre12_init_t))) {
+		return -EFAULT;
+	}
+
+	if ((!init->overlay_physical) || (init->overlay_physical > 4096)) {
+
+		/* This is a v1.2 client, just get the v1.2 init data */
+		DRM_INFO("Using POST v1.2 init.\n");
+		if(copy_from_user(init, (drm_i810_init_t *)arg,
+				  sizeof(drm_i810_init_t))) {
+			return -EFAULT;
+		}
+	} else {
+
+		/* This is a v1.1 client, fix the params */
+		DRM_INFO("Using PRE v1.2 init.\n");
+	 	init->pitch_bits = init->h;
+	 	init->pitch = init->w;
+	 	init->h = init->overlay_physical;
+	 	init->w = init->overlay_offset;
+	 	init->overlay_physical = 0;
+	 	init->overlay_offset = 0;
+	}
+
+	return 0;
+}
+
 int i810_dma_init(struct inode *inode, struct file *filp,
 		  unsigned int cmd, unsigned long arg)
 {
@@ -452,22 +495,46 @@ int i810_dma_init(struct inode *inode, struct file *filp,
    	drm_i810_init_t init;
    	int retcode = 0;
 
-  	if (copy_from_user(&init, (drm_i810_init_t *)arg, sizeof(init)))
+	/* Get only the init func */
+  	if (copy_from_user(&init, (void *)arg, sizeof(drm_i810_init_func_t)))
 		return -EFAULT;
 
    	switch(init.func) {
 	 	case I810_INIT_DMA:
+	 	       	/* This case is for backward compatibility. It
+			 * handles XFree 4.1.0 and 4.2.0, and has to
+			 * do some parameter checking as described below.
+			 * It will someday go away.
+			 */
+			retcode = i810_dma_init_compat(&init, arg);
+			if (retcode)
+				return retcode;
+
 	   		dev_priv = DRM(alloc)(sizeof(drm_i810_private_t),
 					     DRM_MEM_DRIVER);
-	   		if(dev_priv == NULL) return -ENOMEM;
+	   		if (dev_priv == NULL)
+	   			return -ENOMEM;
 	   		retcode = i810_dma_initialize(dev, dev_priv, &init);
-	   	break;
+		   	break;
+
+		default:
+	 	case I810_INIT_DMA_1_4:
+			DRM_INFO("Using v1.4 init.\n");
+  			if (copy_from_user(&init, (drm_i810_init_t *)arg,
+					  sizeof(drm_i810_init_t))) {
+				return -EFAULT;
+			}
+	   		dev_priv = DRM(alloc)(sizeof(drm_i810_private_t),
+					     DRM_MEM_DRIVER);
+	   		if (dev_priv == NULL)
+	   			return -ENOMEM;
+	   		retcode = i810_dma_initialize(dev, dev_priv, &init);
+		   	break;
+
 	 	case I810_CLEANUP_DMA:
+		        DRM_INFO("DMA Cleanup\n");
 	   		retcode = i810_dma_cleanup(dev);
-	   	break;
-	 	default:
-	   		retcode = -EINVAL;
-	   	break;
+		   	break;
 	}
 
    	return retcode;
@@ -477,12 +544,16 @@ int i810_dma_init(struct inode *inode, struct file *filp,
 
 /* Most efficient way to verify state for the i810 is as it is
  * emitted.  Non-conformant state is silently dropped.
+ *
+ * Use 'volatile' & local var tmp to force the emitted values to be
+ * identical to the verified ones.
  */
 static void i810EmitContextVerified( drm_device_t *dev,
-				     unsigned int *code )
+				     volatile unsigned int *code )
 {
    	drm_i810_private_t *dev_priv = dev->dev_private;
 	int i, j = 0;
+	unsigned int tmp;
 	RING_LOCALS;
 
 	BEGIN_LP_RING( I810_CTX_SETUP_SIZE );
@@ -494,10 +565,12 @@ static void i810EmitContextVerified( drm_device_t *dev,
 	OUT_RING( code[I810_CTXREG_ST1] );
 
 	for ( i = 4 ; i < I810_CTX_SETUP_SIZE ; i++ ) {
-		if ((code[i] & (7<<29)) == (3<<29) &&
-		    (code[i] & (0x1f<<24)) < (0x1d<<24))
+		tmp = code[i];
+
+		if ((tmp & (7<<29)) == (3<<29) &&
+		    (tmp & (0x1f<<24)) < (0x1d<<24))
 		{
-			OUT_RING( code[i] );
+			OUT_RING( tmp );
 			j++;
 		}
 		else printk("constext state dropped!!!\n");
@@ -514,6 +587,7 @@ static void i810EmitTexVerified( drm_device_t *dev,
 {
    	drm_i810_private_t *dev_priv = dev->dev_private;
 	int i, j = 0;
+	unsigned int tmp;
 	RING_LOCALS;
 
 	BEGIN_LP_RING( I810_TEX_SETUP_SIZE );
@@ -524,11 +598,12 @@ static void i810EmitTexVerified( drm_device_t *dev,
 	OUT_RING( code[I810_TEXREG_MI3] );
 
 	for ( i = 4 ; i < I810_TEX_SETUP_SIZE ; i++ ) {
+		tmp = code[i];
 
-		if ((code[i] & (7<<29)) == (3<<29) &&
-		    (code[i] & (0x1f<<24)) < (0x1d<<24))
+		if ((tmp & (7<<29)) == (3<<29) &&
+		    (tmp & (0x1f<<24)) < (0x1d<<24))
 		{
-			OUT_RING( code[i] );
+			OUT_RING( tmp );
 			j++;
 		}
 		else printk("texture state dropped!!!\n");
@@ -556,9 +631,9 @@ static void i810EmitDestVerified( drm_device_t *dev,
 	if (tmp == dev_priv->front_di1 || tmp == dev_priv->back_di1) {
 		OUT_RING( CMD_OP_DESTBUFFER_INFO );
 		OUT_RING( tmp );
-	} 
-	else
-	   printk("buffer state dropped\n");
+	} else
+	   DRM_DEBUG("bad di1 %x (allow %x or %x)\n",
+		     tmp, dev_priv->front_di1, dev_priv->back_di1);
 
 	/* invarient:
 	 */
@@ -986,6 +1061,9 @@ int i810_dma_vertex(struct inode *inode, struct file *filp,
 		return -EINVAL;
 	}
 
+	DRM_DEBUG("i810 dma vertex, idx %d used %d discard %d\n",
+		  vertex.idx, vertex.used, vertex.discard);
+
 	if(vertex.idx < 0 || vertex.idx > dma->buf_count) return -EINVAL;
 
 	i810_dma_dispatch_vertex( dev,
@@ -1034,6 +1112,8 @@ int i810_swap_bufs(struct inode *inode, struct file *filp,
 	drm_file_t *priv = filp->private_data;
 	drm_device_t *dev = priv->dev;
 
+	DRM_DEBUG("i810_swap_bufs\n");
+
    	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
 		DRM_ERROR("i810_swap_buf called without lock held\n");
 		return -EINVAL;
@@ -1081,6 +1161,9 @@ int i810_getbuf(struct inode *inode, struct file *filp, unsigned int cmd,
 
 	retcode = i810_dma_get_buffer(dev, &d, filp);
 
+	DRM_DEBUG("i810_dma: %d returning %d, granted = %d\n",
+		  current->pid, retcode, d.granted);
+
 	if (copy_to_user((drm_dma_t *)arg, &d, sizeof(d)))
 		return -EFAULT;
    	sarea_priv->last_dispatch = (int) hw_status[5];
diff --git a/drivers/char/drm/i810_drm.h b/drivers/char/drm/i810_drm.h
index b35593bd41e9417fbbd3870d6bb46aa1d38471c5..c1d08efa736085dc0941aed7a40647d4791fd19a 100644
--- a/drivers/char/drm/i810_drm.h
+++ b/drivers/char/drm/i810_drm.h
@@ -94,12 +94,15 @@
 #define I810_BACK    0x2
 #define I810_DEPTH   0x4
 
+typedef enum _drm_i810_init_func {
+	I810_INIT_DMA = 0x01,
+	I810_CLEANUP_DMA = 0x02,
+	I810_INIT_DMA_1_4 = 0x03
+ } drm_i810_init_func_t;
 
+/* This is the init structure after v1.2 */
 typedef struct _drm_i810_init {
-	enum {
-		I810_INIT_DMA = 0x01,
-		I810_CLEANUP_DMA = 0x02
-	} func;
+	drm_i810_init_func_t func;
 #if CONFIG_XFREE86_VERSION < XFREE86_VERSION(4,1,0,0)
 	int ring_map_idx;
 	int buffer_map_idx;
@@ -122,6 +125,24 @@ typedef struct _drm_i810_init {
 	unsigned int pitch_bits; 
 } drm_i810_init_t;
 
+/* This is the init structure prior to v1.2 */
+typedef struct _drm_i810_pre12_init {
+	drm_i810_init_func_t func;
+	unsigned int mmio_offset;
+	unsigned int buffers_offset;
+	int sarea_priv_offset;
+	unsigned int ring_start;
+	unsigned int ring_end;
+	unsigned int ring_size;
+	unsigned int front_offset;
+	unsigned int back_offset;
+	unsigned int depth_offset;
+	unsigned int w;
+	unsigned int h;
+	unsigned int pitch;
+	unsigned int pitch_bits; 
+} drm_i810_pre12_init_t;
+
 /* Warning: If you change the SAREA structure you must change the Xserver
  * structure as well */