📄 frontend.c
字号:
/* * AGPGART driver frontend * Copyright (C) 2004 Silicon Graphics, Inc. * Copyright (C) 2002-2003 Dave Jones * Copyright (C) 1999 Jeff Hartmann * Copyright (C) 1999 Precision Insight, Inc. * Copyright (C) 1999 Xi Graphics, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM, * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */#include <linux/types.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/mman.h>#include <linux/pci.h>#include <linux/init.h>#include <linux/miscdevice.h>#include <linux/agp_backend.h>#include <linux/agpgart.h>#include <linux/slab.h>#include <linux/mm.h>#include <asm/uaccess.h>#include <asm/pgtable.h>#include "agp.h"static struct agp_front_data agp_fe;static struct agp_memory *agp_find_mem_by_key(int key){ struct agp_memory *curr; if (agp_fe.current_controller == NULL) return NULL; curr = agp_fe.current_controller->pool; while (curr != NULL) { if (curr->key == key) break; curr = curr->next; } DBG("key=%d -> mem=%p", key, curr); return curr;}static void agp_remove_from_pool(struct agp_memory *temp){ struct agp_memory *prev; struct agp_memory *next; /* Check to see if this is even in the memory pool */ DBG("mem=%p", temp); if (agp_find_mem_by_key(temp->key) != NULL) { next = temp->next; prev = temp->prev; if (prev != NULL) { prev->next = next; if (next != NULL) next->prev = prev; } else { /* This is the first item on the list */ if (next != NULL) next->prev = NULL; agp_fe.current_controller->pool = next; } }}/* * Routines for managing each client's segment list - * These routines handle adding and removing segments * to each auth'ed client. */static structagp_segment_priv *agp_find_seg_in_client(const struct agp_client *client, unsigned long offset, int size, pgprot_t page_prot){ struct agp_segment_priv *seg; int num_segments, i; off_t pg_start; size_t pg_count; pg_start = offset / 4096; pg_count = size / 4096; seg = *(client->segments); num_segments = client->num_segments; for (i = 0; i < client->num_segments; i++) { if ((seg[i].pg_start == pg_start) && (seg[i].pg_count == pg_count) && (pgprot_val(seg[i].prot) == pgprot_val(page_prot))) { return seg + i; } } return NULL;}static void agp_remove_seg_from_client(struct agp_client *client){ DBG("client=%p", client); if (client->segments != NULL) { if (*(client->segments) != NULL) { DBG("Freeing %p from client %p", *(client->segments), client); kfree(*(client->segments)); } DBG("Freeing %p from client %p", client->segments, client); kfree(client->segments); client->segments = NULL; }}static void agp_add_seg_to_client(struct agp_client *client, struct agp_segment_priv ** seg, int num_segments){ struct agp_segment_priv **prev_seg; prev_seg = client->segments; if (prev_seg != NULL) agp_remove_seg_from_client(client); DBG("Adding seg %p (%d segments) to client %p", seg, num_segments, client); client->num_segments = num_segments; client->segments = seg;}/* Originally taken from linux/mm/mmap.c from the array * protection_map. * The original really should be exported to modules, or * some routine which does the conversion for you */static const pgprot_t my_protect_map[16] ={ __P000, __P001, __P010, __P011, __P100, __P101, __P110, __P111, __S000, __S001, __S010, __S011, __S100, __S101, __S110, __S111};static pgprot_t agp_convert_mmap_flags(int prot){#define _trans(x,bit1,bit2) \((bit1==bit2)?(x&bit1):(x&bit1)?bit2:0) unsigned long prot_bits; pgprot_t temp; prot_bits = _trans(prot, PROT_READ, VM_READ) | _trans(prot, PROT_WRITE, VM_WRITE) | _trans(prot, PROT_EXEC, VM_EXEC); prot_bits |= VM_SHARED; temp = my_protect_map[prot_bits & 0x0000000f]; return temp;}static int agp_create_segment(struct agp_client *client, struct agp_region *region){ struct agp_segment_priv **ret_seg; struct agp_segment_priv *seg; struct agp_segment *user_seg; size_t i; seg = kzalloc((sizeof(struct agp_segment_priv) * region->seg_count), GFP_KERNEL); if (seg == NULL) { kfree(region->seg_list); region->seg_list = NULL; return -ENOMEM; } user_seg = region->seg_list; for (i = 0; i < region->seg_count; i++) { seg[i].pg_start = user_seg[i].pg_start; seg[i].pg_count = user_seg[i].pg_count; seg[i].prot = agp_convert_mmap_flags(user_seg[i].prot); } kfree(region->seg_list); region->seg_list = NULL; ret_seg = kmalloc(sizeof(void *), GFP_KERNEL); if (ret_seg == NULL) { kfree(seg); return -ENOMEM; } *ret_seg = seg; agp_add_seg_to_client(client, ret_seg, region->seg_count); return 0;}/* End - Routines for managing each client's segment list *//* This function must only be called when current_controller != NULL */static void agp_insert_into_pool(struct agp_memory * temp){ struct agp_memory *prev; prev = agp_fe.current_controller->pool; if (prev != NULL) { prev->prev = temp; temp->next = prev; } agp_fe.current_controller->pool = temp;}/* File private list routines */static struct agp_file_private *agp_find_private(pid_t pid){ struct agp_file_private *curr; curr = agp_fe.file_priv_list; while (curr != NULL) { if (curr->my_pid == pid) return curr; curr = curr->next; } return NULL;}static void agp_insert_file_private(struct agp_file_private * priv){ struct agp_file_private *prev; prev = agp_fe.file_priv_list; if (prev != NULL) prev->prev = priv; priv->next = prev; agp_fe.file_priv_list = priv;}static void agp_remove_file_private(struct agp_file_private * priv){ struct agp_file_private *next; struct agp_file_private *prev; next = priv->next; prev = priv->prev; if (prev != NULL) { prev->next = next; if (next != NULL) next->prev = prev; } else { if (next != NULL) next->prev = NULL; agp_fe.file_priv_list = next; }}/* End - File flag list routines *//* * Wrappers for agp_free_memory & agp_allocate_memory * These make sure that internal lists are kept updated. */static void agp_free_memory_wrap(struct agp_memory *memory){ agp_remove_from_pool(memory); agp_free_memory(memory);}static struct agp_memory *agp_allocate_memory_wrap(size_t pg_count, u32 type){ struct agp_memory *memory; memory = agp_allocate_memory(agp_bridge, pg_count, type); if (memory == NULL) return NULL; agp_insert_into_pool(memory); return memory;}/* Routines for managing the list of controllers - * These routines manage the current controller, and the list of * controllers */static struct agp_controller *agp_find_controller_by_pid(pid_t id){ struct agp_controller *controller; controller = agp_fe.controllers; while (controller != NULL) { if (controller->pid == id) return controller; controller = controller->next; } return NULL;}static struct agp_controller *agp_create_controller(pid_t id){ struct agp_controller *controller; controller = kzalloc(sizeof(struct agp_controller), GFP_KERNEL); if (controller == NULL) return NULL; controller->pid = id; return controller;}static int agp_insert_controller(struct agp_controller *controller){ struct agp_controller *prev_controller; prev_controller = agp_fe.controllers; controller->next = prev_controller; if (prev_controller != NULL) prev_controller->prev = controller; agp_fe.controllers = controller; return 0;}static void agp_remove_all_clients(struct agp_controller *controller){ struct agp_client *client; struct agp_client *temp; client = controller->clients; while (client) { struct agp_file_private *priv; temp = client; agp_remove_seg_from_client(temp); priv = agp_find_private(temp->pid); if (priv != NULL) { clear_bit(AGP_FF_IS_VALID, &priv->access_flags); clear_bit(AGP_FF_IS_CLIENT, &priv->access_flags); } client = client->next; kfree(temp); }}static void agp_remove_all_memory(struct agp_controller *controller){ struct agp_memory *memory; struct agp_memory *temp; memory = controller->pool; while (memory) { temp = memory; memory = memory->next; agp_free_memory_wrap(temp); }}static int agp_remove_controller(struct agp_controller *controller){ struct agp_controller *prev_controller; struct agp_controller *next_controller; prev_controller = controller->prev; next_controller = controller->next; if (prev_controller != NULL) { prev_controller->next = next_controller; if (next_controller != NULL) next_controller->prev = prev_controller; } else { if (next_controller != NULL) next_controller->prev = NULL; agp_fe.controllers = next_controller; } agp_remove_all_memory(controller); agp_remove_all_clients(controller); if (agp_fe.current_controller == controller) { agp_fe.current_controller = NULL; agp_fe.backend_acquired = FALSE; agp_backend_release(agp_bridge); } kfree(controller); return 0;}static void agp_controller_make_current(struct agp_controller *controller){ struct agp_client *clients; clients = controller->clients; while (clients != NULL) { struct agp_file_private *priv; priv = agp_find_private(clients->pid); if (priv != NULL) { set_bit(AGP_FF_IS_VALID, &priv->access_flags); set_bit(AGP_FF_IS_CLIENT, &priv->access_flags); } clients = clients->next; } agp_fe.current_controller = controller;}static void agp_controller_release_current(struct agp_controller *controller, struct agp_file_private *controller_priv){ struct agp_client *clients; clear_bit(AGP_FF_IS_VALID, &controller_priv->access_flags); clients = controller->clients; while (clients != NULL) { struct agp_file_private *priv; priv = agp_find_private(clients->pid); if (priv != NULL) clear_bit(AGP_FF_IS_VALID, &priv->access_flags); clients = clients->next; } agp_fe.current_controller = NULL; agp_fe.used_by_controller = FALSE; agp_backend_release(agp_bridge);}/* * Routines for managing client lists - * These routines are for managing the list of auth'ed clients. */static struct agp_client*agp_find_client_in_controller(struct agp_controller *controller, pid_t id){ struct agp_client *client; if (controller == NULL) return NULL; client = controller->clients; while (client != NULL) { if (client->pid == id) return client; client = client->next; } return NULL;}static struct agp_controller *agp_find_controller_for_client(pid_t id){ struct agp_controller *controller; controller = agp_fe.controllers; while (controller != NULL) { if ((agp_find_client_in_controller(controller, id)) != NULL) return controller; controller = controller->next; } return NULL;}static struct agp_client *agp_find_client_by_pid(pid_t id){ struct agp_client *temp; if (agp_fe.current_controller == NULL) return NULL; temp = agp_find_client_in_controller(agp_fe.current_controller, id); return temp;}static void agp_insert_client(struct agp_client *client){ struct agp_client *prev_client; prev_client = agp_fe.current_controller->clients; client->next = prev_client; if (prev_client != NULL) prev_client->prev = client; agp_fe.current_controller->clients = client; agp_fe.current_controller->num_clients++;}static struct agp_client *agp_create_client(pid_t id){ struct agp_client *new_client; new_client = kzalloc(sizeof(struct agp_client), GFP_KERNEL); if (new_client == NULL) return NULL; new_client->pid = id; agp_insert_client(new_client); return new_client;}static int agp_remove_client(pid_t id){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -