zoukankan      html  css  js  c++  java
  • Linux Platform驱动模型(三) _platform+cdev

    平台总线是一种实现设备信息与驱动方法相分离的方法,利用这种方法,我们可以写出一个更像样一点的字符设备驱动,即使用cdev作为接口,平台总线作为分离方式:

    xjkeydrv_init():模块加载函数
    └──platform_driver_register()将驱动对象模块注册到平台总线
            └──platform_driver.probe()探测函数,提取相应的信息
                    └──xjkey_init():初始化cdev对象,创建设备文件等关于cdev接口创建的工作
                            └──cdev_init():将cdev结构与fops绑定到一起,在fops实现操作接口与控制硬件的逻辑

    static struct class *cls = NULL;
    
    static int major = 0;
    static int minor = 0;
    const  int count = 1;
    
    #define DEVNAME	"xjkey"
    
    static struct cdev *xjkeyp = NULL;
    
    static unsigned long irqflags;
    static int irq;
    
    static atomic_t tv;
    
    #if 0
    /{
    	key@26{
    		compatible = "xj4412,key";
    		interrupt-parent = <&gpx1>;
    		interrupts = <2 2>;
    	};
    };
    #endif
    
    static irqreturn_t handler_t(int irq, void *dev_id)
    {
    	printk(KERN_INFO "%s : %s : %d
    ", __FILE__, __func__, __LINE__);
    	return IRQ_HANDLED;
    }
    
    //打开设备
    static int xjkey_open(struct inode *inode, struct file *filp)
    {
    	//get major and minor from inode
    	printk(KERN_INFO "(major=%d, minor=%d), %s : %s : %d
    ",
    		imajor(inode), iminor(inode), __FILE__, __func__, __LINE__);
    
    	if(!atomic_dec_and_test(&tv)){
    		atomic_inc(&tv);
    		return -EBUSY;
    	}
    
    	return request_irq(irq, handler_t, irqflags, DEVNAME, NULL);
    }
    
    //关闭设备
    static int xjkey_release(struct inode *inode, struct file *filp)
    {
    	//get major and minor from irqflagsinode
    	printk(KERN_INFO "(major=%d, minor=%d), %s : %s : %d
    ",
    		imajor(inode), iminor(inode), __FILE__, __func__, __LINE__);
    
    	free_irq(irq, NULL);
    
    	atomic_inc(&tv);
    	return 0;
    }
    
    static struct file_operations fops = {
    	.owner	= THIS_MODULE,
    	.open	= xjkey_open,
    	.release= xjkey_release,
    };
    
    static int xjkey_init(void)
    {
    	dev_t devnum;
    	int ret, i;
    
    	struct device *devp = NULL;
    
    	//get command and pid
    	printk(KERN_INFO "(%s:pid=%d), %s : %s : %d
    ",
    		current->comm, current->pid, __FILE__, __func__, __LINE__);
    
    	//1. alloc cdev objxjkey_init
    	xjkeyp = cdev_alloc();
    	if(NULL == xjkeyp){
    		return -ENOMEM;
    	}
    
    	//2. init cdev obj
    	cdev_init(xjkeyp, &fops);
    
    	ret = alloc_chrdev_region(&devnum, minor, count, DEVNAME);
    	if(ret){
    		goto ERR_STEP;
    	}
    	major = MAJOR(devnum);
    
    	//3. register cdev obj
    	ret = cdev_add(xjkeyp, devnum, count);
    	if(ret){
    		goto ERR_STEP1;
    	}
    
    	cls = class_create(THIS_MODULE, DEVNAME);
    	if(IS_ERR(cls)){
    		ret = PTR_ERR(cls);
    		goto ERR_STEP1;
    	}
    
    	for(i = minor; i < (count+minor); i++){
    		devp = device_create(cls, NULL, MKDEV(major, i), NULL, "%s%d", DEVNAME, i);
    		if(IS_ERR(devp)){
    			ret = PTR_ERR(devp);
    			goto ERR_STEP2;
    		}
    	}
    
    	// init atomic_t
    	atomic_set(&tv, 1);
    
    	//get command and pid
    	printk(KERN_INFO "(%s:pid=%d), %s : %s : %d - ok.
    ",
    		current->comm, current->pid, __FILE__, __func__, __LINE__);
    	return 0;
    
    ERR_STEP2:
    	for(--i; i >= minor; i--){
    		device_destroy(cls, MKDEV(major, i));
    	}
    	class_destroy(cls);
    
    ERR_STEP1:
    	unregister_chrdev_region(devnum, count);
    
    ERR_STEP:
    	cdev_del(xjkeyp);
    
    	//get command and pid
    	printk(KERN_INFO "(%s:pid=%d), %s : %s : %d - fail.
    ",
    		current->comm, current->pid, __FILE__, __func__, __LINE__);
    	return ret;
    }
    
    static void xjkey_exit(void)
    {
    	int i;
    	//get command and pid
    	printk(KERN_INFO "(%s:pid=%d), %s : %s : %d - leave.
    ",
    		current->comm, current->pid, __FILE__, __func__, __LINE__);
    
    	for(i=minor; i < (count+minor); i++){
    		device_destroy(cls, MKDEV(major, i));
    	}
    	class_destroy(cls);
    
    	unregister_chrdev_region(MKDEV(major, minor), count);
    	cdev_del(xjkeyp);
    }
    
    static int xjkey_probe(struct platform_device *pdev)
    {
    	struct resource *irq_res;
    	irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
    	if(irq_res){
    		irq = irq_res->start;
    		irqflags = irq_res->flags & IRQF_TRIGGER_MASK;
    	}else{
    		printk(KERN_INFO "No 0 irq
    ");
    		return -EINVAL;		
    	}
    
    	return xjkey_init();
    }
    
    static int xjkey_remove(struct platform_device *pdev)
    {
    	printk(KERN_INFO "%s : %s : %d - leave.
    ", __FILE__, __func__, __LINE__);
    	xjkey_exit();
    	return 0;
    }
    
    struct of_device_id of_tbl[] = {
    	{.compatible = "xj4412,key",},
    	{},
    };
    MODULE_DEVICE_TABLE(of, of_tbl);
    
    
    //1. alloc obj
    static struct platform_driver xjkeydrv = {
    	.probe	= xjkey_probe,
    	.remove	= xjkey_remove,
    
    	.driver = {
    		.name = DEVNAME,
    		.of_match_table = of_tbl,
    	},
    };
    
    //3. register obj
    module_platform_driver(xjkeydrv);
    
    MODULE_LICENSE("GPL");
    
  • 相关阅读:
    Jstorm执行task报错windows CONFIG SET protected-mode no
    windows搭建redis集群最佳实践
    windows下golang实现Kfaka消息发送及kafka环境搭建
    go报错unimplemented: 64-bit mode not compiled in与mingw 64位安装报错ERROR res已解决
    GoLand配置数据库、远程host以及远程调试
    Go项目中beego的orm使用和gorm的使用
    windows下Go升级及GoLand的安装激活
    记一次解脱
    golang开源项目qor快速搭建网站qor-example运行实践
    使用img2html把图片转为网页
  • 原文地址:https://www.cnblogs.com/xiaojiang1025/p/6369065.html
Copyright © 2011-2022 走看看