drm: add 32/64 support for MGA/R128/i915
authorDave Airlie <airlied@starflyer.(none)>
Thu, 7 Jul 2005 11:51:26 +0000 (21:51 +1000)
committerDave Airlie <airlied@linux.ie>
Thu, 7 Jul 2005 11:51:26 +0000 (21:51 +1000)
This adds compatiblity ioctls for mga/r128 and i915 DRM drivers.

From: Paul Mackerras, David Airlie, Alan Hourihane, Egbert Eich.
Signed-off-by: David Airlie <airlied@linux.ie>
drivers/char/drm/Makefile
drivers/char/drm/i915_drv.c
drivers/char/drm/i915_drv.h
drivers/char/drm/i915_ioc32.c [new file with mode: 0644]
drivers/char/drm/mga_drv.c
drivers/char/drm/mga_drv.h
drivers/char/drm/mga_ioc32.c [new file with mode: 0644]
drivers/char/drm/r128_drv.c
drivers/char/drm/r128_drv.h
drivers/char/drm/r128_ioc32.c [new file with mode: 0644]

index 7444dec40b9488cd874c408696694940cdccfdfd..b36b0158582e9103cde51c5a247b44e93d3a9a07 100644 (file)
@@ -22,6 +22,9 @@ sis-objs    := sis_drv.o sis_ds.o sis_mm.o
 ifeq ($(CONFIG_COMPAT),y)
 drm-objs    += drm_ioc32.o
 radeon-objs += radeon_ioc32.o
+mga-objs    += mga_ioc32.o
+r128-objs   += r128_ioc32.o
+i915-objs   += i915_ioc32.o
 endif
 
 obj-$(CONFIG_DRM)      += drm.o
