http://drm.bkbits.net/drm-2.6
airlied@starflyer.(none)|ChangeSet|20050304080538|35823 airlied

# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2005/03/07 15:13:33-08:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-drm
# 
# MAINTAINERS
#   2005/03/07 15:13:29-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2005/03/07 14:19:28-08:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-drm
# 
# MAINTAINERS
#   2005/03/07 14:19:23-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2005/03/06 19:44:49-08:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-drm
# 
# drivers/char/drm/drm_drv.c
#   2005/03/06 19:44:44-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/char/drm/drmP.h
#   2005/03/06 19:44:44-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# MAINTAINERS
#   2005/03/06 19:44:44-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2005/03/05 15:44:10-08:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-drm
# 
# MAINTAINERS
#   2005/03/05 15:44:05-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# CREDITS
#   2005/03/05 15:44:05-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2005/03/04 22:18:24-08:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-drm
# 
# MAINTAINERS
#   2005/03/04 22:18:20-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2005/03/04 19:05:38+11:00 airlied@starflyer.(none) 
#   add ioctl32 compat files
# 
# drivers/char/drm/radeon_ioc32.c
#   2005/03/04 19:05:07+11:00 airlied@starflyer.(none) +481 -0
# 
# drivers/char/drm/radeon_ioc32.c
#   2005/03/04 19:05:07+11:00 airlied@starflyer.(none) +0 -0
#   BitKeeper file /foo/airlied/bitkeeper/drm-latest/drivers/char/drm/radeon_ioc32.c
# 
# drivers/char/drm/drm_ioc32.c
#   2005/03/04 19:05:06+11:00 airlied@starflyer.(none) +1234 -0
# 
# drivers/char/drm/drm_ioc32.c
#   2005/03/04 19:05:06+11:00 airlied@starflyer.(none) +0 -0
#   BitKeeper file /foo/airlied/bitkeeper/drm-latest/drivers/char/drm/drm_ioc32.c
# 
# ChangeSet
#   2005/03/03 21:55:58+11:00 airlied@starflyer.(none) 
#   drm: 32/64-bit DRM ioctl compatibility patch
#   
#   The patch is against a 2.6.11 kernel tree.  I am running this with a
#   32-bit X server (compiled up from X.org CVS as of a couple of weeks
#   ago) and 32-bit DRI libraries and clients.  All the userland stuff is
#   identical to what I am using under a 32-bit kernel on my G4 powerbook
#   (which is a 32-bit machine of course).  I haven't tried compiling up a
#   64-bit X server or clients yet.
#   
#   In the compatibility routines I have assumed that the kernel can
#   safely access user addresses after set_fs(KERNEL_DS).  That is, where
#   an ioctl argument structure contains pointers to other structures, and
#   those other structures are already compatible between the 32-bit and
#   64-bit ABIs (i.e. they only contain things like chars, shorts or
#   ints), I just check the address with access_ok() and then pass it
#   through to the 64-bit ioctl code.  I believe this approach may not
#   work on sparc64, but it does work on ppc64 and x86_64 at least.
#   
#   One tricky area which may need to be revisited is the question of how
#   to handle the handles which we pass back to userspace to identify
#   mappings.  These handles are generated in the ADDMAP ioctl and then
#   passed in as the offset value to mmap.  However, offset values for
#   mmap seem to be generated in other ways as well, particularly for AGP
#   mappings.
#   
#   The approach I have ended up with is to generate a fake 32-bit handle
#   only for _DRM_SHM mappings.  The handles for other mappings (AGP, REG,
#   FB) are physical addresses which are already limited to 32 bits, and
#   generating fake handles for them created all sorts of problems in the
#   mmap/nopage code.
#   
#   
#   From: Paul Mackerras <paulus@samba.org>
#   Signed-off-by: Dave Airlie <airlied@linux.ie>
# 
# drivers/char/drm/radeon_drv.h
#   2005/03/03 21:55:49+11:00 airlied@starflyer.(none) +3 -0
#   drm: 32/64-bit DRM ioctl compatibility patch
#   
#   The patch is against a 2.6.11 kernel tree.  I am running this with a
#   32-bit X server (compiled up from X.org CVS as of a couple of weeks
#   ago) and 32-bit DRI libraries and clients.  All the userland stuff is
#   identical to what I am using under a 32-bit kernel on my G4 powerbook
#   (which is a 32-bit machine of course).  I haven't tried compiling up a
#   64-bit X server or clients yet.
#   
#   In the compatibility routines I have assumed that the kernel can
#   safely access user addresses after set_fs(KERNEL_DS).  That is, where
#   an ioctl argument structure contains pointers to other structures, and
#   those other structures are already compatible between the 32-bit and
#   64-bit ABIs (i.e. they only contain things like chars, shorts or
#   ints), I just check the address with access_ok() and then pass it
#   through to the 64-bit ioctl code.  I believe this approach may not
#   work on sparc64, but it does work on ppc64 and x86_64 at least.
#   
#   One tricky area which may need to be revisited is the question of how
#   to handle the handles which we pass back to userspace to identify
#   mappings.  These handles are generated in the ADDMAP ioctl and then
#   passed in as the offset value to mmap.  However, offset values for
#   mmap seem to be generated in other ways as well, particularly for AGP
#   mappings.
#   
#   The approach I have ended up with is to generate a fake 32-bit handle
#   only for _DRM_SHM mappings.  The handles for other mappings (AGP, REG,
#   FB) are physical addresses which are already limited to 32 bits, and
#   generating fake handles for them created all sorts of problems in the
#   mmap/nopage code.
#   
#   
#   From: Paul Mackerras <paulus@samba.org>
#   Signed-off-by: Dave Airlie <airlied@linux.ie>
# 
# drivers/char/drm/radeon_drv.c
#   2005/03/03 21:55:49+11:00 airlied@starflyer.(none) +6 -0
#   drm: 32/64-bit DRM ioctl compatibility patch
#   
#   The patch is against a 2.6.11 kernel tree.  I am running this with a
#   32-bit X server (compiled up from X.org CVS as of a couple of weeks
#   ago) and 32-bit DRI libraries and clients.  All the userland stuff is
#   identical to what I am using under a 32-bit kernel on my G4 powerbook
#   (which is a 32-bit machine of course).  I haven't tried compiling up a
#   64-bit X server or clients yet.
#   
#   In the compatibility routines I have assumed that the kernel can
#   safely access user addresses after set_fs(KERNEL_DS).  That is, where
#   an ioctl argument structure contains pointers to other structures, and
#   those other structures are already compatible between the 32-bit and
#   64-bit ABIs (i.e. they only contain things like chars, shorts or
#   ints), I just check the address with access_ok() and then pass it
#   through to the 64-bit ioctl code.  I believe this approach may not
#   work on sparc64, but it does work on ppc64 and x86_64 at least.
#   
#   One tricky area which may need to be revisited is the question of how
#   to handle the handles which we pass back to userspace to identify
#   mappings.  These handles are generated in the ADDMAP ioctl and then
#   passed in as the offset value to mmap.  However, offset values for
#   mmap seem to be generated in other ways as well, particularly for AGP
#   mappings.
#   
#   The approach I have ended up with is to generate a fake 32-bit handle
#   only for _DRM_SHM mappings.  The handles for other mappings (AGP, REG,
#   FB) are physical addresses which are already limited to 32 bits, and
#   generating fake handles for them created all sorts of problems in the
#   mmap/nopage code.
#   
#   
#   From: Paul Mackerras <paulus@samba.org>
#   Signed-off-by: Dave Airlie <airlied@linux.ie>
# 
# drivers/char/drm/drm_vm.c
#   2005/03/03 21:55:49+11:00 airlied@starflyer.(none) +4 -0
#   drm: 32/64-bit DRM ioctl compatibility patch
#   
#   The patch is against a 2.6.11 kernel tree.  I am running this with a
#   32-bit X server (compiled up from X.org CVS as of a couple of weeks
#   ago) and 32-bit DRI libraries and clients.  All the userland stuff is
#   identical to what I am using under a 32-bit kernel on my G4 powerbook
#   (which is a 32-bit machine of course).  I haven't tried compiling up a
#   64-bit X server or clients yet.
#   
#   In the compatibility routines I have assumed that the kernel can
#   safely access user addresses after set_fs(KERNEL_DS).  That is, where
#   an ioctl argument structure contains pointers to other structures, and
#   those other structures are already compatible between the 32-bit and
#   64-bit ABIs (i.e. they only contain things like chars, shorts or
#   ints), I just check the address with access_ok() and then pass it
#   through to the 64-bit ioctl code.  I believe this approach may not
#   work on sparc64, but it does work on ppc64 and x86_64 at least.
#   
#   One tricky area which may need to be revisited is the question of how
#   to handle the handles which we pass back to userspace to identify
#   mappings.  These handles are generated in the ADDMAP ioctl and then
#   passed in as the offset value to mmap.  However, offset values for
#   mmap seem to be generated in other ways as well, particularly for AGP
#   mappings.
#   
#   The approach I have ended up with is to generate a fake 32-bit handle
#   only for _DRM_SHM mappings.  The handles for other mappings (AGP, REG,
#   FB) are physical addresses which are already limited to 32 bits, and
#   generating fake handles for them created all sorts of problems in the
#   mmap/nopage code.
#   
#   
#   From: Paul Mackerras <paulus@samba.org>
#   Signed-off-by: Dave Airlie <airlied@linux.ie>
# 
# drivers/char/drm/drm_drv.c
#   2005/03/03 21:55:49+11:00 airlied@starflyer.(none) +7 -0
#   drm: 32/64-bit DRM ioctl compatibility patch
#   
#   The patch is against a 2.6.11 kernel tree.  I am running this with a
#   32-bit X server (compiled up from X.org CVS as of a couple of weeks
#   ago) and 32-bit DRI libraries and clients.  All the userland stuff is
#   identical to what I am using under a 32-bit kernel on my G4 powerbook
#   (which is a 32-bit machine of course).  I haven't tried compiling up a
#   64-bit X server or clients yet.
#   
#   In the compatibility routines I have assumed that the kernel can
#   safely access user addresses after set_fs(KERNEL_DS).  That is, where
#   an ioctl argument structure contains pointers to other structures, and
#   those other structures are already compatible between the 32-bit and
#   64-bit ABIs (i.e. they only contain things like chars, shorts or
#   ints), I just check the address with access_ok() and then pass it
#   through to the 64-bit ioctl code.  I believe this approach may not
#   work on sparc64, but it does work on ppc64 and x86_64 at least.
#   
#   One tricky area which may need to be revisited is the question of how
#   to handle the handles which we pass back to userspace to identify
#   mappings.  These handles are generated in the ADDMAP ioctl and then
#   passed in as the offset value to mmap.  However, offset values for
#   mmap seem to be generated in other ways as well, particularly for AGP
#   mappings.
#   
#   The approach I have ended up with is to generate a fake 32-bit handle
#   only for _DRM_SHM mappings.  The handles for other mappings (AGP, REG,
#   FB) are physical addresses which are already limited to 32 bits, and
#   generating fake handles for them created all sorts of problems in the
#   mmap/nopage code.
#   
#   
#   From: Paul Mackerras <paulus@samba.org>
#   Signed-off-by: Dave Airlie <airlied@linux.ie>
# 
# drivers/char/drm/drmP.h
#   2005/03/03 21:55:49+11:00 airlied@starflyer.(none) +10 -0
#   drm: 32/64-bit DRM ioctl compatibility patch
#   
#   The patch is against a 2.6.11 kernel tree.  I am running this with a
#   32-bit X server (compiled up from X.org CVS as of a couple of weeks
#   ago) and 32-bit DRI libraries and clients.  All the userland stuff is
#   identical to what I am using under a 32-bit kernel on my G4 powerbook
#   (which is a 32-bit machine of course).  I haven't tried compiling up a
#   64-bit X server or clients yet.
#   
#   In the compatibility routines I have assumed that the kernel can
#   safely access user addresses after set_fs(KERNEL_DS).  That is, where
#   an ioctl argument structure contains pointers to other structures, and
#   those other structures are already compatible between the 32-bit and
#   64-bit ABIs (i.e. they only contain things like chars, shorts or
#   ints), I just check the address with access_ok() and then pass it
#   through to the 64-bit ioctl code.  I believe this approach may not
#   work on sparc64, but it does work on ppc64 and x86_64 at least.
#   
#   One tricky area which may need to be revisited is the question of how
#   to handle the handles which we pass back to userspace to identify
#   mappings.  These handles are generated in the ADDMAP ioctl and then
#   passed in as the offset value to mmap.  However, offset values for
#   mmap seem to be generated in other ways as well, particularly for AGP
#   mappings.
#   
#   The approach I have ended up with is to generate a fake 32-bit handle
#   only for _DRM_SHM mappings.  The handles for other mappings (AGP, REG,
#   FB) are physical addresses which are already limited to 32 bits, and
#   generating fake handles for them created all sorts of problems in the
#   mmap/nopage code.
#   
#   
#   From: Paul Mackerras <paulus@samba.org>
#   Signed-off-by: Dave Airlie <airlied@linux.ie>
# 
# drivers/char/drm/Makefile
#   2005/03/03 21:55:49+11:00 airlied@starflyer.(none) +5 -0
#   drm: 32/64-bit DRM ioctl compatibility patch
#   
#   The patch is against a 2.6.11 kernel tree.  I am running this with a
#   32-bit X server (compiled up from X.org CVS as of a couple of weeks
#   ago) and 32-bit DRI libraries and clients.  All the userland stuff is
#   identical to what I am using under a 32-bit kernel on my G4 powerbook
#   (which is a 32-bit machine of course).  I haven't tried compiling up a
#   64-bit X server or clients yet.
#   
#   In the compatibility routines I have assumed that the kernel can
#   safely access user addresses after set_fs(KERNEL_DS).  That is, where
#   an ioctl argument structure contains pointers to other structures, and
#   those other structures are already compatible between the 32-bit and
#   64-bit ABIs (i.e. they only contain things like chars, shorts or
#   ints), I just check the address with access_ok() and then pass it
#   through to the 64-bit ioctl code.  I believe this approach may not
#   work on sparc64, but it does work on ppc64 and x86_64 at least.
#   
#   One tricky area which may need to be revisited is the question of how
#   to handle the handles which we pass back to userspace to identify
#   mappings.  These handles are generated in the ADDMAP ioctl and then
#   passed in as the offset value to mmap.  However, offset values for
#   mmap seem to be generated in other ways as well, particularly for AGP
#   mappings.
#   
#   The approach I have ended up with is to generate a fake 32-bit handle
#   only for _DRM_SHM mappings.  The handles for other mappings (AGP, REG,
#   FB) are physical addresses which are already limited to 32 bits, and
#   generating fake handles for them created all sorts of problems in the
#   mmap/nopage code.
#   
#   
#   From: Paul Mackerras <paulus@samba.org>
#   Signed-off-by: Dave Airlie <airlied@linux.ie>
# 
# ChangeSet
#   2005/03/03 07:20:20+11:00 airlied@starflyer.(none) 
#   drm credits/maintainers update
#   
#   Update my entry in the CREDITS file and also
#   add me to the MAINTAINERS for drm.
#   change drm to maintained not supported as no-one pays me 
#   or anyone else doing the core drm work.
#   
#   Signed-off-by: Dave Airlie <airlied@linux.ie>
# 
# MAINTAINERS
#   2005/03/03 07:20:12+11:00 airlied@starflyer.(none) +3 -1
#   drm credits/maintainers update
#   
#   Update my entry in the CREDITS file and also
#   add me to the MAINTAINERS for drm.
#   change drm to maintained not supported as no-one pays me 
#   or anyone else doing the core drm work.
#   
#   Signed-off-by: Dave Airlie <airlied@linux.ie>
# 
# CREDITS
#   2005/03/03 07:20:12+11:00 airlied@starflyer.(none) +3 -2
#   drm credits/maintainers update
#   
#   Update my entry in the CREDITS file and also
#   add me to the MAINTAINERS for drm.
#   change drm to maintained not supported as no-one pays me 
#   or anyone else doing the core drm work.
#   
#   Signed-off-by: Dave Airlie <airlied@linux.ie>
# 
diff -Nru a/CREDITS b/CREDITS
--- a/CREDITS	2005-03-07 15:15:08 -08:00
+++ b/CREDITS	2005-03-07 15:15:08 -08:00
@@ -34,8 +34,9 @@
 E: airlied@linux.ie
 W: http://www.csn.ul.ie/~airlied
 D: NFS over TCP patches
