linux简单按键驱动程序

作者: 爪爪熊 | 来源:发表于2017-07-10 20:11 被阅读206次

    一、混杂设备模型

    1.1、混杂设备概念

    在linux系统中,存在一类字符设备,它们拥有相同的主设备号(10),但次设备号不同,我们称这类设备为混杂设备(miscdevice)。所有的混杂设备形成一个链表,对设备访问时,内核根据次设备号查找相应的混杂设备。

    1.2、设备描述

    Linux中使用 struct miscdevice来描述一个混杂设备。

    struct miscdevice {
        int minor;   /* 次设备号 */
        const char *name; /* 设备名 */
        const struct file_operations *fops; /* 文件操作 */
        struct list_head list;
        struct device *parent;
        struct device *this_device;
    }
    

    1.3、设备注册

    linux中使用 misc_register 函数来注册一个混杂设备驱动。使用 misc

    int misc_register(struct miscdevice *misc)
    int misc_deregister(struct miscdevice *misc)
    

    1.4、简单代码编写示例

    #include <linux/module.h>
    #include <linux/init.h>
    #include <linux/miscdevice.h>
    
    int key_open(struct inode *node, struct file *filp)
    {
    
        return 0 ;
    }
    
    struct file_operations key_fops = {
        .open = key_open,
    };
    
    struct miscdevice key_miscdev = {
        .minor = 200 ,
        .name  = "key",
        .fops  = &key_fops,
    };
    
    static int key_init()
    {
        misc_register(&key_miscdev);
    }
    
    static void key_exit()
    {
        misc_deregister(&key_miscdev);
    }
    
    module_init(key_init);
    module_init(key_exit);
    

    二、linux 中断处理程序

    2.1、裸机中断处理流程

    事先需要通过相关寄存器的初始化,并且将中断处理程序进行注册,裸机发生中断的时候,CPU先跳到中断向量表,再根据中断源编号,跳转到中断处理函数。期间可能会有现场保护与环境恢复等问题。

    2.2、linux 中断处理流程分析

    irq.svc 拿到产生中断号,根据中断号找出 irq_desc 结构中 action (存放用户事先填写的中断处理函数等) 来运行。

    2.3、Linux 中断处理程序设计

    2.3.1、中断注册

    request_irq函数用于注册中断。返回0表示成功,或者返回一个错误码。

    int request_irq(unsigned int irq,void (*handler)(int,void*,struct pt_regs *),unsigned long flags,const char * devname, void *dev_id)
    // 中断号
    unsigned int irq
    //中断处理函数
    void (*handler)(int,void*,struct pt_regs *);
    //与中断管理有关的各种选项
    unsigned long flags
    //设备名
    const char * devname
    //共享中断时使用
    void *dev_id
    

    在flags 参数中,可以选择一些与中断管理有关的选项,如:

    IRQF_DISABLEED (SA_INTERRUPT)
    //如果设置该位,表示一个“快速”中断处理程序;如果没有设置该位,那么是一个“慢速”中断处理程序。
    IRQF_SHARED(SA_SHIRQ)
    //该位表明该中断号是多个设备共享的。
    

    快/慢速中断的主要区别在于:快速中断保证中断处理的原子性(不被打破),而慢速中断则不保证。换句话说,也就是“开启中断”标志位(处理器IF)在运行快速中断处理程序时是关闭的,因此在服务该中断时,不会被其他类型的中断打断;而调用慢速中断处理时,其他类型的中断仍可以得到服务。

    共享中断:多个硬件共享同一个中断号。裸机中也时常有。

    2.3.2 中断处理程序

    中断处理程序的特别之处是在中断上下文中运行的,它的行为受到某些限制:

    1. 不能使用可能引起阻塞的函数。(死循环,信号量这类)
    2. 不能够使用可能引起调度的函数。

    中断处理程序的一般流程:

    1. 检测设备是否发生中断。
    2. 清除中断产生标识。
    3. 相应的硬件操作。

    2.3.3 注销中断

    当设备不再需要使用中断的时候(通常在驱动卸载的时候),应当把他们注销,使用函数:

    void free_irq(unsigned int irq, void *dev_id)
    

    根据不同的 中断号和devid 进行注销中断。

    2.3.4 完善上节课代码

    #include <linux/module.h>
    #include <linux/init.h>
    #include <linux/miscdevice.h>
    #include <linux/interrupt.h>
    #include <linux/io.h>
    #include <linux/fs.h>
    
    #define GPFCON 0x56000050
    irqreturn_t key_int(int irq, void *dev_id)
    {
        // 1.检测是否发生了按键中断(非共享不用检查)
        // 2.清除已经发生了按键中断(CPU内部寄存器,系统已经清除)
        // 3.打印按键值
        printk("key down !\n");
        return 0 ;
    }
    
    void key_hw_init()
    {
        unsigned int * gpio_config;
        unsigned int short delta;
        gpio_config = ioremap(GPFCON,4);
        delta = readw(gpio_config);
        delta &= ~0b11;
        dalta |= 0b10 ;
        writew(data,gpio_config);
    }
    int key_open(struct inode *node, struct file *filp)
    {
    
        return 0 ;
    }
    
    struct file_operations key_fops = {
        .open = key_open;
    };
    
    struct miscdevice key_miscdev = {
        .minor = 200 ,
        .name  = "key",
        .fops  = &key_fops,
    };
    
    static int key_init()
    {
        misc_register(&key_miscdev);
        //注册中断处理程序
        request_irq(IRQ_EINT0,key_int, IRQF_TRIGGER_FALLING, "key" , 0 );
        //按键初始化
        key_hw_init();
        return 0 ;
    }
    
    static void key_exit()
    {
        misc_deregister(&key_miscdev);
        //卸载中断处理程序
        free_irq(irqno,0);
    }
    
    module_init(key_init);
    module_init(key_exit);
    

    三、编写相关makefile

    obj-m := key.o
    KDIR:=/home/driver/key_2440
    
    all:
        make -C $(KDIR) M=$(PWD) modules CROSS_COMPILE=arm-linux- ARCH=arm
    clean:
        rm -rf *.ko *.o
    

    注意:相关代码来自国嵌。

    相关文章

      网友评论

        本文标题:linux简单按键驱动程序

        本文链接:https://www.haomeiwen.com/subject/hlpuhxtx.html