📄 frontend.c
字号:
struct agp_client *client; struct agp_client *prev_client; struct agp_client *next_client; struct agp_controller *controller; controller = agp_find_controller_for_client(id); if (controller == NULL) return -EINVAL; client = agp_find_client_in_controller(controller, id); if (client == NULL) return -EINVAL; prev_client = client->prev; next_client = client->next; if (prev_client != NULL) { prev_client->next = next_client; if (next_client != NULL) next_client->prev = prev_client; } else { if (next_client != NULL) next_client->prev = NULL; controller->clients = next_client; } controller->num_clients--; agp_remove_seg_from_client(client); kfree(client); return 0;}/* End - Routines for managing client lists *//* File Operations */static int agp_mmap(struct file *file, struct vm_area_struct *vma){ unsigned int size, current_size; unsigned long offset; struct agp_client *client; struct agp_file_private *priv = file->private_data; struct agp_kern_info kerninfo; down(&(agp_fe.agp_mutex)); if (agp_fe.backend_acquired != TRUE) goto out_eperm; if (!(test_bit(AGP_FF_IS_VALID, &priv->access_flags))) goto out_eperm; agp_copy_info(agp_bridge, &kerninfo); size = vma->vm_end - vma->vm_start; current_size = kerninfo.aper_size; current_size = current_size * 0x100000; offset = vma->vm_pgoff << PAGE_SHIFT; DBG("%lx:%lx", offset, offset+size); if (test_bit(AGP_FF_IS_CLIENT, &priv->access_flags)) { if ((size + offset) > current_size) goto out_inval; client = agp_find_client_by_pid(current->pid); if (client == NULL) goto out_eperm; if (!agp_find_seg_in_client(client, offset, size, vma->vm_page_prot)) goto out_inval; DBG("client vm_ops=%p", kerninfo.vm_ops); if (kerninfo.vm_ops) { vma->vm_ops = kerninfo.vm_ops; } else if (io_remap_pfn_range(vma, vma->vm_start, (kerninfo.aper_base + offset) >> PAGE_SHIFT, size, vma->vm_page_prot)) { goto out_again; } up(&(agp_fe.agp_mutex)); return 0; } if (test_bit(AGP_FF_IS_CONTROLLER, &priv->access_flags)) { if (size != current_size) goto out_inval; DBG("controller vm_ops=%p", kerninfo.vm_ops); if (kerninfo.vm_ops) { vma->vm_ops = kerninfo.vm_ops; } else if (io_remap_pfn_range(vma, vma->vm_start, kerninfo.aper_base >> PAGE_SHIFT, size, vma->vm_page_prot)) { goto out_again; } up(&(agp_fe.agp_mutex)); return 0; }out_eperm: up(&(agp_fe.agp_mutex)); return -EPERM;out_inval: up(&(agp_fe.agp_mutex)); return -EINVAL;out_again: up(&(agp_fe.agp_mutex)); return -EAGAIN;}static int agp_release(struct inode *inode, struct file *file){ struct agp_file_private *priv = file->private_data; down(&(agp_fe.agp_mutex)); DBG("priv=%p", priv); if (test_bit(AGP_FF_IS_CONTROLLER, &priv->access_flags)) { struct agp_controller *controller; controller = agp_find_controller_by_pid(priv->my_pid); if (controller != NULL) { if (controller == agp_fe.current_controller) agp_controller_release_current(controller, priv); agp_remove_controller(controller); controller = NULL; } } if (test_bit(AGP_FF_IS_CLIENT, &priv->access_flags)) agp_remove_client(priv->my_pid); agp_remove_file_private(priv); kfree(priv); file->private_data = NULL; up(&(agp_fe.agp_mutex)); return 0;}static int agp_open(struct inode *inode, struct file *file){ int minor = iminor(inode); struct agp_file_private *priv; struct agp_client *client; int rc = -ENXIO; down(&(agp_fe.agp_mutex)); if (minor != AGPGART_MINOR) goto err_out; priv = kzalloc(sizeof(struct agp_file_private), GFP_KERNEL); if (priv == NULL) goto err_out_nomem; set_bit(AGP_FF_ALLOW_CLIENT, &priv->access_flags); priv->my_pid = current->pid; if ((current->uid == 0) || (current->suid == 0)) { /* Root priv, can be controller */ set_bit(AGP_FF_ALLOW_CONTROLLER, &priv->access_flags); } client = agp_find_client_by_pid(current->pid); if (client != NULL) { set_bit(AGP_FF_IS_CLIENT, &priv->access_flags); set_bit(AGP_FF_IS_VALID, &priv->access_flags); } file->private_data = (void *) priv; agp_insert_file_private(priv); DBG("private=%p, client=%p", priv, client); up(&(agp_fe.agp_mutex)); return 0;err_out_nomem: rc = -ENOMEM;err_out: up(&(agp_fe.agp_mutex)); return rc;}static ssize_t agp_read(struct file *file, char __user *buf, size_t count, loff_t * ppos){ return -EINVAL;}static ssize_t agp_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos){ return -EINVAL;}static int agpioc_info_wrap(struct agp_file_private *priv, void __user *arg){ struct agp_info userinfo; struct agp_kern_info kerninfo; agp_copy_info(agp_bridge, &kerninfo); userinfo.version.major = kerninfo.version.major; userinfo.version.minor = kerninfo.version.minor; userinfo.bridge_id = kerninfo.device->vendor | (kerninfo.device->device << 16); userinfo.agp_mode = kerninfo.mode; userinfo.aper_base = kerninfo.aper_base; userinfo.aper_size = kerninfo.aper_size; userinfo.pg_total = userinfo.pg_system = kerninfo.max_memory; userinfo.pg_used = kerninfo.current_memory; if (copy_to_user(arg, &userinfo, sizeof(struct agp_info))) return -EFAULT; return 0;}static int agpioc_acquire_wrap(struct agp_file_private *priv){ struct agp_controller *controller; DBG(""); if (!(test_bit(AGP_FF_ALLOW_CONTROLLER, &priv->access_flags))) return -EPERM; if (agp_fe.current_controller != NULL) return -EBUSY; if(!agp_bridge) return -ENODEV; if (atomic_read(&agp_bridge->agp_in_use)) return -EBUSY; atomic_inc(&agp_bridge->agp_in_use); agp_fe.backend_acquired = TRUE; controller = agp_find_controller_by_pid(priv->my_pid); if (controller != NULL) { agp_controller_make_current(controller); } else { controller = agp_create_controller(priv->my_pid); if (controller == NULL) { agp_fe.backend_acquired = FALSE; agp_backend_release(agp_bridge); return -ENOMEM; } agp_insert_controller(controller); agp_controller_make_current(controller); } set_bit(AGP_FF_IS_CONTROLLER, &priv->access_flags); set_bit(AGP_FF_IS_VALID, &priv->access_flags); return 0;}static int agpioc_release_wrap(struct agp_file_private *priv){ DBG(""); agp_controller_release_current(agp_fe.current_controller, priv); return 0;}static int agpioc_setup_wrap(struct agp_file_private *priv, void __user *arg){ struct agp_setup mode; DBG(""); if (copy_from_user(&mode, arg, sizeof(struct agp_setup))) return -EFAULT; agp_enable(agp_bridge, mode.agp_mode); return 0;}static int agpioc_reserve_wrap(struct agp_file_private *priv, void __user *arg){ struct agp_region reserve; struct agp_client *client; struct agp_file_private *client_priv; DBG(""); if (copy_from_user(&reserve, arg, sizeof(struct agp_region))) return -EFAULT; if ((unsigned) reserve.seg_count >= ~0U/sizeof(struct agp_segment)) return -EFAULT; client = agp_find_client_by_pid(reserve.pid); if (reserve.seg_count == 0) { /* remove a client */ client_priv = agp_find_private(reserve.pid); if (client_priv != NULL) { set_bit(AGP_FF_IS_CLIENT, &client_priv->access_flags); set_bit(AGP_FF_IS_VALID, &client_priv->access_flags); } if (client == NULL) { /* client is already removed */ return 0; } return agp_remove_client(reserve.pid); } else { struct agp_segment *segment; if (reserve.seg_count >= 16384) return -EINVAL; segment = kmalloc((sizeof(struct agp_segment) * reserve.seg_count), GFP_KERNEL); if (segment == NULL) return -ENOMEM; if (copy_from_user(segment, (void __user *) reserve.seg_list, sizeof(struct agp_segment) * reserve.seg_count)) { kfree(segment); return -EFAULT; } reserve.seg_list = segment; if (client == NULL) { /* Create the client and add the segment */ client = agp_create_client(reserve.pid); if (client == NULL) { kfree(segment); return -ENOMEM; } client_priv = agp_find_private(reserve.pid); if (client_priv != NULL) { set_bit(AGP_FF_IS_CLIENT, &client_priv->access_flags); set_bit(AGP_FF_IS_VALID, &client_priv->access_flags); } } return agp_create_segment(client, &reserve); } /* Will never really happen */ return -EINVAL;}static int agpioc_protect_wrap(struct agp_file_private *priv){ DBG(""); /* This function is not currently implemented */ return -EINVAL;}static int agpioc_allocate_wrap(struct agp_file_private *priv, void __user *arg){ struct agp_memory *memory; struct agp_allocate alloc; DBG(""); if (copy_from_user(&alloc, arg, sizeof(struct agp_allocate))) return -EFAULT; memory = agp_allocate_memory_wrap(alloc.pg_count, alloc.type); if (memory == NULL) return -ENOMEM; alloc.key = memory->key; alloc.physical = memory->physical; if (copy_to_user(arg, &alloc, sizeof(struct agp_allocate))) { agp_free_memory_wrap(memory); return -EFAULT; } return 0;}static int agpioc_deallocate_wrap(struct agp_file_private *priv, int arg){ struct agp_memory *memory; DBG(""); memory = agp_find_mem_by_key(arg); if (memory == NULL) return -EINVAL; agp_free_memory_wrap(memory); return 0;}static int agpioc_bind_wrap(struct agp_file_private *priv, void __user *arg){ struct agp_bind bind_info; struct agp_memory *memory; DBG(""); if (copy_from_user(&bind_info, arg, sizeof(struct agp_bind))) return -EFAULT; memory = agp_find_mem_by_key(bind_info.key); if (memory == NULL) return -EINVAL; return agp_bind_memory(memory, bind_info.pg_start);}static int agpioc_unbind_wrap(struct agp_file_private *priv, void __user *arg){ struct agp_memory *memory; struct agp_unbind unbind; DBG(""); if (copy_from_user(&unbind, arg, sizeof(struct agp_unbind))) return -EFAULT; memory = agp_find_mem_by_key(unbind.key); if (memory == NULL) return -EINVAL; return agp_unbind_memory(memory);}static int agp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ struct agp_file_private *curr_priv = file->private_data; int ret_val = -ENOTTY; DBG("priv=%p, cmd=%x", curr_priv, cmd); down(&(agp_fe.agp_mutex)); if ((agp_fe.current_controller == NULL) && (cmd != AGPIOC_ACQUIRE)) { ret_val = -EINVAL; goto ioctl_out; } if ((agp_fe.backend_acquired != TRUE) && (cmd != AGPIOC_ACQUIRE)) { ret_val = -EBUSY; goto ioctl_out; } if (cmd != AGPIOC_ACQUIRE) { if (!(test_bit(AGP_FF_IS_CONTROLLER, &curr_priv->access_flags))) { ret_val = -EPERM; goto ioctl_out; } /* Use the original pid of the controller, * in case it's threaded */ if (agp_fe.current_controller->pid != curr_priv->my_pid) { ret_val = -EBUSY; goto ioctl_out; } } switch (cmd) { case AGPIOC_INFO: ret_val = agpioc_info_wrap(curr_priv, (void __user *) arg); break; case AGPIOC_ACQUIRE: ret_val = agpioc_acquire_wrap(curr_priv); break; case AGPIOC_RELEASE: ret_val = agpioc_release_wrap(curr_priv); break; case AGPIOC_SETUP: ret_val = agpioc_setup_wrap(curr_priv, (void __user *) arg); break; case AGPIOC_RESERVE: ret_val = agpioc_reserve_wrap(curr_priv, (void __user *) arg); break; case AGPIOC_PROTECT: ret_val = agpioc_protect_wrap(curr_priv); break; case AGPIOC_ALLOCATE: ret_val = agpioc_allocate_wrap(curr_priv, (void __user *) arg); break; case AGPIOC_DEALLOCATE: ret_val = agpioc_deallocate_wrap(curr_priv, (int) arg); break; case AGPIOC_BIND: ret_val = agpioc_bind_wrap(curr_priv, (void __user *) arg); break; case AGPIOC_UNBIND: ret_val = agpioc_unbind_wrap(curr_priv, (void __user *) arg); break; }ioctl_out: DBG("ioctl returns %d\n", ret_val); up(&(agp_fe.agp_mutex)); return ret_val;}static struct file_operations agp_fops ={ .owner = THIS_MODULE, .llseek = no_llseek, .read = agp_read, .write = agp_write, .ioctl = agp_ioctl, .mmap = agp_mmap, .open = agp_open, .release = agp_release,};static struct miscdevice agp_miscdev ={ .minor = AGPGART_MINOR, .name = "agpgart", .fops = &agp_fops};int agp_frontend_initialize(void){ memset(&agp_fe, 0, sizeof(struct agp_front_data)); sema_init(&(agp_fe.agp_mutex), 1); if (misc_register(&agp_miscdev)) { printk(KERN_ERR PFX "unable to get minor: %d\n", AGPGART_MINOR); return -EIO; } return 0;}void agp_frontend_cleanup(void){ misc_deregister(&agp_miscdev);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -