summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--linux-core/i810_dma.c72
-rw-r--r--linux-core/i810_drm.h34
-rw-r--r--linux/i810.h3
-rw-r--r--linux/i810_dma.c72
-rw-r--r--linux/i810_drm.h34
5 files changed, 198 insertions, 17 deletions
diff --git a/linux-core/i810_dma.c b/linux-core/i810_dma.c
index 88e5b9db..6af9181a 100644
--- a/linux-core/i810_dma.c
+++ b/linux-core/i810_dma.c
@@ -450,6 +450,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)
{
@@ -459,22 +502,43 @@ 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;
+ retcode = i810_dma_initialize(dev, dev_priv, &init);
+ 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;
}
return retcode;
diff --git a/linux-core/i810_drm.h b/linux-core/i810_drm.h
index b35593bd..93775f68 100644
--- a/linux-core/i810_drm.h
+++ b/linux-core/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,29 @@ 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;
+#if CONFIG_XFREE86_VERSION < XFREE86_VERSION(4,1,0,0)
+ int ring_map_idx;
+ int buffer_map_idx;
+#else
+ unsigned int mmio_offset;
+ unsigned int buffers_offset;
+#endif
+ 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 */
diff --git a/linux/i810.h b/linux/i810.h
index ba40892f..a5d300a2 100644
--- a/linux/i810.h
+++ b/linux/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/linux/i810_dma.c b/linux/i810_dma.c
index 88e5b9db..6af9181a 100644
--- a/linux/i810_dma.c
+++ b/linux/i810_dma.c
@@ -450,6 +450,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)
{
@@ -459,22 +502,43 @@ 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;
+ retcode = i810_dma_initialize(dev, dev_priv, &init);
+ 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;
}
return retcode;
diff --git a/linux/i810_drm.h b/linux/i810_drm.h
index b35593bd..93775f68 100644
--- a/linux/i810_drm.h
+++ b/linux/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,29 @@ 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;
+#if CONFIG_XFREE86_VERSION < XFREE86_VERSION(4,1,0,0)
+ int ring_map_idx;
+ int buffer_map_idx;
+#else
+ unsigned int mmio_offset;
+ unsigned int buffers_offset;
+#endif
+ 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 */