-S: University of Limerick
-S: Ireland
+D: in-kernel DRM Maintainer
+S: Longford, Ireland.
+S: Sydney, Australia.
 
 N: Tigran A. Aivazian
 E: tigran@veritas.com
diff -Nru a/MAINTAINERS b/MAINTAINERS
--- a/MAINTAINERS	2005-03-07 15:15:08 -08:00
+++ b/MAINTAINERS	2005-03-07 15:15:08 -08:00
@@ -758,8 +758,10 @@
 S:	Supported
 
 DRM DRIVERS
+P:	Dave Airlie
+M:	airlied@linux.ie
 L:	dri-devel@lists.sourceforge.net
-S:	Supported
+S:	Maintained
 
 DSCC4 DRIVER
 P:	François Romieu
diff -Nru a/drivers/char/drm/Makefile b/drivers/char/drm/Makefile
--- a/drivers/char/drm/Makefile	2005-03-07 15:15:08 -08:00
+++ b/drivers/char/drm/Makefile	2005-03-07 15:15:08 -08:00
@@ -19,6 +19,11 @@
 ffb-objs    := ffb_drv.o ffb_context.o
 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
+endif
+
 obj-$(CONFIG_DRM)	+= drm.o
 obj-$(CONFIG_DRM_GAMMA) += gamma.o
 obj-$(CONFIG_DRM_TDFX)	+= tdfx.o
diff -Nru a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h
--- a/drivers/char/drm/drmP.h	2005-03-07 15:15:08 -08:00
+++ b/drivers/char/drm/drmP.h	2005-03-07 15:15:08 -08:00
@@ -528,6 +528,9 @@
 typedef struct drm_map_list {
 	struct list_head	head;	/**< list head */
 	drm_map_t		*map;	/**< mapping */
+#ifdef CONFIG_COMPAT
+	u32			handle32;
+#endif
 } drm_map_list_t;
 
 typedef drm_map_t drm_local_map_t;
@@ -1033,6 +1036,10 @@
 		     _entry->map->offset == offset ) {
 			return _entry->map;
 		}
+#ifdef CONFIG_COMPAT
+		if (offset && _entry->map && offset == _entry->handle32)
+			return _entry->map;
+#endif
 	}
 	return NULL;
 }
@@ -1062,6 +1069,9 @@
 
 extern unsigned long drm_core_get_map_ofs(drm_map_t *map);
 extern unsigned long drm_core_get_reg_ofs(struct drm_device *dev);
+
+extern int drm_register_ioc32(void);
+extern void drm_unregister_ioc32(void);
 
 #endif /* __KERNEL__ */
 #endif
diff -Nru a/drivers/char/drm/drm_drv.c b/drivers/char/drm/drm_drv.c
--- a/drivers/char/drm/drm_drv.c	2005-03-07 15:15:08 -08:00
+++ b/drivers/char/drm/drm_drv.c	2005-03-07 15:15:08 -08:00
@@ -417,6 +417,10 @@
 		goto err_p3;
 	}
 		
