一、单片机下的中断处理
1)分辨是哪一个中断
2)调用处理函数
3)清中断
二、linux下的中断处理
1)/arch/arm/kernel/irq.c
asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
{
struct pt_regs *old_regs = set_irq_regs(regs);
struct irq_desc *desc = irq_desc + irq;
/*
* Some hardware gives randomly wrong interrupts. Rather
* than crashing, do something sensible.
*/
if (irq >= NR_IRQS)
desc = &bad_irq_desc;
irq_enter();
desc_handle_irq(irq, desc);
/* AT91 specific workaround */
irq_finish(irq);
irq_exit();
set_irq_regs(old_regs);
}
2)/kernel/irq/handle.c
static inline void desc_handle_irq(unsigned int irq, struct irq_desc *desc)
{
desc->handle_irq(irq, desc);
}
3)/kernel/irq/chip.c
__set_irq_handler{
...
desc->handle_irq = handle;
...
}
4)/include/linux/irq.h
static inline void
set_irq_handler(unsigned int irq, irq_flow_handler_t handle)
{
__set_irq_handler(irq, handle, 0, NULL);
}
5)/arch/arm/plat-s3c24xx/irq.c
void __init s3c24xx_init_irq(void)
6)/arch/arm/plat-s3c24xx/irq.c
set_irq_handler(irqno, handle_edge_irq);
7)/kernel/irq/chip.c
调用4)
调用3)
8)在s3c24xx_init_irq这个函数里面,初始化irq_desc结构体
struct irq_desc {
irq_flow_handler_t handle_irq; //set_irq_handler(irqno, handle_edge_irq);
struct irq_chip *chip; //set_irq_chip(irqno, &s3c_irq_eint0t4);
struct msi_desc *msi_desc;
void *handler_data;
void *chip_data;
struct irqaction *action; /* IRQ action list */
unsigned int status; /* IRQ status */
....
9)/kernel/irq/chip.c
分析handle_edge_irq:
void fastcall
handle_edge_irq(unsigned int irq, struct irq_desc *desc)
{
const unsigned int cpu = smp_processor_id();
spin_lock(&desc->lock);
desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);
/*
* If we're currently running this IRQ, or its disabled,
* we shouldn't process the IRQ. Mark it pending, handle
* the necessary masking and go out
*/
if (unlikely((desc->status & (IRQ_INPROGRESS | IRQ_DISABLED)) ||
!desc->action)) {
desc->status |= (IRQ_PENDING | IRQ_MASKED);
mask_ack_irq(desc, irq);
goto out_unlock;
}
kstat_cpu(cpu).irqs[irq]++; //发生中断的次数
/* Start handling the irq */ //开始处理中断
desc->chip->ack(irq); //desc->chip chip是之前初始化的s3c_irqext_chip
/* Mark the IRQ currently in progress.*/
desc->status |= IRQ_INPROGRESS;
do {
struct irqaction *action = desc->action;
irqreturn_t action_ret;
if (unlikely(!action)) { //判断链表是否为空
desc->chip->mask(irq);
goto out_unlock;
}
/*
* When another irq arrived while we were handling
* one, we could have masked the irq.
* Renable it, if it was not disabled in meantime.
*/
if (unlikely((desc->status &
(IRQ_PENDING | IRQ_MASKED | IRQ_DISABLED)) ==
(IRQ_PENDING | IRQ_MASKED))) {
desc->chip->unmask(irq);
desc->status &= ~IRQ_MASKED;
}
desc->status &= ~IRQ_PENDING;
spin_unlock(&desc->lock);
action_ret = handle_IRQ_event(irq, action);//真正的处理过程
if (!noirqdebug)
note_interrupt(irq, desc, action_ret);
......
}
10)
/arch/arm/plat-s3c24xx/irq.c
s3c_irqext_chip中的.ack
static struct irq_chip s3c_irqext_chip = {
.name = "s3c-ext",
.mask = s3c_irqext_mask,
.unmask = s3c_irqext_unmask,
.ack = s3c_irqext_ack,
.set_type = s3c_irqext_type,
.set_wake = s3c_irqext_wake
};
s3c_irqext_ack分析:
static void
s3c_irqext_ack(unsigned int irqno)
{
unsigned long req;
unsigned long bit;
unsigned long mask;
bit = 1UL << (irqno - EXTINT_OFF);
mask = __raw_readl(S3C24XX_EINTMASK);
__raw_writel(bit, S3C24XX_EINTPEND);
req = __raw_readl(S3C24XX_EINTPEND);
req &= ~mask;
/* not sure if we should be acking the parent irq... */
if (irqno <= IRQ_EINT7 ) {
if ((req & 0xf0) == 0)
s3c_irq_ack(IRQ_EINT4t7);
} else {
if ((req >> 8) == 0)
s3c_irq_ack(IRQ_EINT8t23);
}
}
static inline void
s3c_irq_ack(unsigned int irqno)
{
unsigned long bitval = 1UL << (irqno - IRQ_EINT0);
__raw_writel(bitval, S3C2410_SRCPND);
__raw_writel(bitval, S3C2410_INTPND);
}
①desc->chip->ack(irq);//上面是清理中断
============================================================
②handle_edge_irq取出action链表中的成员,执行action->handler
irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)
{
irqreturn_t ret, retval = IRQ_NONE;
unsigned int status = 0;
handle_dynamic_tick(action);
if (!(action->flags & IRQF_DISABLED))
local_irq_enable_in_hardirq();
do {
ret = action->handler(irq, action->dev_id);
if (ret == IRQ_HANDLED)
status |= action->flags;
retval |= ret;
action = action->next;
} while (action);
if (status & IRQF_SAMPLE_RANDOM)
add_interrupt_randomness(irq);
local_irq_disable();
return retval;
}
总结:
按下按键
1>cup进入异常处理模式
b vector_irq + ...
2>__irq_user
3>asm_do_IRQ
4>irq_des[irq]以中断号为下标取出一项 ->handle_irq
struct irq_desc {
irq_flow_handler_t handle_irq; //set_irq_handler(irqno, handle_edge_irq);
//handle_edge_irq取出action链表中的成员,
//执行action->handler(自定义实现)
struct irq_chip *chip; //set_irq_chip(irqno, &s3c_irq_eint0t4);
//芯片相关的一些操作
...
}
5>handle_irq = handle_edge_irq
6>handle_edge_irq的操作:
(1)desc->chip->ack(irq);
(2)handle_IRQ_event(irq, action);
===========================================================================================
自定义异常处理函数action->handler,注册进内核
request_irq
1./kernel/irq/manage.c
int request_irq(unsigned int irq, irq_handler_t handler,
unsigned long irqflags, const char *devname, void *dev_id)
{
//1)分配了一个结构,结构中的成员指向传递进来的参数
action = kmalloc(sizeof(struct irqaction), GFP_ATOMIC);
//2)设置irq
retval = setup_irq(irq, action);
}
2.setup_irq()函数分析:
1)irq_des[irq] 已irq为下标找到数组项
2)在irq_des[irq]链表里面加入传递进来的参数action
3)desc->chip->settype()设置为中断引脚
4)desc->chip->startup / desc->chip->enable 使能中断
free_irq(irq, dev_id)
1)从链表中除去
2)禁止中断