6410之linux中断处理结构

单片机下的中断处理:

1.分辨是哪个中断

2.调用处理函数

3.清中断


在linux中,上面的这些操作基本上都是在asm_do_IRQ中进行操作的,下面进行分析:

asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
{
。。。
if (unlikely(irq >= nr_irqs)) {
if (printk_ratelimit())
printk(KERN_WARNING "Bad IRQ%u\n", irq);
ack_bad_irq(irq);
} else {
generic_handle_irq(irq);   //调用中断处理函数
}
。。。
}


static inline void generic_handle_irq_desc(unsigned int irq, struct irq_desc *desc)
{
#ifdef CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ
desc->handle_irq(irq, desc);   //最终调用的中断处理函数
#else
if (likely(desc->handle_irq))
desc->handle_irq(irq, desc);
else
__do_IRQ(irq);
#endif
}


查找代码发现handle_irq在下面代码中被调用:

路径:Chip.c (kernel\irq)

void
__set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
 const char *name)
{
。。。

desc->handle_irq = handle;
desc->name = name;



if (handle != handle_bad_irq && is_chained) {
desc->status &= ~IRQ_DISABLED;
desc->status |= IRQ_NOREQUEST | IRQ_NOPROBE;
desc->depth = 0;
desc->chip->startup(irq);
}
raw_spin_unlock_irqrestore(&desc->lock, flags);
chip_bus_sync_unlock(irq, desc);
}


继续搜说:

路径:Irq.h (include\linux)

static inline void
set_irq_handler(unsigned int irq, irq_flow_handler_t handle)
{
__set_irq_handler(irq, handle, 0, NULL);
}

最后发现该函数在Irq-eint.c (arch\arm\mach-s3c64xx) 中被调用,代码如下:

static int __init s3c64xx_init_irq_eint(void)
{
int irq;


for (irq = IRQ_EINT(0); irq <= IRQ_EINT(27); irq++) {
set_irq_chip(irq, &s3c_irq_eint);//chip = s3c_irq_eint
set_irq_handler(irq, handle_level_irq);       //这里的handle_level_irq就是前面所说的desc->handle_irq(irq, desc);
set_irq_flags(irq, IRQF_VALID);
}


set_irq_chained_handler(IRQ_EINT0_3, s3c_irq_demux_eint0_3);
set_irq_chained_handler(IRQ_EINT4_11, s3c_irq_demux_eint4_11);
set_irq_chained_handler(IRQ_EINT12_19, s3c_irq_demux_eint12_19);
set_irq_chained_handler(IRQ_EINT20_27, s3c_irq_demux_eint20_27);


return 0;
}

然后:arch_initcall(s3c64xx_init_irq_eint);   //这个arch_initcall的意义可以参考:http://blog.csdn.net/longshan_2009/article/details/9978913

意思就是在系统初始化的时候会自动调用s3c64xx_init_irq_eint这个函数。


分析到这里看下handle_level_irq

void
handle_level_irq(unsigned int irq, struct irq_desc *desc)
{
。。。
mask_ack_irq(desc, irq);   //清除中断

。。。
action = desc->action;   //取出desc中的action

action_ret = handle_IRQ_event(irq, action);   //处理中断
。。。
}

下面看下mask_ack_irq和handle_IRQ_event

mask_ack_irq

static inline void mask_ack_irq(struct irq_desc *desc, int irq)
{
if (desc->chip->mask_ack)
desc->chip->mask_ack(irq);  //这个mask_ack就是之前的s3c_irq_eint

else {
desc->chip->mask(irq);
if (desc->chip->ack)
desc->chip->ack(irq);
}
desc->status |= IRQ_MASKED;
}

mask_ack的实现如下:

static void s3c_irq_eint_maskack(unsigned int irq)
{
/* compiler should in-line these */
s3c_irq_eint_mask(irq);//最终操作:S3C64XX_EINT0MASK寄存器
s3c_irq_eint_ack(irq); // 操作S3C64XX_EINT0PEND寄存器
}

handle_IRQ_event

irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)
{
irqreturn_t ret, retval = IRQ_NONE;
unsigned int status = 0;


do {
trace_irq_handler_entry(irq, action);
ret = action->handler(irq, action->dev_id);
。。。
action = action->next;        //action是一个链表
} while (action);
...


return retval;

}

到这里先总结一下:

按下按键:

1.进入异常模式:比如 b vector_irq + 偏移

2.进入__irq_usr

3.b asm_do_IRQ

4.irq_desc[irq] -> handle_irq,即handle_level_irq

handle_level_irq的工作:

1.mask_ack_irq

2.handle_IRQ_event ,最终调用action->handler

下面为图示:

6410之linux中断处理结构_第1张图片

以上都是linux系统帮我们做好的,那么我们如何告诉内核我们的处理函数?

使用request_irq函数来注册


request_irq的工作:

1.分配irqaction结构

2.setuo_irq(irq,action)

a.在irq_desc[irq]-> action链表中假如action

b.desc->chip->settype()

c.desc -> chip -> startup/enable

你可能感兴趣的:(6410之linux中断处理结构)