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 <linux/uaccess.h> 35 #include "agp.h" 36 #include "compat_ioctl.h" 37 38 static 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 61 static 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_array(ureserve.seg_count, 102 sizeof(*usegment), 103 GFP_KERNEL); 104 if (!usegment) 105 return -ENOMEM; 106 107 ksegment = kmalloc_array(kreserve.seg_count, 108 sizeof(*ksegment), 109 GFP_KERNEL); 110 if (!ksegment) { 111 kfree(usegment); 112 return -ENOMEM; 113 } 114 115 if (copy_from_user(usegment, (void __user *) ureserve.seg_list, 116 sizeof(*usegment) * ureserve.seg_count)) { 117 kfree(usegment); 118 kfree(ksegment); 119 return -EFAULT; 120 } 121 122 for (seg = 0; seg < ureserve.seg_count; seg++) { 123 ksegment[seg].pg_start = usegment[seg].pg_start; 124 ksegment[seg].pg_count = usegment[seg].pg_count; 125 ksegment[seg].prot = usegment[seg].prot; 126 } 127 128 kfree(usegment); 129 kreserve.seg_list = ksegment; 130 131 if (client == NULL) { 132 /* Create the client and add the segment */ 133 client = agp_create_client(kreserve.pid); 134 135 if (client == NULL) { 136 kfree(ksegment); 137 return -ENOMEM; 138 } 139 client_priv = agp_find_private(kreserve.pid); 140 141 if (client_priv != NULL) { 142 set_bit(AGP_FF_IS_CLIENT, &client_priv->access_flags); 143 set_bit(AGP_FF_IS_VALID, &client_priv->access_flags); 144 } 145 } 146 return agp_create_segment(client, &kreserve); 147 } 148 /* Will never really happen */ 149 return -EINVAL; 150 } 151 152 static int compat_agpioc_allocate_wrap(struct agp_file_private *priv, void __user *arg) 153 { 154 struct agp_memory *memory; 155 struct agp_allocate32 alloc; 156 157 DBG(""); 158 if (copy_from_user(&alloc, arg, sizeof(alloc))) 159 return -EFAULT; 160 161 memory = agp_allocate_memory_wrap(alloc.pg_count, alloc.type); 162 163 if (memory == NULL) 164 return -ENOMEM; 165 166 alloc.key = memory->key; 167 alloc.physical = memory->physical; 168 169 if (copy_to_user(arg, &alloc, sizeof(alloc))) { 170 agp_free_memory_wrap(memory); 171 return -EFAULT; 172 } 173 return 0; 174 } 175 176 static int compat_agpioc_bind_wrap(struct agp_file_private *priv, void __user *arg) 177 { 178 struct agp_bind32 bind_info; 179 struct agp_memory *memory; 180 181 DBG(""); 182 if (copy_from_user(&bind_info, arg, sizeof(bind_info))) 183 return -EFAULT; 184 185 memory = agp_find_mem_by_key(bind_info.key); 186 187 if (memory == NULL) 188 return -EINVAL; 189 190 return agp_bind_memory(memory, bind_info.pg_start); 191 } 192 193 static int compat_agpioc_unbind_wrap(struct agp_file_private *priv, void __user *arg) 194 { 195 struct agp_memory *memory; 196 struct agp_unbind32 unbind; 197 198 DBG(""); 199 if (copy_from_user(&unbind, arg, sizeof(unbind))) 200 return -EFAULT; 201 202 memory = agp_find_mem_by_key(unbind.key); 203 204 if (memory == NULL) 205 return -EINVAL; 206 207 return agp_unbind_memory(memory); 208 } 209 210 long compat_agp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 211 { 212 struct agp_file_private *curr_priv = file->private_data; 213 int ret_val = -ENOTTY; 214 215 mutex_lock(&(agp_fe.agp_mutex)); 216 217 if ((agp_fe.current_controller == NULL) && 218 (cmd != AGPIOC_ACQUIRE32)) { 219 ret_val = -EINVAL; 220 goto ioctl_out; 221 } 222 if ((agp_fe.backend_acquired != true) && 223 (cmd != AGPIOC_ACQUIRE32)) { 224 ret_val = -EBUSY; 225 goto ioctl_out; 226 } 227 if (cmd != AGPIOC_ACQUIRE32) { 228 if (!(test_bit(AGP_FF_IS_CONTROLLER, &curr_priv->access_flags))) { 229 ret_val = -EPERM; 230 goto ioctl_out; 231 } 232 /* Use the original pid of the controller, 233 * in case it's threaded */ 234 235 if (agp_fe.current_controller->pid != curr_priv->my_pid) { 236 ret_val = -EBUSY; 237 goto ioctl_out; 238 } 239 } 240 241 switch (cmd) { 242 case AGPIOC_INFO32: 243 ret_val = compat_agpioc_info_wrap(curr_priv, (void __user *) arg); 244 break; 245 246 case AGPIOC_ACQUIRE32: 247 ret_val = agpioc_acquire_wrap(curr_priv); 248 break; 249 250 case AGPIOC_RELEASE32: 251 ret_val = agpioc_release_wrap(curr_priv); 252 break; 253 254 case AGPIOC_SETUP32: 255 ret_val = agpioc_setup_wrap(curr_priv, (void __user *) arg); 256 break; 257 258 case AGPIOC_RESERVE32: 259 ret_val = compat_agpioc_reserve_wrap(curr_priv, (void __user *) arg); 260 break; 261 262 case AGPIOC_PROTECT32: 263 ret_val = agpioc_protect_wrap(curr_priv); 264 break; 265 266 case AGPIOC_ALLOCATE32: 267 ret_val = compat_agpioc_allocate_wrap(curr_priv, (void __user *) arg); 268 break; 269 270 case AGPIOC_DEALLOCATE32: 271 ret_val = agpioc_deallocate_wrap(curr_priv, (int) arg); 272 break; 273 274 case AGPIOC_BIND32: 275 ret_val = compat_agpioc_bind_wrap(curr_priv, (void __user *) arg); 276 break; 277 278 case AGPIOC_UNBIND32: 279 ret_val = compat_agpioc_unbind_wrap(curr_priv, (void __user *) arg); 280 break; 281 282 case AGPIOC_CHIPSET_FLUSH32: 283 break; 284 } 285 286 ioctl_out: 287 DBG("ioctl returns %d\n", ret_val); 288 mutex_unlock(&(agp_fe.agp_mutex)); 289 return ret_val; 290 } 291 292