本文使用韦东山老师讲的Linux-2-6-22-6的内核,在此内核中对中断框架进行讲解。本文只是回顾一下自己所学中断的内容,如有雷同,纯属巧合。
下面进入正题:讲解内核中断
我们可以大致的将内核中断分为三部分:
1.建立中断体系框架:init_IRQ函数
2.使用request_irq函数填充上面所建立的框架
3.使用框架执行用户编写的中断处理函数:asm_do_IRQ函数
1.建立框架即建立一个横向为以irq为基底,所填写的irq_desc[irq]结构体。而结构体中包含irq号所对应的中断入口函数,指向底层的函数以及action链表头。详细的代码为:
struct irq_desc {
irq_flow_handler_thandle_irq;
struct irq_chip*chip;
struct msi_desc*msi_desc;
void *handler_data;
void *chip_data;
struct irqaction*action;/* IRQ action list */
unsigned int status; /* IRQ status */
};
而在纵向则是以不同的dev_id为区分的irq_action结构
struct irqaction {
irq_handler_t handler;
unsigned long flags;
cpumask_t mask;
const char *name;
void *dev_id;
struct irqaction *next;
int irq;
};
而此横向和纵向的分布将中断的框架大体搭建,而init_IRQ则是对这个框架的详细装饰:
init_IRQ(void)
init_arch_irq();//该函数指向s3c2440所对应开发板的s3c24xx_init_irq函数
s3c24xx_init_irq
set_irq_chip(irqno, &s3c_irq_chip); //设置s3c所对应的底层函数
set_irq_handler(irqno, handle_edge_irq);
set_irq_flags(irqno, IRQF_VALID);
通过上边的定义中断的框架搭建成功。
2.使用request_irq函数填充上面所建立的框架
使用int request_irq(unsigned int irq, irq_handler_t handler,unsigned long irqflags, const char *devname, void *dev_id)对框架中各个项进行填充;
其中irq为中断号,handler为用户编写的中断处理函数,irqflags为中断的触发方式,devname为/dev/interrupts中中断的名字,而dev_id即为前面介绍的irq_action中的dev_id。
3..使用框架执行用户编写的中断处理函数:asm_do_IRQ函数
asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
struct irq_desc *desc = irq_desc + irq;//找到irq对应的irq_desc[irq],对应于上边框架中的横轴
desc_handle_irq(irq, desc); //Obsolete inline function for calling irq descriptor handlers.
desc->handle_irq(irq, desc);//其中handle_irq函数通过s3c24xx_init_irq函数定义指向handle_edge_irq函数
handle_edge_irq(unsigned int irq, struct irq_desc *desc)
handle_IRQ_event(irq, action); //Handles the action chain of an irq event
action->handler(irq, action->dev_id); //此时的handler函数就是指向用户编写的中断处理函数
通过从asm_do_IRQ到 action->handler(irq, action->dev_id); 逐步调用框架中的函数最终实现对用户编写的中断处理函数的调用。