1/* 2 * AGPGART driver frontend compatibility ioctls 3 * Copyright (C) 2004 Silicon Graphics, Inc. 4 * Copyright (C) 2002-2003 Dave Jones 5 * Copyright (C) 1999 Jeff Hartmann 6 * Copyright (C) 1999 Precision Insight, Inc. 7 * Copyright (C) 1999 Xi Graphics, Inc. 8 * 9 * Permission is hereby granted, free of charge, to any person obtaining a 10 * copy of this software and associated documentation files (the "Software"), 11 * to deal in the Software without restriction, including without limitation 12 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 13 * and/or sell copies of the Software, and to permit persons to whom the 14 * Software is furnished to do so, subject to the following conditions: 15 * 16 * The above copyright notice and this permission notice shall be included 17 * in all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 22 * JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM, 23 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 24 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 25 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 * 27 */ 28 29#include <linux/kernel.h> 30#include <linux/pci.h> 31#include <linux/fs.h> 32#include <linux/agpgart.h> 33#include <linux/slab.h> 34#include <asm/uaccess.h> 35#include "agp.h" 36#include "compat_ioctl.h" 37 38static int compat_agpioc_info_wrap(struct agp_file_private *priv, void __user *arg) 39{ 40 struct agp_info32 userinfo; 41 struct agp_kern_info kerninfo; 42 43 agp_copy_info(agp_bridge, &kerninfo); 44 45 userinfo.version.major = kerninfo.version.major; 46 userinfo.version.minor = kerninfo.version.minor; 47 userinfo.bridge_id = kerninfo.device->vendor | 48 (kerninfo.device->device << 16); 49 userinfo.agp_mode = kerninfo.mode; 50 userinfo.aper_base = (compat_long_t)kerninfo.aper_base; 51 userinfo.aper_size = kerninfo.aper_size; 52 userinfo.pg_total = userinfo.pg_system = kerninfo.max_memory; 53 userinfo.pg_used = kerninfo.current_memory; 54 55 if (copy_to_user(arg, &userinfo, sizeof(userinfo))) 56 return -EFAULT; 57 58 return 0; 59} 60 61static int compat_agpioc_reserve_wrap(struct agp_file_private *priv, void __user *arg) 62{ 63 struct agp_region32 ureserve; 64 struct agp_region kreserve; 65 struct agp_client *client; 66 struct agp_file_private *client_priv; 67 68 DBG(""); 69 if (copy_from_user(&ureserve, arg, sizeof(ureserve))) 70 return -EFAULT; 71 72 if ((unsigned) ureserve.seg_count >= ~0U/sizeof(struct agp_segment32)) 73 return -EFAULT; 74 75 kreserve.pid = ureserve.pid; 76 kreserve.seg_count = ureserve.seg_count; 77 78 client = agp_find_client_by_pid(kreserve.pid); 79 80 if (kreserve.seg_count == 0) { 81 /* remove a client */ 82 client_priv = agp_find_private(kreserve.pid); 83 84 if (client_priv != NULL) { 85 set_bit(AGP_FF_IS_CLIENT, &client_priv->access_flags); 86 set_bit(AGP_FF_IS_VALID, &client_priv->access_flags); 87 } 88 if (client == NULL) { 89 /* client is already removed */ 90 return 0; 91 } 92 return agp_remove_client(kreserve.pid); 93 } else { 94 struct agp_segment32 *usegment; 95 struct agp_segment *ksegment; 96 int seg; 97 98 if (ureserve.seg_count >= 16384) 99 return -EINVAL; 100 101 usegment = kmalloc(sizeof(*usegment) * ureserve.seg_count, GFP_KERNEL); 102 if (!usegment) 103 return -ENOMEM; 104 105 ksegment = kmalloc(sizeof(*ksegment) * kreserve.seg_count, GFP_KERNEL); 106 if (!ksegment) { 107 kfree(usegment); 108 return -ENOMEM; 109 } 110 111 if (copy_from_user(usegment, (void __user *) ureserve.seg_list, 112 sizeof(*usegment) * ureserve.seg_count)) { 113 kfree(usegment); 114 kfree(ksegment); 115 return -EFAULT; 116 } 117 118 for (seg = 0; seg < ureserve.seg_count; seg++) { 119 ksegment[seg].pg_start = usegment[seg].pg_start; 120 ksegment[seg].pg_count = usegment[seg].pg_count; 121 ksegment[seg].prot = usegment[seg].prot; 122 } 123 124 kfree(usegment); 125 kreserve.seg_list = ksegment; 126 127 if (client == NULL) { 128 /* Create the client and add the segment */ 129 client = agp_create_client(kreserve.pid); 130 131 if (client == NULL) { 132 kfree(ksegment); 133 return -ENOMEM; 134 } 135 client_priv = agp_find_private(kreserve.pid); 136 137 if (client_priv != NULL) { 138 set_bit(AGP_FF_IS_CLIENT, &client_priv->access_flags); 139 set_bit(AGP_FF_IS_VALID, &client_priv->access_flags); 140 } 141 } 142 return agp_create_segment(client, &kreserve); 143 } 144 /* Will never really happen */ 145 return -EINVAL; 146} 147 148static int compat_agpioc_allocate_wrap(struct agp_file_private *priv, void __user *arg) 149{ 150 struct agp_memory *memory; 151 struct agp_allocate32 alloc; 152 153 DBG(""); 154 if (copy_from_user(&alloc, arg, sizeof(alloc))) 155 return -EFAULT; 156 157 memory = agp_allocate_memory_wrap(alloc.pg_count, alloc.type); 158 159 if (memory == NULL) 160 return -ENOMEM; 161 162 alloc.key = memory->key; 163 alloc.physical = memory->physical; 164 165 if (copy_to_user(arg, &alloc, sizeof(alloc))) { 166 agp_free_memory_wrap(memory); 167 return -EFAULT; 168 } 169 return 0; 170} 171 172static int compat_agpioc_bind_wrap(struct agp_file_private *priv, void __user *arg) 173{ 174 struct agp_bind32 bind_info; 175 struct agp_memory *memory; 176 177 DBG(""); 178 if (copy_from_user(&bind_info, arg, sizeof(bind_info))) 179 return -EFAULT; 180 181 memory = agp_find_mem_by_key(bind_info.key); 182 183 if (memory == NULL) 184 return -EINVAL; 185 186 return agp_bind_memory(memory, bind_info.pg_start); 187} 188 189static int compat_agpioc_unbind_wrap(struct agp_file_private *priv, void __user *arg) 190{ 191 struct agp_memory *memory; 192 struct agp_unbind32 unbind; 193 194 DBG(""); 195 if (copy_from_user(&unbind, arg, sizeof(unbind))) 196 return -EFAULT; 197 198 memory = agp_find_mem_by_key(unbind.key); 199 200 if (memory == NULL) 201 return -EINVAL; 202 203 return agp_unbind_memory(memory); 204} 205 206long compat_agp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 207{ 208 struct agp_file_private *curr_priv = file->private_data; 209 int ret_val = -ENOTTY; 210 211 mutex_lock(&(agp_fe.agp_mutex)); 212 213 if ((agp_fe.current_controller == NULL) && 214 (cmd != AGPIOC_ACQUIRE32)) { 215 ret_val = -EINVAL; 216 goto ioctl_out; 217 } 218 if ((agp_fe.backend_acquired != true) && 219 (cmd != AGPIOC_ACQUIRE32)) { 220 ret_val = -EBUSY; 221 goto ioctl_out; 222 } 223 if (cmd != AGPIOC_ACQUIRE32) { 224 if (!(test_bit(AGP_FF_IS_CONTROLLER, &curr_priv->access_flags))) { 225 ret_val = -EPERM; 226 goto ioctl_out; 227 } 228 /* Use the original pid of the controller, 229 * in case it's threaded */ 230 231 if (agp_fe.current_controller->pid != curr_priv->my_pid) { 232 ret_val = -EBUSY; 233 goto ioctl_out; 234 } 235 } 236 237 switch (cmd) { 238 case AGPIOC_INFO32: 239 ret_val = compat_agpioc_info_wrap(curr_priv, (void __user *) arg); 240 break; 241 242 case AGPIOC_ACQUIRE32: 243 ret_val = agpioc_acquire_wrap(curr_priv); 244 break; 245 246 case AGPIOC_RELEASE32: 247 ret_val = agpioc_release_wrap(curr_priv); 248 break; 249 250 case AGPIOC_SETUP32: 251 ret_val = agpioc_setup_wrap(curr_priv, (void __user *) arg); 252 break; 253 254 case AGPIOC_RESERVE32: 255 ret_val = compat_agpioc_reserve_wrap(curr_priv, (void __user *) arg); 256 break; 257 258 case AGPIOC_PROTECT32: 259 ret_val = agpioc_protect_wrap(curr_priv); 260 break; 261 262 case AGPIOC_ALLOCATE32: 263 ret_val = compat_agpioc_allocate_wrap(curr_priv, (void __user *) arg); 264 break; 265 266 case AGPIOC_DEALLOCATE32: 267 ret_val = agpioc_deallocate_wrap(curr_priv, (int) arg); 268 break; 269 270 case AGPIOC_BIND32: 271 ret_val = compat_agpioc_bind_wrap(curr_priv, (void __user *) arg); 272 break; 273 274 case AGPIOC_UNBIND32: 275 ret_val = compat_agpioc_unbind_wrap(curr_priv, (void __user *) arg); 276 break; 277 278 case AGPIOC_CHIPSET_FLUSH32: 279 break; 280 } 281 282ioctl_out: 283 DBG("ioctl returns %d\n", ret_val); 284 mutex_unlock(&(agp_fe.agp_mutex)); 285 return ret_val; 286} 287 288