一个完整的字符设备驱动程序导读

#include <linux/module.h>  #include <linux/types.h> #include <linux/fs.h> #include <linux/errno.h> #include <linux/mm.h> #include <linux/sched.h> #include <linux/init.h> #include <linux/slab.h> /**void *kmalloc(size_t size,int flags);	*/ #include <linux/cdev.h> #include <asm/io.h> #include <asm/system.h> #include <asm/uaccess.h> //#include <asm/semaphore.h>  #define MEMDEV_MAJOR 251 #define MEMDEV_NUM 2 #define MEMDEV_SIZE 1024  struct mem_dev { 	unsigned int size; 	char *data; 	struct semaphore sem; };   static int mem_major = MEMDEV_MAJOR;  struct cdev mem_cdev; struct mem_dev *mem_devp;  static int mem_open(struct inode *inode,struct file *filp) { 	struct mem_dev *dev; 	unsigned int num;  	printk("mem_open.\n");  	num = MINOR(inode->i_rdev);//获得次设备号 	if(num> (MEMDEV_NUM -1)) //检查次设备号有效性 	{ 		return -ENODEV; 	}  	dev= &mem_devp[num]; 	filp->private_data= dev; //将设备结构保存为私有数据  	return 0; }  static int mem_release(struct inode *inode,struct file *filp) { 	printk("mem_release.\n"); 	return 0; }  static ssize_t mem_read(struct file *filp,char __user *buf, size_t size, loff_t *ppos) { 	int ret = 0; 	struct mem_dev *dev; 	unsigned long p; 	unsigned long count;  	printk("mem_read.\n");  	dev= filp->private_data;//获得设备结构 	count= size; 	p= *ppos;  	//检查偏移量和数据大小的有效性 	if(p> MEMDEV_SIZE) 		return 0; 	if(count> (MEMDEV_SIZE-p)) 	count= MEMDEV_SIZE - p;  	if(down_interruptible(&dev->sem))//锁定互斥信号量 	return -ERESTARTSYS;  	//读取数据到用户空间 	if(copy_to_user(buf,dev->data+p, count)){ 		ret= -EFAULT; 		printk("copyfrom user failed\n"); 	} 	else{ 		*ppos+= count; 		ret= count; 		printk("read %ld bytes from dev\n", count); 	}  	up(&dev->sem);//解锁互斥信号量  	return ret; }  static ssize_t mem_write(struct file *filp,const char __user *buf, size_t size, loff_t *ppos)//注意:第二个参数和read方法不同 { 	int ret = 0; 	struct mem_dev *dev; 	unsigned long p; 	unsigned long count;  	printk("mem_write.\n");  	dev= filp->private_data; 	count= size; 	p= *ppos;  	if(p> MEMDEV_SIZE) 		return 0; 	if(count> (MEMDEV_SIZE-p)) 		count= MEMDEV_SIZE - p;  	if(down_interruptible(&dev->sem))//锁定互斥信号量 		return -ERESTARTSYS;  	if(copy_from_user(dev->data+p,buf, count)){ 		ret= -EFAULT; 		printk("copyfrom user failed\n"); 	} 	else{ 		*ppos+= count; 		ret= count; 		printk("write%ld bytes to dev\n", count); 	}  	up(&dev->sem);//解锁互斥信号量  	return ret; }  static loff_t mem_llseek(struct file *filp,loff_t offset, int whence) { 	int newpos; 	printk("mem_llseek.\n"); 	switch(whence) 	{ 		case 0: 			newpos= offset; 			break; 		case 1: 			newpos= filp->f_pos + offset; 			break; 		case 2: 			newpos= MEMDEV_SIZE - 1 + offset; 			break; 		default: 				return -EINVAL; 	} 	if((newpos<0)|| (newpos>(MEMDEV_SIZE - 1))) 		return -EINVAL; 	filp->f_pos= newpos; 	return newpos; }  static const struct file_operations mem_fops = { 	.owner= THIS_MODULE, 	.open= mem_open, 	.write= mem_write, 	.read= mem_read, 	.release= mem_release, 	.llseek= mem_llseek, };  static int __init memdev_init(void) {  	int result; 	int err; 	int i;  	//申请设备号	 	dev_t devno = MKDEV(mem_major, 0);  	if(mem_major) 		result= register_chrdev_region(devno, MEMDEV_NUM, "memdev"); 		//注意静态申请的dev_t参数和动态dev_t参数的区别 	else{ //静态直接传变量,动态传变量指针 		result= alloc_chrdev_region(&devno, 0, MEMDEV_NUM, "memdev"); 		mem_major= MAJOR(devno); 	}  	if(result< 0){ 		printk("can'tget major devno:%d\n", mem_major); 		return result; 	}  	//注册设备驱动 	cdev_init(&mem_cdev,&mem_fops); 	mem_cdev.owner= THIS_MODULE;  	err= cdev_add(&mem_cdev, MKDEV(mem_major, 0), MEMDEV_NUM); 	//如果有N个设备就要添加N个设备号 	if(err) 		printk("addcdev faild,err is %d\n", err);  	//分配设备内存 	mem_devp= kmalloc(MEMDEV_NUM*(sizeof(struct mem_dev)), GFP_KERNEL); 	if(!mem_devp){ 		result = - ENOMEM; 		goto fail_malloc; 	}  	memset(mem_devp,0, MEMDEV_NUM*(sizeof(struct mem_dev)));  	for(i=0;i<MEMDEV_NUM; i++){	 		mem_devp[i].size= MEMDEV_SIZE; 		mem_devp[i].data= kmalloc(MEMDEV_SIZE, GFP_KERNEL); 		memset(mem_devp[i].data,0, MEMDEV_SIZE); 		sema_init(&mem_devp[i].sem,1);//初始化互斥锁 	}  	return result;  fail_malloc: 	unregister_chrdev_region(MKDEV(mem_major,0), MEMDEV_NUM); 	return result; }  static void memdev_exit(void) {		 	cdev_del(&mem_cdev); 	unregister_chrdev_region(MKDEV(mem_major,0), MEMDEV_NUM);//注意释放的设备号个数一定要和申请的设备号个数保存一致 	//否则会导致设备号资源流失 	printk("memdev_exit\n"); }  module_init(memdev_init); module_exit(memdev_exit);  MODULE_AUTHOR("Y-Kee"); MODULE_LICENSE("GPL");  


你可能感兴趣的:(一个完整的字符设备驱动程序导读)