6410虚拟字符设备读写测试程序
View Code
1 #include <linux/init.h> 2 #include <linux/kernel.h> 3 #include <linux/module.h> 4 #include <linux/types.h> 5 #include <linux/fs.h> 6 #include <linux/errno.h> 7 #include <linux/mm.h> 8 #include <linux/sched.h> 9 #include <linux/cdev.h> 10 #include <linux/slab.h> 11 #include <asm/io.h> 12 #include <asm/uaccess.h> 13 #include <asm/system.h> 14 #include "memdev.h"//在头文件中定义了MEMDEV_SIZE=256,MEMDEV_NR=2,MEM_MAJOR=251; 15 16 17 int mem_major = MEM_MAJOR; 18 19 module_param(mem_major, int , S_IWUSR);//用mem_major作为内核参数,随时可以改变设备号 20 21 struct cdev cdev; 22 struct memdev *memdevp; 23 dev_t dev_no; 24 25 /*函数打开时调用*/ 26 int mem_open(struct inode *inode, struct file *file) 27 { 28 struct memdev *memdev; 29 int i = MINOR(inode->i_rdev); 30 if(i > MEMDEV_NR) 31 return -EFAULT; 32 memdev = &memdevp[i]; 33 34 file->private_data = memdev;//将设备指针保存在private_data里面,方便以后读写时取用; 35 return 0; 36 37 } 38 39 int mem_release(struct inode *inode, struct file *file) 40 { 41 return 0; 42 } 43 /*读文件时调用该函数*/ 44 ssize_t mem_read(struct file *file, char __user *buffer, size_t size, loff_t *pos) 45 { 46 struct memdev *memdev; 47 int count = size; 48 int p = *pos; 49 int ret = 0; 50 51 if(p > MEMDEV_SIZE) 52 return -EFAULT; 53 if(count > MEMDEV_SIZE - p) 54 count = MEMDEV_SIZE -p; 55 56 memdev = file->private_data; 57 ret = copy_to_user(buffer, memdev->data + p, count);//在内核空间中不能直接使用用户空间的指针。 58 59 if(ret) 60 return -ENOMEM; 61 else{ 62 *pos += count; 63 ret = count; 64 } 65 66 return ret; 67 } 68 /*写文件的时候调用该函数*/ 69 ssize_t mem_write(struct file *file, const char __user *buffer, size_t size, loff_t *pos) 70 { 71 struct memdev *memdev; 72 int count = size; 73 int p = *pos; 74 int ret = 0; 75 76 if(p > MEMDEV_SIZE) 77 return -EFAULT; 78 if(count > MEMDEV_SIZE - p) 79 count = MEMDEV_SIZE - p; 80 81 memdev = file->private_data;//取出打开时,保存在private_data中的memdev指针; 82 ret = copy_from_user(memdev->data + p , buffer, count);//用户空间指针,不能直接在内核空间使用; 83 84 if(ret) 85 return -ENOMEM; 86 else{ 87 *pos += count;//更新文件读写指针位置; 88 ret = count; 89 } 90 91 return ret; 92 } 93 94 loff_t mem_llseek(struct file *file, loff_t off, int whence) 95 { 96 loff_t newpos=0; 97 98 switch(whence){ 99 case 0://seek_set 100 newpos = off; 101 break; 102 case 1://seek_cur 103 newpos = file->f_pos + off; //file_pos是文件原来的读写指针位置; 104 break; 105 case 2://seek_end 106 newpos = MEMDEV_SIZE -1 + off; 107 break; 108 default: 109 return -EFAULT; 110 } 111 112 file->f_pos = newpos;//更新文件读写指针位置; 113 return newpos; 114 } 115 116 /*定义一个mem_fops变量,并初始化它*/ 117 struct file_operations mem_fops = { 118 .owner = THIS_MODULE,//此语句必须; 119 .open = mem_open, 120 .llseek = mem_llseek, 121 .read = mem_read, 122 .write = mem_write, 123 .release = mem_release, 124 }; 125 126 127 static int __init memdev_init(void) 128 { 129 dev_no = MKDEV(mem_major, 0); 130 int result = 0; 131 int i=0; 132 133 if(mem_major){ 134 result = register_chrdev_region(dev_no, MEMDEV_NR ,"memdev0");//当mem_major大于0的时候,使用静态分配设备号方式; 135 }else{ 136 result = alloc_chrdev_region(&dev_no, 0 ,MEMDEV_NR,"memdev0");//当mem_major为0的时候,选用动态分配设备号的方式 137 mem_major = MAJOR(dev_no); 138 } 139 140 if(result != 0) 141 return -ENOMEM; 142 143 cdev_init(&cdev, &mem_fops);//使用mem_fops初始化设备结构cdev; 144 cdev.owner = THIS_MODULE;//制定该设备结构的拥有者为THIS_MODULE; 145 146 cdev_add(&cdev,dev_no,MEMDEV_NR);//使用设备号,以及设备结构,向内核注册设备; 147 148 memdevp = kmalloc(MEMDEV_NR * sizeof(struct memdev), GFP_KERNEL);//为虚拟的设备结构分配空间 149 if(!memdevp) 150 goto fail_malloc; 151 memset(memdevp , 0, MEMDEV_NR * sizeof(struct memdev));//初始化为0; 152 153 for(i = 0; i < MEMDEV_NR; i++){ 154 memdevp[i].size = MEMDEV_SIZE; 155 memdevp[i].data = kmalloc(MEMDEV_SIZE ,GFP_KERNEL);//为虚拟设备结构中的数据部分分配空间; 156 if(!(memdevp[i].data)){ 157 goto fail_malloc; 158 } 159 memset(memdevp[i].data , 0, MEMDEV_SIZE); 160 } 161 162 return 0; 163 fail_malloc: 164 unregister_chrdev_region(dev_no, MEMDEV_NR);//当出错的时候,释放设备号; 165 return -ENOMEM; 166 } 167 168 static void __exit memdev_exit(void) 169 { 170 int i=0; 171 for(i=0;i < MEMDEV_NR; i++) 172 kfree(memdevp[i].data);//释放数据部分所占用的空间 173 kfree(memdevp);//释放设备结构所占用的空间; 174 unregister_chrdev_region(dev_no,MEMDEV_NR);//注销该设备号; 175 cdev_del(&cdev);//删除设备结构... 176 } 177 178 MODULE_LICENSE("GPL"); 179 MODULE_AUTHOR("rzchong"); 180 181 module_init(memdev_init); 182 module_exit(memdev_exit);