linux-old/drivers/char/agp/agpgart_fe.c
<<
>>
Prefs
   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
  53static struct agp_front_data agp_fe;
  54
  55static 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
  74static 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
 106static 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
 129static 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
 139static 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
 159static 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
 165static 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
 184static 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 */
 220static 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
 236agp_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
 252void 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
 265void 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 */
 293static void agp_free_memory_wrap(agp_memory * memory)
 294{
 295        agp_remove_from_pool(memory);
 296        agp_free_memory(memory);
 297}
 298
 299static 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
 317static 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
 333static 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
 348static 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
 363static 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
 386static 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
 400static 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
 432static 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
 453static 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
 482static 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
 502static 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
 518static 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
 529static 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
 543static 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
 558static 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
 600static 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
 679static 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
 709static 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
 744err_out_nomem:
 745        rc = -ENOMEM;
 746err_out:
 747        AGP_UNLOCK();
 748        return rc;
 749}
 750
 751
 752static ssize_t agp_read(struct file *file, char *buf,
 753                        size_t count, loff_t * ppos)
 754{
 755        return -EINVAL;
 756}
 757
 758static ssize_t agp_write(struct file *file, const char *buf,
 759                         size_t count, loff_t * ppos)
 760{
 761        return -EINVAL;
 762}
 763
 764static 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
 787static 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
 823static 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
 829static 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
 840static 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
 914static int agpioc_protect_wrap(agp_file_private * priv, unsigned long arg)
 915{
 916        /* This function is not currently implemented */
 917        return -EINVAL;
 918}
 919
 920static 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
 943static 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
 956static 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
 972static 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
 988static 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   
1073ioctl_out:
1074        AGP_UNLOCK();
1075        return ret_val;
1076}
1077
1078static 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
1090static struct miscdevice agp_miscdev =
1091{
1092        AGPGART_MINOR,
1093        AGPGART_MODULE_NAME,
1094        &agp_fops
1095};
1096
1097int __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
1109void __exit agp_frontend_cleanup(void)
1110{
1111        misc_deregister(&agp_miscdev);
1112}
1113
1114
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.