单片机下的中断处理:
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
下面为图示:
以上都是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