diff -urN linux-2.5/drivers/char/drm/Makefile test/drivers/char/drm/Makefile --- linux-2.5/drivers/char/drm/Makefile 2005-02-03 18:00:27.000000000 +1100 +++ test/drivers/char/drm/Makefile 2005-03-03 19:45:56.000000000 +1100 @@ -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 -urN linux-2.5/drivers/char/drm/drmP.h test/drivers/char/drm/drmP.h --- linux-2.5/drivers/char/drm/drmP.h 2005-02-03 18:00:27.000000000 +1100 +++ test/drivers/char/drm/drmP.h 2005-03-03 19:45:56.000000000 +1100 @@ -527,6 +527,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; @@ -1032,6 +1035,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,5 +1069,8 @@ 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 -urN linux-2.5/drivers/char/drm/drm_drv.c test/drivers/char/drm/drm_drv.c --- linux-2.5/drivers/char/drm/drm_drv.c 2005-02-10 09:06:38.000000000 +1100 +++ test/drivers/char/drm/drm_drv.c 2005-03-03 19:45:56.000000000 +1100 @@ -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 -urN linux-2.5/drivers/char/drm/drm_ioc32.c test/drivers/char/drm/drm_ioc32.c --- /dev/null 2005-02-22 20:41:05.000000000 +1100 +++ test/drivers/char/drm/drm_ioc32.c 2005-03-03 19:50:42.000000000 +1100 @@ -0,0 +1,1234 @@ +/** + * \file drm_ioc32.c + * + * 32-bit ioctl compatibility routines for the DRM. + * + * \author Paul Mackerras + * + * 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 +#include + +#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 -urN linux-2.5/drivers/char/drm/drm_vm.c test/drivers/char/drm/drm_vm.c --- linux-2.5/drivers/char/drm/drm_vm.c 2005-01-27 09:07:53.000000000 +1100 +++ test/drivers/char/drm/drm_vm.c 2005-03-03 19:45:56.000000000 +1100 @@ -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 -urN linux-2.5/drivers/char/drm/radeon_drv.c test/drivers/char/drm/radeon_drv.c --- linux-2.5/drivers/char/drm/radeon_drv.c 2005-02-03 18:00:27.000000000 +1100 +++ test/drivers/char/drm/radeon_drv.c 2005-03-03 19:45:56.000000000 +1100 @@ -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 -urN linux-2.5/drivers/char/drm/radeon_drv.h test/drivers/char/drm/radeon_drv.h --- linux-2.5/drivers/char/drm/radeon_drv.h 2005-02-10 09:06:38.000000000 +1100 +++ test/drivers/char/drm/radeon_drv.h 2005-03-03 19:45:56.000000000 +1100 @@ -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 -urN linux-2.5/drivers/char/drm/radeon_ioc32.c test/drivers/char/drm/radeon_ioc32.c --- /dev/null 2005-02-22 20:41:05.000000000 +1100 +++ test/drivers/char/drm/radeon_ioc32.c 2005-03-03 19:50:44.000000000 +1100 @@ -0,0 +1,481 @@ +/** + * \file radeon_ioc32.c + * + * 32-bit ioctl compatibility routines for the Radeon DRM. + * + * \author Paul Mackerras + * + * 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 +#include + +#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.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); +} +