index e6a9e1d1d2831a6fa17ff660c12146359a58e33a..6a6cc3c0c4c33bc8cb1c602327c1ddd8dc012dca 100644 (file)
@@ -97,6 +97,9 @@ static struct drm_driver driver = {
                .mmap = drm_mmap,
                .poll = drm_poll,
                .fasync = drm_fasync,
+#ifdef CONFIG_COMPAT
+               .compat_ioctl = i915_compat_ioctl,
+#endif
        },
        .pci_driver = {
                .name          = DRIVER_NAME,
index fa940d64b85d6da335a2ea2a21b84a8079d1ceac..3a21223267cba29b3ff8b7d99280c37aebb917a5 100644 (file)
@@ -130,6 +130,10 @@ extern void i915_mem_takedown(struct mem_block **heap);
 extern void i915_mem_release(drm_device_t * dev,
                             DRMFILE filp, struct mem_block *heap);
 
+extern long i915_compat_ioctl(struct file *filp, unsigned int cmd,
+                             unsigned long arg)
+
+
 #define I915_READ(reg)          DRM_READ32(dev_priv->mmio_map, reg)
 #define I915_WRITE(reg,val)     DRM_WRITE32(dev_priv->mmio_map, reg, val)
 #define I915_READ16(reg)       DRM_READ16(dev_priv->mmio_map, reg)
diff --git a/drivers/char/drm/i915_ioc32.c b/drivers/char/drm/i915_ioc32.c
new file mode 100644 (file)
index 0000000..fe009e1
--- /dev/null
@@ -0,0 +1,221 @@
+/**
+ * \file i915_ioc32.c
+ *
+ * 32-bit ioctl compatibility routines for the i915 DRM.
+ *
+ * \author Alan Hourihane <alanh@fairlite.demon.co.uk> 
+ *
+ *
+ * Copyright (C) Paul Mackerras 2005
+ * Copyright (C) Alan Hourihane 2005
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#include <linux/compat.h>
+#include <linux/ioctl32.h>
+
+#include "drmP.h"
+#include "drm.h"
+#include "i915_drm.h"
+
+typedef struct _drm_i915_batchbuffer32 {
+       int start;              /* agp offset */
+       int used;               /* nr bytes in use */
+       int DR1;                /* hw flags for GFX_OP_DRAWRECT_INFO */
+       int DR4;                /* window origin for GFX_OP_DRAWRECT_INFO */
+       int num_cliprects;      /* mulitpass with multiple cliprects? */
+       u32 cliprects;  /* pointer to userspace cliprects */
+} drm_i915_batchbuffer32_t;
+
+static int compat_i915_batchbuffer(struct file *file, unsigned int cmd,
+                          unsigned long arg)
+{
+       drm_i915_batchbuffer32_t batchbuffer32;
+       drm_i915_batchbuffer_t __user *batchbuffer;
+       
+       if (copy_from_user(&batchbuffer32, (void __user *)arg, sizeof(batchbuffer32)))
+               return -EFAULT;
+       
+       batchbuffer = compat_alloc_user_space(sizeof(*batchbuffer));
+       if (!access_ok(VERIFY_WRITE, batchbuffer, sizeof(*batchbuffer))
+           || __put_user(batchbuffer32.start, &batchbuffer->start)
+           || __put_user(batchbuffer32.used, &batchbuffer->used)
+           || __put_user(batchbuffer32.DR1, &batchbuffer->DR1)
+           || __put_user(batchbuffer32.DR4, &batchbuffer->DR4)
+           || __put_user(batchbuffer32.num_cliprects, &batchbuffer->num_cliprects)
+           || __put_user((int __user *)(unsigned long)batchbuffer32.cliprects,
+                         &batchbuffer->cliprects))
+               return -EFAULT;
+       
+       return drm_ioctl(file->f_dentry->d_inode, file,
+                        DRM_IOCTL_I915_BATCHBUFFER, (unsigned long) batchbuffer);
+}
+
+typedef struct _drm_i915_cmdbuffer32 {
+       u32 buf;        /* pointer to userspace command buffer */
+       int sz;                 /* nr bytes in buf */
+       int DR1;                /* hw flags for GFX_OP_DRAWRECT_INFO */
+       int DR4;                /* window origin for GFX_OP_DRAWRECT_INFO */
+       int num_cliprects;      /* mulitpass with multiple cliprects? */
+       u32 cliprects;  /* pointer to userspace cliprects */
+} drm_i915_cmdbuffer32_t;
+
+static int compat_i915_cmdbuffer(struct file *file, unsigned int cmd,
+                          unsigned long arg)
+{
+       drm_i915_cmdbuffer32_t cmdbuffer32;
+       drm_i915_cmdbuffer_t __user *cmdbuffer;
+       
+       if (copy_from_user(&cmdbuffer32, (void __user *)arg, sizeof(cmdbuffer32)))
+               return -EFAULT;
+       
+       cmdbuffer = compat_alloc_user_space(sizeof(*cmdbuffer));
+       if (!access_ok(VERIFY_WRITE, cmdbuffer, sizeof(*cmdbuffer))
+           || __put_user((int __user *)(unsigned long)cmdbuffer32.buf,
+                         &cmdbuffer->buf)
+           || __put_user(cmdbuffer32.sz, &cmdbuffer->sz)
+           || __put_user(cmdbuffer32.DR1, &cmdbuffer->DR1)
+           || __put_user(cmdbuffer32.DR4, &cmdbuffer->DR4)
+           || __put_user(cmdbuffer32.num_cliprects, &cmdbuffer->num_cliprects)
+           || __put_user((int __user *)(unsigned long)cmdbuffer32.cliprects,
+                         &cmdbuffer->cliprects))
+               return -EFAULT;
+       
+       return drm_ioctl(file->f_dentry->d_inode, file,
+                        DRM_IOCTL_I915_CMDBUFFER, (unsigned long) cmdbuffer);
+}
+
+typedef struct drm_i915_irq_emit32 {
+       u32 irq_seq;
+} drm_i915_irq_emit32_t;
+
+static int compat_i915_irq_emit(struct file *file, unsigned int cmd,
+                                 unsigned long arg)
+{
+       drm_i915_irq_emit32_t req32;
+       drm_i915_irq_emit_t __user *request;
+
+       if (copy_from_user(&req32, (void __user *) arg, sizeof(req32)))
+               return -EFAULT;
+
+       request = compat_alloc_user_space(sizeof(*request));
+       if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
+           || __put_user((int __user *)(unsigned long)req32.irq_seq,
+                         &request->irq_seq))
+               return -EFAULT;
+
+       return drm_ioctl(file->f_dentry->d_inode, file,
+                        DRM_IOCTL_I915_IRQ_EMIT, (unsigned long) request);
+}
+typedef struct drm_i915_getparam32 {
+       int param;
+       u32 value;
+} drm_i915_getparam32_t;
+
+static int compat_i915_getparam(struct file *file, unsigned int cmd,
+                                    unsigned long arg)
+{
+       drm_i915_getparam32_t req32;
+       drm_i915_getparam_t __user *request;
+
+       if (copy_from_user(&req32, (void __user *) arg, sizeof(req32)))
+               return -EFAULT;
+
+       request = compat_alloc_user_space(sizeof(*request));
+       if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
+           || __put_user(req32.param, &request->param)
+           || __put_user((void __user *)(unsigned long)req32.value,
+                         &request->value))
+               return -EFAULT;
+
+       return drm_ioctl(file->f_dentry->d_inode, file,
+                        DRM_IOCTL_I915_GETPARAM, (unsigned long) request);
+}
+
+typedef struct drm_i915_mem_alloc32 {
+       int region;
+       int alignment;
+       int size;
+       u32 region_offset;      /* offset from start of fb or agp */
+} drm_i915_mem_alloc32_t;
+
+static int compat_i915_alloc(struct file *file, unsigned int cmd,
+                                    unsigned long arg)
+{
+       drm_i915_mem_alloc32_t req32;
+       drm_i915_mem_alloc_t __user *request;
+
+       if (copy_from_user(&req32, (void __user *) arg, sizeof(req32)))
+               return -EFAULT;
+
+       request = compat_alloc_user_space(sizeof(*request));
+       if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
+           || __put_user(req32.region, &request->region)
+           || __put_user(req32.alignment, &request->alignment)
+           || __put_user(req32.size, &request->size)
+           || __put_user((void __user *)(unsigned long)req32.region_offset,
+                         &request->region_offset))
+               return -EFAULT;
+
+       return drm_ioctl(file->f_dentry->d_inode, file,
+                        DRM_IOCTL_I915_ALLOC, (unsigned long) request);
+}
+
+
+drm_ioctl_compat_t *i915_compat_ioctls[] = {
+       [DRM_I915_BATCHBUFFER] = compat_i915_batchbuffer,
+       [DRM_I915_CMDBUFFER] = compat_i915_cmdbuffer,
+       [DRM_I915_GETPARAM] = compat_i915_getparam,
+       [DRM_I915_IRQ_EMIT] = compat_i915_irq_emit,
+       [DRM_I915_ALLOC] = compat_i915_alloc
+};
+
+/**
+ * Called whenever a 32-bit process running under a 64-bit kernel
+ * performs an ioctl on /dev/dri/card<n>.
+ *
+ * \param filp file pointer.
+ * \param cmd command.
+ * \param arg user argument.
+ * \return zero on success or negative number on failure.
+ */
+long i915_compat_ioctl(struct file *filp, unsigned int cmd,
+                        unsigned long arg)
+{
+       unsigned int nr = DRM_IOCTL_NR(cmd);
+       drm_ioctl_compat_t *fn = NULL;
+       int ret;
+
+       if (nr < DRM_COMMAND_BASE)
+               return drm_compat_ioctl(filp, cmd, arg);
+       
+       if (nr < DRM_COMMAND_BASE + DRM_ARRAY_SIZE(i915_compat_ioctls))
+               fn = i915_compat_ioctls[nr - DRM_COMMAND_BASE];
+
+       lock_kernel();          /* XXX for now */
+       if (fn != NULL)
+               ret = (*fn)(filp, cmd, arg);
+       else
+               ret = drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
+       unlock_kernel();
+
+       return ret;
+}
index 22dab3e9d92a03bf8f1787cafffd0008080b82dc..844cca9cb29dfa65cf0d8bb3a44171846875c942 100644 (file)
@@ -101,6 +101,9 @@ static struct drm_driver driver = {
                .mmap = drm_mmap,
                .poll = drm_poll,
                .fasync = drm_fasync,
+#ifdef CONFIG_COMPAT
+               .compat_ioctl = mga_compat_ioctl,
+#endif
        },
        .pci_driver = {
                .name = DRIVER_NAME,
index 1d84a1eb34dbbe6f0dab735ee20664acd5ee5ef0..9412e2816eb720d1794aeeb948c74b6ce274c495 100644 (file)
@@ -137,6 +137,8 @@ extern irqreturn_t mga_driver_irq_handler( DRM_IRQ_ARGS );
 extern void mga_driver_irq_preinstall( drm_device_t *dev );
 extern void mga_driver_irq_postinstall( drm_device_t *dev );
 extern void mga_driver_irq_uninstall( drm_device_t *dev );
+extern long mga_compat_ioctl(struct file *filp, unsigned int cmd,
+                            unsigned long arg);
 
 #define mga_flush_write_combine()      DRM_WRITEMEMORYBARRIER()
 
diff --git a/drivers/char/drm/mga_ioc32.c b/drivers/char/drm/mga_ioc32.c
new file mode 100644 (file)
index 0000000..bc745cf
--- /dev/null
@@ -0,0 +1,167 @@
+/**
+ * \file mga_ioc32.c
+ *
+ * 32-bit ioctl compatibility routines for the MGA DRM.
+ *
+ * \author Dave Airlie <airlied@linux.ie> with code from patches by Egbert Eich
+ *
+ *
+ * Copyright (C) Paul Mackerras 2005
+ * Copyright (C) Egbert Eich 2003,2004
+ * Copyright (C) Dave Airlie 2005
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#include <linux/compat.h>
+#include <linux/ioctl32.h>
+
+#include "drmP.h"
+#include "drm.h"
+#include "mga_drm.h"
+
+typedef struct drm32_mga_init {
+       int func;
+       u32 sarea_priv_offset;
+       int chipset;
+       int sgram;
+       unsigned int maccess;
+       unsigned int fb_cpp;
+       unsigned int front_offset, front_pitch;
+       unsigned int back_offset, back_pitch;
+       unsigned int depth_cpp;
+       unsigned int depth_offset, depth_pitch;
+       unsigned int texture_offset[MGA_NR_TEX_HEAPS];
+       unsigned int texture_size[MGA_NR_TEX_HEAPS];
+       u32 fb_offset;
+       u32 mmio_offset;
+       u32 status_offset;
+       u32 warp_offset;
+       u32 primary_offset;
+       u32 buffers_offset;
+} drm_mga_init32_t;
+
+static int compat_mga_init(struct file *file, unsigned int cmd,
+                          unsigned long arg)
+{
+       drm_mga_init32_t init32;
+       drm_mga_init_t __user *init;
+       int err = 0, i;
+       
+       if (copy_from_user(&init32, (void __user *)arg, sizeof(init32)))
+               return -EFAULT;
+       
+       init = compat_alloc_user_space(sizeof(*init));
+       if (!access_ok(VERIFY_WRITE, init, sizeof(*init))
+           || __put_user(init32.func, &init->func)
+           || __put_user(init32.sarea_priv_offset, &init->sarea_priv_offset)
+           || __put_user(init32.chipset, &init->chipset)
+           || __put_user(init32.sgram, &init->sgram)
+           || __put_user(init32.maccess, &init->maccess)
+           || __put_user(init32.fb_cpp, &init->fb_cpp)
+           || __put_user(init32.front_offset, &init->front_offset)
+           || __put_user(init32.front_pitch, &init->front_pitch)
+           || __put_user(init32.back_offset, &init->back_offset)
+           || __put_user(init32.back_pitch, &init->back_pitch)
+           || __put_user(init32.depth_cpp, &init->depth_cpp)
+           || __put_user(init32.depth_offset, &init->depth_offset)
+           || __put_user(init32.depth_pitch, &init->depth_pitch)
+           || __put_user(init32.fb_offset, &init->fb_offset)
+           || __put_user(init32.mmio_offset, &init->mmio_offset)
+           || __put_user(init32.status_offset, &init->status_offset)
+           || __put_user(init32.warp_offset, &init->warp_offset)
+           || __put_user(init32.primary_offset, &init->primary_offset)
+           || __put_user(init32.buffers_offset, &init->buffers_offset))
+               return -EFAULT;
+       
+       for (i=0; i<MGA_NR_TEX_HEAPS; i++)
+       {
+               err |= __put_user(init32.texture_offset[i], &init->texture_offset[i]);
+               err |= __put_user(init32.texture_size[i], &init->texture_size[i]);
+       }
+       if (err)
+               return -EFAULT;
+       
+       return drm_ioctl(file->f_dentry->d_inode, file,
+                        DRM_IOCTL_MGA_INIT, (unsigned long) init);
+}
+
+
+typedef struct drm_mga_getparam32 {
+       int param;
+       u32 value;
+} drm_mga_getparam32_t;
+
+
+static int compat_mga_getparam(struct file *file, unsigned int cmd,
+                              unsigned long arg)
+{
+       drm_mga_getparam32_t getparam32;
+       drm_mga_getparam_t __user *getparam;
+       
+       if (copy_from_user(&getparam32, (void __user *)arg, sizeof(getparam32)))
+               return -EFAULT;
+
+       getparam = compat_alloc_user_space(sizeof(*getparam));
+       if (!access_ok(VERIFY_WRITE, getparam, sizeof(*getparam))
+           || __put_user(getparam32.param, &getparam->param)
+           || __put_user((void __user *)(unsigned long)getparam32.value, &getparam->value))
+               return -EFAULT;
+
+       return drm_ioctl(file->f_dentry->d_inode, file, 
+                        DRM_IOCTL_MGA_GETPARAM, (unsigned long)getparam);
+}
+
+drm_ioctl_compat_t *mga_compat_ioctls[] = {
+       [DRM_MGA_INIT] = compat_mga_init,
+       [DRM_MGA_GETPARAM] = compat_mga_getparam,
+};
+
+/**
+ * Called whenever a 32-bit process running under a 64-bit kernel
+ * performs an ioctl on /dev/dri/card<n>.
+ *
+ * \param filp file pointer.
+ * \param cmd command.
+ * \param arg user argument.
+ * \return zero on success or negative number on failure.
+ */
+long mga_compat_ioctl(struct file *filp, unsigned int cmd,
+                        unsigned long arg)
+{
+       unsigned int nr = DRM_IOCTL_NR(cmd);
+       drm_ioctl_compat_t *fn = NULL;
+       int ret;
+
+       if (nr < DRM_COMMAND_BASE)
+               return drm_compat_ioctl(filp, cmd, arg);
+       
+       if (nr < DRM_COMMAND_BASE + DRM_ARRAY_SIZE(mga_compat_ioctls))
+               fn = mga_compat_ioctls[nr - DRM_COMMAND_BASE];
+
+       lock_kernel();          /* XXX for now */
+       if (fn != NULL)
+               ret = (*fn)(filp, cmd, arg);
+       else
+               ret = drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
+       unlock_kernel();
+
+       return ret;
+}
index ced63810237b003e60b21a80a4b16e1bfabbd5e2..bc446da1b2109bb68a55d1b4f832e7a4cca86bd8 100644 (file)
@@ -96,6 +96,9 @@ static struct drm_driver driver = {
                .mmap = drm_mmap,
                .poll = drm_poll,
                .fasync = drm_fasync,
+#ifdef CONFIG_COMPAT
+               .compat_ioctl = r128_compat_ioctl,
+#endif
        },
        .pci_driver = {
                .name          = DRIVER_NAME,
index cf1aa5df459e042aaa928e58eb6be1aec5aa436d..0fb687c9505e5e254c742fad6249db45d401b16b 100644 (file)
@@ -156,6 +156,9 @@ extern void r128_driver_irq_uninstall( drm_device_t *dev );
 extern void r128_driver_pretakedown(drm_device_t *dev);
 extern void r128_driver_prerelease(drm_device_t *dev, DRMFILE filp);
 
+extern long r128_compat_ioctl(struct file *filp, unsigned int cmd,
+                             unsigned long arg);
+
 /* Register definitions, register access macros and drmAddMap constants
  * for Rage 128 kernel driver.
  */
diff --git a/drivers/char/drm/r128_ioc32.c b/drivers/char/drm/r128_ioc32.c
new file mode 100644 (file)
index 0000000..60598ef
--- /dev/null
@@ -0,0 +1,219 @@
+/**
+ * \file r128_ioc32.c
+ *
+ * 32-bit ioctl compatibility routines for the R128 DRM.
+ *
+ * \author Dave Airlie <airlied@linux.ie> with code from patches by Egbert Eich
+ *
+ * Copyright (C) Paul Mackerras 2005
+ * Copyright (C) Egbert Eich 2003,2004
+ * Copyright (C) Dave Airlie 2005
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#include <linux/compat.h>
+#include <linux/ioctl32.h>
+
+#include "drmP.h"
+#include "drm.h"
+#include "r128_drm.h"
+
+typedef struct drm_r128_init32 {
+       int func;
+       unsigned int sarea_priv_offset;
+       int is_pci;
+       int cce_mode;
+       int cce_secure;
+       int ring_size;
+       int usec_timeout;
+
+       unsigned int fb_bpp;
+       unsigned int front_offset, front_pitch;
+       unsigned int back_offset, back_pitch;
+       unsigned int depth_bpp;
+       unsigned int depth_offset, depth_pitch;
+       unsigned int span_offset;
+
+       unsigned int fb_offset;
+       unsigned int mmio_offset;
+       unsigned int ring_offset;
+       unsigned int ring_rptr_offset;
+       unsigned int buffers_offset;
+       unsigned int agp_textures_offset;
+} drm_r128_init32_t;
+
+static int compat_r128_init(struct file *file, unsigned int cmd,
+                           unsigned long arg)
+{
+       drm_r128_init32_t init32;
+       drm_r128_init_t __user *init;
+       
+       if (copy_from_user(&init32, (void __user *)arg, sizeof(init32)))
+               return -EFAULT;
+       
+       init = compat_alloc_user_space(sizeof(*init));
+       if (!access_ok(VERIFY_WRITE, init, sizeof(*init))
+           || __put_user(init32.func, &init->func)
+           || __put_user(init32.sarea_priv_offset, &init->sarea_priv_offset)
+           || __put_user(init32.is_pci, &init->is_pci)
+           || __put_user(init32.cce_mode, &init->cce_mode)
+           || __put_user(init32.cce_secure, &init->cce_secure)
+           || __put_user(init32.ring_size, &init->ring_size)
+           || __put_user(init32.usec_timeout, &init->usec_timeout)
+           || __put_user(init32.fb_bpp, &init->fb_bpp)
+           || __put_user(init32.front_offset, &init->front_offset)
+           || __put_user(init32.front_pitch, &init->front_pitch)
+           || __put_user(init32.back_offset, &init->back_offset)
+           || __put_user(init32.back_pitch, &init->back_pitch)
+           || __put_user(init32.depth_bpp, &init->depth_bpp)
+           || __put_user(init32.depth_offset, &init->depth_offset)
+           || __put_user(init32.depth_pitch, &init->depth_pitch)
+           || __put_user(init32.span_offset, &init->span_offset)
+           || __put_user(init32.fb_offset, &init->fb_offset)
+           || __put_user(init32.mmio_offset, &init->mmio_offset)
+           || __put_user(init32.ring_offset, &init->ring_offset)
+           || __put_user(init32.ring_rptr_offset, &init->ring_rptr_offset)
+           || __put_user(init32.buffers_offset, &init->buffers_offset)
+           || __put_user(init32.agp_textures_offset, &init->agp_textures_offset))
+               return -EFAULT;
+       
+       return drm_ioctl(file->f_dentry->d_inode, file,
+                        DRM_IOCTL_R128_INIT, (unsigned long)init);
+}
+
+
+typedef struct drm_r128_depth32 {
+       int func;
+       int n;
+       u32 x;
+       u32 y;
+       u32 buffer;
+       u32 mask;
+} drm_r128_depth32_t;
+
+static int compat_r128_depth(struct file *file, unsigned int cmd,
+                            unsigned long arg)
+{
+       drm_r128_depth32_t depth32;
+       drm_r128_depth_t __user *depth;
+
+       if (copy_from_user(&depth32, (void __user *)arg, sizeof(depth32)))
+               return -EFAULT;
+
+       depth = compat_alloc_user_space(sizeof(*depth));
+       if (!access_ok(VERIFY_WRITE, depth, sizeof(*depth))
+           || __put_user(depth32.func, &depth->func)
+           || __put_user(depth32.n, &depth->n)
+           || __put_user((int __user *)(unsigned long)depth32.x, &depth->x)
+           || __put_user((int __user *)(unsigned long)depth32.y, &depth->y)
+           || __put_user((unsigned int __user *)(unsigned long)depth32.buffer, &depth->buffer)
+           || __put_user((unsigned char __user *)(unsigned long)depth32.mask, &depth->mask))
+               return -EFAULT;
+       
+       return drm_ioctl(file->f_dentry->d_inode, file,
+                        DRM_IOCTL_R128_DEPTH, (unsigned long)depth);   
+       
+}
+
+typedef struct drm_r128_stipple32 {
+       u32 mask;
+} drm_r128_stipple32_t;
+
+static int compat_r128_stipple(struct file *file, unsigned int cmd,
+                              unsigned long arg)
+{
+       drm_r128_stipple32_t stipple32;
+       drm_r128_stipple_t __user *stipple;
+
+       if (copy_from_user(&stipple32, (void __user *)arg, sizeof(stipple32)))
+               return -EFAULT;
+
+       stipple = compat_alloc_user_space(sizeof(*stipple));
+       if (!access_ok(VERIFY_WRITE, stipple, sizeof(*stipple))
+           || __put_user((unsigned int __user *)(unsigned long)stipple32.mask, &stipple->mask))
+               return -EFAULT;
+
+       return drm_ioctl(file->f_dentry->d_inode, file,
+                        DRM_IOCTL_R128_STIPPLE, (unsigned long)stipple);
+}
+
+typedef struct drm_r128_getparam32 {
+       int param;
+       u32 value;
+} drm_r128_getparam32_t;
+
+static int compat_r128_getparam(struct file *file, unsigned int cmd,
+                               unsigned long arg)
+{
+       drm_r128_getparam32_t getparam32;
+       drm_r128_getparam_t __user *getparam;
+
+       if (copy_from_user(&getparam32, (void __user *)arg, sizeof(getparam32)))
+               return -EFAULT;
+
+       getparam = compat_alloc_user_space(sizeof(*getparam));
+       if (!access_ok(VERIFY_WRITE, getparam, sizeof(*getparam))
+           || __put_user(getparam32.param, &getparam->param)
+           || __put_user((void __user *)(unsigned long)getparam32.value, &getparam->value))
+               return -EFAULT;
+       
+       return drm_ioctl(file->f_dentry->d_inode, file,
+                        DRM_IOCTL_R128_GETPARAM, (unsigned long)getparam);
+}
+
+drm_ioctl_compat_t *r128_compat_ioctls[] = {
+       [DRM_R128_INIT] = compat_r128_init,
+       [DRM_R128_DEPTH] = compat_r128_depth,
+       [DRM_R128_STIPPLE] = compat_r128_stipple,
+       [DRM_R128_GETPARAM] = compat_r128_getparam,
+};
+
+/**
+ * Called whenever a 32-bit process running under a 64-bit kernel
+ * performs an ioctl on /dev/dri/card<n>.
+ *
+ * \param filp file pointer.
+ * \param cmd command.
+ * \param arg user argument.
+ * \return zero on success or negative number on failure.
+ */
+long r128_compat_ioctl(struct file *filp, unsigned int cmd,
+                        unsigned long arg)
+{
+       unsigned int nr = DRM_IOCTL_NR(cmd);
+       drm_ioctl_compat_t *fn = NULL;
+       int ret;
+
+       if (nr < DRM_COMMAND_BASE)
+               return drm_compat_ioctl(filp, cmd, arg);
+
+       if (nr < DRM_COMMAND_BASE + DRM_ARRAY_SIZE(r128_compat_ioctls))
+               fn = r128_compat_ioctls[nr - DRM_COMMAND_BASE];
+
+       lock_kernel();          /* XXX for now */
+       if (fn != NULL)
+               ret = (*fn)(filp, cmd, arg);
+       else
+               ret = drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
+       unlock_kernel();
+
+       return ret;
+}