Linux驱动开发-中断处理模型笔记 5

Posted hntea-hong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux驱动开发-中断处理模型笔记 5相关的知识,希望对你有一定的参考价值。

中断处理模型

1、概念解析

a) I/O操作的不确定因素以及处理器和I/O设备之间速度不匹配,设备往往通过某种硬件信号异步唤起处理器的注意

b) 这些硬件信号就称为 中断,每个设备都被分配了一个相关的标示符,别称为中断请求号(IRQ)

c) 处理器检测到某一 IRQ 号对应的中断产生时,它将停止工作并启动IRQ所对应的中断服务程序

d) 共享中断:多个设备使用同一个中断源;注销区分用设备号dev_id和 服务函数区分,共享中断的多个设备在申请中断时都要使用SA_SHIRQ标志,而一个设备以SA_SHIRQ申请某中断成功的前提是之前申请该中断的所有设备也都以SA_SHIRQ标志申请

2、分配IRQ(中断)号

a) 现代设备可直接分配

b) TQ210的硬件中断号是从32开始的,0-31的中断号分配给软中断

c) 现代设备能够响应对IRQ的查询(系统启动过程中由Bios分配)

d) 系统中活动的IRQ列表:/proc/interrupts 文件中由记录

3、中断结构体详解

a) struct irq_desc 中的主要成员

i.  * @irq_data: per irq and chip data passed down to chip functions

ii.  * @action: the irq action chain,/* IRQ action list */

1. struct irqaction 

    irq_handler_t handler; /*用户注册的中断处理函数放在这里*/

    unsigned long flags; /*中断模式*/

    void *dev_id; /*设备号*/

    struct irqaction *next; /*将共享中断连接成单向链表*/

    int irq; /*中断号*/

    irq_handler_t thread_fn;

    struct task_struct *thread;

    unsigned long thread_flags;

    unsigned long thread_mask;

    const char *name; /*中断设备名*/

    struct proc_dir_entry *dir; /*pointer to the proc/irq/NN/name entry*/

4、Linux 中断驱动设计函数解析

a) 头文件:

/*
 参数说明:
     irq:中断号 所在目录linux/arch/arm/mach-xxx/include/mach/irqs.h
    dev_id:传递给中断处理函数的变量,无传参一般写为0
函数返回:
    0表示成功
    -INCAL表示中断号无效或处理函数指针为 NULL
    -EBUSY表示中断已经被占用且不能共享
*/
static irqreturn_t xxx_interrupt(int irq,void *dev_id);

c) 注册中断处理函数

/*
参数说明:

irq:中断号
 在源码目录linux/arch/arm/mach-xxx/include/mach/irqs.h中有定义
hander:中断函数服务函数
flags:中断类型标志:中断触发方式----- <linux/interrupt.h>
devname:产生中断的设备名
*/
int request_irq(unsigned int irq, irq_handler_t handler,
    unsigned long flags, const char *devname, void *dev_id);

d) 注销中断处理函数

/*
 irq:注册的中断号
 dev_id:传递给中断处理函数的数据
*/
void free_irq(unsigned int irq, void *dev_id);

5、使能与屏蔽中断函数解析

a) 屏蔽一个中断源

i. void disable_irq(int irq):立即返回

ii. void disable_irq_nosync(int irq):等待目前的中断处理完

iii. void enable_irq(int irq):取消屏蔽

注:这三个函数作用于可编程中断控制器,对系统内的所有CPU都生效

b) 屏蔽CPU内所有中断

i. void local_irq_restore(unsigned long flags);

ii. void local_irq_enable(void)

注:local_开头的方法作用范围是本CPU内,也就是上面的中断与屏蔽,只有执行该local_xxx_xxx()函数的CPU才会有响应

6、编程套路

a) 编写中断服务函数

b) 请求(注册)中断号

c) 释放(注销)中断号

模板:

<.......> 头文件

static irqreturn_t xxx_interrupt(int irq,void *dev_id)



.....



static int xxx_init()



int ret = 0;

ret = request_irq(irq_num,xxx_interrupt,

xxxflag, “devname”, 0/....)

return ret;



static void xxx_exit()



free(irq,xxx_interrupt);



module_init(xxx_init);

module_exit(xxx_exit);

7、小结:

a) 对比之前的字符设备和混杂字符设备,LINUX模块编程的套路就是

