diff options
-rw-r--r-- | linux-core/i810_dma.c | 72 | ||||
-rw-r--r-- | linux-core/i810_drm.h | 34 | ||||
-rw-r--r-- | linux/i810.h | 3 | ||||
-rw-r--r-- | linux/i810_dma.c | 72 | ||||
-rw-r--r-- | linux/i810_drm.h | 34 |
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 */ |