Branch data Line data Source code
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 : 0 : long compat_agp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
211 : : {
212 : 0 : struct agp_file_private *curr_priv = file->private_data;
213 : 0 : int ret_val = -ENOTTY;
214 : :
215 : 0 : mutex_lock(&(agp_fe.agp_mutex));
216 : :
217 [ # # # # ]: 0 : if ((agp_fe.current_controller == NULL) &&
218 : : (cmd != AGPIOC_ACQUIRE32)) {
219 : 0 : ret_val = -EINVAL;
220 : 0 : goto ioctl_out;
221 : : }
222 [ # # # # ]: 0 : if ((agp_fe.backend_acquired != true) &&
223 : : (cmd != AGPIOC_ACQUIRE32)) {
224 : 0 : ret_val = -EBUSY;
225 : 0 : goto ioctl_out;
226 : : }
227 [ # # ]: 0 : if (cmd != AGPIOC_ACQUIRE32) {
228 [ # # ]: 0 : if (!(test_bit(AGP_FF_IS_CONTROLLER, &curr_priv->access_flags))) {
229 : 0 : ret_val = -EPERM;
230 : 0 : goto ioctl_out;
231 : : }
232 : : /* Use the original pid of the controller,
233 : : * in case it's threaded */
234 : :
235 [ # # ]: 0 : if (agp_fe.current_controller->pid != curr_priv->my_pid) {
236 : 0 : ret_val = -EBUSY;
237 : 0 : goto ioctl_out;
238 : : }
239 : : }
240 : :
241 [ # # # # : 0 : switch (cmd) {
# # # # #
# # ]
242 : 0 : case AGPIOC_INFO32:
243 : 0 : ret_val = compat_agpioc_info_wrap(curr_priv, (void __user *) arg);
244 : 0 : break;
245 : :
246 : 0 : case AGPIOC_ACQUIRE32:
247 : 0 : ret_val = agpioc_acquire_wrap(curr_priv);
248 : 0 : break;
249 : :
250 : 0 : case AGPIOC_RELEASE32:
251 : 0 : ret_val = agpioc_release_wrap(curr_priv);
252 : 0 : break;
253 : :
254 : 0 : case AGPIOC_SETUP32:
255 : 0 : ret_val = agpioc_setup_wrap(curr_priv, (void __user *) arg);
256 : 0 : break;
257 : :
258 : 0 : case AGPIOC_RESERVE32:
259 : 0 : ret_val = compat_agpioc_reserve_wrap(curr_priv, (void __user *) arg);
260 : 0 : break;
261 : :
262 : 0 : case AGPIOC_PROTECT32:
263 : 0 : ret_val = agpioc_protect_wrap(curr_priv);
264 : 0 : break;
265 : :
266 : 0 : case AGPIOC_ALLOCATE32:
267 : 0 : ret_val = compat_agpioc_allocate_wrap(curr_priv, (void __user *) arg);
268 : 0 : break;
269 : :
270 : 0 : case AGPIOC_DEALLOCATE32:
271 : 0 : ret_val = agpioc_deallocate_wrap(curr_priv, (int) arg);
272 : 0 : break;
273 : :
274 : 0 : case AGPIOC_BIND32:
275 : 0 : ret_val = compat_agpioc_bind_wrap(curr_priv, (void __user *) arg);
276 : 0 : break;
277 : :
278 : 0 : case AGPIOC_UNBIND32:
279 : 0 : ret_val = compat_agpioc_unbind_wrap(curr_priv, (void __user *) arg);
280 : 0 : break;
281 : :
282 : : case AGPIOC_CHIPSET_FLUSH32:
283 : : break;
284 : : }
285 : :
286 : 0 : ioctl_out:
287 : 0 : DBG("ioctl returns %d\n", ret_val);
288 : 0 : mutex_unlock(&(agp_fe.agp_mutex));
289 : 0 : return ret_val;
290 : : }
291 : :
|