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 <asm/uaccess.h> 34 #include "agp.h" 35 #include "compat_ioctl.h" 36 37 static int compat_agpioc_info_wrap(struct agp_file_private *priv, void __user *arg) 38 { 39 struct agp_info32 userinfo; 40 struct agp_kern_info kerninfo; 41 42 agp_copy_info(agp_bridge, &kerninfo); 43 44 userinfo.version.major = kerninfo.version.major; 45 userinfo.version.minor = kerninfo.version.minor; 46 userinfo.bridge_id = kerninfo.device->vendor | 47 (kerninfo.device->device << 16); 48 userinfo.agp_mode = kerninfo.mode; 49 userinfo.aper_base = (compat_long_t)kerninfo.aper_base; 50 userinfo.aper_size = kerninfo.aper_size; 51 userinfo.pg_total = userinfo.pg_system = kerninfo.max_memory; 52 userinfo.pg_used = kerninfo.current_memory; 53 54 if (copy_to_user(arg, &userinfo, sizeof(userinfo))) 55 return -EFAULT; 56 57 return 0; 58 } 59 60 static int compat_agpioc_reserve_wrap(struct agp_file_private *priv, void __user *arg) 61 { 62 struct agp_region32 ureserve; 63 struct agp_region kreserve; 64 struct agp_client *client; 65 struct agp_file_private *client_priv; 66 67 DBG(""); 68 if (copy_from_user(&ureserve, arg, sizeof(ureserve))) 69 return -EFAULT; 70 71 if ((unsigned) ureserve.seg_count >= ~0U/sizeof(struct agp_segment32)) 72 return -EFAULT; 73 74 kreserve.pid = ureserve.pid; 75 kreserve.seg_count = ureserve.seg_count; 76 77 client = agp_find_client_by_pid(kreserve.pid); 78 79 if (kreserve.seg_count == 0) { 80 /* remove a client */ 81 client_priv = agp_find_private(kreserve.pid); 82 83 if (client_priv != NULL) { 84 set_bit(AGP_FF_IS_CLIENT, &client_priv->access_flags); 85 set_bit(AGP_FF_IS_VALID, &client_priv->access_flags); 86 } 87 if (client == NULL) { 88 /* client is already removed */ 89 return 0; 90 } 91 return agp_remove_client(kreserve.pid); 92 } else { 93 struct agp_segment32 *usegment; 94 struct agp_segment *ksegment; 95 int seg; 96 97 if (ureserve.seg_count >= 16384) 98 return -EINVAL; 99 100 usegment = kmalloc(sizeof(*usegment) * ureserve.seg_count, GFP_KERNEL); 101 if (!usegment) 102 return -ENOMEM; 103 104 ksegment = kmalloc(sizeof(*ksegment) * kreserve.seg_count, GFP_KERNEL); 105 if (!ksegment) { 106 kfree(usegment); 107 return -ENOMEM; 108 } 109 110 if (copy_from_user(usegment, (void __user *) ureserve.seg_list, 111 sizeof(*usegment) * ureserve.seg_count)) { 112 kfree(usegment); 113 kfree(ksegment); 114 return -EFAULT; 115 } 116 117 for (seg = 0; seg < ureserve.seg_count; seg++) { 118 ksegment[seg].pg_start = usegment[seg].pg_start; 119 ksegment[seg].pg_count = usegment[seg].pg_count; 120 ksegment[seg].prot = usegment[seg].prot; 121 } 122 123 kfree(usegment); 124 kreserve.seg_list = ksegment; 125 126 if (client == NULL) { 127 /* Create the client and add the segment */ 128 client = agp_create_client(kreserve.pid); 129 130 if (client == NULL) { 131 kfree(ksegment); 132 return -ENOMEM; 133 } 134 client_priv = agp_find_private(kreserve.pid); 135 136 if (client_priv != NULL) { 137 set_bit(AGP_FF_IS_CLIENT, &client_priv->access_flags); 138 set_bit(AGP_FF_IS_VALID, &client_priv->access_flags); 139 } 140 } 141 return agp_create_segment(client, &kreserve); 142 } 143 /* Will never really happen */ 144 return -EINVAL; 145 } 146 147 static int compat_agpioc_allocate_wrap(struct agp_file_private *priv, void __user *arg) 148 { 149 struct agp_memory *memory; 150 struct agp_allocate32 alloc; 151 152 DBG(""); 153 if (copy_from_user(&alloc, arg, sizeof(alloc))) 154 return -EFAULT; 155 156 memory = agp_allocate_memory_wrap(alloc.pg_count, alloc.type); 157 158 if (memory == NULL) 159 return -ENOMEM; 160 161 alloc.key = memory->key; 162 alloc.physical = memory->physical; 163 164 if (copy_to_user(arg, &alloc, sizeof(alloc))) { 165 agp_free_memory_wrap(memory); 166 return -EFAULT; 167 } 168 return 0; 169 } 170 171 static int compat_agpioc_bind_wrap(struct agp_file_private *priv, void __user *arg) 172 { 173 struct agp_bind32 bind_info; 174 struct agp_memory *memory; 175 176 DBG(""); 177 if (copy_from_user(&bind_info, arg, sizeof(bind_info))) 178 return -EFAULT; 179 180 memory = agp_find_mem_by_key(bind_info.key); 181 182 if (memory == NULL) 183 return -EINVAL; 184 185 return agp_bind_memory(memory, bind_info.pg_start); 186 } 187 188 static int compat_agpioc_unbind_wrap(struct agp_file_private *priv, void __user *arg) 189 { 190 struct agp_memory *memory; 191 struct agp_unbind32 unbind; 192 193 DBG(""); 194 if (copy_from_user(&unbind, arg, sizeof(unbind))) 195 return -EFAULT; 196 197 memory = agp_find_mem_by_key(unbind.key); 198 199 if (memory == NULL) 200 return -EINVAL; 201 202 return agp_unbind_memory(memory); 203 } 204 205 long compat_agp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 206 { 207 struct agp_file_private *curr_priv = file->private_data; 208 int ret_val = -ENOTTY; 209 210 mutex_lock(&(agp_fe.agp_mutex)); 211 212 if ((agp_fe.current_controller == NULL) && 213 (cmd != AGPIOC_ACQUIRE32)) { 214 ret_val = -EINVAL; 215 goto ioctl_out; 216 } 217 if ((agp_fe.backend_acquired != TRUE) && 218 (cmd != AGPIOC_ACQUIRE32)) { 219 ret_val = -EBUSY; 220 goto ioctl_out; 221 } 222 if (cmd != AGPIOC_ACQUIRE32) { 223 if (!(test_bit(AGP_FF_IS_CONTROLLER, &curr_priv->access_flags))) { 224 ret_val = -EPERM; 225 goto ioctl_out; 226 } 227 /* Use the original pid of the controller, 228 * in case it's threaded */ 229 230 if (agp_fe.current_controller->pid != curr_priv->my_pid) { 231 ret_val = -EBUSY; 232 goto ioctl_out; 233 } 234 } 235 236 switch (cmd) { 237 case AGPIOC_INFO32: 238 ret_val = compat_agpioc_info_wrap(curr_priv, (void __user *) arg); 239 break; 240 241 case AGPIOC_ACQUIRE32: 242 ret_val = agpioc_acquire_wrap(curr_priv); 243 break; 244 245 case AGPIOC_RELEASE32: 246 ret_val = agpioc_release_wrap(curr_priv); 247 break; 248 249 case AGPIOC_SETUP32: 250 ret_val = agpioc_setup_wrap(curr_priv, (void __user *) arg); 251 break; 252 253 case AGPIOC_RESERVE32: 254 ret_val = compat_agpioc_reserve_wrap(curr_priv, (void __user *) arg); 255 break; 256 257 case AGPIOC_PROTECT32: 258 ret_val = agpioc_protect_wrap(curr_priv); 259 break; 260 261 case AGPIOC_ALLOCATE32: 262 ret_val = compat_agpioc_allocate_wrap(curr_priv, (void __user *) arg); 263 break; 264 265 case AGPIOC_DEALLOCATE32: 266 ret_val = agpioc_deallocate_wrap(curr_priv, (int) arg); 267 break; 268 269 case AGPIOC_BIND32: 270 ret_val = compat_agpioc_bind_wrap(curr_priv, (void __user *) arg); 271 break; 272 273 case AGPIOC_UNBIND32: 274 ret_val = compat_agpioc_unbind_wrap(curr_priv, (void __user *) arg); 275 break; 276 } 277 278 ioctl_out: 279 DBG("ioctl returns %d\n", ret_val); 280 mutex_unlock(&(agp_fe.agp_mutex)); 281 return ret_val; 282 } 283 284