字符设备驱动第十二课-----中断

来源:互联网 发布:淘宝的权重是什么意思 编辑:程序博客网 时间:2024/05/17 09:03

概述

1.中断描述表

是一个数组,每个元素是一个结构体,描述一个中断
<include/linux/interrupt.h>struct irqaction {    irq_handler_t       handler; //中断服务子程序函数指针    void            *dev_id;     //设备标识    void __percpu       *percpu_dev_id;    struct irqaction    *next;   //指向下一个描述符    irq_handler_t       thread_fn;    struct task_struct  *thread;    struct irqaction    *secondary;    unsigned int        irq;      //IRQ线    unsigned int        flags;   //中断标志    unsigned long       thread_flags;    unsigned long       thread_mask;   //中断掩码    const char      *name;             //IO设备名    struct proc_dir_entry   *dir;      //指向IRQ相关的/proc/irq/n目录描述符} ____cacheline_internodealigned_in_smp;

中断描述符表

2.

函数接口

1.中断总开关

/** 功能:禁止所有中断*/raw_local_irq_save(x)
/** 功能:使能所有中断*/raw_local_irq_enable()

2.申请中断:

<include/linux/interrupt.h>/** 功能;注册中断* 输入参数:unsigned int irq:     软中断号*         irq_handler_t handler:中断服务程序指针*         unsigned long flags:  触发方式*         const char *name:      名字*         void *dev:             设备* 返回值:成功:0   失败:负数**/request_irq(unsigned int irq, irq_handler_t handler,             unsigned long flags,             const char *name, void *dev)
/** 功能;注册中断* 输入参数:struct device *dev:   设备句柄*         unsigned int irq:     软中断号*         irq_handler_t handler:中断服务程序指针*         unsigned long flags:  触发方式*         const char *devname:  设备名   *          void *dev_id:        设备ID* 返回值:成功:0   失败:负数**/devm_request_irq(struct device *dev, unsigned int irq,                  irq_handler_t handler,                 unsigned long irqflags,                  const char *devname, void *dev_id)

3.注销中断:

/** 功能:注销中断* 输入参数:unsigned int irq:中断号*         void *dev:       注册中断时怎么写,这里就怎么写*/void free_irq(unsigned int irq,void *dev);
/** 功能:注销中断* 输入参数:struct device *dev; 设备句柄*         unsigned int irq:   中断号*         void *dev:          注册中断时怎么写,这里就怎么写*/extern void devm_free_irq(struct device *dev,                         unsigned int irq,                         void *dev_id);

3.触发方式宏:

<include/linux/interrupt.h>#define IRQF_TRIGGER_NONE   0x00000000#define IRQF_TRIGGER_RISING 0x00000001#define IRQF_TRIGGER_FALLING    0x00000002#define IRQF_TRIGGER_HIGH   0x00000004#define IRQF_TRIGGER_LOW    0x00000008#define IRQF_TRIGGER_MASK   (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW | \                 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)#define IRQF_TRIGGER_PROBE  0x00000010#define IRQF_SHARED     0x00000080  //共享中断

4.中断服务子函数:

/** 功能:中断服务子程序* 输入参数: int irq:    软中断号*           void *dev   设备ID,一般为NULL* 返回值:枚举量:  enum irqreturn {*                           IRQ_NONE        = (0 << 0),//处理失败*                           IRQ_HANDLED     = (1 << 0),//处理成功*                           IRQ_WAKE_THREAD = (1 << 1),//*                       };*/enum irq_handle(int irq,void *dev);

5.从设备树中选出特定的gpio:

<include/linux/of_gpio.h>/** 功能:从指定节点中提取指定属性(提取GPIO)* 输入参数:struct device_node *fsnd:  设备节点*          const char *nasme;        属性名字*          int index:               索引(属性名下的第几个cell)* 返回值: gpio的cell编号*/int of_get_named_gpio(struct device_node *fsnd,                      const char *nasme,                      int index);
<include/linux/gpio.h>/** 功能:判断上一步找出的标号是否是gpio* 输入参数:int number:GPIO编号* 返回值: */bool gpio_is_valid(int number)

6.为gpio指定中断号:

<include/linux/gpio.h>/** 功能:将gpio的复用功能能设置成中断功能* 输入参数:unsigned int gpio:   gpio号*         unsigned long flags: 模式,如GPIOF_IN(定义在include/linux/gpio.h中的宏)*         const char *label:   本gpio名字* 返回值:成功:0   失败:负数*/int gpio_request_one(unsigned int gpio,                    unsigned long flags,                     const char *label)
<include/linux/gpio.h>/** 功能:为gpio申请一个软中断号* 输入参数:unsigned int gpio: gpio号* 返回值:成功:软中断号 失败:负数,其绝对值是错误码*/ int gpio_to_irq(unsigned int gpio)
<include/linux/gpio.h>/** 功能:释放gpio* 输入参数:unsigned gpio: gpio号* 返回值:none*/void gpio_free(unsigned gpio)

工程实例

#include <linux/init.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/of.h>#include <linux/of_gpio.h>#include <linux/of_irq.h>#include <linux/interrupt.h>#include <linux/gpio.h>static int irq;static int gpio;/*自己写的中断服务回调函数*/static irqreturn_t handler_t(int irq, void *dev){    printk(KERN_INFO "%s : %s : %d - ok.\n", __FILE__, __func__, __LINE__);    return IRQ_HANDLED;}static int __init demo_init(void){    struct device_node *np = NULL;    int ret;    printk(KERN_INFO "%s : %s : %d - ok.\n", __FILE__, __func__, __LINE__);    np = of_find_node_by_name(NULL, "key");//从设备树中找到key这个设备    if(NULL == np){        return -EINVAL;    }    gpio = of_get_named_gpio(np, "key-intr", 0);//从设备中的key-intr属性域的cell0中找出gpio    if(gpio_is_valid(gpio)){//判断是不是一个可用的gpio号        ret = gpio_request_one(gpio, GPIOF_IN, "key-intr");//将这个gpio的引脚复用功能设置成中断功能        if(ret){            printk(KERN_INFO "%s : %s : %d - gpio_request_one fail.\n",                 __FILE__, __func__, __LINE__);            return ret;        }        irq = gpio_to_irq(gpio);//为gpio申请一个软中断号        if(0 > irq){            printk(KERN_INFO "%s : %s : %d - gpio_to_irq fail.\n",                 __FILE__, __func__, __LINE__);            return irq;        }        ret = request_irq(irq, handler_t, IRQF_TRIGGER_RISING, "demo", NULL);//将申请到的软中断号注册进内核(绑定回调函数)        if(ret){            printk(KERN_INFO "%s : %s : %d - request_irq fail.\n",                 __FILE__, __func__, __LINE__);            return ret;        }    }else{        printk(KERN_INFO "%s : %s : %d - of_get_named_gpio fail.\n",             __FILE__, __func__, __LINE__);        return gpio;    }    return 0;}static void __exit demo_exit(void){    printk(KERN_INFO "%s : %s : %d - ok.\n", __FILE__, __func__, __LINE__);    free_irq(irq, NULL); //注销软中断号    gpio_free(gpio);     //注销gpio号}module_init(demo_init);module_exit(demo_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("Farsight");MODULE_DESCRIPTION("Demo for kernel module");
0 0
原创粉丝点击