中断的处理流程
1
.发生中断的时候, CPU 执行异常向量的代码,如下:__vectors_start:
swi SYS_ERROR0
b vector_und + stubs_offset
ldr pc, .LCvswi + stubs_offset
b vector_pabt + stubs_offset
b vector_dabt + stubs_offset
b vector_addrexcptn + stubs_offset
b vector_irq + stubs_offset
b vector_fiq + stubs_offset
.globl __vectors_end
__vectors_end:
2.在执行上面地址的代码的时候,最终会调用中断处理的总入口函数asm_do_IRQ,在执行asm_do_IRQ之前一直是跑汇编代码的,asm_do_IRQ的第一个参数irq的取值范围为(IRQ_EINT0~(IRQ_ENINT0+31))只有32个取值,这个值是根据INTOFFSET寄存器的每个位得到的。
3.asm_do_IRQ根据中断号调用irq_desc数组项中的handle_irq
4.handle_irq会使用chip成员中的函数来设置硬件,比如清除中断,禁止中断,重新使能中断等。
5.Handle_irq逐个调用用户在action链表中注册的处理函数
(a) Irq_desc结构数组,他的成员“struct irq_chip * chip”,“struct irqaction * action”这三种数据结构构成了中断处理体系的框架。
中断处理体系结构的初始化
1. Init_IRQ函数初始化中断处理体系
{
Init_arch_irq();
}
Init_arch_irq()函数执行的实体在开发板初始化的时候就给了。在mach-smdk2440.c
在驱动中中断的使用过程
1. 通过request_irq 函数向内核注册中断处理函数,处理如下:
int request_irq(unsigned int irq, irq_handler_t handler,
unsigned long irqflags, const char *devname, void *dev_id)
{
…
action->handler = handler;
action->flags = irqflags;
cpus_clear(action->mask);
action->name = devname;
action->next = NULL;
action->dev_id = dev_id;
//构造一个irqaction结构
Retval = Setup_irq(irq,action);
//调用setup_irq函数讲它链入链表中
…
}
2. Setup_irq函数完成以下功能
(1) 将新建的irqaction结构链入irq_desc[irq]结构的action链表中
(a) 如果这个链表是空的,直接链入
(b) 否则先判断新建的irqaction结构和链表中的irqaction结构所表示的中断类型是否一致:即是否都声明为“可共享的”,是否都使用相同的触发方式(电平,边沿,极性),如果一致将新建的irqaction结构链入。
(2) 设置irq_desc[irq]结构中chip成员的还没设置的指针,让它们指向一些默认函数
这个通过irq_chip_set_defaults(desc->chip);实现
(3) 设置中断的触发方式
利用request_irq传入的参数irqflags来设置中断触发方式(高电平出发,低电平触发,上升沿触发,下降沿触发)
(4) 启动中断
chip->startup 或chip->enable 来启动中断的
小结使用request_irq函数之后的“成果”
(1) Irq_desc[irq]结构中的action链表中已经链入了用户注册的中断处理函数
(2) 中断的触发方式已经设置好
(3) 中断已经被使能了
总之,执行完request_irq函数之后,中断就可以发生并能够被处理了。