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