i. 申请资源

ii. 注销资源

b) 一个明显的特点是彼此之间没有干扰,就像使用LINUX中断的流程和使用LINUX字符设备的流程都可以分割出来,没半毛钱关系。

8、下面就操起小刀测试

a) 开发板:tq210

b) 注意事项:

i. 测试该驱动时,应该查看中断号是否被使用了,如果被使用了,从新配置内核,把驱动选项中的输入设备中的按键支持去掉;命令:

cat /proc/interrupts

按键中断驱动程序设计

/******************************************

author : hntea

date: 2016/3/14

function : key interrupt test

******************************************/



#include<linux/module.h>

#include<linux/init.h>

#include<linux/miscdevice.h>

#include<linux/fs.h>

#include<linux/types.h>

#include<linux/io.h>

#include<linux/interrupt.h>



#define DEV_MINIR 11 /*自己随便取咯*/

#define DEV_NAME "key" /*自己随便取咯,该设备名会在 /dev目录下生成相应的设备文件*/



#define KEY_GPH0CON  0xE0200C00 /*key_1 /key_2 EXIT0/1*/

#define EXT_INT_0_CON  0xE0200E00 /*配置电平触发方式,在中断注册程序中已经解释*/

#define EXT_INT_0_MASK    0xE0200F00 /*外部中断掩码寄存器*/

#define VIC0INTENABLE  0xF2000010 /*中断使能寄存器*/

#define EXINT0ENABLE (1) /*打开中断0*/

#define EXINT1ENABLE (1<<1) /*打开中断1*/



/******************************************

函数名: key_hardinit

函数功能:硬件初始化

******************************************/

void key_hardinit(void)



    unsigned int *key_ioconfig = 0;

    unsigned int *irq_mask = 0;

    unsigned int *irq_enable = 0;

    unsigned int temdata = 0;

    /*GPIO初始化 32位寄存器*/

    key_ioconfig = ioremap(KEY_GPH0CON,4);  /*按键1和2设置成外部中断*/

    temdata = ioread32(key_ioconfig);

    temdata &= (~0xff);

    temdata |= 0xff;

    iowrite32(temdata,key_ioconfig);

    /*中断控制初始化,这个在中断注册时内核帮我们初始化了*/



/******************************************

函数名: key_interrupt

函数功能:中断服务函数入口

******************************************/

static irqreturn_t key_interrupt (int irq, void *dev_id)



   printk("key interrupt .........\\n");

    printk(“i get dev_id is:%d”,(int)dev_id);

    return 0;





/******************************************

函数名: key_open

函数功能:文件操作

******************************************/

int  key_open(struct inode *inode, struct file *filp)



    key_hardinit();

    return 0;





/******************************************

函数名:

函数功能:文件操作

******************************************/



struct file_operations key_fop =



    .open = key_open,

;



struct miscdevice key=



    .minor = DEV_MINIR ,

    .name = DEV_NAME,

    .fops = &key_fop,

;



static int keyInit(void)



    int ret = 0;

    /*1、注册设备文件*/

    ret = misc_register(&key);

    /*2、注册中断号*/

    ret = request_irq(IRQ_EINT0,key_interrupt,

    IRQF_SHARED, "key", 1); /



    printk("ret val is:%d\\n",ret); //-16:中断号已经被申请;-22:中断号错误

    if(ret < 0)

    

    printk("EXINT0 request fail!\\n");

    else

    printk("EXINT0 request sucess!\\n");

    

    return 0;



static void keyExit(void)



    int ret = 0;

    /*注销中断*/

     free_irq(IRQ_EINT0, 1);

    /*注销混杂设备*/

    ret = misc_deregister(&key);

    /*注销设备*/





MODULE_LICENSE("GPL");

MODULE_AUTHOR("Hntea");



module_init(keyInit);

module_exit(keyExit);

以上是关于Linux驱动开发-中断处理模型笔记 5的主要内容,如果未能解决你的问题,请参考以下文章

Linux驱动开发-中断分层机制笔记 6

Linux驱动开发-中断分层机制笔记 6

Linux驱动开发-中断分层机制_工作队列 笔记 7

Linux驱动开发-中断分层机制_工作队列 笔记 7

《Linux内核设计与实现》读书笔记- 中断处理转

Linux编写一个Linux按键中断Demo