zoukankan      html  css  js  c++  java
  • 一个完整的字符设备驱动程序导读

    #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");
    
    


  • 相关阅读:
    查看单据项目文本对应的参数信息
    下载EPM包详细运行日志
    ABAP 字符串换行符处理
    PyCharm编辑HTML文件时输入{%不能自动补全
    Ubuntu 18.04安装MongoDB 4.0
    ubuntu18.04(bionic) 配置阿里数据源
    【Python】迭代器
    【python】多任务(2. 进程)
    【python】多任务(1. 线程)
    【python】文件下载---基础版
  • 原文地址:https://www.cnblogs.com/xuddong/p/3071742.html
Copyright © 2011-2022 走看看