1 /*
2  * AGPGART module frontend version 0.99
3  * Copyright (C) 1999 Jeff Hartmann
4  * Copyright (C) 1999 Precision Insight, Inc.
5  * Copyright (C) 1999 Xi Graphics, Inc.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation
10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11  * and/or sell copies of the Software, and to permit persons to whom the
12  * Software is furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included
15  * in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20  * JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
21  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
23  * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  *
25  */
26 
27 #define __NO_VERSION__
28 #include <linux/version.h>
29 #include <linux/types.h>
30 #include <linux/kernel.h>
31 #include <linux/module.h>
32 #include <linux/sched.h>
33 #include <linux/mm.h>
34 #include <linux/string.h>
35 #include <linux/errno.h>
36 #include <linux/slab.h>
37 #include <linux/vmalloc.h>
38 #include <linux/pci.h>
39 #include <linux/init.h>
40 #include <linux/pagemap.h>
41 #include <linux/miscdevice.h>
42 #include <linux/agp_backend.h>
43 #include <linux/agpgart.h>
44 #include <linux/smp_lock.h>
45 #include <asm/system.h>
46 #include <asm/uaccess.h>
47 #include <asm/io.h>
48 #include <asm/page.h>
49 #include <asm/mman.h>
50 
51 #include "agp.h"
52 
53 static struct agp_front_data agp_fe;
54 
agp_find_mem_by_key(int key)55 static agp_memory *agp_find_mem_by_key(int key)
56 {
57 	agp_memory *curr;
58 
59 	if (agp_fe.current_controller == NULL) {
60 		return NULL;
61 	}
62 	curr = agp_fe.current_controller->pool;
63 
64 	while (curr != NULL) {
65 		if (curr->key == key) {
66 			return curr;
67 		}
68 		curr = curr->next;
69 	}
70 
71 	return NULL;
72 }
73 
agp_remove_from_pool(agp_memory * temp)74 static void agp_remove_from_pool(agp_memory * temp)
75 {
76 	agp_memory *prev;
77 	agp_memory *next;
78 
79 	/* Check to see if this is even in the memory pool */
80 
81 	if (agp_find_mem_by_key(temp->key) != NULL) {
82 		next = temp->next;
83 		prev = temp->prev;
84 
85 		if (prev != NULL) {
86 			prev->next = next;
87 			if (next != NULL) {
88 				next->prev = prev;
89 			}
90 		} else {
91 			/* This is the first item on the list */
92 			if (next != NULL) {
93 				next->prev = NULL;
94 			}
95 			agp_fe.current_controller->pool = next;
96 		}
97 	}
98 }
99 
100 /*
101  * Routines for managing each client's segment list -
102  * These routines handle adding and removing segments
103  * to each auth'ed client.
104  */
105 
agp_find_seg_in_client(const agp_client * client,unsigned long offset,int size,pgprot_t page_prot)106 static agp_segment_priv *agp_find_seg_in_client(const agp_client * client,
107 						unsigned long offset,
108 					    int size, pgprot_t page_prot)
109 {
110 	agp_segment_priv *seg;
111 	int num_segments, pg_start, pg_count, i;
112 
113 	pg_start = offset / 4096;
114 	pg_count = size / 4096;
115 	seg = *(client->segments);
116 	num_segments = client->num_segments;
117 
118 	for (i = 0; i < client->num_segments; i++) {
119 		if ((seg[i].pg_start == pg_start) &&
120 		    (seg[i].pg_count == pg_count) &&
121 		    (pgprot_val(seg[i].prot) == pgprot_val(page_prot))) {
122 			return seg + i;
123 		}
124 	}
125 
126 	return NULL;
127 }
128 
agp_remove_seg_from_client(agp_client * client)129 static void agp_remove_seg_from_client(agp_client * client)
130 {
131 	if (client->segments != NULL) {
132 		if (*(client->segments) != NULL) {
133 			kfree(*(client->segments));
134 		}
135 		kfree(client->segments);
136 	}
137 }
138 
agp_add_seg_to_client(agp_client * client,agp_segment_priv ** seg,int num_segments)139 static void agp_add_seg_to_client(agp_client * client,
140 			       agp_segment_priv ** seg, int num_segments)
141 {
142 	agp_segment_priv **prev_seg;
143 
144 	prev_seg = client->segments;
145 
146 	if (prev_seg != NULL) {
147 		agp_remove_seg_from_client(client);
148 	}
149 	client->num_segments = num_segments;
150 	client->segments = seg;
151 }
152 
153 /* Originally taken from linux/mm/mmap.c from the array
154  * protection_map.
155  * The original really should be exported to modules, or
156  * some routine which does the conversion for you
157  */
158 
159 static const pgprot_t my_protect_map[16] =
160 {
161 	__P000, __P001, __P010, __P011, __P100, __P101, __P110, __P111,
162 	__S000, __S001, __S010, __S011, __S100, __S101, __S110, __S111
163 };
164 
agp_convert_mmap_flags(int prot)165 static pgprot_t agp_convert_mmap_flags(int prot)
166 {
167 #define _trans(x,bit1,bit2) \
168 ((bit1==bit2)?(x&bit1):(x&bit1)?bit2:0)
169 
170 	unsigned long prot_bits;
171 	pgprot_t temp;
172 
173 	prot_bits = _trans(prot, PROT_READ, VM_READ) |
174 	    _trans(prot, PROT_WRITE, VM_WRITE) |
175 	    _trans(prot, PROT_EXEC, VM_EXEC);
176 
177 	prot_bits |= VM_SHARED;
178 
179 	temp = my_protect_map[prot_bits & 0x0000000f];
180 
181 	return temp;
182 }
183 
agp_create_segment(agp_client * client,agp_region * region)184 static int agp_create_segment(agp_client * client, agp_region * region)
185 {
186 	agp_segment_priv **ret_seg;
187 	agp_segment_priv *seg;
188 	agp_segment *user_seg;
189 	int i;
190 
191 	seg = kmalloc((sizeof(agp_segment_priv) * region->seg_count),
192 		      GFP_KERNEL);
193 	if (seg == NULL) {
194 		kfree(region->seg_list);
195 		return -ENOMEM;
196 	}
197 	memset(seg, 0, (sizeof(agp_segment_priv) * region->seg_count));
198 	user_seg = region->seg_list;
199 
200 	for (i = 0; i < region->seg_count; i++) {
201 		seg[i].pg_start = user_seg[i].pg_start;
202 		seg[i].pg_count = user_seg[i].pg_count;
203 		seg[i].prot = agp_convert_mmap_flags(user_seg[i].prot);
204 	}
205 	ret_seg = kmalloc(sizeof(void *), GFP_KERNEL);
206 	if (ret_seg == NULL) {
207 		kfree(region->seg_list);
208 		kfree(seg);
209 		return -ENOMEM;
210 	}
211 	*ret_seg = seg;
212 	kfree(region->seg_list);
213 	agp_add_seg_to_client(client, ret_seg, region->seg_count);
214 	return 0;
215 }
216 
217 /* End - Routines for managing each client's segment list */
218 
219 /* This function must only be called when current_controller != NULL */
agp_insert_into_pool(agp_memory * temp)220 static void agp_insert_into_pool(agp_memory * temp)
221 {
222 	agp_memory *prev;
223 
224 	prev = agp_fe.current_controller->pool;
225 
226 	if (prev != NULL) {
227 		prev->prev = temp;
228 		temp->next = prev;
229 	}
230 	agp_fe.current_controller->pool = temp;
231 }
232 
233 
234 /* File private list routines */
235 
agp_find_private(pid_t pid)236 agp_file_private *agp_find_private(pid_t pid)
237 {
238 	agp_file_private *curr;
239 
240 	curr = agp_fe.file_priv_list;
241 
242 	while (curr != NULL) {
243 		if (curr->my_pid == pid) {
244 			return curr;
245 		}
246 		curr = curr->next;
247 	}
248 
249 	return NULL;
250 }
251 
agp_insert_file_private(agp_file_private * priv)252 void agp_insert_file_private(agp_file_private * priv)
253 {
254 	agp_file_private *prev;
255 
256 	prev = agp_fe.file_priv_list;
257 
258 	if (prev != NULL) {
259 		prev->prev = priv;
260 	}
261 	priv->next = prev;
262 	agp_fe.file_priv_list = priv;
263 }
264 
agp_remove_file_private(agp_file_private * priv)265 void agp_remove_file_private(agp_file_private * priv)
266 {
267 	agp_file_private *next;
268 	agp_file_private *prev;
269 
270 	next = priv->next;
271 	prev = priv->prev;
272 
273 	if (prev != NULL) {
274 		prev->next = next;
275 
276 		if (next != NULL) {
277 			next->prev = prev;
278 		}
279 	} else {
280 		if (next != NULL) {
281 			next->prev = NULL;
282 		}
283 		agp_fe.file_priv_list = next;
284 	}
285 }
286 
287 /* End - File flag list routines */
288 
289 /*
290  * Wrappers for agp_free_memory & agp_allocate_memory
291  * These make sure that internal lists are kept updated.
292  */
agp_free_memory_wrap(agp_memory * memory)293 static void agp_free_memory_wrap(agp_memory * memory)
294 {
295 	agp_remove_from_pool(memory);
296 	agp_free_memory(memory);
297 }
298 
agp_allocate_memory_wrap(size_t pg_count,u32 type)299 static agp_memory *agp_allocate_memory_wrap(size_t pg_count, u32 type)
300 {
301 	agp_memory *memory;
302 
303 	memory = agp_allocate_memory(pg_count, type);
304 //   	printk(KERN_DEBUG "memory : %p\n", memory);
305 	if (memory == NULL) {
306 		return NULL;
307 	}
308 	agp_insert_into_pool(memory);
309 	return memory;
310 }
311 
312 /* Routines for managing the list of controllers -
313  * These routines manage the current controller, and the list of
314  * controllers
315  */
316 
agp_find_controller_by_pid(pid_t id)317 static agp_controller *agp_find_controller_by_pid(pid_t id)
318 {
319 	agp_controller *controller;
320 
321 	controller = agp_fe.controllers;
322 
323 	while (controller != NULL) {
324 		if (controller->pid == id) {
325 			return controller;
326 		}
327 		controller = controller->next;
328 	}
329 
330 	return NULL;
331 }
332 
agp_create_controller(pid_t id)333 static agp_controller *agp_create_controller(pid_t id)
334 {
335 	agp_controller *controller;
336 
337 	controller = kmalloc(sizeof(agp_controller), GFP_KERNEL);
338 
339 	if (controller == NULL) {
340 		return NULL;
341 	}
342 	memset(controller, 0, sizeof(agp_controller));
343 	controller->pid = id;
344 
345 	return controller;
346 }
347 
agp_insert_controller(agp_controller * controller)348 static int agp_insert_controller(agp_controller * controller)
349 {
350 	agp_controller *prev_controller;
351 
352 	prev_controller = agp_fe.controllers;
353 	controller->next = prev_controller;
354 
355 	if (prev_controller != NULL) {
356 		prev_controller->prev = controller;
357 	}
358 	agp_fe.controllers = controller;
359 
360 	return 0;
361 }
362 
agp_remove_all_clients(agp_controller * controller)363 static void agp_remove_all_clients(agp_controller * controller)
364 {
365 	agp_client *client;
366 	agp_client *temp;
367 
368 	client = controller->clients;
369 
370 	while (client) {
371 		agp_file_private *priv;
372 
373 		temp = client;
374 		agp_remove_seg_from_client(temp);
375 		priv = agp_find_private(temp->pid);
376 
377 		if (priv != NULL) {
378 			clear_bit(AGP_FF_IS_VALID, &priv->access_flags);
379 			clear_bit(AGP_FF_IS_CLIENT, &priv->access_flags);
380 		}
381 		client = client->next;
382 		kfree(temp);
383 	}
384 }
385 
agp_remove_all_memory(agp_controller * controller)386 static void agp_remove_all_memory(agp_controller * controller)
387 {
388 	agp_memory *memory;
389 	agp_memory *temp;
390 
391 	memory = controller->pool;
392 
393 	while (memory) {
394 		temp = memory;
395 		memory = memory->next;
396 		agp_free_memory_wrap(temp);
397 	}
398 }
399 
agp_remove_controller(agp_controller * controller)400 static int agp_remove_controller(agp_controller * controller)
401 {
402 	agp_controller *prev_controller;
403 	agp_controller *next_controller;
404 
405 	prev_controller = controller->prev;
406 	next_controller = controller->next;
407 
408 	if (prev_controller != NULL) {
409 		prev_controller->next = next_controller;
410 		if (next_controller != NULL) {
411 			next_controller->prev = prev_controller;
412 		}
413 	} else {
414 		if (next_controller != NULL) {
415 			next_controller->prev = NULL;
416 		}
417 		agp_fe.controllers = next_controller;
418 	}
419 
420 	agp_remove_all_memory(controller);
421 	agp_remove_all_clients(controller);
422 
423 	if (agp_fe.current_controller == controller) {
424 		agp_fe.current_controller = NULL;
425 		agp_fe.backend_acquired = FALSE;
426 		agp_backend_release();
427 	}
428 	kfree(controller);
429 	return 0;
430 }
431 
agp_controller_make_current(agp_controller * controller)432 static void agp_controller_make_current(agp_controller * controller)
433 {
434 	agp_client *clients;
435 
436 	clients = controller->clients;
437 
438 	while (clients != NULL) {
439 		agp_file_private *priv;
440 
441 		priv = agp_find_private(clients->pid);
442 
443 		if (priv != NULL) {
444 			set_bit(AGP_FF_IS_VALID, &priv->access_flags);
445 			set_bit(AGP_FF_IS_CLIENT, &priv->access_flags);
446 		}
447 		clients = clients->next;
448 	}
449 
450 	agp_fe.current_controller = controller;
451 }
452 
agp_controller_release_current(agp_controller * controller,agp_file_private * controller_priv)453 static void agp_controller_release_current(agp_controller * controller,
454 				      agp_file_private * controller_priv)
455 {
456 	agp_client *clients;
457 
458 	clear_bit(AGP_FF_IS_VALID, &controller_priv->access_flags);
459 	clients = controller->clients;
460 
461 	while (clients != NULL) {
462 		agp_file_private *priv;
463 
464 		priv = agp_find_private(clients->pid);
465 
466 		if (priv != NULL) {
467 			clear_bit(AGP_FF_IS_VALID, &priv->access_flags);
468 		}
469 		clients = clients->next;
470 	}
471 
472 	agp_fe.current_controller = NULL;
473 	agp_fe.used_by_controller = FALSE;
474 	agp_backend_release();
475 }
476 
477 /*
478  * Routines for managing client lists -
479  * These routines are for managing the list of auth'ed clients.
480  */
481 
agp_find_client_in_controller(agp_controller * controller,pid_t id)482 static agp_client *agp_find_client_in_controller(agp_controller * controller,
483 						 pid_t id)
484 {
485 	agp_client *client;
486 
487 	if (controller == NULL) {
488 		return NULL;
489 	}
490 	client = controller->clients;
491 
492 	while (client != NULL) {
493 		if (client->pid == id) {
494 			return client;
495 		}
496 		client = client->next;
497 	}
498 
499 	return NULL;
500 }
501 
agp_find_controller_for_client(pid_t id)502 static agp_controller *agp_find_controller_for_client(pid_t id)
503 {
504 	agp_controller *controller;
505 
506 	controller = agp_fe.controllers;
507 
508 	while (controller != NULL) {
509 		if ((agp_find_client_in_controller(controller, id)) != NULL) {
510 			return controller;
511 		}
512 		controller = controller->next;
513 	}
514 
515 	return NULL;
516 }
517 
agp_find_client_by_pid(pid_t id)518 static agp_client *agp_find_client_by_pid(pid_t id)
519 {
520 	agp_client *temp;
521 
522 	if (agp_fe.current_controller == NULL) {
523 		return NULL;
524 	}
525 	temp = agp_find_client_in_controller(agp_fe.current_controller, id);
526 	return temp;
527 }
528 
agp_insert_client(agp_client * client)529 static void agp_insert_client(agp_client * client)
530 {
531 	agp_client *prev_client;
532 
533 	prev_client = agp_fe.current_controller->clients;
534 	client->next = prev_client;
535 
536 	if (prev_client != NULL) {
537 		prev_client->prev = client;
538 	}
539 	agp_fe.current_controller->clients = client;
540 	agp_fe.current_controller->num_clients++;
541 }
542 
agp_create_client(pid_t id)543 static agp_client *agp_create_client(pid_t id)
544 {
545 	agp_client *new_client;
546 
547 	new_client = kmalloc(sizeof(agp_client), GFP_KERNEL);
548 
549 	if (new_client == NULL) {
550 		return NULL;
551 	}
552 	memset(new_client, 0, sizeof(agp_client));
553 	new_client->pid = id;
554 	agp_insert_client(new_client);
555 	return new_client;
556 }
557 
agp_remove_client(pid_t id)558 static int agp_remove_client(pid_t id)
559 {
560 	agp_client *client;
561 	agp_client *prev_client;
562 	agp_client *next_client;
563 	agp_controller *controller;
564 
565 	controller = agp_find_controller_for_client(id);
566 
567 	if (controller == NULL) {
568 		return -EINVAL;
569 	}
570 	client = agp_find_client_in_controller(controller, id);
571 
572 	if (client == NULL) {
573 		return -EINVAL;
574 	}
575 	prev_client = client->prev;
576 	next_client = client->next;
577 
578 	if (prev_client != NULL) {
579 		prev_client->next = next_client;
580 		if (next_client != NULL) {
581 			next_client->prev = prev_client;
582 		}
583 	} else {
584 		if (next_client != NULL) {
585 			next_client->prev = NULL;
586 		}
587 		controller->clients = next_client;
588 	}
589 
590 	controller->num_clients--;
591 	agp_remove_seg_from_client(client);
592 	kfree(client);
593 	return 0;
594 }
595 
596 /* End - Routines for managing client lists */
597 
598 /* File Operations */
599 
agp_mmap(struct file * file,struct vm_area_struct * vma)600 static int agp_mmap(struct file *file, struct vm_area_struct *vma)
601 {
602 	int size;
603 	int current_size;
604 	unsigned long offset;
605 	agp_client *client;
606 	agp_file_private *priv = (agp_file_private *) file->private_data;
607 	agp_kern_info kerninfo;
608 
609 	lock_kernel();
610 	AGP_LOCK();
611 
612 	if (agp_fe.backend_acquired != TRUE) {
613 		AGP_UNLOCK();
614 		unlock_kernel();
615 		return -EPERM;
616 	}
617 	if (!(test_bit(AGP_FF_IS_VALID, &priv->access_flags))) {
618 		AGP_UNLOCK();
619 		unlock_kernel();
620 		return -EPERM;
621 	}
622 	agp_copy_info(&kerninfo);
623 	size = vma->vm_end - vma->vm_start;
624 	current_size = kerninfo.aper_size;
625 	current_size = current_size * 0x100000;
626 	offset = vma->vm_pgoff << PAGE_SHIFT;
627 
628 	if (test_bit(AGP_FF_IS_CLIENT, &priv->access_flags)) {
629 		if ((size + offset) > current_size) {
630 			AGP_UNLOCK();
631 			unlock_kernel();
632 			return -EINVAL;
633 		}
634 		client = agp_find_client_by_pid(current->pid);
635 
636 		if (client == NULL) {
637 			AGP_UNLOCK();
638 			unlock_kernel();
639 			return -EPERM;
640 		}
641 		if (!agp_find_seg_in_client(client, offset,
642 					    size, vma->vm_page_prot)) {
643 			AGP_UNLOCK();
644 			unlock_kernel();
645 			return -EINVAL;
646 		}
647 		if (remap_page_range(vma->vm_start,
648 				     (kerninfo.aper_base + offset),
649 				     size, vma->vm_page_prot)) {
650 			AGP_UNLOCK();
651 			unlock_kernel();
652 			return -EAGAIN;
653 		}
654 		AGP_UNLOCK();
655 		unlock_kernel();
656 		return 0;
657 	}
658 	if (test_bit(AGP_FF_IS_CONTROLLER, &priv->access_flags)) {
659 		if (size != current_size) {
660 			AGP_UNLOCK();
661 			unlock_kernel();
662 			return -EINVAL;
663 		}
664 		if (remap_page_range(vma->vm_start, kerninfo.aper_base,
665 				     size, vma->vm_page_prot)) {
666 			AGP_UNLOCK();
667 			unlock_kernel();
668 			return -EAGAIN;
669 		}
670 		AGP_UNLOCK();
671 		unlock_kernel();
672 		return 0;
673 	}
674 	AGP_UNLOCK();
675 	unlock_kernel();
676 	return -EPERM;
677 }
678 
agp_release(struct inode * inode,struct file * file)679 static int agp_release(struct inode *inode, struct file *file)
680 {
681 	agp_file_private *priv = (agp_file_private *) file->private_data;
682 
683 	lock_kernel();
684 	AGP_LOCK();
685 
686 	if (test_bit(AGP_FF_IS_CONTROLLER, &priv->access_flags)) {
687 		agp_controller *controller;
688 
689 		controller = agp_find_controller_by_pid(priv->my_pid);
690 
691 		if (controller != NULL) {
692 			if (controller == agp_fe.current_controller) {
693 				agp_controller_release_current(controller,
694 							       priv);
695 			}
696 			agp_remove_controller(controller);
697 		}
698 	}
699 	if (test_bit(AGP_FF_IS_CLIENT, &priv->access_flags)) {
700 		agp_remove_client(priv->my_pid);
701 	}
702 	agp_remove_file_private(priv);
703 	kfree(priv);
704 	AGP_UNLOCK();
705 	unlock_kernel();
706 	return 0;
707 }
708 
agp_open(struct inode * inode,struct file * file)709 static int agp_open(struct inode *inode, struct file *file)
710 {
711 	int minor = MINOR(inode->i_rdev);
712 	agp_file_private *priv;
713 	agp_client *client;
714 	int rc = -ENXIO;
715 
716 	AGP_LOCK();
717 
718 	if (minor != AGPGART_MINOR)
719 		goto err_out;
720 
721 	priv = kmalloc(sizeof(agp_file_private), GFP_KERNEL);
722 	if (priv == NULL)
723 		goto err_out_nomem;
724 
725 	memset(priv, 0, sizeof(agp_file_private));
726 	set_bit(AGP_FF_ALLOW_CLIENT, &priv->access_flags);
727 	priv->my_pid = current->pid;
728 
729 	if (capable(CAP_SYS_RAWIO)) {
730 		/* Root priv, can be controller */
731 		set_bit(AGP_FF_ALLOW_CONTROLLER, &priv->access_flags);
732 	}
733 	client = agp_find_client_by_pid(current->pid);
734 
735 	if (client != NULL) {
736 		set_bit(AGP_FF_IS_CLIENT, &priv->access_flags);
737 		set_bit(AGP_FF_IS_VALID, &priv->access_flags);
738 	}
739 	file->private_data = (void *) priv;
740 	agp_insert_file_private(priv);
741 	AGP_UNLOCK();
742 	return 0;
743 
744 err_out_nomem:
745 	rc = -ENOMEM;
746 err_out:
747 	AGP_UNLOCK();
748 	return rc;
749 }
750 
751 
agp_read(struct file * file,char * buf,size_t count,loff_t * ppos)752 static ssize_t agp_read(struct file *file, char *buf,
753 			size_t count, loff_t * ppos)
754 {
755 	return -EINVAL;
756 }
757 
agp_write(struct file * file,const char * buf,size_t count,loff_t * ppos)758 static ssize_t agp_write(struct file *file, const char *buf,
759 			 size_t count, loff_t * ppos)
760 {
761 	return -EINVAL;
762 }
763 
agpioc_info_wrap(agp_file_private * priv,unsigned long arg)764 static int agpioc_info_wrap(agp_file_private * priv, unsigned long arg)
765 {
766 	agp_info userinfo;
767 	agp_kern_info kerninfo;
768 
769 	agp_copy_info(&kerninfo);
770 
771 	userinfo.version.major = kerninfo.version.major;
772 	userinfo.version.minor = kerninfo.version.minor;
773 	userinfo.bridge_id = kerninfo.device->vendor |
774 	    (kerninfo.device->device << 16);
775 	userinfo.agp_mode = kerninfo.mode;
776 	userinfo.aper_base = kerninfo.aper_base;
777 	userinfo.aper_size = kerninfo.aper_size;
778 	userinfo.pg_total = userinfo.pg_system = kerninfo.max_memory;
779 	userinfo.pg_used = kerninfo.current_memory;
780 
781 	if (copy_to_user((void *) arg, &userinfo, sizeof(agp_info))) {
782 		return -EFAULT;
783 	}
784 	return 0;
785 }
786 
agpioc_acquire_wrap(agp_file_private * priv,unsigned long arg)787 static int agpioc_acquire_wrap(agp_file_private * priv, unsigned long arg)
788 {
789 	agp_controller *controller;
790 	if (!(test_bit(AGP_FF_ALLOW_CONTROLLER, &priv->access_flags))) {
791 		return -EPERM;
792 	}
793 	if (agp_fe.current_controller != NULL) {
794 		return -EBUSY;
795 	}
796 	if ((agp_backend_acquire()) == 0) {
797 		agp_fe.backend_acquired = TRUE;
798 	} else {
799 		return -EBUSY;
800 	}
801 
802 	controller = agp_find_controller_by_pid(priv->my_pid);
803 
804 	if (controller != NULL) {
805 		agp_controller_make_current(controller);
806 	} else {
807 		controller = agp_create_controller(priv->my_pid);
808 
809 		if (controller == NULL) {
810 			agp_fe.backend_acquired = FALSE;
811 			agp_backend_release();
812 			return -ENOMEM;
813 		}
814 		agp_insert_controller(controller);
815 		agp_controller_make_current(controller);
816 	}
817 
818 	set_bit(AGP_FF_IS_CONTROLLER, &priv->access_flags);
819 	set_bit(AGP_FF_IS_VALID, &priv->access_flags);
820 	return 0;
821 }
822 
agpioc_release_wrap(agp_file_private * priv,unsigned long arg)823 static int agpioc_release_wrap(agp_file_private * priv, unsigned long arg)
824 {
825 	agp_controller_release_current(agp_fe.current_controller, priv);
826 	return 0;
827 }
828 
agpioc_setup_wrap(agp_file_private * priv,unsigned long arg)829 static int agpioc_setup_wrap(agp_file_private * priv, unsigned long arg)
830 {
831 	agp_setup mode;
832 
833 	if (copy_from_user(&mode, (void *) arg, sizeof(agp_setup))) {
834 		return -EFAULT;
835 	}
836 	agp_enable(mode.agp_mode);
837 	return 0;
838 }
839 
agpioc_reserve_wrap(agp_file_private * priv,unsigned long arg)840 static int agpioc_reserve_wrap(agp_file_private * priv, unsigned long arg)
841 {
842 	agp_region reserve;
843 	agp_client *client;
844 	agp_file_private *client_priv;
845 
846 
847 	if (copy_from_user(&reserve, (void *) arg, sizeof(agp_region))) {
848 		return -EFAULT;
849 	}
850 	if ((unsigned) reserve.seg_count >= ~0U/sizeof(agp_segment))
851 		return -EFAULT;
852 
853 	client = agp_find_client_by_pid(reserve.pid);
854 
855 	if (reserve.seg_count == 0) {
856 		/* remove a client */
857 		client_priv = agp_find_private(reserve.pid);
858 
859 		if (client_priv != NULL) {
860 			set_bit(AGP_FF_IS_CLIENT,
861 				&client_priv->access_flags);
862 			set_bit(AGP_FF_IS_VALID,
863 				&client_priv->access_flags);
864 		}
865 		if (client == NULL) {
866 			/* client is already removed */
867 			return 0;
868 		}
869 		return agp_remove_client(reserve.pid);
870 	} else {
871 		agp_segment *segment;
872 
873 		if (reserve.seg_count >= 16384)
874 			return -EINVAL;
875 
876 		segment = kmalloc((sizeof(agp_segment) * reserve.seg_count),
877 				  GFP_KERNEL);
878 
879 		if (segment == NULL) {
880 			return -ENOMEM;
881 		}
882 		if (copy_from_user(segment, (void *) reserve.seg_list,
883 				   sizeof(agp_segment) * reserve.seg_count)) {
884 			kfree(segment);
885 			return -EFAULT;
886 		}
887 		reserve.seg_list = segment;
888 
889 		if (client == NULL) {
890 			/* Create the client and add the segment */
891 			client = agp_create_client(reserve.pid);
892 
893 			if (client == NULL) {
894 				kfree(segment);
895 				return -ENOMEM;
896 			}
897 			client_priv = agp_find_private(reserve.pid);
898 
899 			if (client_priv != NULL) {
900 				set_bit(AGP_FF_IS_CLIENT,
901 					&client_priv->access_flags);
902 				set_bit(AGP_FF_IS_VALID,
903 					&client_priv->access_flags);
904 			}
905 			return agp_create_segment(client, &reserve);
906 		} else {
907 			return agp_create_segment(client, &reserve);
908 		}
909 	}
910 	/* Will never really happen */
911 	return -EINVAL;
912 }
913 
agpioc_protect_wrap(agp_file_private * priv,unsigned long arg)914 static int agpioc_protect_wrap(agp_file_private * priv, unsigned long arg)
915 {
916 	/* This function is not currently implemented */
917 	return -EINVAL;
918 }
919 
agpioc_allocate_wrap(agp_file_private * priv,unsigned long arg)920 static int agpioc_allocate_wrap(agp_file_private * priv, unsigned long arg)
921 {
922 	agp_memory *memory;
923 	agp_allocate alloc;
924 
925 	if (copy_from_user(&alloc, (void *) arg, sizeof(agp_allocate))) {
926 		return -EFAULT;
927 	}
928 	memory = agp_allocate_memory_wrap(alloc.pg_count, alloc.type);
929 
930 	if (memory == NULL) {
931 		return -ENOMEM;
932 	}
933 	alloc.key = memory->key;
934 	alloc.physical = memory->physical;
935 
936 	if (copy_to_user((void *) arg, &alloc, sizeof(agp_allocate))) {
937 		agp_free_memory_wrap(memory);
938 		return -EFAULT;
939 	}
940 	return 0;
941 }
942 
agpioc_deallocate_wrap(agp_file_private * priv,unsigned long arg)943 static int agpioc_deallocate_wrap(agp_file_private * priv, unsigned long arg)
944 {
945 	agp_memory *memory;
946 
947 	memory = agp_find_mem_by_key((int) arg);
948 
949 	if (memory == NULL) {
950 		return -EINVAL;
951 	}
952 	agp_free_memory_wrap(memory);
953 	return 0;
954 }
955 
agpioc_bind_wrap(agp_file_private * priv,unsigned long arg)956 static int agpioc_bind_wrap(agp_file_private * priv, unsigned long arg)
957 {
958 	agp_bind bind_info;
959 	agp_memory *memory;
960 
961 	if (copy_from_user(&bind_info, (void *) arg, sizeof(agp_bind))) {
962 		return -EFAULT;
963 	}
964 	memory = agp_find_mem_by_key(bind_info.key);
965 
966 	if (memory == NULL) {
967 		return -EINVAL;
968 	}
969 	return agp_bind_memory(memory, bind_info.pg_start);
970 }
971 
agpioc_unbind_wrap(agp_file_private * priv,unsigned long arg)972 static int agpioc_unbind_wrap(agp_file_private * priv, unsigned long arg)
973 {
974 	agp_memory *memory;
975 	agp_unbind unbind;
976 
977 	if (copy_from_user(&unbind, (void *) arg, sizeof(agp_unbind))) {
978 		return -EFAULT;
979 	}
980 	memory = agp_find_mem_by_key(unbind.key);
981 
982 	if (memory == NULL) {
983 		return -EINVAL;
984 	}
985 	return agp_unbind_memory(memory);
986 }
987 
agp_ioctl(struct inode * inode,struct file * file,unsigned int cmd,unsigned long arg)988 static int agp_ioctl(struct inode *inode, struct file *file,
989 		     unsigned int cmd, unsigned long arg)
990 {
991 	agp_file_private *curr_priv = (agp_file_private *) file->private_data;
992 	int ret_val = -ENOTTY;
993 
994 	AGP_LOCK();
995 
996 	if ((agp_fe.current_controller == NULL) &&
997 	    (cmd != AGPIOC_ACQUIRE)) {
998 		ret_val = -EINVAL;
999 	   	goto ioctl_out;
1000 	}
1001 	if ((agp_fe.backend_acquired != TRUE) &&
1002 	    (cmd != AGPIOC_ACQUIRE)) {
1003 		ret_val = -EBUSY;
1004 	   	goto ioctl_out;
1005 	}
1006 	if (cmd != AGPIOC_ACQUIRE) {
1007 		if (!(test_bit(AGP_FF_IS_CONTROLLER,
1008 			       &curr_priv->access_flags))) {
1009 			ret_val = -EPERM;
1010 		   	goto ioctl_out;
1011 		}
1012 		/* Use the original pid of the controller,
1013 		 * in case it's threaded */
1014 
1015 		if (agp_fe.current_controller->pid != curr_priv->my_pid) {
1016 			ret_val = -EBUSY;
1017 		   	goto ioctl_out;
1018 		}
1019 	}
1020 	switch (cmd) {
1021 	case AGPIOC_INFO:
1022 		{
1023 			ret_val = agpioc_info_wrap(curr_priv, arg);
1024 		   	goto ioctl_out;
1025 		}
1026 	case AGPIOC_ACQUIRE:
1027 		{
1028 			ret_val = agpioc_acquire_wrap(curr_priv, arg);
1029 		   	goto ioctl_out;
1030 		}
1031 	case AGPIOC_RELEASE:
1032 		{
1033 			ret_val = agpioc_release_wrap(curr_priv, arg);
1034 		   	goto ioctl_out;
1035 		}
1036 	case AGPIOC_SETUP:
1037 		{
1038 			ret_val = agpioc_setup_wrap(curr_priv, arg);
1039 		   	goto ioctl_out;
1040 		}
1041 	case AGPIOC_RESERVE:
1042 		{
1043 			ret_val = agpioc_reserve_wrap(curr_priv, arg);
1044 		   	goto ioctl_out;
1045 		}
1046 	case AGPIOC_PROTECT:
1047 		{
1048 			ret_val = agpioc_protect_wrap(curr_priv, arg);
1049 		   	goto ioctl_out;
1050 		}
1051 	case AGPIOC_ALLOCATE:
1052 		{
1053 			ret_val = agpioc_allocate_wrap(curr_priv, arg);
1054 		   	goto ioctl_out;
1055 		}
1056 	case AGPIOC_DEALLOCATE:
1057 		{
1058 			ret_val = agpioc_deallocate_wrap(curr_priv, arg);
1059 		   	goto ioctl_out;
1060 		}
1061 	case AGPIOC_BIND:
1062 		{
1063 			ret_val = agpioc_bind_wrap(curr_priv, arg);
1064 		   	goto ioctl_out;
1065 		}
1066 	case AGPIOC_UNBIND:
1067 		{
1068 			ret_val = agpioc_unbind_wrap(curr_priv, arg);
1069 		   	goto ioctl_out;
1070 		}
1071 	}
1072 
1073 ioctl_out:
1074 	AGP_UNLOCK();
1075 	return ret_val;
1076 }
1077 
1078 static struct file_operations agp_fops =
1079 {
1080 	owner:		THIS_MODULE,
1081 	llseek:		no_llseek,
1082 	read:		agp_read,
1083 	write:		agp_write,
1084 	ioctl:		agp_ioctl,
1085 	mmap:		agp_mmap,
1086 	open:		agp_open,
1087 	release:	agp_release,
1088 };
1089 
1090 static struct miscdevice agp_miscdev =
1091 {
1092 	AGPGART_MINOR,
1093 	AGPGART_MODULE_NAME,
1094 	&agp_fops
1095 };
1096 
agp_frontend_initialize(void)1097 int __init agp_frontend_initialize(void)
1098 {
1099 	memset(&agp_fe, 0, sizeof(struct agp_front_data));
1100 	AGP_LOCK_INIT();
1101 
1102 	if (misc_register(&agp_miscdev)) {
1103 		printk(KERN_ERR PFX "unable to get minor: %d\n", AGPGART_MINOR);
1104 		return -EIO;
1105 	}
1106 	return 0;
1107 }
1108 
agp_frontend_cleanup(void)1109 void __exit agp_frontend_cleanup(void)
1110 {
1111 	misc_deregister(&agp_miscdev);
1112 }
1113 
1114