v2.4.8 -> v2.4.8.1
[opensuse:kernel.git] / drivers / char / agp / agpgart_fe.c
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
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
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
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
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
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
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
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 */
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
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
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
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  */
293 static void agp_free_memory_wrap(agp_memory * memory)
294 {
295         agp_remove_from_pool(memory);
296         agp_free_memory(memory);
297 }
298
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 ((current->uid == 0) || (current->suid == 0)) {
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
752 static ssize_t agp_read(struct file *file, char *buf,
753                         size_t count, loff_t * ppos)
754 {
755         return -EINVAL;
756 }
757
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
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
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
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
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
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
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
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
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
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
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
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
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
1109 void __exit agp_frontend_cleanup(void)
1110 {
1111         misc_deregister(&agp_miscdev);
1112 }
1113