+#ifdef CONFIG_COMPAT
+	drm_register_ioc32();
+#endif
+
 	DRM_INFO( "Initialized %s %d.%d.%d %s\n",
 		DRIVER_NAME,
 		DRIVER_MAJOR,
@@ -436,6 +440,9 @@
 
 static void __exit drm_core_exit (void)
 {
+#ifdef CONFIG_COMPAT
+	drm_unregister_ioc32();
+#endif
 	remove_proc_entry("dri", NULL);
 	drm_sysfs_destroy(drm_class);
 
diff -Nru a/drivers/char/drm/drm_ioc32.c b/drivers/char/drm/drm_ioc32.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/char/drm/drm_ioc32.c	2005-03-07 15:15:08 -08:00
@@ -0,0 +1,1234 @@
+/**
+ * \file drm_ioc32.c
+ *
+ * 32-bit ioctl compatibility routines for the DRM.
+ *
+ * \author Paul Mackerras <paulus@samba.org>
+ *
+ * Copyright (C) Paul Mackerras 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_core.h"
+
+#define DRM_IOCTL_VERSION32		DRM_IOWR(0x00, drm_version32_t)
+#define DRM_IOCTL_GET_UNIQUE32		DRM_IOWR(0x01, drm_unique32_t)
+#define DRM_IOCTL_GET_MAP32		DRM_IOWR(0x04, drm_map32_t)
+#define DRM_IOCTL_GET_CLIENT32		DRM_IOWR(0x05, drm_client32_t)
+#define DRM_IOCTL_GET_STATS32		DRM_IOR( 0x06, drm_stats32_t)
+
+#define DRM_IOCTL_SET_UNIQUE32		DRM_IOW( 0x10, drm_unique32_t)
+#define DRM_IOCTL_ADD_MAP32		DRM_IOWR(0x15, drm_map32_t)
+#define DRM_IOCTL_ADD_BUFS32		DRM_IOWR(0x16, drm_buf_desc32_t)
+#define DRM_IOCTL_MARK_BUFS32		DRM_IOW( 0x17, drm_buf_desc32_t)
+#define DRM_IOCTL_INFO_BUFS32		DRM_IOWR(0x18, drm_buf_info32_t)
+#define DRM_IOCTL_MAP_BUFS32		DRM_IOWR(0x19, drm_buf_map32_t)
+#define DRM_IOCTL_FREE_BUFS32		DRM_IOW( 0x1a, drm_buf_free32_t)
+
+#define DRM_IOCTL_RM_MAP32		DRM_IOW( 0x1b, drm_map32_t)
+
+#define DRM_IOCTL_SET_SAREA_CTX32	DRM_IOW( 0x1c, drm_ctx_priv_map32_t)
+#define DRM_IOCTL_GET_SAREA_CTX32	DRM_IOWR(0x1d, drm_ctx_priv_map32_t)
+
+#define DRM_IOCTL_RES_CTX32		DRM_IOWR(0x26, drm_ctx_res32_t)
+#define DRM_IOCTL_DMA32			DRM_IOWR(0x29, drm_dma32_t)
+
+#define DRM_IOCTL_AGP_ENABLE32		DRM_IOW( 0x32, drm_agp_mode32_t)
+#define DRM_IOCTL_AGP_INFO32		DRM_IOR( 0x33, drm_agp_info32_t)
+#define DRM_IOCTL_AGP_ALLOC32		DRM_IOWR(0x34, drm_agp_buffer32_t)
+#define DRM_IOCTL_AGP_FREE32		DRM_IOW( 0x35, drm_agp_buffer32_t)
+#define DRM_IOCTL_AGP_BIND32		DRM_IOW( 0x36, drm_agp_binding32_t)
+#define DRM_IOCTL_AGP_UNBIND32		DRM_IOW( 0x37, drm_agp_binding32_t)
+
+#define DRM_IOCTL_SG_ALLOC32		DRM_IOW( 0x38, drm_scatter_gather32_t)
+#define DRM_IOCTL_SG_FREE32		DRM_IOW( 0x39, drm_scatter_gather32_t)
+
+#define DRM_IOCTL_WAIT_VBLANK32		DRM_IOWR(0x3a, drm_wait_vblank32_t)
+
+typedef struct drm_version_32 {
+	int	version_major;	  /**< Major version */
+	int	version_minor;	  /**< Minor version */
+	int	version_patchlevel;/**< Patch level */
+	u32	name_len;	  /**< Length of name buffer */
+	u32	name;		  /**< Name of driver */
+	u32	date_len;	  /**< Length of date buffer */
+	u32	date;		  /**< User-space buffer to hold date */
+	u32	desc_len;	  /**< Length of desc buffer */
+	u32	desc;		  /**< User-space buffer to hold desc */
+} drm_version32_t;
+
+static int compat_drm_version(unsigned int fd, unsigned int cmd, 
+			      unsigned long arg, struct file *file)
+{
+	drm_version32_t v32;
+	drm_version_t version;
+	mm_segment_t oldfs;
+	int err;
+
+	if (copy_from_user(&v32, (void __user *) arg, sizeof(v32)))
+		return -EFAULT;
+	version.name_len = v32.name_len;
+	version.name = (void __user *)(unsigned long)v32.name;
+	version.date_len = v32.date_len;
+	version.date = (void __user *)(unsigned long)v32.date;
+	version.desc_len = v32.desc_len;
+	version.desc = (void __user *)(unsigned long)v32.desc;
+
+	if (!access_ok(VERIFY_WRITE, version.name, version.name_len)
+	    || !access_ok(VERIFY_WRITE, version.date, version.date_len)
+	    || !access_ok(VERIFY_WRITE, version.desc, version.desc_len))
+		return -EFAULT;
+
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	err = drm_ioctl(file->f_dentry->d_inode, file,
+			DRM_IOCTL_VERSION, (unsigned long) &version);
+	set_fs(oldfs);
+	if (err)
+		return err;
+
+	v32.version_major = version.version_major;
+	v32.version_minor = version.version_minor;
+	v32.version_patchlevel = version.version_patchlevel;
+	v32.name_len = version.name_len;
+	v32.date_len = version.date_len;
+	v32.desc_len = version.desc_len;
+
+	if (copy_to_user((void __user *) arg, &v32, sizeof(v32)))
+		return -EFAULT;
+	return 0;
+}
+
+typedef struct drm_unique32 {
+	u32 unique_len;	/**< Length of unique */
+	u32 unique;	/**< Unique name for driver instantiation */
+} drm_unique32_t;
+
+static int compat_drm_getunique(unsigned int fd, unsigned int cmd, 
+				unsigned long arg, struct file *file)
+{
+	drm_unique32_t u32;
+	drm_unique_t u;
+	mm_segment_t oldfs;
+	int err;
+
+	if (copy_from_user(&u32, (void __user *) arg, sizeof(u32)))
+		return -EFAULT;
+	u.unique_len = u32.unique_len;
+	u.unique = (void __user *)(unsigned long) u32.unique;
+	if (!access_ok(VERIFY_WRITE, u.unique, u.unique_len))
+		return -EFAULT;
+
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	err = drm_ioctl(file->f_dentry->d_inode, file,
+			DRM_IOCTL_GET_UNIQUE, (unsigned long) &u);
+	set_fs(oldfs);
+	if (err)
+		return err;
+
+	u32.unique_len = u.unique_len;
+	if (copy_to_user((void __user *) arg, &u32, sizeof(u32)))
+		return -EFAULT;
+	return 0;
+}
+
+static int compat_drm_setunique(unsigned int fd, unsigned int cmd, 
+				unsigned long arg, struct file *file)
+{
+	drm_unique32_t u32;
+	drm_unique_t u;
+	int err;
+	mm_segment_t oldfs;
+
+	if (copy_from_user(&u32, (void __user *) arg, sizeof(u32)))
+		return -EFAULT;
+
+	u.unique_len = u32.unique_len;
+	u.unique = (void __user *)(unsigned long) u32.unique;
+	if (!access_ok(VERIFY_READ, u.unique, u.unique_len))
+		return -EFAULT;
+
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	err = drm_ioctl(file->f_dentry->d_inode, file,
+			DRM_IOCTL_SET_UNIQUE, (unsigned long) &u);
+	set_fs(oldfs);
+
+	return err;
+}
+
+typedef struct drm_map32 {
+	u32	offset;	 	/**< Requested physical address (0 for SAREA)*/
+	u32	size;	 	/**< Requested physical size (bytes) */
+	drm_map_type_t	type;	/**< Type of memory to map */
+	drm_map_flags_t flags;	/**< Flags */
+	u32	handle;		/**< User-space: "Handle" to pass to mmap() */
+	int	mtrr;		/**< MTRR slot used */
+} drm_map32_t;
+
+static int compat_drm_getmap(unsigned int fd, unsigned int cmd, 
+			     unsigned long arg, struct file *file)
+{
+	drm_map32_t __user *argp = (void __user *)arg;
+	drm_map32_t m32;
+	drm_map_t map;
+	int idx, err;
+	mm_segment_t oldfs;
+
+	if (get_user(idx, &argp->offset))
+		return -EFAULT;
+	map.offset = idx;
+
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	err = drm_ioctl(file->f_dentry->d_inode, file,
+			DRM_IOCTL_GET_MAP, (unsigned long) &map);
+	set_fs(oldfs);
+
+	if (err)
+		return err;
+
+	m32.offset = map.offset;
+	m32.size   = map.size;
+	m32.type   = map.type;
+	m32.flags  = map.flags;
+	m32.handle = (unsigned long) map.handle;
+	m32.mtrr   = map.mtrr;
+
+	if (copy_to_user(argp, &m32, sizeof(m32)))
+		return -EFAULT;
+	return 0;
+
+}
+
+static unsigned int map32_count = 16;
+
+static int compat_drm_addmap(unsigned int fd, unsigned int cmd, 
+			     unsigned long arg, struct file *file)
+{
+	drm_file_t *priv = file->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_map32_t __user *argp = (void __user *)arg;
+	drm_map32_t m32;
+	drm_map_t map;
+	drm_map_list_t *list;
+	int err;
+	mm_segment_t oldfs;
+
+	if (copy_from_user(&m32, argp, sizeof(m32)))
+		return -EFAULT;
+
+	map.offset = m32.offset;
+	map.size   = m32.size;
+	map.type   = m32.type;
+	map.flags  = m32.flags;
+
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	err = drm_ioctl(file->f_dentry->d_inode, file,
+			DRM_IOCTL_ADD_MAP, (unsigned long) &map);
+	set_fs(oldfs);
+	if (err)
+		return err;
+
+	m32.offset = map.offset;
+	m32.mtrr   = map.mtrr;
+
+	if (map.type == _DRM_SHM) {
+		/* allocate a new 32-bit handle for this mapping */
+		/* but only for shared memory mappings */
+		down(&dev->struct_sem);
+		list_for_each_entry(list, &dev->maplist->head, head) {
+			if (list->map && list->map->type == map.type
+			    && list->map->offset == map.offset) {
+				list->handle32 = ++map32_count << PAGE_SHIFT;
+				m32.handle = list->handle32;
+				break;
+			}
+		}
+		up(&dev->struct_sem);
+	} else {
+		m32.handle = (unsigned long) map.handle;
+		if (m32.handle != (unsigned long) map.handle)
+			printk(KERN_ERR "compat_drm_addmap truncated handle"
+			       " %p for type %d offset %lx\n", map.handle,
+			       map.type, map.offset);
+	}
+
+	if (copy_to_user(argp, &m32, sizeof(m32)))
+		return -EFAULT;
+
+	return 0;
+}
+
+static void map_handle32(drm_device_t *dev, u32 handle, void **hret)
+{
+	drm_map_list_t *list;
+
+	*hret = (void *)(unsigned long) handle;
+	if (handle == 0)
+		return;
+	down(&dev->struct_sem);
+	list_for_each_entry(list, &dev->maplist->head, head) {
+		if (list->map && handle == list->handle32) {
+			*hret = list->map->handle;
+			break;
+		}
+	}
+	up(&dev->struct_sem);
+}
+
+static void map_handle_to32(drm_device_t *dev, void *handle, u32 *hret)
+{
+	drm_map_list_t *list;
+
+	*hret = (unsigned long) handle;
+	down(&dev->struct_sem);
+	list_for_each_entry(list, &dev->maplist->head, head) {
+		if (list->map && handle == list->map->handle) {
+			if (list->handle32)
+				*hret = list->handle32;
+			break;
+		}
+	}
+	up(&dev->struct_sem);
+}
+
+static int compat_drm_rmmap(unsigned int fd, unsigned int cmd, 
+			    unsigned long arg, struct file *file)
+{
+	drm_file_t *priv = file->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_map32_t __user *argp = (void __user *)arg;
+	drm_map_t map;
+	u32 handle;
+	int err;
+	mm_segment_t oldfs;
+
+	if (get_user(handle, &argp->handle))
+		return -EFAULT;
+
+	map_handle32(dev, handle, &map.handle);
+
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	err = drm_ioctl(file->f_dentry->d_inode, file,
+			DRM_IOCTL_RM_MAP, (unsigned long) &map);
+	set_fs(oldfs);
+
+	return err;
+}
+
+typedef struct drm_client32 {
+	int	idx;	/**< Which client desired? */
+	int	auth;	/**< Is client authenticated? */
+	u32	pid;	/**< Process ID */
+	u32	uid;	/**< User ID */
+	u32	magic;	/**< Magic */
+	u32	iocs;	/**< Ioctl count */
+} drm_client32_t;
+
+static int compat_drm_getclient(unsigned int fd, unsigned int cmd, 
+				unsigned long arg, struct file *file)
+{
+	drm_client32_t c32;
+	drm_client32_t __user *argp = (void __user *)arg;
+	drm_client_t client;
+	int idx, err;
+	mm_segment_t oldfs;
+
+	if (get_user(idx, &argp->idx))
+		return -EFAULT;
+
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	client.idx = idx;
+	err = drm_ioctl(file->f_dentry->d_inode, file,
+			DRM_IOCTL_GET_CLIENT, (unsigned long) &client);
+	set_fs(oldfs);
+
+	if (err)
+		return err;
+
+	c32.auth  = client.auth;
+	c32.pid   = client.pid;
+	c32.uid   = client.uid;
+	c32.magic = client.magic;
+	c32.iocs  = client.iocs;
+
+	if (copy_to_user(argp, &c32, sizeof(c32)))
+		return -EFAULT;
+	return 0;
+}
+
+typedef struct drm_stats32 {
+	u32 count;
+	struct {
+		u32 value;
+		drm_stat_type_t type;
+	} data[15];
+} drm_stats32_t;
+
+static int compat_drm_getstats(unsigned int fd, unsigned int cmd, 
+			       unsigned long arg, struct file *file)
+{
+	drm_stats32_t s32;
+	drm_stats32_t __user *argp = (void __user *)arg;
+	drm_stats_t stats;
+	mm_segment_t oldfs;
+	int i, err;
+
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	err = drm_ioctl(file->f_dentry->d_inode, file,
+			DRM_IOCTL_GET_STATS, (unsigned long) &stats);
+	set_fs(oldfs);
+
+	if (err)
+		return err;
+
+	s32.count = stats.count;
+	for (i = 0; i < 15; ++i) {
+		s32.data[i].value = stats.data[i].value;
+		s32.data[i].type = stats.data[i].type;
+	}
+
+	if (copy_to_user(argp, &s32, sizeof(s32)))
+		return -EFAULT;
+	return 0;
+}
+
+typedef struct drm_buf_desc32 {
+	int	      count;	 /**< Number of buffers of this size */
+	int	      size;	 /**< Size in bytes */
+	int	      low_mark;	 /**< Low water mark */
+	int	      high_mark; /**< High water mark */
+	int	      flags;
+	u32	      agp_start; /**< Start address in the AGP aperture */
+} drm_buf_desc32_t;
+
+static int compat_drm_addbufs(unsigned int fd, unsigned int cmd, 
+			      unsigned long arg, struct file *file)
+{
+	drm_buf_desc32_t b32;
+	drm_buf_desc32_t __user *argp = (void __user *)arg;
+	drm_buf_desc_t buf;
+	mm_segment_t oldfs;
+	int err;
+
+	if (copy_from_user(&b32, argp, sizeof(b32)))
+		return -EFAULT;
+	buf.count = b32.count;
+	buf.size = b32.size;
+	buf.low_mark = b32.low_mark;
+	buf.high_mark = b32.high_mark;
+	buf.flags = b32.flags;
+	buf.agp_start = b32.agp_start;
+
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	err = drm_ioctl(file->f_dentry->d_inode, file,
+			DRM_IOCTL_ADD_BUFS, (unsigned long) &buf);
+	set_fs(oldfs);
+	if (err)
+		return err;
+
+	b32.count = buf.count;
+	b32.size = buf.size;
+	b32.low_mark = buf.low_mark;
+	b32.high_mark = buf.high_mark;
+	b32.flags = buf.flags;
+	b32.agp_start = buf.agp_start;
+	if (copy_to_user(argp, &b32, sizeof(b32)))
+		return -EFAULT;
+
+	return 0;
+}
+
+static int compat_drm_markbufs(unsigned int fd, unsigned int cmd, 
+			       unsigned long arg, struct file *file)
+{
+	drm_buf_desc32_t b32;
+	drm_buf_desc32_t __user *argp = (void __user *)arg;
+	drm_buf_desc_t buf;
+	mm_segment_t oldfs;
+	int err;
+
+	if (copy_from_user(&b32, argp, sizeof(b32)))
+		return -EFAULT;
+	buf.size = b32.size;
+	buf.low_mark = b32.low_mark;
+	buf.high_mark = b32.high_mark;
+
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	err = drm_ioctl(file->f_dentry->d_inode, file,
+			DRM_IOCTL_MARK_BUFS, (unsigned long) &buf);
+	set_fs(oldfs);
+
+	return err;
+}
+
+typedef struct drm_buf_info32 {
+	int	       count;	/**< Entries in list */
+	u32	       list;
+} drm_buf_info32_t;
+
+static int compat_drm_infobufs(unsigned int fd, unsigned int cmd, 
+			       unsigned long arg, struct file *file)
+{
+	drm_buf_info32_t req32;
+	drm_buf_info32_t __user *argp = (void __user *)arg;
+	drm_buf_desc32_t __user *to;
+	drm_buf_info_t request;
+	drm_buf_desc_t *list = NULL;
+	int i, err;
+	int count;
+	mm_segment_t oldfs;
+
+	if (copy_from_user( &request, argp, sizeof(request)))
+		return -EFAULT;
+	count = req32.count;
+	to = (drm_buf_desc32_t __user *)(unsigned long) req32.list;
+
+	if (count > 0) {
+		if (count > DRM_MAX_ORDER + 2)
+			count = DRM_MAX_ORDER + 2;
+		if (!access_ok(VERIFY_WRITE, to,
+			       count * sizeof(drm_buf_desc32_t)))
+			return -EFAULT;
+		list = kmalloc(count * sizeof(drm_buf_desc_t), GFP_KERNEL);
+		if (list == NULL)
+			return -ENOMEM;
+	}
+
+	request.count = count;
+	request.list = (drm_buf_desc_t __user *) list;
+
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	err = drm_ioctl(file->f_dentry->d_inode, file,
+			DRM_IOCTL_INFO_BUFS, (unsigned long) &request);
+	set_fs(oldfs);
+	if (err)
+		goto out;
+
+	err = -EFAULT;
+	if (count >= request.count) {
+		for (i = 0; i < request.count; ++i) {
+			if (__put_user(list[i].count, &to->count) ||
+			    __put_user(list[i].size, &to->size) ||
+			    __put_user(list[i].low_mark, &to->low_mark) ||
+			    __put_user(list[i].high_mark, &to->high_mark))
+				goto out;
+			++to;
+		}
+	}
+
+	request.count = count;
+	if (copy_to_user(argp, &request, sizeof(request)))
+		goto out;
+	err = 0;
+
+ out:
+	kfree(list);
+	return err;
+}
+
+typedef struct drm_buf_pub32 {
+	int	idx;		/**< Index into the master buffer list */
+	int	total;		/**< Buffer size */
+	int	used;		/**< Amount of buffer in use (for DMA) */
+	u32	address;	/**< Address of buffer */
+} drm_buf_pub32_t;
+
+typedef struct drm_buf_map32 {
+	int	count;		/**< Length of the buffer list */
+	u32	virtual;	/**< Mmap'd area in user-virtual */
+	u32	list;		/**< Buffer information */
+} drm_buf_map32_t;
+
+static int compat_drm_mapbufs(unsigned int fd, unsigned int cmd, 
+			      unsigned long arg, struct file *file)
+{
+	drm_buf_map32_t req32;
+	drm_buf_pub32_t __user *list32;
+	drm_buf_map_t request;
+	drm_buf_pub_t *list;
+	drm_buf_map32_t __user *argp = (void __user *)arg;
+	mm_segment_t oldfs;
+	int i, err;
+
+	if (copy_from_user(&req32, argp, sizeof(req32)))
+		return -EFAULT;
+
+	if (req32.count < 0 || req32.count > 100)
+		return -EINVAL;		/* somewhat arbitrary limit */
+	list = kmalloc(req32.count * sizeof(drm_buf_pub_t), GFP_KERNEL);
+	if (list == NULL)
+		return -ENOMEM;
+
+	request.count = req32.count;
+	request.list = list;
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	err = drm_ioctl(file->f_dentry->d_inode, file,
+			DRM_IOCTL_MAP_BUFS, (unsigned long) &request);
+	set_fs(oldfs);
+	if (err)
+		goto out;
+
+	if (req32.count >= request.count) {
+		list32 = (void __user *)(unsigned long)req32.list;
+		for (i = 0; i < request.count; ++i) {
+			err = -EFAULT;
+			if (put_user(list[i].idx, &list32[i].idx) ||
+			    put_user(list[i].total, &list32[i].total) ||
+			    put_user(list[i].used, &list32[i].used) ||
+			    put_user((unsigned long)list[i].address,
+				     &list32[i].address))
+				goto out;
+		}
+	}
+	req32.count = request.count;
+	req32.virtual = (unsigned long) request.virtual;
+
+	err = -EFAULT;
+	if (copy_to_user(argp, &req32, sizeof(req32)))
+		goto out;
+	err = 0;
+
+ out:
+	kfree(list);
+	return err;
+}
+
+typedef struct drm_buf_free32 {
+	int	count;
+	u32	list;
+} drm_buf_free32_t;
+
+static int compat_drm_freebufs(unsigned int fd, unsigned int cmd, 
+			       unsigned long arg, struct file *file)
+{
+	drm_buf_free32_t req32;
+	drm_buf_free_t request;
+	drm_buf_free32_t __user *argp = (void __user *)arg;
+	mm_segment_t oldfs;
+	int err;
+
+	if (copy_from_user(&req32, argp, sizeof(req32)))
+		return -EFAULT;
+
+	request.count = req32.count;
+	request.list = (int __user *)(unsigned long) req32.list;
+	if (!access_ok(VERIFY_WRITE, request.list, request.count))
+		return -EFAULT;
+
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	err = drm_ioctl(file->f_dentry->d_inode, file,
+			DRM_IOCTL_FREE_BUFS, (unsigned long) &request);
+	set_fs(oldfs);
+
+	return err;
+}
+
+typedef struct drm_ctx_priv_map32 {
+	unsigned int	ctx_id;  /**< Context requesting private mapping */
+	u32		handle; /**< Handle of map */
+} drm_ctx_priv_map32_t;
+
+static int compat_drm_setsareactx(unsigned int fd, unsigned int cmd, 
+				  unsigned long arg, struct file *file)
+{
+	drm_file_t *priv = file->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_ctx_priv_map32_t req32;
+	drm_ctx_priv_map_t request;
+	drm_ctx_priv_map32_t __user *argp = (void __user *)arg;
+	int err;
+	mm_segment_t oldfs;
+
+	if (copy_from_user(&req32, argp, sizeof(req32)))
+		return -EFAULT;
+	request.ctx_id = req32.ctx_id;
+	map_handle32(dev, req32.handle, &request.handle);
+
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	err = drm_ioctl(file->f_dentry->d_inode, file,
+			DRM_IOCTL_SET_SAREA_CTX, (unsigned long) &request);
+	set_fs(oldfs);
+
+	return err;
+}
+
+static int compat_drm_getsareactx(unsigned int fd, unsigned int cmd, 
+				  unsigned long arg, struct file *file)
+{
+	drm_file_t *priv = file->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_ctx_priv_map32_t req32;
+	drm_ctx_priv_map_t request;
+	drm_ctx_priv_map32_t __user *argp = (void __user *)arg;
+	int err;
+	mm_segment_t oldfs;
+
+	if (copy_from_user(&req32, argp, sizeof(req32)))
+		return -EFAULT;
+	request.ctx_id = req32.ctx_id;
+
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	err = drm_ioctl(file->f_dentry->d_inode, file,
+			DRM_IOCTL_GET_SAREA_CTX, (unsigned long) &request);
+	set_fs(oldfs);
+	if (err)
+		return err;
+
+	map_handle_to32(dev, request.handle, &req32.handle);
+
+	if (copy_to_user(argp, &req32, sizeof(req32)))
+		return -EFAULT;
+
+	return 0;
+}
+
+typedef struct drm_ctx_res32 {
+	int	count;
+	u32	contexts;
+} drm_ctx_res32_t;
+
+static int compat_drm_resctx(unsigned int fd, unsigned int cmd, 
+			     unsigned long arg, struct file *file)
+{
+	drm_ctx_res32_t res32;
+	drm_ctx_res_t res;
+	int err;
+	mm_segment_t oldfs;
+
+	if (copy_from_user(&res32, (void __user *)arg, sizeof(res32)))
+		return -EFAULT;
+
+	res.count = res32.count;
+	res.contexts = (drm_ctx_t __user *)(unsigned long) res32.contexts;
+	if (!access_ok(VERIFY_WRITE, res.contexts,
+		       res.count * sizeof(drm_ctx_t)))
+		return -EFAULT;
+
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	err = drm_ioctl(file->f_dentry->d_inode, file,
+			DRM_IOCTL_RES_CTX, (unsigned long) &res);
+	set_fs(oldfs);
+	if (err)
+		return err;
+
+	res32.count = res.count;
+	if (copy_to_user((void __user *)arg, &res32, sizeof(res32)))
+		return -EFAULT;
+
+	return 0;
+}
+
+typedef struct drm_dma32 {
+	int	context;	  /**< Context handle */
+	int	send_count;	  /**< Number of buffers to send */
+	u32	send_indices;	  /**< List of handles to buffers */
+	u32	send_sizes;	  /**< Lengths of data to send */
+	drm_dma_flags_t flags;		  /**< Flags */
+	int	request_count;	  /**< Number of buffers requested */
+	int	request_size;	  /**< Desired size for buffers */
+	u32	request_indices;  /**< Buffer information */
+	u32	request_sizes;
+	int	granted_count;	  /**< Number of buffers granted */
+} drm_dma32_t;
+
+static int compat_drm_dma(unsigned int fd, unsigned int cmd, 
+			  unsigned long arg, struct file *file)
+{
+	drm_dma32_t d32;
+	drm_dma32_t __user *argp = (void __user *) arg;
+	drm_dma_t d;
+	int err;
+	mm_segment_t oldfs;
+
+	if (copy_from_user(&d32, argp, sizeof(d32)))
+		return -EFAULT;
+
+	d.context = d32.context;
+	d.send_count = d32.send_count;
+	d.send_indices = (int __user *)(unsigned long) d32.send_indices;
+	d.send_sizes = (int __user *)(unsigned long) d32.send_sizes;
+	d.flags = d32.flags;
+	d.request_count = d32.request_count;
+	d.request_size = d32.request_size;
+	d.request_indices = (int __user *)(unsigned long) d32.request_indices;
+	d.request_sizes = (int __user *)(unsigned long) d32.request_sizes;
+
+	if (d.send_count) {
+		size_t nb = d.send_count * sizeof(int);
+		if (!access_ok(VERIFY_READ, d.send_indices, nb)
+		    || !access_ok(VERIFY_READ, d.send_sizes, nb))
+			return -EFAULT;
+	}
+	if (d.request_count) {
+		size_t nb = d.request_count * sizeof(int);
+		if (!access_ok(VERIFY_WRITE, d.request_indices, nb)
+		    || !access_ok(VERIFY_WRITE, d.request_sizes, nb))
+			return -EFAULT;
+	}
+
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	err = drm_ioctl(file->f_dentry->d_inode, file,
+			DRM_IOCTL_DMA, (unsigned long) &d);
+	set_fs(oldfs);
+	if (err)
+		return err;
+
+	d32.request_size = d.request_size;
+	d32.granted_count = d.granted_count;
+
+	if (copy_to_user(argp, &d32, sizeof(d32)))
+		return -EFAULT;
+	return 0;
+}
+
+typedef struct drm_agp_mode32 {
+	u32 mode;	/**< AGP mode */
+} drm_agp_mode32_t;
+
+static int compat_drm_agp_enable(unsigned int fd, unsigned int cmd, 
+				 unsigned long arg, struct file *file)
+{
+	drm_agp_mode32_t __user *argp = (void __user *)arg;
+	drm_agp_mode32_t m32;
+	drm_agp_mode_t mode;
+	mm_segment_t oldfs;
+	int err;
+
+	if (copy_from_user(&m32, argp, sizeof(m32)))
+		return -EFAULT;
+	mode.mode = m32.mode;
+
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	err = drm_ioctl(file->f_dentry->d_inode, file,
+			DRM_IOCTL_AGP_ENABLE, (unsigned long) &mode);
+	set_fs(oldfs);
+
+	return err;
+}
+
+typedef struct drm_agp_info32 {
+	int       agp_version_major;
+	int       agp_version_minor;
+	u32	  mode;
+	u32	  aperture_base;  /* physical address */
+	u32	  aperture_size;  /* bytes */
+	u32	  memory_allowed; /* bytes */
+	u32	  memory_used;
+
+				/* PCI information */
+	unsigned short id_vendor;
+	unsigned short id_device;
+} drm_agp_info32_t;
+
+static int compat_drm_agp_info(unsigned int fd, unsigned int cmd, 
+			       unsigned long arg, struct file *file)
+{
+	drm_agp_info32_t __user *argp = (void __user *)arg;
+	drm_agp_info32_t i32;
+	drm_agp_info_t info;
+	mm_segment_t oldfs;
+	int err;
+
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	err = drm_ioctl(file->f_dentry->d_inode, file,
+			DRM_IOCTL_AGP_INFO, (unsigned long) &info);
+	set_fs(oldfs);
+
+	if (err)
+		return err;
+
+	i32.agp_version_major = info.agp_version_major;
+	i32.agp_version_minor = info.agp_version_minor;
+	i32.mode = info.mode;
+	i32.aperture_base = info.aperture_base;
+	i32.aperture_size = info.aperture_size;
+	i32.memory_allowed = info.memory_allowed;
+	i32.memory_used = info.memory_used;
+	i32.id_vendor = info.id_vendor;
+	i32.id_device = info.id_device;
+
+	if (copy_to_user(argp, &i32, sizeof(i32)))
+		return -EFAULT;
+
+	return 0;
+}
+
+typedef struct drm_agp_buffer32 {
+	u32 size;	/**< In bytes -- will round to page boundary */
+	u32 handle;	/**< Used for binding / unbinding */
+	u32 type;	/**< Type of memory to allocate */
+        u32 physical;	/**< Physical used by i810 */
+} drm_agp_buffer32_t;
+
+static int compat_drm_agp_alloc(unsigned int fd, unsigned int cmd, 
+				unsigned long arg, struct file *file)
+{
+	drm_agp_buffer32_t __user *argp = (void __user *)arg;
+	drm_agp_buffer32_t req32;
+	drm_agp_buffer_t request;
+	mm_segment_t oldfs;
+	int err;
+
+	if (copy_from_user(&req32, argp, sizeof(req32)))
+		return -EFAULT;
+	request.size = req32.size;
+	request.type = req32.type;
+
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	err = drm_ioctl(file->f_dentry->d_inode, file,
+			DRM_IOCTL_AGP_ALLOC, (unsigned long) &request);
+	set_fs(oldfs);
+
+	if (err)
+		return err;
+
+	req32.handle = request.handle;
+	req32.physical = request.physical;
+	if (copy_to_user(argp, &req32, sizeof(req32))) {
+		drm_ioctl(file->f_dentry->d_inode, file,
+			  DRM_IOCTL_AGP_FREE, (unsigned long) &request);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int compat_drm_agp_free(unsigned int fd, unsigned int cmd, 
+			       unsigned long arg, struct file *file)
+{
+	drm_agp_buffer32_t __user *argp = (void __user *)arg;
+	drm_agp_buffer32_t req32;
+	drm_agp_buffer_t request;
+	mm_segment_t oldfs;
+	int err;
+
+	if (copy_from_user(&req32, argp, sizeof(req32)))
+		return -EFAULT;
+	request.handle = req32.handle;
+
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	err = drm_ioctl(file->f_dentry->d_inode, file,
+			DRM_IOCTL_AGP_FREE, (unsigned long) &request);
+	set_fs(oldfs);
+
+	return err;
+}
+
+typedef struct drm_agp_binding32 {
+	u32 handle;	/**< From drm_agp_buffer */
+	u32 offset;	/**< In bytes -- will round to page boundary */
+} drm_agp_binding32_t;
+
+static int compat_drm_agp_bind(unsigned int fd, unsigned int cmd, 
+			       unsigned long arg, struct file *file)
+{
+	drm_agp_binding32_t __user *argp = (void __user *)arg;
+	drm_agp_binding32_t req32;
+	drm_agp_binding_t request;
+	mm_segment_t oldfs;
+	int err;
+
+	if (copy_from_user(&req32, argp, sizeof(req32)))
+		return -EFAULT;
+	request.handle = req32.handle;
+	request.offset = req32.offset;
+
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	err = drm_ioctl(file->f_dentry->d_inode, file,
+			DRM_IOCTL_AGP_BIND, (unsigned long) &request);
+	set_fs(oldfs);
+
+	return err;
+}
+
+static int compat_drm_agp_unbind(unsigned int fd, unsigned int cmd, 
+				 unsigned long arg, struct file *file)
+{
+	drm_agp_binding32_t __user *argp = (void __user *)arg;
+	drm_agp_binding32_t req32;
+	drm_agp_binding_t request;
+	mm_segment_t oldfs;
+	int err;
+
+	if (copy_from_user(&req32, argp, sizeof(req32)))
+		return -EFAULT;
+	request.handle = req32.handle;
+
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	err = drm_ioctl(file->f_dentry->d_inode, file,
+			DRM_IOCTL_AGP_UNBIND, (unsigned long) &request);
+	set_fs(oldfs);
+
+	return err;
+}
+
+typedef struct drm_scatter_gather32 {
+	u32 size;	/**< In bytes -- will round to page boundary */
+	u32 handle;	/**< Used for mapping / unmapping */
+} drm_scatter_gather32_t;
+
+static int compat_drm_sg_alloc(unsigned int fd, unsigned int cmd, 
+			       unsigned long arg, struct file *file)
+{
+	drm_scatter_gather32_t __user *argp = (void __user *)arg;
+	drm_scatter_gather32_t req32;
+	drm_scatter_gather_t request;
+	mm_segment_t oldfs;
+	int err;
+
+	if (copy_from_user(&req32, argp, sizeof(req32)))
+		return -EFAULT;
+	request.size = req32.size;
+
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	err = drm_ioctl(file->f_dentry->d_inode, file,
+			DRM_IOCTL_SG_ALLOC, (unsigned long) &request);
+	set_fs(oldfs);
+
+	if (err)
+		return err;
+
+	req32.handle = request.handle >> PAGE_SHIFT;
+	if (copy_to_user(argp, &req32, sizeof(req32)))
+		return -EFAULT;
+	return 0;
+}
+
+static int compat_drm_sg_free(unsigned int fd, unsigned int cmd, 
+			      unsigned long arg, struct file *file)
+{
+	drm_file_t *priv = file->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_scatter_gather32_t __user *argp = (void __user *)arg;
+	drm_scatter_gather32_t req32;
+	drm_scatter_gather_t request;
+	mm_segment_t oldfs;
+	int err;
+
+	if (copy_from_user(&req32, argp, sizeof(req32)))
+		return -EFAULT;
+	if (!dev->sg || req32.handle != (u32)(dev->sg->handle >> PAGE_SHIFT))
+		return -EINVAL;
+	request.handle = dev->sg->handle;
+
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	err = drm_ioctl(file->f_dentry->d_inode, file,
+			DRM_IOCTL_SG_FREE, (unsigned long) &request);
+	set_fs(oldfs);
+
+	return err;
+}
+
+struct drm_wait_vblank_request32 {
+	drm_vblank_seq_type_t type;
+	unsigned int sequence;
+	u32 signal;
+};
+
+struct drm_wait_vblank_reply32 {
+	drm_vblank_seq_type_t type;
+	unsigned int sequence;
+	s32 tval_sec;
+	s32 tval_usec;
+};
+
+typedef union drm_wait_vblank32 {
+	struct drm_wait_vblank_request32 request;
+	struct drm_wait_vblank_reply32 reply;
+} drm_wait_vblank32_t;
+
+static int compat_drm_wait_vblank(unsigned int fd, unsigned int cmd, 
+				  unsigned long arg, struct file *file)
+{
+	drm_wait_vblank32_t __user *argp = (void __user *)arg;
+	drm_wait_vblank32_t req32;
+	drm_wait_vblank_t request;
+	mm_segment_t oldfs;
+	int err;
+
+	if (copy_from_user(&req32, argp, sizeof(req32)))
+		return -EFAULT;
+	request.request.type = req32.request.type;
+	request.request.sequence = req32.request.sequence;
+	request.request.signal = req32.request.signal;
+
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	err = drm_ioctl(file->f_dentry->d_inode, file,
+			DRM_IOCTL_WAIT_VBLANK, (unsigned long) &request);
+	set_fs(oldfs);
+	if (err)
+		return err;
+
+	req32.reply.type = request.reply.type;
+	req32.reply.sequence = request.reply.sequence;
+	req32.reply.tval_sec = request.reply.tval_sec;
+	req32.reply.tval_usec = request.reply.tval_usec;
+
+	if (copy_to_user(argp, &req32, sizeof(req32)))
+		return -EFAULT;
+
+	return 0;
+}
+
+#define R	register_ioctl32_conversion
+
+int drm_register_ioc32(void)
+{
+	int err;
+
+	if ((err = R(DRM_IOCTL_VERSION32, compat_drm_version)) != 0 ||
+	    (err = R(DRM_IOCTL_GET_UNIQUE32, compat_drm_getunique)) != 0 ||
+	    (err = R(DRM_IOCTL_GET_MAGIC, NULL)) != 0 ||
+	    (err = R(DRM_IOCTL_IRQ_BUSID, NULL)) != 0 ||
+	    (err = R(DRM_IOCTL_GET_MAP32, compat_drm_getmap)) != 0 ||
+	    (err = R(DRM_IOCTL_GET_CLIENT32, compat_drm_getclient)) != 0 ||
+	    (err = R(DRM_IOCTL_GET_STATS32, compat_drm_getstats)) != 0 ||
+	    (err = R(DRM_IOCTL_SET_VERSION, NULL)) != 0 ||
+	    (err = R(DRM_IOCTL_SET_UNIQUE32, compat_drm_setunique)) != 0 ||
+	    (err = R(DRM_IOCTL_AUTH_MAGIC, NULL)) != 0 ||
+	    (err = R(DRM_IOCTL_BLOCK, NULL)) != 0 ||
+	    (err = R(DRM_IOCTL_UNBLOCK, NULL)) != 0 ||
+	    (err = R(DRM_IOCTL_CONTROL, NULL)) != 0 ||
+	    (err = R(DRM_IOCTL_ADD_MAP32, compat_drm_addmap)) != 0 ||
+	    (err = R(DRM_IOCTL_ADD_BUFS32, compat_drm_addbufs)) != 0 ||
+	    (err = R(DRM_IOCTL_MARK_BUFS32, compat_drm_markbufs)) != 0 ||
+	    (err = R(DRM_IOCTL_INFO_BUFS32, compat_drm_infobufs)) != 0 ||
+	    (err = R(DRM_IOCTL_MAP_BUFS32, compat_drm_mapbufs)) != 0 ||
+	    (err = R(DRM_IOCTL_FREE_BUFS32, compat_drm_freebufs)) != 0 ||
+	    (err = R(DRM_IOCTL_RM_MAP32, compat_drm_rmmap)) != 0 ||
+	    (err = R(DRM_IOCTL_SET_SAREA_CTX32, compat_drm_setsareactx)) != 0 ||
+	    (err = R(DRM_IOCTL_GET_SAREA_CTX32, compat_drm_getsareactx)) != 0 ||
+	    (err = R(DRM_IOCTL_ADD_CTX, NULL)) != 0 ||
+	    (err = R(DRM_IOCTL_RM_CTX, NULL)) != 0 ||
+	    (err = R(DRM_IOCTL_MOD_CTX, NULL)) != 0 ||
+	    (err = R(DRM_IOCTL_GET_CTX, NULL)) != 0 ||
+	    (err = R(DRM_IOCTL_SWITCH_CTX, NULL)) != 0 ||
+	    (err = R(DRM_IOCTL_NEW_CTX, NULL)) != 0 ||
+	    (err = R(DRM_IOCTL_RES_CTX32, compat_drm_resctx)) != 0 ||
+	    (err = R(DRM_IOCTL_ADD_DRAW, NULL)) != 0 ||
+	    (err = R(DRM_IOCTL_RM_DRAW, NULL)) != 0 ||
+	    (err = R(DRM_IOCTL_DMA32, compat_drm_dma)) != 0 ||
+	    (err = R(DRM_IOCTL_LOCK, NULL)) != 0 ||
+	    (err = R(DRM_IOCTL_UNLOCK, NULL)) != 0 ||
+	    (err = R(DRM_IOCTL_FINISH, NULL)) != 0 ||
+#if __OS_HAS_AGP
+	    (err = R(DRM_IOCTL_AGP_ACQUIRE, NULL)) != 0 ||
+	    (err = R(DRM_IOCTL_AGP_RELEASE, NULL)) != 0 ||
+	    (err = R(DRM_IOCTL_AGP_ENABLE32, compat_drm_agp_enable)) != 0 ||
+	    (err = R(DRM_IOCTL_AGP_INFO32, compat_drm_agp_info)) != 0 ||
+	    (err = R(DRM_IOCTL_AGP_ALLOC32, compat_drm_agp_alloc)) != 0 ||
+	    (err = R(DRM_IOCTL_AGP_FREE32, compat_drm_agp_free)) != 0 ||
+	    (err = R(DRM_IOCTL_AGP_BIND32, compat_drm_agp_bind)) != 0 ||
+	    (err = R(DRM_IOCTL_AGP_UNBIND32, compat_drm_agp_unbind)) != 0 ||
+#endif
+	    (err = R(DRM_IOCTL_SG_ALLOC32, compat_drm_sg_alloc)) != 0 ||
+	    (err = R(DRM_IOCTL_SG_FREE32, compat_drm_sg_free)) != 0 ||
+	    (err = R(DRM_IOCTL_WAIT_VBLANK32, compat_drm_wait_vblank)) != 0) {
+		printk(KERN_ERR "DRM: couldn't register ioctl conversions"
+		       " (error %d)\n", err);
+		return err;
+	}
+	return 0;
+}
+#undef R
+
+#define U	unregister_ioctl32_conversion
+
+void drm_unregister_ioc32(void)
+{
+	U(DRM_IOCTL_VERSION32);
+	U(DRM_IOCTL_GET_UNIQUE32);
+	U(DRM_IOCTL_GET_MAGIC);
+	U(DRM_IOCTL_IRQ_BUSID);
+	U(DRM_IOCTL_GET_MAP32);
+	U(DRM_IOCTL_GET_CLIENT32);
+	U(DRM_IOCTL_GET_STATS32);
+	U(DRM_IOCTL_SET_VERSION);
+	U(DRM_IOCTL_SET_UNIQUE32);
+	U(DRM_IOCTL_AUTH_MAGIC);
+	U(DRM_IOCTL_BLOCK);
+	U(DRM_IOCTL_UNBLOCK);
+	U(DRM_IOCTL_CONTROL);
+	U(DRM_IOCTL_ADD_MAP32);
+	U(DRM_IOCTL_ADD_BUFS32);
+	U(DRM_IOCTL_MARK_BUFS32);
+	U(DRM_IOCTL_INFO_BUFS32);
+	U(DRM_IOCTL_MAP_BUFS32);
+	U(DRM_IOCTL_FREE_BUFS32);
+	U(DRM_IOCTL_RM_MAP32);
+	U(DRM_IOCTL_SET_SAREA_CTX32);
+	U(DRM_IOCTL_GET_SAREA_CTX32);
+	U(DRM_IOCTL_ADD_CTX);
+	U(DRM_IOCTL_RM_CTX);
+	U(DRM_IOCTL_MOD_CTX);
+	U(DRM_IOCTL_GET_CTX);
+	U(DRM_IOCTL_SWITCH_CTX);
+	U(DRM_IOCTL_NEW_CTX);
+	U(DRM_IOCTL_RES_CTX32);
+	U(DRM_IOCTL_ADD_DRAW);
+	U(DRM_IOCTL_RM_DRAW);
+	U(DRM_IOCTL_DMA32);
+	U(DRM_IOCTL_LOCK);
+	U(DRM_IOCTL_UNLOCK);
+	U(DRM_IOCTL_FINISH);
+#if __OS_HAS_AGP
+	U(DRM_IOCTL_AGP_ACQUIRE);
+	U(DRM_IOCTL_AGP_RELEASE);
+	U(DRM_IOCTL_AGP_ENABLE32);
+	U(DRM_IOCTL_AGP_INFO32);
+	U(DRM_IOCTL_AGP_ALLOC32);
+	U(DRM_IOCTL_AGP_FREE32);
+	U(DRM_IOCTL_AGP_BIND32);
+	U(DRM_IOCTL_AGP_UNBIND32);
+#endif
+	U(DRM_IOCTL_SG_ALLOC32);
+	U(DRM_IOCTL_SG_FREE32);
+	U(DRM_IOCTL_WAIT_VBLANK32);
+}
diff -Nru a/drivers/char/drm/drm_vm.c b/drivers/char/drm/drm_vm.c
--- a/drivers/char/drm/drm_vm.c	2005-03-07 15:15:08 -08:00
+++ b/drivers/char/drm/drm_vm.c	2005-03-07 15:15:08 -08:00
@@ -565,6 +565,10 @@
 		if (!map) continue;
 		off = dev->driver->get_map_ofs(map);
 		if (off == VM_OFFSET(vma)) break;
+#ifdef CONFIG_COMPAT
+		if (r_list->handle32 && r_list->handle32 == VM_OFFSET(vma))
+			break;
+#endif
 	}
 
 	if (!map || ((map->flags&_DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN)))
diff -Nru a/drivers/char/drm/radeon_drv.c b/drivers/char/drm/radeon_drv.c
--- a/drivers/char/drm/radeon_drv.c	2005-03-07 15:15:08 -08:00
+++ b/drivers/char/drm/radeon_drv.c	2005-03-07 15:15:08 -08:00
@@ -110,6 +110,9 @@
 
 static int __init radeon_init(void)
 {
+#ifdef CONFIG_COMPAT
+	radeon_register_ioc32();
+#endif
 	driver.num_ioctls = radeon_max_ioctl;
 	return drm_init(&driver);
 }
@@ -117,6 +120,9 @@
 static void __exit radeon_exit(void)
 {
 	drm_exit(&driver);
+#ifdef CONFIG_COMPAT
+	radeon_unregister_ioc32();
+#endif
 }
 
 module_init(radeon_init);
diff -Nru a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h
--- a/drivers/char/drm/radeon_drv.h	2005-03-07 15:15:08 -08:00
+++ b/drivers/char/drm/radeon_drv.h	2005-03-07 15:15:08 -08:00
@@ -335,6 +335,9 @@
 extern int radeon_postinit( struct drm_device *dev, unsigned long flags );
 extern int radeon_postcleanup( struct drm_device *dev );
 
+extern int radeon_register_ioc32(void);
+extern void radeon_unregister_ioc32(void);
+
 /* Flags for stats.boxes
  */
 #define RADEON_BOX_DMA_IDLE      0x1
diff -Nru a/drivers/char/drm/radeon_ioc32.c b/drivers/char/drm/radeon_ioc32.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/char/drm/radeon_ioc32.c	2005-03-07 15:15:08 -08:00
@@ -0,0 +1,481 @@
+/**
+ * \file radeon_ioc32.c
+ *
+ * 32-bit ioctl compatibility routines for the Radeon DRM.
+ *
+ * \author Paul Mackerras <paulus@samba.org>
+ *
+ * Copyright (C) Paul Mackerras 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 "radeon_drm.h"
+#include "radeon_drv.h"
+
+#define DRM_IOCTL_RADEON_CP_INIT32  \
+	DRM_IOW(DRM_COMMAND_BASE + DRM_RADEON_CP_INIT, drm_radeon_init32_t)
+#define DRM_IOCTL_RADEON_CLEAR32    \
+	DRM_IOW(DRM_COMMAND_BASE + DRM_RADEON_CLEAR, drm_radeon_clear32_t)
+#define DRM_IOCTL_RADEON_STIPPLE32  \
+	DRM_IOW(DRM_COMMAND_BASE + DRM_RADEON_STIPPLE, drm_radeon_stipple32_t)
+#define DRM_IOCTL_RADEON_TEXTURE32  \
+	DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_TEXTURE, drm_radeon_texture32_t)
+#define DRM_IOCTL_RADEON_VERTEX2_32 \
+	DRM_IOW(DRM_COMMAND_BASE + DRM_RADEON_VERTEX2, drm_radeon_vertex2_32_t)
+#define DRM_IOCTL_RADEON_CMDBUF32   \
+	DRM_IOW(DRM_COMMAND_BASE + DRM_RADEON_CMDBUF, drm_radeon_cmd_buffer32_t)
+#define DRM_IOCTL_RADEON_GETPARAM32 \
+	DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GETPARAM, drm_radeon_getparam32_t)
+#define DRM_IOCTL_RADEON_ALLOC32    \
+	DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_ALLOC, drm_radeon_mem_alloc32_t)
+#define DRM_IOCTL_RADEON_IRQ_EMIT32 \
+	DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_IRQ_EMIT, drm_radeon_irq_emit32_t)
+
+typedef struct drm_radeon_init32 {
+	int func;
+	u32 sarea_priv_offset;
+	int is_pci;
+	int cp_mode;
+	int gart_size;
+	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;
+
+	u32 fb_offset;
+	u32 mmio_offset;
+	u32 ring_offset;
+	u32 ring_rptr_offset;
+	u32 buffers_offset;
+	u32 gart_textures_offset;
+} drm_radeon_init32_t;
+
+static int compat_radeon_cp_init(unsigned int fd, unsigned int cmd, 
+				 unsigned long arg, struct file *file)
+{
+	drm_radeon_init32_t init32;
+	drm_radeon_init_t init;
+	int err;
+	mm_segment_t oldfs;
+
+	if (copy_from_user(&init32, (void __user *)arg, sizeof(init32)))
+		return -EFAULT;
+	init.func = init32.func;
+	init.sarea_priv_offset = init32.sarea_priv_offset;
+	init.is_pci = init32.is_pci;
+	init.cp_mode = init32.cp_mode;
+	init.gart_size = init32.gart_size;
+	init.ring_size = init32.ring_size;
+	init.usec_timeout = init32.usec_timeout;
+	init.fb_bpp = init32.fb_bpp;
+	init.front_offset = init32.front_offset;
+	init.front_pitch = init32.front_pitch;
+	init.back_offset = init32.back_offset;
+	init.back_pitch = init32.back_pitch;
+	init.depth_bpp = init32.depth_bpp;
+	init.depth_offset = init32.depth_offset;
+	init.depth_pitch = init32.depth_pitch;
+	init.fb_offset = init32.fb_offset;
+	init.mmio_offset = init32.mmio_offset;
+	init.ring_offset = init32.ring_offset;
+	init.ring_rptr_offset = init32.ring_rptr_offset;
+	init.buffers_offset = init32.buffers_offset;
+	init.gart_textures_offset = init32.gart_textures_offset;
+
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	err = drm_ioctl(file->f_dentry->d_inode, file,
+			DRM_IOCTL_RADEON_CP_INIT, (unsigned long) &init);
+	set_fs(oldfs);
+
+	return err;
+}
+
+typedef struct drm_radeon_clear32 {
+	unsigned int flags;
+	unsigned int clear_color;
+	unsigned int clear_depth;
+	unsigned int color_mask;
+	unsigned int depth_mask;   /* misnamed field:  should be stencil */
+	u32	     depth_boxes;
+} drm_radeon_clear32_t;
+
+static int compat_radeon_cp_clear(unsigned int fd, unsigned int cmd, 
+				  unsigned long arg, struct file *file)
+{
+	drm_radeon_clear32_t clr32;
+	drm_radeon_clear_t clr;
+	int err;
+	mm_segment_t oldfs;
+
+	if (copy_from_user(&clr32, (void __user *)arg, sizeof(clr32)))
+		return -EFAULT;
+	clr.flags = clr32.flags;
+	clr.clear_color = clr32.clear_color;
+	clr.clear_depth = clr32.clear_depth;
+	clr.color_mask = clr32.color_mask;
+	clr.depth_mask = clr32.depth_mask;
+	clr.depth_boxes = (void __user *)(unsigned long)clr32.depth_boxes;
+	if (!access_ok(VERIFY_READ, clr.depth_boxes,
+		    RADEON_NR_SAREA_CLIPRECTS * sizeof(drm_radeon_clear_rect_t)))
+		return -EFAULT;
+
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	err = drm_ioctl(file->f_dentry->d_inode, file,
+			DRM_IOCTL_RADEON_CLEAR, (unsigned long) &clr);
+	set_fs(oldfs);
+
+	return err;	
+}
+
+typedef struct drm_radeon_stipple32 {
+	unsigned int __user *mask;
+} drm_radeon_stipple32_t;
+
+static int compat_radeon_cp_stipple(unsigned int fd, unsigned int cmd, 
+				    unsigned long arg, struct file *file)
+{
+	drm_radeon_stipple32_t req32;
+	drm_radeon_stipple_t request;
+	int err;
+	mm_segment_t oldfs;
+
+	if (copy_from_user(&req32, (void __user *) arg, sizeof(req32)))
+		return -EFAULT;
+	request.mask = (unsigned int __user *)(unsigned long) req32.mask;
+	if (!access_ok(VERIFY_READ, request.mask, 32 * sizeof(u32)))
+		return -EFAULT;
+
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	err = drm_ioctl(file->f_dentry->d_inode, file,
+			DRM_IOCTL_RADEON_STIPPLE, (unsigned long) &request);
+	set_fs(oldfs);
+
+	return err;	
+}
+
+typedef struct drm_radeon_tex_image32 {
+	unsigned int x, y;		/* Blit coordinates */
+	unsigned int width, height;
+	u32 data;
+} drm_radeon_tex_image32_t;
+
+typedef struct drm_radeon_texture32 {
+	unsigned int offset;
+	int pitch;
+	int format;
+	int width;			/* Texture image coordinates */
+	int height;
+	u32 image;
+} drm_radeon_texture32_t;
+
+static int compat_radeon_cp_texture(unsigned int fd, unsigned int cmd, 
+				    unsigned long arg, struct file *file)
+{
+	drm_radeon_texture32_t req32;
+	drm_radeon_texture_t request;
+	drm_radeon_tex_image32_t img32;
+	drm_radeon_tex_image_t image;
+	int err;
+	mm_segment_t oldfs;
+
+	if (copy_from_user(&req32, (void __user *) arg, sizeof(req32)))
+		return -EFAULT;
+	if (req32.image == 0)
+		return -EINVAL;
+	if (copy_from_user(&img32, (void __user *)(unsigned long)req32.image,
+			   sizeof(img32)))
+		return -EFAULT;
+
+	request.offset = req32.offset;
+	request.pitch = req32.pitch;
+	request.format = req32.format;
+	request.width = req32.width;
+	request.height = req32.height;
+	request.image = &image;
+
+	image.x = img32.x;
+	image.y = img32.y;
+	image.width = img32.width;
+	image.height = img32.height;
+	image.data = (const void __user *)(unsigned long)img32.data;
+	/* XXX check this */
+	if (!access_ok(VERIFY_READ, image.data, 4 * image.width * image.height))
+		return -EFAULT;
+
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	err = drm_ioctl(file->f_dentry->d_inode, file,
+			DRM_IOCTL_RADEON_TEXTURE, (unsigned long) &request);
+	set_fs(oldfs);
+
+	return err;	
+}
+
+typedef struct drm_radeon_vertex2_32 {
+	int idx;			/* Index of vertex buffer */
+	int discard;			/* Client finished with buffer? */
+	int nr_states;
+	u32 state;
+	int nr_prims;
+	u32 prim;
+} drm_radeon_vertex2_32_t;
+
+static int compat_radeon_cp_vertex2(unsigned int fd, unsigned int cmd, 
+				    unsigned long arg, struct file *file)
+{
+	drm_radeon_vertex2_32_t req32;
+	drm_radeon_vertex2_t request;
+	int err;
+	mm_segment_t oldfs;
+
+	if (copy_from_user(&req32, (void __user *) arg, sizeof(req32)))
+		return -EFAULT;
+	request.idx = req32.idx;
+	request.discard = req32.discard;
+	request.nr_states = req32.nr_states;
+	request.state = (void __user *)(unsigned long)req32.state;
+	request.nr_prims = req32.nr_prims;
+	request.prim = (void __user *)(unsigned long)req32.prim;
+	if (!access_ok(VERIFY_READ, request.state,
+		       request.nr_states * sizeof(drm_radeon_state_t))
+	    || !access_ok(VERIFY_READ, request.prim,
+			  request.nr_prims * sizeof(drm_radeon_prim_t)))
+		return -EFAULT;
+
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	err = drm_ioctl(file->f_dentry->d_inode, file,
+			DRM_IOCTL_RADEON_VERTEX2, (unsigned long) &request);
+	set_fs(oldfs);
+
+	return err;	
+}
+
+typedef struct drm_radeon_cmd_buffer32 {
+	int bufsz;
+	u32 buf;
+	int nbox;
+	u32 boxes;
+} drm_radeon_cmd_buffer32_t;
+
+static int compat_radeon_cp_cmdbuf(unsigned int fd, unsigned int cmd, 
+				   unsigned long arg, struct file *file)
+{
+	drm_radeon_cmd_buffer32_t req32;
+	drm_radeon_cmd_buffer_t request;
+	int err;
+	mm_segment_t oldfs;
+
+	if (copy_from_user(&req32, (void __user *) arg, sizeof(req32)))
+		return -EFAULT;
+	request.bufsz = req32.bufsz;
+	request.buf = (void __user *)(unsigned long)req32.buf;
+	request.nbox = req32.nbox;
+	request.boxes = (void __user *)(unsigned long)req32.boxes;
+	if (!access_ok(VERIFY_READ, request.buf, request.bufsz)
+	    || !access_ok(VERIFY_READ, request.boxes,
+			  request.nbox * sizeof(drm_clip_rect_t)))
+		return -EFAULT;
+
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	err = drm_ioctl(file->f_dentry->d_inode, file,
+			DRM_IOCTL_RADEON_CMDBUF, (unsigned long) &request);
+	set_fs(oldfs);
+
+	return err;	
+}
+
+typedef struct drm_radeon_getparam32 {
+	int param;
+	u32 value;
+} drm_radeon_getparam32_t;
+
+static int compat_radeon_cp_getparam(unsigned int fd, unsigned int cmd, 
+				     unsigned long arg, struct file *file)
+{
+	drm_radeon_getparam32_t req32;
+	drm_radeon_getparam_t request;
+	int err;
+	mm_segment_t oldfs;
+
+	if (copy_from_user(&req32, (void __user *) arg, sizeof(req32)))
+		return -EFAULT;
+	request.param = req32.param;
+	request.value = (void __user *)(unsigned long)req32.value;
+	if (!access_ok(VERIFY_WRITE, request.value, sizeof(int)))
+		return -EFAULT;
+
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	err = drm_ioctl(file->f_dentry->d_inode, file,
+			DRM_IOCTL_RADEON_GETPARAM, (unsigned long) &request);
+	set_fs(oldfs);
+
+	return err;	
+}
+
+typedef struct drm_radeon_mem_alloc32 {
+	int region;
+	int alignment;
+	int size;
+	u32 region_offset;	/* offset from start of fb or GART */
+} drm_radeon_mem_alloc32_t;
+
+static int compat_radeon_mem_alloc(unsigned int fd, unsigned int cmd, 
+				   unsigned long arg, struct file *file)
+{
+	drm_radeon_mem_alloc32_t req32;
+	drm_radeon_mem_alloc_t request;
+	int err;
+	mm_segment_t oldfs;
+
+	if (copy_from_user(&req32, (void __user *) arg, sizeof(req32)))
+		return -EFAULT;
+	request.region = req32.region;
+	request.alignment = req32.alignment;
+	request.size = req32.size;
+	request.region_offset = (int __user *)(unsigned long)req32.region_offset;
+	if (!access_ok(VERIFY_WRITE, request.region_offset, sizeof(int)))
+		return -EFAULT;
+
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	err = drm_ioctl(file->f_dentry->d_inode, file,
+			DRM_IOCTL_RADEON_ALLOC, (unsigned long) &request);
+	set_fs(oldfs);
+
+	return err;	
+}
+
+typedef struct drm_radeon_irq_emit32 {
+	u32 irq_seq;
+} drm_radeon_irq_emit32_t;
+
+static int compat_radeon_irq_emit(unsigned int fd, unsigned int cmd, 
+				  unsigned long arg, struct file *file)
+{
+	drm_radeon_irq_emit32_t req32;
+	drm_radeon_irq_emit_t request;
+	int err;
+	mm_segment_t oldfs;
+
+	if (copy_from_user(&req32, (void __user *) arg, sizeof(req32)))
+		return -EFAULT;
+	request.irq_seq = (int __user *)(unsigned long)req32.irq_seq;
+	if (!access_ok(VERIFY_WRITE, request.irq_seq, sizeof(int)))
+		return -EFAULT;
+
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	err = drm_ioctl(file->f_dentry->d_inode, file,
+			DRM_IOCTL_RADEON_IRQ_EMIT, (unsigned long) &request);
+	set_fs(oldfs);
+
+	return err;	
+}
+
+#define R	register_ioctl32_conversion
+
+int radeon_register_ioc32(void)
+{
+	int err;
+
+	if ((err = R(DRM_IOCTL_RADEON_CP_INIT32, compat_radeon_cp_init)) != 0 ||
+	    (err = R(DRM_IOCTL_RADEON_CP_START, NULL)) != 0 ||
+	    (err = R(DRM_IOCTL_RADEON_CP_STOP, NULL)) != 0 ||
+	    (err = R(DRM_IOCTL_RADEON_CP_RESET, NULL)) != 0 ||
+	    (err = R(DRM_IOCTL_RADEON_CP_IDLE, NULL)) != 0 ||
+	    (err = R(DRM_IOCTL_RADEON_RESET, NULL)) != 0 ||
+	    (err = R(DRM_IOCTL_RADEON_FULLSCREEN, NULL)) != 0 ||
+	    (err = R(DRM_IOCTL_RADEON_SWAP, NULL)) != 0 ||
+	    (err = R(DRM_IOCTL_RADEON_CLEAR32, compat_radeon_cp_clear)) != 0 ||
+	    (err = R(DRM_IOCTL_RADEON_VERTEX, NULL)) != 0 ||
+	    (err = R(DRM_IOCTL_RADEON_INDICES, NULL)) != 0 ||
+	    (err = R(DRM_IOCTL_RADEON_STIPPLE32, compat_radeon_cp_stipple)) != 0 ||
+	    (err = R(DRM_IOCTL_RADEON_INDIRECT, NULL)) != 0 ||
+	    (err = R(DRM_IOCTL_RADEON_TEXTURE32, compat_radeon_cp_texture)) != 0 ||
+	    (err = R(DRM_IOCTL_RADEON_VERTEX2_32, compat_radeon_cp_vertex2)) != 0 ||
+	    (err = R(DRM_IOCTL_RADEON_CMDBUF32, compat_radeon_cp_cmdbuf)) != 0 ||
+	    (err = R(DRM_IOCTL_RADEON_GETPARAM32, compat_radeon_cp_getparam)) != 0 ||
+	    (err = R(DRM_IOCTL_RADEON_FLIP, NULL)) != 0 ||
+	    (err = R(DRM_IOCTL_RADEON_ALLOC32, compat_radeon_mem_alloc)) != 0 ||
+	    (err = R(DRM_IOCTL_RADEON_FREE, NULL)) != 0 ||
+	    (err = R(DRM_IOCTL_RADEON_INIT_HEAP, NULL)) != 0 ||
+	    (err = R(DRM_IOCTL_RADEON_IRQ_EMIT32, compat_radeon_irq_emit)) != 0 ||
+	    (err = R(DRM_IOCTL_RADEON_IRQ_WAIT, NULL)) != 0 ||
+	    (err = R(DRM_IOCTL_RADEON_CP_RESUME, NULL)) != 0 ||
+	    (err = R(DRM_IOCTL_RADEON_SETPARAM, NULL)) != 0 ||
+	    (err = R(DRM_IOCTL_RADEON_SURF_ALLOC, NULL)) != 0 ||
+	    (err = R(DRM_IOCTL_RADEON_SURF_FREE, NULL)) != 0) {
+		printk(KERN_ERR "radeon DRM: couldn't register ioctl conversions"
+		       " (error %d)\n", err);
+		return err;
+	}
+	return 0;
+}
+#undef R
+
+#define U	unregister_ioctl32_conversion
+
+void radeon_unregister_ioc32(void)
+{
+	U(DRM_IOCTL_RADEON_CP_INIT32);
+	U(DRM_IOCTL_RADEON_CP_START);
+	U(DRM_IOCTL_RADEON_CP_STOP);
+	U(DRM_IOCTL_RADEON_CP_RESET);
+	U(DRM_IOCTL_RADEON_CP_IDLE);
+	U(DRM_IOCTL_RADEON_RESET);
+	U(DRM_IOCTL_RADEON_FULLSCREEN);
+	U(DRM_IOCTL_RADEON_SWAP);
+	U(DRM_IOCTL_RADEON_CLEAR32);
+	U(DRM_IOCTL_RADEON_VERTEX);
+	U(DRM_IOCTL_RADEON_INDICES);
+	U(DRM_IOCTL_RADEON_STIPPLE32);
+	U(DRM_IOCTL_RADEON_INDIRECT);
+	U(DRM_IOCTL_RADEON_TEXTURE32);
+	U(DRM_IOCTL_RADEON_VERTEX2_32);
+	U(DRM_IOCTL_RADEON_CMDBUF32);
+	U(DRM_IOCTL_RADEON_GETPARAM32);
+	U(DRM_IOCTL_RADEON_FLIP);
+	U(DRM_IOCTL_RADEON_ALLOC32);
+	U(DRM_IOCTL_RADEON_FREE);
+	U(DRM_IOCTL_RADEON_INIT_HEAP);
+	U(DRM_IOCTL_RADEON_IRQ_EMIT32);
+	U(DRM_IOCTL_RADEON_IRQ_WAIT);
+	U(DRM_IOCTL_RADEON_CP_RESUME);
+	U(DRM_IOCTL_RADEON_SETPARAM);
+	U(DRM_IOCTL_RADEON_SURF_ALLOC);
+	U(DRM_IOCTL_RADEON_SURF_FREE);
+}
+
