linux 下的中断初始化,实际就是对 irq_desc 这个结构体进行初始化,其中最关键莫过于
irq_flow_handler_t handle_irq 中断处理函数
struct irqaction *action 用户自己设置的处理函数链表,由handle_irq调用
struct irq_chip *chip 硬件相关的操作,比如设置管脚为中断模式,使能中断等等。
这三个结构体成员变量的赋值了,其中handle_irq和chip一般官方的bsp里会为我们设置好,而action链表是我们自己的中断处理函数,handle_irq会去遍历action链表并执行。系统中每一个中断号会对应一个irq_desc结构体。
在kernel/irq/handle.c 中,系统为我们定义并初始化了一个irq_desc的结构体数组,中断号为数组下标。也就是
说每一个中断号会对应一个irq_desc结构体。linux整个中断机制实际就是围绕这个结构体数组进行的,即,
赋值,调用等等。
1. arch/mips/kernel/irq_cpu.c
mips_cpu_irq_init
for (i = irq_base + 2; i < irq_base + 8; i++)
set_irq_chip_and_handler(i, &mips_cpu_irq_controller,handle_level_irq);
irq_base为0,实际上注册了2 -- 7 中断号的处理函数
2. kernel/irq/chip.c
set_irq_chip_and_handler
__set_irq_handler
desc->handle_irq = handle
最终是把handle_level_irq作为这个6个中断号的中断处理函数
handle_level_irq
1. kernel/irq/chip.c
handle_level_irq
handle_IRQ_event(irq, action)
2.kernel/irq/handle.c
handle_IRQ_event
do {
ret = action->handler(irq, action->dev_id);
if (ret == IRQ_HANDLED)
status |= action->flags;
retval |= ret;
action = action->next;
} while (action);
这里挨个调用desc中action链表中的处理函数进行真正的中断处理
下面分析rt5350中对gpio中断的初始化,从 include/asm-mips/rt2880/surfboardint.h 中可以看到
#define SURFBOARDINT_GPIO 6 /* GPIO */
说明GPIO中断的中断号为6,这块和三星的芯片差别比较大,三星的芯片有专门的外部中断管脚(虽然也是
GPIO管脚复用),但是每个外部中断管脚对应一个中断号。而且ralink的是所有的GPIO复用中断管脚共用一个
中断号6. 而且ralink的bsp中给6号中断已经注册了action链表,那,我想我们就不用自己调用request_irq函数去
给他注册action链表了吧,直接修改ralink_gpio_irqaction应该就行了吧
1. arch/mips/kernel/head.S
j start_kernel
2. init/main.c
start_kernel
init_IRQ
3. arch/mips/kernel/irq.c
init_IRQ
arch_init_irq
4. arch/mips/rt2880/irq.c
arch_init_irq
ralink_gpio_init_irq
5. drivers/char/ralink_gpio.cralink_gpio_init_irq
setup_irq(SURFBOARDINT_GPIO, &ralink_gpio_irqaction);
实际上request_irq也是调用setup_irq来注册中断处理函数,那么我们就不应该再去调用request_irq了,实际上系统已经为我们做好了6号中断的注册,我们应该只需要将我们需要的GPIO管脚设置为中断模式即可。
其中SURFBOARDINT_GPIO=6,在这个函数中注册action,以供handle_IRQ_event调用
使用cat /proc/interrupts命令可以看到gpio中断号的确是6