1/** 2 * \file mga_ioc32.c 3 * 4 * 32-bit ioctl compatibility routines for the MGA DRM. 5 * 6 * \author Dave Airlie <airlied@linux.ie> with code from patches by Egbert Eich 7 * 8 * 9 * Copyright (C) Paul Mackerras 2005 10 * Copyright (C) Egbert Eich 2003,2004 11 * Copyright (C) Dave Airlie 2005 12 * All Rights Reserved. 13 * 14 * Permission is hereby granted, free of charge, to any person obtaining a 15 * copy of this software and associated documentation files (the "Software"), 16 * to deal in the Software without restriction, including without limitation 17 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 18 * and/or sell copies of the Software, and to permit persons to whom the 19 * Software is furnished to do so, subject to the following conditions: 20 * 21 * The above copyright notice and this permission notice (including the next 22 * paragraph) shall be included in all copies or substantial portions of the 23 * Software. 24 * 25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 28 * THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 29 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 30 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 31 * IN THE SOFTWARE. 32 */ 33#include <linux/compat.h> 34 35#include <drm/drmP.h> 36#include <drm/mga_drm.h> 37#include "mga_drv.h" 38 39typedef struct drm32_mga_init { 40 int func; 41 u32 sarea_priv_offset; 42 int chipset; 43 int sgram; 44 unsigned int maccess; 45 unsigned int fb_cpp; 46 unsigned int front_offset, front_pitch; 47 unsigned int back_offset, back_pitch; 48 unsigned int depth_cpp; 49 unsigned int depth_offset, depth_pitch; 50 unsigned int texture_offset[MGA_NR_TEX_HEAPS]; 51 unsigned int texture_size[MGA_NR_TEX_HEAPS]; 52 u32 fb_offset; 53 u32 mmio_offset; 54 u32 status_offset; 55 u32 warp_offset; 56 u32 primary_offset; 57 u32 buffers_offset; 58} drm_mga_init32_t; 59 60static int compat_mga_init(struct file *file, unsigned int cmd, 61 unsigned long arg) 62{ 63 drm_mga_init32_t init32; 64 drm_mga_init_t __user *init; 65 int err = 0, i; 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.chipset, &init->chipset) 75 || __put_user(init32.sgram, &init->sgram) 76 || __put_user(init32.maccess, &init->maccess) 77 || __put_user(init32.fb_cpp, &init->fb_cpp) 78 || __put_user(init32.front_offset, &init->front_offset) 79 || __put_user(init32.front_pitch, &init->front_pitch) 80 || __put_user(init32.back_offset, &init->back_offset) 81 || __put_user(init32.back_pitch, &init->back_pitch) 82 || __put_user(init32.depth_cpp, &init->depth_cpp) 83 || __put_user(init32.depth_offset, &init->depth_offset) 84 || __put_user(init32.depth_pitch, &init->depth_pitch) 85 || __put_user(init32.fb_offset, &init->fb_offset) 86 || __put_user(init32.mmio_offset, &init->mmio_offset) 87 || __put_user(init32.status_offset, &init->status_offset) 88 || __put_user(init32.warp_offset, &init->warp_offset) 89 || __put_user(init32.primary_offset, &init->primary_offset) 90 || __put_user(init32.buffers_offset, &init->buffers_offset)) 91 return -EFAULT; 92 93 for (i = 0; i < MGA_NR_TEX_HEAPS; i++) { 94 err |= 95 __put_user(init32.texture_offset[i], 96 &init->texture_offset[i]); 97 err |= 98 __put_user(init32.texture_size[i], &init->texture_size[i]); 99 } 100 if (err) 101 return -EFAULT; 102 103 return drm_ioctl(file, DRM_IOCTL_MGA_INIT, (unsigned long)init); 104} 105 106typedef struct drm_mga_getparam32 { 107 int param; 108 u32 value; 109} drm_mga_getparam32_t; 110 111static int compat_mga_getparam(struct file *file, unsigned int cmd, 112 unsigned long arg) 113{ 114 drm_mga_getparam32_t getparam32; 115 drm_mga_getparam_t __user *getparam; 116 117 if (copy_from_user(&getparam32, (void __user *)arg, sizeof(getparam32))) 118 return -EFAULT; 119 120 getparam = compat_alloc_user_space(sizeof(*getparam)); 121 if (!access_ok(VERIFY_WRITE, getparam, sizeof(*getparam)) 122 || __put_user(getparam32.param, &getparam->param) 123 || __put_user((void __user *)(unsigned long)getparam32.value, 124 &getparam->value)) 125 return -EFAULT; 126 127 return drm_ioctl(file, DRM_IOCTL_MGA_GETPARAM, (unsigned long)getparam); 128} 129 130typedef struct drm_mga_drm_bootstrap32 { 131 u32 texture_handle; 132 u32 texture_size; 133 u32 primary_size; 134 u32 secondary_bin_count; 135 u32 secondary_bin_size; 136 u32 agp_mode; 137 u8 agp_size; 138} drm_mga_dma_bootstrap32_t; 139 140static int compat_mga_dma_bootstrap(struct file *file, unsigned int cmd, 141 unsigned long arg) 142{ 143 drm_mga_dma_bootstrap32_t dma_bootstrap32; 144 drm_mga_dma_bootstrap_t __user *dma_bootstrap; 145 int err; 146 147 if (copy_from_user(&dma_bootstrap32, (void __user *)arg, 148 sizeof(dma_bootstrap32))) 149 return -EFAULT; 150 151 dma_bootstrap = compat_alloc_user_space(sizeof(*dma_bootstrap)); 152 if (!access_ok(VERIFY_WRITE, dma_bootstrap, sizeof(*dma_bootstrap)) 153 || __put_user(dma_bootstrap32.texture_handle, 154 &dma_bootstrap->texture_handle) 155 || __put_user(dma_bootstrap32.texture_size, 156 &dma_bootstrap->texture_size) 157 || __put_user(dma_bootstrap32.primary_size, 158 &dma_bootstrap->primary_size) 159 || __put_user(dma_bootstrap32.secondary_bin_count, 160 &dma_bootstrap->secondary_bin_count) 161 || __put_user(dma_bootstrap32.secondary_bin_size, 162 &dma_bootstrap->secondary_bin_size) 163 || __put_user(dma_bootstrap32.agp_mode, &dma_bootstrap->agp_mode) 164 || __put_user(dma_bootstrap32.agp_size, &dma_bootstrap->agp_size)) 165 return -EFAULT; 166 167 err = drm_ioctl(file, DRM_IOCTL_MGA_DMA_BOOTSTRAP, 168 (unsigned long)dma_bootstrap); 169 if (err) 170 return err; 171 172 if (__get_user(dma_bootstrap32.texture_handle, 173 &dma_bootstrap->texture_handle) 174 || __get_user(dma_bootstrap32.texture_size, 175 &dma_bootstrap->texture_size) 176 || __get_user(dma_bootstrap32.primary_size, 177 &dma_bootstrap->primary_size) 178 || __get_user(dma_bootstrap32.secondary_bin_count, 179 &dma_bootstrap->secondary_bin_count) 180 || __get_user(dma_bootstrap32.secondary_bin_size, 181 &dma_bootstrap->secondary_bin_size) 182 || __get_user(dma_bootstrap32.agp_mode, &dma_bootstrap->agp_mode) 183 || __get_user(dma_bootstrap32.agp_size, &dma_bootstrap->agp_size)) 184 return -EFAULT; 185 186 if (copy_to_user((void __user *)arg, &dma_bootstrap32, 187 sizeof(dma_bootstrap32))) 188 return -EFAULT; 189 190 return 0; 191} 192 193drm_ioctl_compat_t *mga_compat_ioctls[] = { 194 [DRM_MGA_INIT] = compat_mga_init, 195 [DRM_MGA_GETPARAM] = compat_mga_getparam, 196 [DRM_MGA_DMA_BOOTSTRAP] = compat_mga_dma_bootstrap, 197}; 198 199/** 200 * Called whenever a 32-bit process running under a 64-bit kernel 201 * performs an ioctl on /dev/dri/card<n>. 202 * 203 * \param filp file pointer. 204 * \param cmd command. 205 * \param arg user argument. 206 * \return zero on success or negative number on failure. 207 */ 208long mga_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 209{ 210 unsigned int nr = DRM_IOCTL_NR(cmd); 211 drm_ioctl_compat_t *fn = NULL; 212 int ret; 213 214 if (nr < DRM_COMMAND_BASE) 215 return drm_compat_ioctl(filp, cmd, arg); 216 217 if (nr < DRM_COMMAND_BASE + ARRAY_SIZE(mga_compat_ioctls)) 218 fn = mga_compat_ioctls[nr - DRM_COMMAND_BASE]; 219 220 if (fn != NULL) 221 ret = (*fn) (filp, cmd, arg); 222 else 223 ret = drm_ioctl(filp, cmd, arg); 224 225 return ret; 226} 227