aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/drm
diff options
context:
space:
mode:
authorDave Airlie <airlied@starflyer.(none)>2005-06-23 07:29:18 -0400
committerDave Airlie <airlied@linux.ie>2005-06-23 07:29:18 -0400
commit9a18664506dbce5e23f3c5de7b1c5a042dd26520 (patch)
tree8f047c14a507b3f925e50f797650b15e23058a77 /drivers/char/drm
parentee98689be1b054897ff17655008c3048fe88be94 (diff)
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. This patch has been updated to use the new compatibility ioctls. From: Paul Mackerras <paulus@samba.org> Signed-off-by: Dave Airlie <airlied@linux.ie>
Diffstat (limited to 'drivers/char/drm')
-rw-r--r--drivers/char/drm/Makefile5
-rw-r--r--drivers/char/drm/drmP.h5
-rw-r--r--drivers/char/drm/drm_bufs.c25
-rw-r--r--drivers/char/drm/drm_context.c6
-rw-r--r--drivers/char/drm/drm_ioc32.c1069
-rw-r--r--drivers/char/drm/radeon_drv.c3
-rw-r--r--drivers/char/drm/radeon_drv.h3
-rw-r--r--drivers/char/drm/radeon_ioc32.c395
8 files changed, 1501 insertions, 10 deletions
diff --git a/drivers/char/drm/Makefile b/drivers/char/drm/Makefile
index 23ab26321e9a..7444dec40b94 100644
--- a/drivers/char/drm/Makefile
+++ b/drivers/char/drm/Makefile
@@ -19,6 +19,11 @@ radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o
19ffb-objs := ffb_drv.o ffb_context.o 19ffb-objs := ffb_drv.o ffb_context.o
20sis-objs := sis_drv.o sis_ds.o sis_mm.o 20sis-objs := sis_drv.o sis_ds.o sis_mm.o
21 21
22ifeq ($(CONFIG_COMPAT),y)
23drm-objs += drm_ioc32.o
24radeon-objs += radeon_ioc32.o
25endif
26
22obj-$(CONFIG_DRM) += drm.o 27obj-$(CONFIG_DRM) += drm.o
23obj-$(CONFIG_DRM_GAMMA) += gamma.o 28obj-$(CONFIG_DRM_GAMMA) += gamma.o
24obj-$(CONFIG_DRM_TDFX) += tdfx.o 29obj-$(CONFIG_DRM_TDFX) += tdfx.o
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h
index 21f4c54e1a8d..b04ddf12a0ff 100644
--- a/drivers/char/drm/drmP.h
+++ b/drivers/char/drm/drmP.h
@@ -316,6 +316,9 @@ do { \
316typedef int drm_ioctl_t( struct inode *inode, struct file *filp, 316typedef int drm_ioctl_t( struct inode *inode, struct file *filp,
317 unsigned int cmd, unsigned long arg ); 317 unsigned int cmd, unsigned long arg );
318 318
319typedef int drm_ioctl_compat_t(struct file *filp, unsigned int cmd,
320 unsigned long arg);
321
319typedef struct drm_ioctl_desc { 322typedef struct drm_ioctl_desc {
320 drm_ioctl_t *func; 323 drm_ioctl_t *func;
321 int auth_needed; 324 int auth_needed;
@@ -775,6 +778,8 @@ extern int drm_version(struct inode *inode, struct file *filp,
775 unsigned int cmd, unsigned long arg); 778 unsigned int cmd, unsigned long arg);
776extern int drm_ioctl(struct inode *inode, struct file *filp, 779extern int drm_ioctl(struct inode *inode, struct file *filp,
777 unsigned int cmd, unsigned long arg); 780 unsigned int cmd, unsigned long arg);
781extern long drm_compat_ioctl(struct file *filp,
782 unsigned int cmd, unsigned long arg);
778extern int drm_takedown(drm_device_t * dev); 783extern int drm_takedown(drm_device_t * dev);
779 784
780 /* Device support (drm_fops.h) */ 785 /* Device support (drm_fops.h) */
diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c
index 4113bcba67fe..3407380b865a 100644
--- a/drivers/char/drm/drm_bufs.c
+++ b/drivers/char/drm/drm_bufs.c
@@ -60,6 +60,15 @@ int drm_order( unsigned long size )
60} 60}
61EXPORT_SYMBOL(drm_order); 61EXPORT_SYMBOL(drm_order);
62 62
63#ifdef CONFIG_COMPAT
64/*
65 * Used to allocate 32-bit handles for _DRM_SHM regions
66 * The 0x10000000 value is chosen to be out of the way of
67 * FB/register and GART physical addresses.
68 */
69static unsigned int map32_handle = 0x10000000;
70#endif
71
63/** 72/**
64 * Ioctl to specify a range of memory that is available for mapping by a non-root process. 73 * Ioctl to specify a range of memory that is available for mapping by a non-root process.
65 * 74 *
@@ -187,16 +196,18 @@ int drm_addmap( struct inode *inode, struct file *filp,
187 196
188 down(&dev->struct_sem); 197 down(&dev->struct_sem);
189 list_add(&list->head, &dev->maplist->head); 198 list_add(&list->head, &dev->maplist->head);
199#ifdef CONFIG_COMPAT
200 /* Assign a 32-bit handle for _DRM_SHM mappings */
201 /* We do it here so that dev->struct_sem protects the increment */
202 if (map->type == _DRM_SHM)
203 map->offset = map32_handle += PAGE_SIZE;
204#endif
190 up(&dev->struct_sem); 205 up(&dev->struct_sem);
191 206
192 if ( copy_to_user( argp, map, sizeof(*map) ) ) 207 if ( copy_to_user( argp, map, sizeof(*map) ) )
193 return -EFAULT; 208 return -EFAULT;
194 if ( map->type != _DRM_SHM ) { 209 if (copy_to_user(&argp->handle, &map->offset, sizeof(map->offset)))
195 if ( copy_to_user( &argp->handle, 210 return -EFAULT;
196 &map->offset,
197 sizeof(map->offset) ) )
198 return -EFAULT;
199 }
200 return 0; 211 return 0;
201} 212}
202 213
@@ -240,7 +251,7 @@ int drm_rmmap(struct inode *inode, struct file *filp,
240 r_list = list_entry(list, drm_map_list_t, head); 251 r_list = list_entry(list, drm_map_list_t, head);
241 252
242 if(r_list->map && 253 if(r_list->map &&
243 r_list->map->handle == request.handle && 254 r_list->map->offset == (unsigned long) request.handle &&
244 r_list->map->flags & _DRM_REMOVABLE) break; 255 r_list->map->flags & _DRM_REMOVABLE) break;
245 } 256 }
246 257
diff --git a/drivers/char/drm/drm_context.c b/drivers/char/drm/drm_context.c
index f15c86c57875..fdf661f234ed 100644
--- a/drivers/char/drm/drm_context.c
+++ b/drivers/char/drm/drm_context.c
@@ -225,7 +225,7 @@ int drm_getsareactx(struct inode *inode, struct file *filp,
225 map = dev->context_sareas[request.ctx_id]; 225 map = dev->context_sareas[request.ctx_id];
226 up(&dev->struct_sem); 226 up(&dev->struct_sem);
227 227
228 request.handle = map->handle; 228 request.handle = (void *) map->offset;
229 if (copy_to_user(argp, &request, sizeof(request))) 229 if (copy_to_user(argp, &request, sizeof(request)))
230 return -EFAULT; 230 return -EFAULT;
231 return 0; 231 return 0;
@@ -261,8 +261,8 @@ int drm_setsareactx(struct inode *inode, struct file *filp,
261 down(&dev->struct_sem); 261 down(&dev->struct_sem);
262 list_for_each(list, &dev->maplist->head) { 262 list_for_each(list, &dev->maplist->head) {
263 r_list = list_entry(list, drm_map_list_t, head); 263 r_list = list_entry(list, drm_map_list_t, head);
264 if(r_list->map && 264 if (r_list->map
265 r_list->map->handle == request.handle) 265 && r_list->map->offset == (unsigned long) request.handle)
266 goto found; 266 goto found;
267 } 267 }
268bad: 268bad:
diff --git a/drivers/char/drm/drm_ioc32.c b/drivers/char/drm/drm_ioc32.c
new file mode 100644
index 000000000000..8087a9636399
--- /dev/null
+++ b/drivers/char/drm/drm_ioc32.c
@@ -0,0 +1,1069 @@
1/**
2 * \file drm_ioc32.c
3 *
4 * 32-bit ioctl compatibility routines for the DRM.
5 *
6 * \author Paul Mackerras <paulus@samba.org>
7 *
8 * Copyright (C) Paul Mackerras 2005.
9 * All Rights Reserved.
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a
12 * copy of this software and associated documentation files (the "Software"),
13 * to deal in the Software without restriction, including without limitation
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 * and/or sell copies of the Software, and to permit persons to whom the
16 * Software is furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice (including the next
19 * paragraph) shall be included in all copies or substantial portions of the
20 * Software.
21 *
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 * THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
28 * IN THE SOFTWARE.
29 */
30#include <linux/compat.h>
31#include <linux/ioctl32.h>
32
33#include "drmP.h"
34#include "drm_core.h"
35
36#define DRM_IOCTL_VERSION32 DRM_IOWR(0x00, drm_version32_t)
37#define DRM_IOCTL_GET_UNIQUE32 DRM_IOWR(0x01, drm_unique32_t)
38#define DRM_IOCTL_GET_MAP32 DRM_IOWR(0x04, drm_map32_t)
39#define DRM_IOCTL_GET_CLIENT32 DRM_IOWR(0x05, drm_client32_t)
40#define DRM_IOCTL_GET_STATS32 DRM_IOR( 0x06, drm_stats32_t)
41
42#define DRM_IOCTL_SET_UNIQUE32 DRM_IOW( 0x10, drm_unique32_t)
43#define DRM_IOCTL_ADD_MAP32 DRM_IOWR(0x15, drm_map32_t)
44#define DRM_IOCTL_ADD_BUFS32 DRM_IOWR(0x16, drm_buf_desc32_t)
45#define DRM_IOCTL_MARK_BUFS32 DRM_IOW( 0x17, drm_buf_desc32_t)
46#define DRM_IOCTL_INFO_BUFS32 DRM_IOWR(0x18, drm_buf_info32_t)
47#define DRM_IOCTL_MAP_BUFS32 DRM_IOWR(0x19, drm_buf_map32_t)
48#define DRM_IOCTL_FREE_BUFS32 DRM_IOW( 0x1a, drm_buf_free32_t)
49
50#define DRM_IOCTL_RM_MAP32 DRM_IOW( 0x1b, drm_map32_t)
51
52#define DRM_IOCTL_SET_SAREA_CTX32 DRM_IOW( 0x1c, drm_ctx_priv_map32_t)
53#define DRM_IOCTL_GET_SAREA_CTX32 DRM_IOWR(0x1d, drm_ctx_priv_map32_t)
54
55#define DRM_IOCTL_RES_CTX32 DRM_IOWR(0x26, drm_ctx_res32_t)
56#define DRM_IOCTL_DMA32 DRM_IOWR(0x29, drm_dma32_t)
57
58#define DRM_IOCTL_AGP_ENABLE32 DRM_IOW( 0x32, drm_agp_mode32_t)
59#define DRM_IOCTL_AGP_INFO32 DRM_IOR( 0x33, drm_agp_info32_t)
60#define DRM_IOCTL_AGP_ALLOC32 DRM_IOWR(0x34, drm_agp_buffer32_t)
61#define DRM_IOCTL_AGP_FREE32 DRM_IOW( 0x35, drm_agp_buffer32_t)
62#define DRM_IOCTL_AGP_BIND32 DRM_IOW( 0x36, drm_agp_binding32_t)
63#define DRM_IOCTL_AGP_UNBIND32 DRM_IOW( 0x37, drm_agp_binding32_t)
64
65#define DRM_IOCTL_SG_ALLOC32 DRM_IOW( 0x38, drm_scatter_gather32_t)
66#define DRM_IOCTL_SG_FREE32 DRM_IOW( 0x39, drm_scatter_gather32_t)
67
68#define DRM_IOCTL_WAIT_VBLANK32 DRM_IOWR(0x3a, drm_wait_vblank32_t)
69
70typedef struct drm_version_32 {
71 int version_major; /**< Major version */
72 int version_minor; /**< Minor version */
73 int version_patchlevel;/**< Patch level */
74 u32 name_len; /**< Length of name buffer */
75 u32 name; /**< Name of driver */
76 u32 date_len; /**< Length of date buffer */
77 u32 date; /**< User-space buffer to hold date */
78 u32 desc_len; /**< Length of desc buffer */
79 u32 desc; /**< User-space buffer to hold desc */
80} drm_version32_t;
81
82static int compat_drm_version(struct file *file, unsigned int cmd,
83 unsigned long arg)
84{
85 drm_version32_t v32;
86 drm_version_t __user *version;
87 int err;
88
89 if (copy_from_user(&v32, (void __user *) arg, sizeof(v32)))
90 return -EFAULT;
91
92 version = compat_alloc_user_space(sizeof(*version));
93 if (!access_ok(VERIFY_WRITE, version, sizeof(*version)))
94 return -EFAULT;
95 if (__put_user(v32.name_len, &version->name_len)
96 || __put_user((void __user *)(unsigned long)v32.name,
97 &version->name)
98 || __put_user(v32.date_len, &version->date_len)
99 || __put_user((void __user *)(unsigned long)v32.date,
100 &version->date)
101 || __put_user(v32.desc_len, &version->desc_len)
102 || __put_user((void __user *)(unsigned long)v32.desc,
103 &version->desc))
104 return -EFAULT;
105
106 err = drm_ioctl(file->f_dentry->d_inode, file,
107 DRM_IOCTL_VERSION, (unsigned long) version);
108 if (err)
109 return err;
110
111 if (__get_user(v32.version_major, &version->version_major)
112 || __get_user(v32.version_minor, &version->version_minor)
113 || __get_user(v32.version_patchlevel, &version->version_patchlevel)
114 || __get_user(v32.name_len, &version->name_len)
115 || __get_user(v32.date_len, &version->date_len)
116 || __get_user(v32.desc_len, &version->desc_len))
117 return -EFAULT;
118
119 if (copy_to_user((void __user *) arg, &v32, sizeof(v32)))
120 return -EFAULT;
121 return 0;
122}
123
124typedef struct drm_unique32 {
125 u32 unique_len; /**< Length of unique */
126 u32 unique; /**< Unique name for driver instantiation */
127} drm_unique32_t;
128
129static int compat_drm_getunique(struct file *file, unsigned int cmd,
130 unsigned long arg)
131{
132 drm_unique32_t uq32;
133 drm_unique_t __user *u;
134 int err;
135
136 if (copy_from_user(&uq32, (void __user *) arg, sizeof(uq32)))
137 return -EFAULT;
138
139 u = compat_alloc_user_space(sizeof(*u));
140 if (!access_ok(VERIFY_WRITE, u, sizeof(*u)))
141 return -EFAULT;
142 if (__put_user(uq32.unique_len, &u->unique_len)
143 || __put_user((void __user *)(unsigned long) uq32.unique,
144 &u->unique))
145 return -EFAULT;
146
147 err = drm_ioctl(file->f_dentry->d_inode, file,
148 DRM_IOCTL_GET_UNIQUE, (unsigned long) u);
149 if (err)
150 return err;
151
152 if (__get_user(uq32.unique_len, &u->unique_len))
153 return -EFAULT;
154 if (copy_to_user((void __user *) arg, &uq32, sizeof(uq32)))
155 return -EFAULT;
156 return 0;
157}
158
159static int compat_drm_setunique(struct file *file, unsigned int cmd,
160 unsigned long arg)
161{
162 drm_unique32_t uq32;
163 drm_unique_t __user *u;
164
165 if (copy_from_user(&uq32, (void __user *) arg, sizeof(uq32)))
166 return -EFAULT;
167
168 u = compat_alloc_user_space(sizeof(*u));
169 if (!access_ok(VERIFY_WRITE, u, sizeof(*u)))
170 return -EFAULT;
171 if (__put_user(uq32.unique_len, &u->unique_len)
172 || __put_user((void __user *)(unsigned long) uq32.unique,
173 &u->unique))
174 return -EFAULT;
175
176 return drm_ioctl(file->f_dentry->d_inode, file,
177 DRM_IOCTL_SET_UNIQUE, (unsigned long) u);
178}
179
180typedef struct drm_map32 {
181 u32 offset; /**< Requested physical address (0 for SAREA)*/
182 u32 size; /**< Requested physical size (bytes) */
183 drm_map_type_t type; /**< Type of memory to map */
184 drm_map_flags_t flags; /**< Flags */
185 u32 handle; /**< User-space: "Handle" to pass to mmap() */
186 int mtrr; /**< MTRR slot used */
187} drm_map32_t;
188
189static int compat_drm_getmap(struct file *file, unsigned int cmd,
190 unsigned long arg)
191{
192 drm_map32_t __user *argp = (void __user *)arg;
193 drm_map32_t m32;
194 drm_map_t __user *map;
195 int idx, err;
196 void *handle;
197
198 if (get_user(idx, &argp->offset))
199 return -EFAULT;
200
201 map = compat_alloc_user_space(sizeof(*map));
202 if (!access_ok(VERIFY_WRITE, map, sizeof(*map)))
203 return -EFAULT;
204 if (__put_user(idx, &map->offset))
205 return -EFAULT;
206
207 err = drm_ioctl(file->f_dentry->d_inode, file,
208 DRM_IOCTL_GET_MAP, (unsigned long) map);
209 if (err)
210 return err;
211
212 if (__get_user(m32.offset, &map->offset)
213 || __get_user(m32.size, &map->size)
214 || __get_user(m32.type, &map->type)
215 || __get_user(m32.flags, &map->flags)
216 || __get_user(handle, &map->handle)
217 || __get_user(m32.mtrr, &map->mtrr))
218 return -EFAULT;
219
220 m32.handle = (unsigned long) handle;
221 if (copy_to_user(argp, &m32, sizeof(m32)))
222 return -EFAULT;
223 return 0;
224
225}
226
227static int compat_drm_addmap(struct file *file, unsigned int cmd,
228 unsigned long arg)
229{
230 drm_map32_t __user *argp = (void __user *)arg;
231 drm_map32_t m32;
232 drm_map_t __user *map;
233 int err;
234 void *handle;
235
236 if (copy_from_user(&m32, argp, sizeof(m32)))
237 return -EFAULT;
238
239 map = compat_alloc_user_space(sizeof(*map));
240 if (!access_ok(VERIFY_WRITE, map, sizeof(*map)))
241 return -EFAULT;
242 if (__put_user(m32.offset, &map->offset)
243 || __put_user(m32.size, &map->size)
244 || __put_user(m32.type, &map->type)
245 || __put_user(m32.flags, &map->flags))
246 return -EFAULT;
247
248 err = drm_ioctl(file->f_dentry->d_inode, file,
249 DRM_IOCTL_ADD_MAP, (unsigned long) map);
250 if (err)
251 return err;
252
253 if (__get_user(m32.offset, &map->offset)
254 || __get_user(m32.mtrr, &map->mtrr)
255 || __get_user(handle, &map->handle))
256 return -EFAULT;
257
258 m32.handle = (unsigned long) handle;
259 if (m32.handle != (unsigned long) handle && printk_ratelimit())
260 printk(KERN_ERR "compat_drm_addmap truncated handle"
261 " %p for type %d offset %x\n",
262 handle, m32.type, m32.offset);
263
264 if (copy_to_user(argp, &m32, sizeof(m32)))
265 return -EFAULT;
266
267 return 0;
268}
269
270static int compat_drm_rmmap(struct file *file, unsigned int cmd,
271 unsigned long arg)
272{
273 drm_map32_t __user *argp = (void __user *)arg;
274 drm_map_t __user *map;
275 u32 handle;
276
277 if (get_user(handle, &argp->handle))
278 return -EFAULT;
279
280 map = compat_alloc_user_space(sizeof(*map));
281 if (!access_ok(VERIFY_WRITE, map, sizeof(*map)))
282 return -EFAULT;
283 if (__put_user((void *)(unsigned long) handle, &map->handle))
284 return -EFAULT;
285
286 return drm_ioctl(file->f_dentry->d_inode, file,
287 DRM_IOCTL_RM_MAP, (unsigned long) map);
288}
289
290typedef struct drm_client32 {
291 int idx; /**< Which client desired? */
292 int auth; /**< Is client authenticated? */
293 u32 pid; /**< Process ID */
294 u32 uid; /**< User ID */
295 u32 magic; /**< Magic */
296 u32 iocs; /**< Ioctl count */
297} drm_client32_t;
298
299static int compat_drm_getclient(struct file *file, unsigned int cmd,
300 unsigned long arg)
301{
302 drm_client32_t c32;
303 drm_client32_t __user *argp = (void __user *)arg;
304 drm_client_t __user *client;
305 int idx, err;
306
307 if (get_user(idx, &argp->idx))
308 return -EFAULT;
309
310 client = compat_alloc_user_space(sizeof(*client));
311 if (!access_ok(VERIFY_WRITE, client, sizeof(*client)))
312 return -EFAULT;
313 if (__put_user(idx, &client->idx))
314 return -EFAULT;
315
316 err = drm_ioctl(file->f_dentry->d_inode, file,
317 DRM_IOCTL_GET_CLIENT, (unsigned long) client);
318 if (err)
319 return err;
320
321 if (__get_user(c32.auth, &client->auth)
322 || __get_user(c32.pid, &client->pid)
323 || __get_user(c32.uid, &client->uid)
324 || __get_user(c32.magic, &client->magic)
325 || __get_user(c32.iocs, &client->iocs))
326 return -EFAULT;
327
328 if (copy_to_user(argp, &c32, sizeof(c32)))
329 return -EFAULT;
330 return 0;
331}
332
333typedef struct drm_stats32 {
334 u32 count;
335 struct {
336 u32 value;
337 drm_stat_type_t type;
338 } data[15];
339} drm_stats32_t;
340
341static int compat_drm_getstats(struct file *file, unsigned int cmd,
342 unsigned long arg)
343{
344 drm_stats32_t s32;
345 drm_stats32_t __user *argp = (void __user *)arg;
346 drm_stats_t __user *stats;
347 int i, err;
348
349 stats = compat_alloc_user_space(sizeof(*stats));
350 if (!access_ok(VERIFY_WRITE, stats, sizeof(*stats)))
351 return -EFAULT;
352
353 err = drm_ioctl(file->f_dentry->d_inode, file,
354 DRM_IOCTL_GET_STATS, (unsigned long) stats);
355 if (err)
356 return err;
357
358 if (__get_user(s32.count, &stats->count))
359 return -EFAULT;
360 for (i = 0; i < 15; ++i)
361 if (__get_user(s32.data[i].value, &stats->data[i].value)
362 || __get_user(s32.data[i].type, &stats->data[i].type))
363 return -EFAULT;
364
365 if (copy_to_user(argp, &s32, sizeof(s32)))
366 return -EFAULT;
367 return 0;
368}
369
370typedef struct drm_buf_desc32 {
371 int count; /**< Number of buffers of this size */
372 int size; /**< Size in bytes */
373 int low_mark; /**< Low water mark */
374 int high_mark; /**< High water mark */
375 int flags;
376 u32 agp_start; /**< Start address in the AGP aperture */
377} drm_buf_desc32_t;
378
379static int compat_drm_addbufs(struct file *file, unsigned int cmd,
380 unsigned long arg)
381{
382 drm_buf_desc32_t __user *argp = (void __user *)arg;
383 drm_buf_desc_t __user *buf;
384 int err;
385 unsigned long agp_start;
386
387 buf = compat_alloc_user_space(sizeof(*buf));
388 if (!access_ok(VERIFY_WRITE, buf, sizeof(*buf))
389 || !access_ok(VERIFY_WRITE, argp, sizeof(*argp)))
390 return -EFAULT;
391
392 if (__copy_in_user(buf, argp, offsetof(drm_buf_desc32_t, agp_start))
393 || __get_user(agp_start, &argp->agp_start)
394 || __put_user(agp_start, &buf->agp_start))
395 return -EFAULT;
396
397 err = drm_ioctl(file->f_dentry->d_inode, file,
398 DRM_IOCTL_ADD_BUFS, (unsigned long) buf);
399 if (err)
400 return err;
401
402 if (__copy_in_user(argp, buf, offsetof(drm_buf_desc32_t, agp_start))
403 || __get_user(agp_start, &buf->agp_start)
404 || __put_user(agp_start, &argp->agp_start))
405 return -EFAULT;
406
407 return 0;
408}
409
410static int compat_drm_markbufs(struct file *file, unsigned int cmd,
411 unsigned long arg)
412{
413 drm_buf_desc32_t b32;
414 drm_buf_desc32_t __user *argp = (void __user *)arg;
415 drm_buf_desc_t __user *buf;
416
417 if (copy_from_user(&b32, argp, sizeof(b32)))
418 return -EFAULT;
419
420 buf = compat_alloc_user_space(sizeof(*buf));
421 if (!access_ok(VERIFY_WRITE, buf, sizeof(*buf)))
422 return -EFAULT;
423
424 if (__put_user(b32.size, &buf->size)
425 || __put_user(b32.low_mark, &buf->low_mark)
426 || __put_user(b32.high_mark, &buf->high_mark))
427 return -EFAULT;
428
429 return drm_ioctl(file->f_dentry->d_inode, file,
430 DRM_IOCTL_MARK_BUFS, (unsigned long) buf);
431}
432
433typedef struct drm_buf_info32 {
434 int count; /**< Entries in list */
435 u32 list;
436} drm_buf_info32_t;
437
438static int compat_drm_infobufs(struct file *file, unsigned int cmd,
439 unsigned long arg)
440{
441 drm_buf_info32_t req32;
442 drm_buf_info32_t __user *argp = (void __user *)arg;
443 drm_buf_desc32_t __user *to;
444 drm_buf_info_t __user *request;
445 drm_buf_desc_t __user *list;
446 size_t nbytes;
447 int i, err;
448 int count, actual;
449
450 if (copy_from_user(&req32, argp, sizeof(req32)))
451 return -EFAULT;
452
453 count = req32.count;
454 to = (drm_buf_desc32_t __user *)(unsigned long) req32.list;
455 if (count < 0)
456 count = 0;
457 if (count > 0
458 && !access_ok(VERIFY_WRITE, to, count * sizeof(drm_buf_desc32_t)))
459 return -EFAULT;
460
461 nbytes = sizeof(*request) + count * sizeof(drm_buf_desc_t);
462 request = compat_alloc_user_space(nbytes);
463 if (!access_ok(VERIFY_WRITE, request, nbytes))
464 return -EFAULT;
465 list = (drm_buf_desc_t *) (request + 1);
466
467 if (__put_user(count, &request->count)
468 || __put_user(list, &request->list))
469 return -EFAULT;
470
471 err = drm_ioctl(file->f_dentry->d_inode, file,
472 DRM_IOCTL_INFO_BUFS, (unsigned long) request);
473 if (err)
474 return err;
475
476 if (__get_user(actual, &request->count))
477 return -EFAULT;
478 if (count >= actual)
479 for (i = 0; i < actual; ++i)
480 if (__copy_in_user(&to[i], &list[i],
481 offsetof(drm_buf_desc_t, flags)))
482 return -EFAULT;
483
484 if (__put_user(actual, &argp->count))
485 return -EFAULT;
486
487 return 0;
488}
489
490typedef struct drm_buf_pub32 {
491 int idx; /**< Index into the master buffer list */
492 int total; /**< Buffer size */
493 int used; /**< Amount of buffer in use (for DMA) */
494 u32 address; /**< Address of buffer */
495} drm_buf_pub32_t;
496
497typedef struct drm_buf_map32 {
498 int count; /**< Length of the buffer list */
499 u32 virtual; /**< Mmap'd area in user-virtual */
500 u32 list; /**< Buffer information */
501} drm_buf_map32_t;
502
503static int compat_drm_mapbufs(struct file *file, unsigned int cmd,
504 unsigned long arg)
505{
506 drm_buf_map32_t __user *argp = (void __user *)arg;
507 drm_buf_map32_t req32;
508 drm_buf_pub32_t __user *list32;
509 drm_buf_map_t __user *request;
510 drm_buf_pub_t __user *list;
511 int i, err;
512 int count, actual;
513 size_t nbytes;
514 void __user *addr;
515
516 if (copy_from_user(&req32, argp, sizeof(req32)))
517 return -EFAULT;
518 count = req32.count;
519 list32 = (void __user *)(unsigned long)req32.list;
520
521 if (count < 0)
522 return -EINVAL;
523 nbytes = sizeof(*request) + count * sizeof(drm_buf_pub_t);
524 request = compat_alloc_user_space(nbytes);
525 if (!access_ok(VERIFY_WRITE, request, nbytes))
526 return -EFAULT;
527 list = (drm_buf_pub_t *) (request + 1);
528
529 if (__put_user(count, &request->count)
530 || __put_user(list, &request->list))
531 return -EFAULT;
532
533 err = drm_ioctl(file->f_dentry->d_inode, file,
534 DRM_IOCTL_MAP_BUFS, (unsigned long) request);
535 if (err)
536 return err;
537
538 if (__get_user(actual, &request->count))
539 return -EFAULT;
540 if (count >= actual)
541 for (i = 0; i < actual; ++i)
542 if (__copy_in_user(&list32[i], &list[i],
543 offsetof(drm_buf_pub_t, address))
544 || __get_user(addr, &list[i].address)
545 || __put_user((unsigned long) addr,
546 &list32[i].address))
547 return -EFAULT;
548
549 if (__put_user(actual, &argp->count)
550 || __get_user(addr, &request->virtual)
551 || __put_user((unsigned long) addr, &argp->virtual))
552 return -EFAULT;
553
554 return 0;
555}
556
557typedef struct drm_buf_free32 {
558 int count;
559 u32 list;
560} drm_buf_free32_t;
561
562static int compat_drm_freebufs(struct file *file, unsigned int cmd,
563 unsigned long arg)
564{
565 drm_buf_free32_t req32;
566 drm_buf_free_t __user *request;
567 drm_buf_free32_t __user *argp = (void __user *)arg;
568
569 if (copy_from_user(&req32, argp, sizeof(req32)))
570 return -EFAULT;
571
572 request = compat_alloc_user_space(sizeof(*request));
573 if (!access_ok(VERIFY_WRITE, request, sizeof(*request)))
574 return -EFAULT;
575 if (__put_user(req32.count, &request->count)
576 || __put_user((int __user *)(unsigned long) req32.list,
577 &request->list))
578 return -EFAULT;
579
580 return drm_ioctl(file->f_dentry->d_inode, file,
581 DRM_IOCTL_FREE_BUFS, (unsigned long) request);
582}
583
584typedef struct drm_ctx_priv_map32 {
585 unsigned int ctx_id; /**< Context requesting private mapping */
586 u32 handle; /**< Handle of map */
587} drm_ctx_priv_map32_t;
588
589static int compat_drm_setsareactx(struct file *file, unsigned int cmd,
590 unsigned long arg)
591{
592 drm_ctx_priv_map32_t req32;
593 drm_ctx_priv_map_t __user *request;
594 drm_ctx_priv_map32_t __user *argp = (void __user *)arg;
595
596 if (copy_from_user(&req32, argp, sizeof(req32)))
597 return -EFAULT;
598
599 request = compat_alloc_user_space(sizeof(*request));
600 if (!access_ok(VERIFY_WRITE, request, sizeof(*request)))
601 return -EFAULT;
602 if (__put_user(req32.ctx_id, &request->ctx_id)
603 || __put_user((void *)(unsigned long) req32.handle,
604 &request->handle))
605 return -EFAULT;
606
607 return drm_ioctl(file->f_dentry->d_inode, file,
608 DRM_IOCTL_SET_SAREA_CTX, (unsigned long) request);
609}
610
611static int compat_drm_getsareactx(struct file *file, unsigned int cmd,
612 unsigned long arg)
613{
614 drm_ctx_priv_map_t __user *request;
615 drm_ctx_priv_map32_t __user *argp = (void __user *)arg;
616 int err;
617 unsigned int ctx_id;
618 void *handle;
619
620 if (!access_ok(VERIFY_WRITE, argp, sizeof(*argp))
621 || __get_user(ctx_id, &argp->ctx_id))
622 return -EFAULT;
623
624 request = compat_alloc_user_space(sizeof(*request));
625 if (!access_ok(VERIFY_WRITE, request, sizeof(*request)))
626 return -EFAULT;
627 if (__put_user(ctx_id, &request->ctx_id))
628 return -EFAULT;
629
630 err = drm_ioctl(file->f_dentry->d_inode, file,
631 DRM_IOCTL_GET_SAREA_CTX, (unsigned long) request);
632 if (err)
633 return err;
634
635 if (__get_user(handle, &request->handle)
636 || __put_user((unsigned long) handle, &argp->handle))
637 return -EFAULT;
638
639 return 0;
640}
641
642typedef struct drm_ctx_res32 {
643 int count;
644 u32 contexts;
645} drm_ctx_res32_t;
646
647static int compat_drm_resctx(struct file *file, unsigned int cmd,
648 unsigned long arg)
649{
650 drm_ctx_res32_t __user *argp = (void __user *)arg;
651 drm_ctx_res32_t res32;
652 drm_ctx_res_t __user *res;
653 int err;
654
655 if (copy_from_user(&res32, argp, sizeof(res32)))
656 return -EFAULT;
657
658 res = compat_alloc_user_space(sizeof(*res));
659 if (!access_ok(VERIFY_WRITE, res, sizeof(*res)))
660 return -EFAULT;
661 if (__put_user(res32.count, &res->count)
662 || __put_user((drm_ctx_t __user *)(unsigned long) res32.contexts,
663 &res->contexts))
664 return -EFAULT;
665
666 err = drm_ioctl(file->f_dentry->d_inode, file,
667 DRM_IOCTL_RES_CTX, (unsigned long) res);
668 if (err)
669 return err;
670
671 if (__get_user(res32.count, &res->count)
672 || __put_user(res32.count, &argp->count))
673 return -EFAULT;
674
675 return 0;
676}
677
678typedef struct drm_dma32 {
679 int context; /**< Context handle */
680 int send_count; /**< Number of buffers to send */
681 u32 send_indices; /**< List of handles to buffers */
682 u32 send_sizes; /**< Lengths of data to send */
683 drm_dma_flags_t flags; /**< Flags */
684 int request_count; /**< Number of buffers requested */
685 int request_size; /**< Desired size for buffers */
686 u32 request_indices; /**< Buffer information */
687 u32 request_sizes;
688 int granted_count; /**< Number of buffers granted */
689} drm_dma32_t;
690
691static int compat_drm_dma(struct file *file, unsigned int cmd,
692 unsigned long arg)
693{
694 drm_dma32_t d32;
695 drm_dma32_t __user *argp = (void __user *) arg;
696 drm_dma_t __user *d;
697 int err;
698
699 if (copy_from_user(&d32, argp, sizeof(d32)))
700 return -EFAULT;
701
702 d = compat_alloc_user_space(sizeof(*d));
703 if (!access_ok(VERIFY_WRITE, d, sizeof(*d)))
704 return -EFAULT;
705
706 if (__put_user(d32.context, &d->context)
707 || __put_user(d32.send_count, &d->send_count)
708 || __put_user((int __user *)(unsigned long) d32.send_indices,
709 &d->send_indices)
710 || __put_user((int __user *)(unsigned long) d32.send_sizes,
711 &d->send_sizes)
712 || __put_user(d32.flags, &d->flags)
713 || __put_user(d32.request_count, &d->request_count)
714 || __put_user((int __user *)(unsigned long) d32.request_indices,
715 &d->request_indices)
716 || __put_user((int __user *)(unsigned long) d32.request_sizes,
717 &d->request_sizes))
718 return -EFAULT;
719
720 err = drm_ioctl(file->f_dentry->d_inode, file,
721 DRM_IOCTL_DMA, (unsigned long) d);
722 if (err)
723 return err;
724
725 if (__get_user(d32.request_size, &d->request_size)
726 || __get_user(d32.granted_count, &d->granted_count)
727 || __put_user(d32.request_size, &argp->request_size)
728 || __put_user(d32.granted_count, &argp->granted_count))
729 return -EFAULT;
730
731 return 0;
732}
733
734#if __OS_HAS_AGP
735typedef struct drm_agp_mode32 {
736 u32 mode; /**< AGP mode */
737} drm_agp_mode32_t;
738
739static int compat_drm_agp_enable(struct file *file, unsigned int cmd,
740 unsigned long arg)
741{
742 drm_agp_mode32_t __user *argp = (void __user *)arg;
743 drm_agp_mode32_t m32;
744 drm_agp_mode_t __user *mode;
745
746 if (get_user(m32.mode, &argp->mode))
747 return -EFAULT;
748
749 mode = compat_alloc_user_space(sizeof(*mode));
750 if (put_user(m32.mode, &mode->mode))
751 return -EFAULT;
752
753 return drm_ioctl(file->f_dentry->d_inode, file,
754 DRM_IOCTL_AGP_ENABLE, (unsigned long) mode);
755}
756
757typedef struct drm_agp_info32 {
758 int agp_version_major;
759 int agp_version_minor;
760 u32 mode;
761 u32 aperture_base; /* physical address */
762 u32 aperture_size; /* bytes */
763 u32 memory_allowed; /* bytes */
764 u32 memory_used;
765
766 /* PCI information */
767 unsigned short id_vendor;
768 unsigned short id_device;
769} drm_agp_info32_t;
770
771static int compat_drm_agp_info(struct file *file, unsigned int cmd,
772 unsigned long arg)
773{
774 drm_agp_info32_t __user *argp = (void __user *)arg;
775 drm_agp_info32_t i32;
776 drm_agp_info_t __user *info;
777 int err;
778
779 info = compat_alloc_user_space(sizeof(*info));
780 if (!access_ok(VERIFY_WRITE, info, sizeof(*info)))
781 return -EFAULT;
782
783 err = drm_ioctl(file->f_dentry->d_inode, file,
784 DRM_IOCTL_AGP_INFO, (unsigned long) info);
785 if (err)
786 return err;
787
788 if (__get_user(i32.agp_version_major, &info->agp_version_major)
789 || __get_user(i32.agp_version_minor, &info->agp_version_minor)
790 || __get_user(i32.mode, &info->mode)
791 || __get_user(i32.aperture_base, &info->aperture_base)
792 || __get_user(i32.aperture_size, &info->aperture_size)
793 || __get_user(i32.memory_allowed, &info->memory_allowed)
794 || __get_user(i32.memory_used, &info->memory_used)
795 || __get_user(i32.id_vendor, &info->id_vendor)
796 || __get_user(i32.id_device, &info->id_device))
797 return -EFAULT;
798
799 if (copy_to_user(argp, &i32, sizeof(i32)))
800 return -EFAULT;
801
802 return 0;
803}
804
805typedef struct drm_agp_buffer32 {
806 u32 size; /**< In bytes -- will round to page boundary */
807 u32 handle; /**< Used for binding / unbinding */
808 u32 type; /**< Type of memory to allocate */
809 u32 physical; /**< Physical used by i810 */
810} drm_agp_buffer32_t;
811
812static int compat_drm_agp_alloc(struct file *file, unsigned int cmd,
813 unsigned long arg)
814{
815 drm_agp_buffer32_t __user *argp = (void __user *)arg;
816 drm_agp_buffer32_t req32;
817 drm_agp_buffer_t __user *request;
818 int err;
819
820 if (copy_from_user(&req32, argp, sizeof(req32)))
821 return -EFAULT;
822
823 request = compat_alloc_user_space(sizeof(*request));
824 if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
825 || __put_user(req32.size, &request->size)
826 || __put_user(req32.type, &request->type))
827 return -EFAULT;
828
829 err = drm_ioctl(file->f_dentry->d_inode, file,
830 DRM_IOCTL_AGP_ALLOC, (unsigned long) request);
831 if (err)
832 return err;
833
834 if (__get_user(req32.handle, &request->handle)
835 || __get_user(req32.physical, &request->physical)
836 || copy_to_user(argp, &req32, sizeof(req32))) {
837 drm_ioctl(file->f_dentry->d_inode, file,
838 DRM_IOCTL_AGP_FREE, (unsigned long) request);
839 return -EFAULT;
840 }
841
842 return 0;
843}
844
845static int compat_drm_agp_free(struct file *file, unsigned int cmd,
846 unsigned long arg)
847{
848 drm_agp_buffer32_t __user *argp = (void __user *)arg;
849 drm_agp_buffer_t __user *request;
850 u32 handle;
851
852 request = compat_alloc_user_space(sizeof(*request));
853 if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
854 || get_user(handle, &argp->handle)
855 || __put_user(handle, &request->handle))
856 return -EFAULT;
857
858 return drm_ioctl(file->f_dentry->d_inode, file,
859 DRM_IOCTL_AGP_FREE, (unsigned long) request);
860}
861
862typedef struct drm_agp_binding32 {
863 u32 handle; /**< From drm_agp_buffer */
864 u32 offset; /**< In bytes -- will round to page boundary */
865} drm_agp_binding32_t;
866
867static int compat_drm_agp_bind(struct file *file, unsigned int cmd,
868 unsigned long arg)
869{
870 drm_agp_binding32_t __user *argp = (void __user *)arg;
871 drm_agp_binding32_t req32;
872 drm_agp_binding_t __user *request;
873
874 if (copy_from_user(&req32, argp, sizeof(req32)))
875 return -EFAULT;
876
877 request = compat_alloc_user_space(sizeof(*request));
878 if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
879 || __put_user(req32.handle, &request->handle)
880 || __put_user(req32.offset, &request->offset))
881 return -EFAULT;
882
883 return drm_ioctl(file->f_dentry->d_inode, file,
884 DRM_IOCTL_AGP_BIND, (unsigned long) request);
885}
886
887static int compat_drm_agp_unbind(struct file *file, unsigned int cmd,
888 unsigned long arg)
889{
890 drm_agp_binding32_t __user *argp = (void __user *)arg;
891 drm_agp_binding_t __user *request;
892 u32 handle;
893
894 request = compat_alloc_user_space(sizeof(*request));
895 if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
896 || get_user(handle, &argp->handle)
897 || __put_user(handle, &request->handle))
898 return -EFAULT;
899
900 return drm_ioctl(file->f_dentry->d_inode, file,
901 DRM_IOCTL_AGP_UNBIND, (unsigned long) request);
902}
903#endif /* __OS_HAS_AGP */
904
905typedef struct drm_scatter_gather32 {
906 u32 size; /**< In bytes -- will round to page boundary */
907 u32 handle; /**< Used for mapping / unmapping */
908} drm_scatter_gather32_t;
909
910static int compat_drm_sg_alloc(struct file *file, unsigned int cmd,
911 unsigned long arg)
912{
913 drm_scatter_gather32_t __user *argp = (void __user *)arg;
914 drm_scatter_gather_t __user *request;
915 int err;
916 unsigned long x;
917
918 request = compat_alloc_user_space(sizeof(*request));
919 if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
920 || !access_ok(VERIFY_WRITE, argp, sizeof(*argp))
921 || __get_user(x, &argp->size)
922 || __put_user(x, &request->size))
923 return -EFAULT;
924
925 err = drm_ioctl(file->f_dentry->d_inode, file,
926 DRM_IOCTL_SG_ALLOC, (unsigned long) request);
927 if (err)
928 return err;
929
930 /* XXX not sure about the handle conversion here... */
931 if (__get_user(x, &request->handle)
932 || __put_user(x >> PAGE_SHIFT, &argp->handle))
933 return -EFAULT;
934
935 return 0;
936}
937
938static int compat_drm_sg_free(struct file *file, unsigned int cmd,
939 unsigned long arg)
940{
941 drm_scatter_gather32_t __user *argp = (void __user *)arg;
942 drm_scatter_gather_t __user *request;
943 unsigned long x;
944
945 request = compat_alloc_user_space(sizeof(*request));
946 if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
947 || !access_ok(VERIFY_WRITE, argp, sizeof(*argp))
948 || __get_user(x, &argp->handle)
949 || __put_user(x << PAGE_SHIFT, &request->handle))
950 return -EFAULT;
951
952 return drm_ioctl(file->f_dentry->d_inode, file,
953 DRM_IOCTL_SG_FREE, (unsigned long) request);
954}
955
956struct drm_wait_vblank_request32 {
957 drm_vblank_seq_type_t type;
958 unsigned int sequence;
959 u32 signal;
960};
961
962struct drm_wait_vblank_reply32 {
963 drm_vblank_seq_type_t type;
964 unsigned int sequence;
965 s32 tval_sec;
966 s32 tval_usec;
967};
968
969typedef union drm_wait_vblank32 {
970 struct drm_wait_vblank_request32 request;
971 struct drm_wait_vblank_reply32 reply;
972} drm_wait_vblank32_t;
973
974static int compat_drm_wait_vblank(struct file *file, unsigned int cmd,
975 unsigned long arg)
976{
977 drm_wait_vblank32_t __user *argp = (void __user *)arg;
978 drm_wait_vblank32_t req32;
979 drm_wait_vblank_t __user *request;
980 int err;
981
982 if (copy_from_user(&req32, argp, sizeof(req32)))
983 return -EFAULT;
984
985 request = compat_alloc_user_space(sizeof(*request));
986 if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
987 || __put_user(req32.request.type, &request->request.type)
988 || __put_user(req32.request.sequence, &request->request.sequence)
989 || __put_user(req32.request.signal, &request->request.signal))
990 return -EFAULT;
991
992 err = drm_ioctl(file->f_dentry->d_inode, file,
993 DRM_IOCTL_WAIT_VBLANK, (unsigned long) request);
994 if (err)
995 return err;
996
997 if (__get_user(req32.reply.type, &request->reply.type)
998 || __get_user(req32.reply.sequence, &request->reply.sequence)
999 || __get_user(req32.reply.tval_sec, &request->reply.tval_sec)
1000 || __get_user(req32.reply.tval_usec, &request->reply.tval_usec))
1001 return -EFAULT;
1002
1003 if (copy_to_user(argp, &req32, sizeof(req32)))
1004 return -EFAULT;
1005
1006 return 0;
1007}
1008
1009drm_ioctl_compat_t *drm_compat_ioctls[] = {
1010 [DRM_IOCTL_NR(DRM_IOCTL_VERSION32)] = compat_drm_version,
1011 [DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE32)] = compat_drm_getunique,
1012 [DRM_IOCTL_NR(DRM_IOCTL_GET_MAP32)] = compat_drm_getmap,
1013 [DRM_IOCTL_NR(DRM_IOCTL_GET_CLIENT32)] = compat_drm_getclient,
1014 [DRM_IOCTL_NR(DRM_IOCTL_GET_STATS32)] = compat_drm_getstats,
1015 [DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE32)] = compat_drm_setunique,
1016 [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP32)] = compat_drm_addmap,
1017 [DRM_IOCTL_NR(DRM_IOCTL_ADD_BUFS32)] = compat_drm_addbufs,
1018 [DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS32)] = compat_drm_markbufs,
1019 [DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS32)] = compat_drm_infobufs,
1020 [DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS32)] = compat_drm_mapbufs,
1021 [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS32)] = compat_drm_freebufs,
1022 [DRM_IOCTL_NR(DRM_IOCTL_RM_MAP32)] = compat_drm_rmmap,
1023 [DRM_IOCTL_NR(DRM_IOCTL_SET_SAREA_CTX32)] = compat_drm_setsareactx,
1024 [DRM_IOCTL_NR(DRM_IOCTL_GET_SAREA_CTX32)] = compat_drm_getsareactx,
1025 [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX32)] = compat_drm_resctx,
1026 [DRM_IOCTL_NR(DRM_IOCTL_DMA32)] = compat_drm_dma,
1027#if __OS_HAS_AGP
1028 [DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE32)] = compat_drm_agp_enable,
1029 [DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO32)] = compat_drm_agp_info,
1030 [DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC32)] = compat_drm_agp_alloc,
1031 [DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE32)] = compat_drm_agp_free,
1032 [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND32)] = compat_drm_agp_bind,
1033 [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND32)] = compat_drm_agp_unbind,
1034#endif
1035 [DRM_IOCTL_NR(DRM_IOCTL_SG_ALLOC32)] = compat_drm_sg_alloc,
1036 [DRM_IOCTL_NR(DRM_IOCTL_SG_FREE32)] = compat_drm_sg_free,
1037 [DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK32)] = compat_drm_wait_vblank,
1038};
1039
1040/**
1041 * Called whenever a 32-bit process running under a 64-bit kernel
1042 * performs an ioctl on /dev/drm.
1043 *
1044 * \param filp file pointer.
1045 * \param cmd command.
1046 * \param arg user argument.
1047 * \return zero on success or negative number on failure.
1048 */
1049long drm_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
1050{
1051 unsigned int nr = DRM_IOCTL_NR(cmd);
1052 drm_ioctl_compat_t *fn;
1053 int ret;
1054
1055 if (nr >= DRM_ARRAY_SIZE(drm_compat_ioctls))
1056 return -ENOTTY;
1057
1058 fn = drm_compat_ioctls[nr];
1059
1060 lock_kernel(); /* XXX for now */
1061 if (fn != NULL)
1062 ret = (*fn)(filp, cmd, arg);
1063 else
1064 ret = drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
1065 unlock_kernel();
1066
1067 return ret;
1068}
1069EXPORT_SYMBOL(drm_compat_ioctl);
diff --git a/drivers/char/drm/radeon_drv.c b/drivers/char/drm/radeon_drv.c
index 7b983d96e53b..18e4e5b0952f 100644
--- a/drivers/char/drm/radeon_drv.c
+++ b/drivers/char/drm/radeon_drv.c
@@ -101,6 +101,9 @@ static struct drm_driver driver = {
101 .mmap = drm_mmap, 101 .mmap = drm_mmap,
102 .poll = drm_poll, 102 .poll = drm_poll,
103 .fasync = drm_fasync, 103 .fasync = drm_fasync,
104#ifdef CONFIG_COMPAT
105 .compat_ioctl = radeon_compat_ioctl,
106#endif
104 }, 107 },
105 .pci_driver = { 108 .pci_driver = {
106 .name = DRIVER_NAME, 109 .name = DRIVER_NAME,
diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h
index 5837098afae8..771aa80a5e8c 100644
--- a/drivers/char/drm/radeon_drv.h
+++ b/drivers/char/drm/radeon_drv.h
@@ -317,6 +317,9 @@ extern int radeon_preinit( struct drm_device *dev, unsigned long flags );
317extern int radeon_postinit( struct drm_device *dev, unsigned long flags ); 317extern int radeon_postinit( struct drm_device *dev, unsigned long flags );
318extern int radeon_postcleanup( struct drm_device *dev ); 318extern int radeon_postcleanup( struct drm_device *dev );
319 319
320extern long radeon_compat_ioctl(struct file *filp, unsigned int cmd,
321 unsigned long arg);
322
320/* Flags for stats.boxes 323/* Flags for stats.boxes
321 */ 324 */
322#define RADEON_BOX_DMA_IDLE 0x1 325#define RADEON_BOX_DMA_IDLE 0x1
diff --git a/drivers/char/drm/radeon_ioc32.c b/drivers/char/drm/radeon_ioc32.c
new file mode 100644
index 000000000000..bfe612215fb3
--- /dev/null
+++ b/drivers/char/drm/radeon_ioc32.c
@@ -0,0 +1,395 @@
1/**
2 * \file radeon_ioc32.c
3 *
4 * 32-bit ioctl compatibility routines for the Radeon DRM.
5 *
6 * \author Paul Mackerras <paulus@samba.org>
7 *
8 * Copyright (C) Paul Mackerras 2005
9 * All Rights Reserved.
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a
12 * copy of this software and associated documentation files (the "Software"),
13 * to deal in the Software without restriction, including without limitation
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 * and/or sell copies of the Software, and to permit persons to whom the
16 * Software is furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice (including the next
19 * paragraph) shall be included in all copies or substantial portions of the
20 * Software.
21 *
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 * THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
28 * IN THE SOFTWARE.
29 */
30#include <linux/compat.h>
31#include <linux/ioctl32.h>
32
33#include "drmP.h"
34#include "drm.h"
35#include "radeon_drm.h"
36#include "radeon_drv.h"
37
38typedef struct drm_radeon_init32 {
39 int func;
40 u32 sarea_priv_offset;
41 int is_pci;
42 int cp_mode;
43 int gart_size;
44 int ring_size;
45 int usec_timeout;
46
47 unsigned int fb_bpp;
48 unsigned int front_offset, front_pitch;
49 unsigned int back_offset, back_pitch;
50 unsigned int depth_bpp;
51 unsigned int depth_offset, depth_pitch;
52
53 u32 fb_offset;
54 u32 mmio_offset;
55 u32 ring_offset;
56 u32 ring_rptr_offset;
57 u32 buffers_offset;
58 u32 gart_textures_offset;
59} drm_radeon_init32_t;
60
61static int compat_radeon_cp_init(struct file *file, unsigned int cmd,
62 unsigned long arg)
63{
64 drm_radeon_init32_t init32;
65 drm_radeon_init_t __user *init;
66
67 if (copy_from_user(&init32, (void __user *)arg, sizeof(init32)))
68 return -EFAULT;
69
70 init = compat_alloc_user_space(sizeof(*init));
71 if (!access_ok(VERIFY_WRITE, init, sizeof(*init))
72 || __put_user(init32.func, &init->func)
73 || __put_user(init32.sarea_priv_offset, &init->sarea_priv_offset)
74 || __put_user(init32.is_pci, &init->is_pci)
75 || __put_user(init32.cp_mode, &init->cp_mode)
76 || __put_user(init32.gart_size, &init->gart_size)
77 || __put_user(init32.ring_size, &init->ring_size)
78 || __put_user(init32.usec_timeout, &init->usec_timeout)
79 || __put_user(init32.fb_bpp, &init->fb_bpp)
80 || __put_user(init32.front_offset, &init->front_offset)
81 || __put_user(init32.front_pitch, &init->front_pitch)
82 || __put_user(init32.back_offset, &init->back_offset)
83 || __put_user(init32.back_pitch, &init->back_pitch)
84 || __put_user(init32.depth_bpp, &init->depth_bpp)
85 || __put_user(init32.depth_offset, &init->depth_offset)
86 || __put_user(init32.depth_pitch, &init->depth_pitch)
87 || __put_user(init32.fb_offset, &init->fb_offset)
88 || __put_user(init32.mmio_offset, &init->mmio_offset)
89 || __put_user(init32.ring_offset, &init->ring_offset)
90 || __put_user(init32.ring_rptr_offset, &init->ring_rptr_offset)
91 || __put_user(init32.buffers_offset, &init->buffers_offset)
92 || __put_user(init32.gart_textures_offset,
93 &init->gart_textures_offset))
94 return -EFAULT;
95
96 return drm_ioctl(file->f_dentry->d_inode, file,
97 DRM_IOCTL_RADEON_CP_INIT, (unsigned long) init);
98}
99
100typedef struct drm_radeon_clear32 {
101 unsigned int flags;
102 unsigned int clear_color;
103 unsigned int clear_depth;
104 unsigned int color_mask;
105 unsigned int depth_mask; /* misnamed field: should be stencil */
106 u32 depth_boxes;
107} drm_radeon_clear32_t;
108
109static int compat_radeon_cp_clear(struct file *file, unsigned int cmd,
110 unsigned long arg)
111{
112 drm_radeon_clear32_t clr32;
113 drm_radeon_clear_t __user *clr;
114
115 if (copy_from_user(&clr32, (void __user *)arg, sizeof(clr32)))
116 return -EFAULT;
117
118 clr = compat_alloc_user_space(sizeof(*clr));
119 if (!access_ok(VERIFY_WRITE, clr, sizeof(*clr))
120 || __put_user(clr32.flags, &clr->flags)
121 || __put_user(clr32.clear_color, &clr->clear_color)
122 || __put_user(clr32.clear_depth, &clr->clear_depth)
123 || __put_user(clr32.color_mask, &clr->color_mask)
124 || __put_user(clr32.depth_mask, &clr->depth_mask)
125 || __put_user((void __user *)(unsigned long)clr32.depth_boxes,
126 &clr->depth_boxes))
127 return -EFAULT;
128
129 return drm_ioctl(file->f_dentry->d_inode, file,
130 DRM_IOCTL_RADEON_CLEAR, (unsigned long) clr);
131}
132
133typedef struct drm_radeon_stipple32 {
134 u32 mask;
135} drm_radeon_stipple32_t;
136
137static int compat_radeon_cp_stipple(struct file *file, unsigned int cmd,
138 unsigned long arg)
139{
140 drm_radeon_stipple32_t __user *argp = (void __user *) arg;
141 drm_radeon_stipple_t __user *request;
142 u32 mask;
143
144 if (get_user(mask, &argp->mask))
145 return -EFAULT;
146
147 request = compat_alloc_user_space(sizeof(*request));
148 if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
149 || __put_user((unsigned int __user *)(unsigned long) mask,
150 &request->mask))
151 return -EFAULT;
152
153 return drm_ioctl(file->f_dentry->d_inode, file,
154 DRM_IOCTL_RADEON_STIPPLE, (unsigned long) request);
155}
156
157typedef struct drm_radeon_tex_image32 {
158 unsigned int x, y; /* Blit coordinates */
159 unsigned int width, height;
160 u32 data;
161} drm_radeon_tex_image32_t;
162
163typedef struct drm_radeon_texture32 {
164 unsigned int offset;
165 int pitch;
166 int format;
167 int width; /* Texture image coordinates */
168 int height;
169 u32 image;
170} drm_radeon_texture32_t;
171
172static int compat_radeon_cp_texture(struct file *file, unsigned int cmd,
173 unsigned long arg)
174{
175 drm_radeon_texture32_t req32;
176 drm_radeon_texture_t __user *request;
177 drm_radeon_tex_image32_t img32;
178 drm_radeon_tex_image_t __user *image;
179
180 if (copy_from_user(&req32, (void __user *) arg, sizeof(req32)))
181 return -EFAULT;
182 if (req32.image == 0)
183 return -EINVAL;
184 if (copy_from_user(&img32, (void __user *)(unsigned long)req32.image,
185 sizeof(img32)))
186 return -EFAULT;
187
188 request = compat_alloc_user_space(sizeof(*request) + sizeof(*image));
189 if (!access_ok(VERIFY_WRITE, request,
190 sizeof(*request) + sizeof(*image)))
191 return -EFAULT;
192 image = (drm_radeon_tex_image_t __user *) (request + 1);
193
194 if (__put_user(req32.offset, &request->offset)
195 || __put_user(req32.pitch, &request->pitch)
196 || __put_user(req32.format, &request->format)
197 || __put_user(req32.width, &request->width)
198 || __put_user(req32.height, &request->height)
199 || __put_user(image, &request->image)
200 || __put_user(img32.x, &image->x)
201 || __put_user(img32.y, &image->y)
202 || __put_user(img32.width, &image->width)
203 || __put_user(img32.height, &image->height)
204 || __put_user((const void __user *)(unsigned long)img32.data,
205 &image->data))
206 return -EFAULT;
207
208 return drm_ioctl(file->f_dentry->d_inode, file,
209 DRM_IOCTL_RADEON_TEXTURE, (unsigned long) request);
210}
211
212typedef struct drm_radeon_vertex2_32 {
213 int idx; /* Index of vertex buffer */
214 int discard; /* Client finished with buffer? */
215 int nr_states;
216 u32 state;
217 int nr_prims;
218 u32 prim;
219} drm_radeon_vertex2_32_t;
220
221static int compat_radeon_cp_vertex2(struct file *file, unsigned int cmd,
222 unsigned long arg)
223{
224 drm_radeon_vertex2_32_t req32;
225 drm_radeon_vertex2_t __user *request;
226
227 if (copy_from_user(&req32, (void __user *) arg, sizeof(req32)))
228 return -EFAULT;
229
230 request = compat_alloc_user_space(sizeof(*request));
231 if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
232 || __put_user(req32.idx, &request->idx)
233 || __put_user(req32.discard, &request->discard)
234 || __put_user(req32.nr_states, &request->nr_states)
235 || __put_user((void __user *)(unsigned long)req32.state,
236 &request->state)
237 || __put_user(req32.nr_prims, &request->nr_prims)
238 || __put_user((void __user *)(unsigned long)req32.prim,
239 &request->prim))
240 return -EFAULT;
241
242 return drm_ioctl(file->f_dentry->d_inode, file,
243 DRM_IOCTL_RADEON_VERTEX2, (unsigned long) request);
244}
245
246typedef struct drm_radeon_cmd_buffer32 {
247 int bufsz;
248 u32 buf;
249 int nbox;
250 u32 boxes;
251} drm_radeon_cmd_buffer32_t;
252
253static int compat_radeon_cp_cmdbuf(struct file *file, unsigned int cmd,
254 unsigned long arg)
255{
256 drm_radeon_cmd_buffer32_t req32;
257 drm_radeon_cmd_buffer_t __user *request;
258
259 if (copy_from_user(&req32, (void __user *) arg, sizeof(req32)))
260 return -EFAULT;
261
262 request = compat_alloc_user_space(sizeof(*request));
263 if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
264 || __put_user(req32.bufsz, &request->bufsz)
265 || __put_user((void __user *)(unsigned long)req32.buf,
266 &request->buf)
267 || __put_user(req32.nbox, &request->nbox)
268 || __put_user((void __user *)(unsigned long)req32.boxes,
269 &request->boxes))
270 return -EFAULT;
271
272 return drm_ioctl(file->f_dentry->d_inode, file,
273 DRM_IOCTL_RADEON_CMDBUF, (unsigned long) request);
274}
275
276typedef struct drm_radeon_getparam32 {
277 int param;
278 u32 value;
279} drm_radeon_getparam32_t;
280
281static int compat_radeon_cp_getparam(struct file *file, unsigned int cmd,
282 unsigned long arg)
283{
284 drm_radeon_getparam32_t req32;
285 drm_radeon_getparam_t __user *request;
286
287 if (copy_from_user(&req32, (void __user *) arg, sizeof(req32)))
288 return -EFAULT;
289
290 request = compat_alloc_user_space(sizeof(*request));
291 if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
292 || __put_user(req32.param, &request->param)
293 || __put_user((void __user *)(unsigned long)req32.value,
294 &request->value))
295 return -EFAULT;
296
297 return drm_ioctl(file->f_dentry->d_inode, file,
298 DRM_IOCTL_RADEON_GETPARAM, (unsigned long) request);
299}
300
301typedef struct drm_radeon_mem_alloc32 {
302 int region;
303 int alignment;
304 int size;
305 u32 region_offset; /* offset from start of fb or GART */
306} drm_radeon_mem_alloc32_t;
307
308static int compat_radeon_mem_alloc(struct file *file, unsigned int cmd,
309 unsigned long arg)
310{
311 drm_radeon_mem_alloc32_t req32;
312 drm_radeon_mem_alloc_t __user *request;
313
314 if (copy_from_user(&req32, (void __user *) arg, sizeof(req32)))
315 return -EFAULT;
316
317 request = compat_alloc_user_space(sizeof(*request));
318 if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
319 || __put_user(req32.region, &request->region)
320 || __put_user(req32.alignment, &request->alignment)
321 || __put_user(req32.size, &request->size)
322 || __put_user((int __user *)(unsigned long)req32.region_offset,
323 &request->region_offset))
324 return -EFAULT;
325
326 return drm_ioctl(file->f_dentry->d_inode, file,
327 DRM_IOCTL_RADEON_ALLOC, (unsigned long) request);
328}
329
330typedef struct drm_radeon_irq_emit32 {
331 u32 irq_seq;
332} drm_radeon_irq_emit32_t;
333
334static int compat_radeon_irq_emit(struct file *file, unsigned int cmd,
335 unsigned long arg)
336{
337 drm_radeon_irq_emit32_t req32;
338 drm_radeon_irq_emit_t __user *request;
339
340 if (copy_from_user(&req32, (void __user *) arg, sizeof(req32)))
341 return -EFAULT;
342
343 request = compat_alloc_user_space(sizeof(*request));
344 if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
345 || __put_user((int __user *)(unsigned long)req32.irq_seq,
346 &request->irq_seq))
347 return -EFAULT;
348
349 return drm_ioctl(file->f_dentry->d_inode, file,
350 DRM_IOCTL_RADEON_IRQ_EMIT, (unsigned long) request);
351}
352
353drm_ioctl_compat_t *radeon_compat_ioctls[] = {
354 [DRM_RADEON_CP_INIT] = compat_radeon_cp_init,
355 [DRM_RADEON_CLEAR] = compat_radeon_cp_clear,
356 [DRM_RADEON_STIPPLE] = compat_radeon_cp_stipple,
357 [DRM_RADEON_TEXTURE] = compat_radeon_cp_texture,
358 [DRM_RADEON_VERTEX2] = compat_radeon_cp_vertex2,
359 [DRM_RADEON_CMDBUF] = compat_radeon_cp_cmdbuf,
360 [DRM_RADEON_GETPARAM] = compat_radeon_cp_getparam,
361 [DRM_RADEON_ALLOC] = compat_radeon_mem_alloc,
362 [DRM_RADEON_IRQ_EMIT] = compat_radeon_irq_emit,
363};
364
365/**
366 * Called whenever a 32-bit process running under a 64-bit kernel
367 * performs an ioctl on /dev/dri/card<n>.
368 *
369 * \param filp file pointer.
370 * \param cmd command.
371 * \param arg user argument.
372 * \return zero on success or negative number on failure.
373 */
374long radeon_compat_ioctl(struct file *filp, unsigned int cmd,
375 unsigned long arg)
376{
377 unsigned int nr = DRM_IOCTL_NR(cmd);
378 drm_ioctl_compat_t *fn = NULL;
379 int ret;
380
381 if (nr < DRM_COMMAND_BASE)
382 return drm_compat_ioctl(filp, cmd, arg);
383
384 if (nr < DRM_COMMAND_BASE + DRM_ARRAY_SIZE(radeon_compat_ioctls))
385 fn = radeon_compat_ioctls[nr - DRM_COMMAND_BASE];
386
387 lock_kernel(); /* XXX for now */
388 if (fn != NULL)
389 ret = (*fn)(filp, cmd, arg);
390 else
391 ret = drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
392 unlock_kernel();
393
394 return ret;
395}