当发生中断之后,linux系统在汇编阶段经过一系列跳转,最终跳转到asm_do_irq()函数,开始C程序阶段的处理。在汇编阶段,程序已经计算出发生中断的中断号irq,这个关键参数最终传递给asm_do_irq()。linux驱动中断处理C程序部分,主要涉及linux中断系统数据结构的初始化和C程序的具体执行跳转。
一、中断处理数据结构
linux内核将所有的中断统一编号,使用一个irq_desc[NR_IRQS]的结构体数组来描述这些中断:每个数组项对应着一个中断源(可能是一个中断,也可能是一组中断),记录了中断的入口处理函数(不是用户注册的处理函数)、中断标记,并提供了中断的底层硬件访问函数(中断清除、屏蔽、使能)。另外,通过这个结构体数组项成员action,能够找到用户注册的中断处理函数。结构体irq_desc的数据类型在include/linux/irq.h中定义,内容如下:
struct
irq_desc {
irq_flow_handler_t handle_irq;
/*
当前中断的处理函数入口
*/
struct irq_chip *chip; /* 低层的硬件访问 */struct msi_desc *msi_desc;
void *handler_data;
void *chip_data;
struct irqaction *action; /* 用户提供的中断处理函数链表 */
unsigned int status; /* IRQ状态 */
unsigned int depth; /* nested irq disables */
unsigned int wake_depth; /* nested wake enables */
unsigned int irq_count; /* For detecting broken IRQs */
unsigned int irqs_unhandled;
spinlock_t lock;
constchar *name; /* 中断名称 */
} ____cacheline_internodealigned_in_smp;
irq_desc成员变量handle_irq是这个或这组中断的入口处理函数,成员变量chip结构体包含了这个中断的清除、屏蔽或者使能等底层函数,结构体类型irq_chip的定义也在include/linux/irq.h中,内容如下:
struct
irq_chip {
const
char *name;
unsigned int (*startup)(unsigned int irq);
void (*shutdown)(unsigned int irq);
void (*enable)(unsigned int irq);
void (*disable)(unsigned int irq);
void (*ack)(unsigned int irq);
void (*mask)(unsigned int irq);
void (*mask_ack)(unsigned int irq);
void (*unmask)(unsigned int irq);
constchar *typename;
};
irq_desc成员变量action记录了用户注册的中断处理函数、中断标志等等内容,其类型irqaction类型定义在include/linux/interrupt.h中,内容如下:
struct
irqaction {
irq_handler_t handler;
/*
用户注册的中断处理函数
*/
unsigned
long flags; /* 中断标志,是否共享中断,电平触发还是边沿触发等 */
cpumask_t mask; /* 用于SMP */constchar *name; /* 用户注册的中断名字,/proc/interrupts */void *dev_id; /* 用户传递给handler的参数,还可以用来区分共享中断 */struct irqaction *next; /* 指向下一个irqaciton结构体指针 */int irq; /* 中断号 */struct proc_dir_entry *dir;
};
用户注册的每个中断处理函数对应一个irqaciton结构体,一个中断源可以有多个处理函数(共享终端),它们的irqaciton结构体可以构成一个单项链表,irq_desc[irqn].action则是表头。irq_desc[NR_IRQS]结构体数组的构成情况如下图所示:
原文:http://www.cnblogs.com/amanlikethis/p/6941666.html
【说明】:本文章由站长整理发布,文章内容不代表本站观点,如文中有侵权行为,请与本站客服联系(QQ:254677821)!