中断:以读取按键为例。
单片机的处理方式:
1、按键按下
2、cpu发生中断,跳到异常向量入口执行
3、b function
function处理过程:
3.1 保存被中断的现场
3.2 执行中断处理函数
3.3 恢复现场、清中断
所以代码中必须先设置异常向量入口。
Linux中的中断处理方式:
内核在start_kernel函数中调用trap_init,init_IRQ函数来设置异常的处理函数。
void __init trap_init(void)
{
......
memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);
memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);
......
}
/***********************************/
____.globl____vectors_start
__vectors_start:
____swi_SYS_ERROR0
____b___vector_und + stubs_offset
____ldr_pc, .LCvswi + stubs_offset
____b___vector_pabt + stubs_offset
____b___vector_dabt + stubs_offset
____b___vector_addrexcptn + stubs_offset
____b___vector_irq + stubs_offset
____b___vector_fiq + stubs_offset
____.globl____vectors_end
__vectors_end:
/***********************************/
/*vector_stub_irq:宏需要展开来看,展开后得到一个vector_irq函数,调用下面的函数irq_usr*/
____vector_stub_irq, IRQ_MODE, 4
____.long_____irq_usr___________@ 0 (USR_26 / USR_32)
____.long_____irq_invalid___________@ 1 (FIQ_26 / FIQ_32)
____.long_____irq_invalid___________@ 2 (IRQ_26 / IRQ_32)
____.long_____irq_svc___________@ 3 (SVC_26 / SVC_32)
____.long_____irq_invalid___________@ 4
____.long_____irq_invalid___________@ 5
____.long_____irq_invalid___________@ 6
____.long_____irq_invalid___________@ 7
____.long_____irq_invalid___________@ 8
____.long_____irq_invalid___________@ 9
____.long_____irq_invalid___________@ a
____.long_____irq_invalid___________@ b
____.long_____irq_invalid___________@ c
____.long_____irq_invalid___________@ d
____.long_____irq_invalid___________@ e
____.long_____irq_invalid___________@ f
/***********************************/
____.macro__vector_stub, name, mode, correction=0
____.align__5
vector_\name:
____.if \correction
____sub_lr, lr, #\correction
____.endif
____@
____@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
____@ (parent CPSR)
____@
____stmia___sp, {r0, lr}________@ save r0, lr
____mrs_lr, spsr
____str_lr, [sp, #8]________@ save spsr
____@
____@ Prepare for SVC32 mode. IRQs remain disabled.
____@
____mrs_r0, cpsr
____eor_r0, r0, #(\mode ^ SVC_MODE)
____msr_spsr_cxsf, r0
____@
____@ the branch table must immediately follow this code
____@
____and_lr, lr, #0x0f
____mov_r0, sp
____ldr_lr, [pc, lr, lsl #2]
____movs____pc, lr__________@ branch to handler in SVC mode
____.endm
/***********************************/
__irq_usr->
____usr_entry /*保存寄存器内容到栈中*/
irq_handler->____bne_asm_do_IRQ
/*
* do_IRQ handles all hardware IRQ's. Decoded IRQs should not
* come via this function. Instead, they should provide their
* own 'handler'
*/
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);
}
在asm_do_IRQ中会根据中断号(irq)来查找irq_desc结构。
asm_do_IRQ()
{
......
struct irq_desc *desc = irq_desc + irq;
desc_handle_irq(irq, desc);
......
}
static inline void desc_handle_irq(unsigned int irq, struct irq_desc *desc)
{
____desc->handle_irq(irq, desc); /*执行中断号对应的中断处理函数*/
}
irq_desc全局的结构体在哪注册的?
__set_irq_handler()函数会注册irq_desc。
例如:s3c24xx_init_irq->set_irq_handler(irqno, handle_edge_irq)->__set_irq_handler()
void
__set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
________ const char *name)
{
......
____desc = irq_desc + irq;
......
____desc->handle_irq = handle;
____desc->name = name;
......
}
static inline void
set_irq_handler(unsigned int irq, irq_flow_handler_t handle)
{
______set_irq_handler(irq, handle, 0, NULL);
}
void __init s3c24xx_init_irq(void)
{
......
____for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) {
________irqdbf("registering irq %d (ext int)\n", irqno);
________set_irq_chip(irqno, &s3c_irq_eint0t4);
________set_irq_handler(irqno, handle_edge_irq);
________set_irq_flags(irqno, IRQF_VALID);
____}
......
}
/*以handler(handle_edge_irq)为例分析*/
void fastcall
handle_edge_irq(unsigned int irq, struct irq_desc *desc)
{
......
____/* Start handling the irq */
____desc->chip->ack(irq); /*清中断*/
......
________action_ret = handle_IRQ_event(irq, action);/*中断处理*/
......
}
/**
* handle_IRQ_event - irq action chain handler
* @irq:____the interrupt number
* @action:_the interrupt action chain for this irq
*
* Handles the action chain of an irq event
*/
irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)
{
......
____do {
________ret = action->handler(irq, action->dev_id);
________if (ret == IRQ_HANDLED)
____________status |= action->flags;
________retval |= ret;
________action = action->next;
____} while (action);
......
____return retval;
}
总结:
1、按键按下
2、cpu进入异常模式
__vectors_start:
b vertor_irq + stubs_offset
3、___irq_usr
____usr_entry
____irq_handler
bne_asm_do_IRQ
____desc_handle_irq(irq, desc);
____desc->handle_irq(irq, desc);/*根据中断号查找对应的desc,执行中断处理函数*/
4、s3c24xx_init_irq初始化具体中断号所对应的中断处理函数以及中断号对应的中断引脚
中断处理函数:
set_irq_chip(irqno, &s3c_irq_eint0t4);/*初始化中断号对应的底层中断管脚*/
static struct irq_chip s3c_irq_eint0t4 = {
____.name_______= "s3c-ext0",
____.ack________= s3c_irq_ack,
____.mask_______= s3c_irq_mask,
____.unmask_____= s3c_irq_unmask,
____.set_wake___= s3c_irq_wake,
____.set_type___= s3c_irqext_type,
};
set_irq_handler(irqno, handle_edge_irq);/*初始化中断号对应的中断处理函数*/
handle_edge_irq
{
____desc->chip->ack(irq); /*清中断*/
________action_ret = handle_IRQ_event(irq, action);/*中断处理*/
}
5、
int request_irq(unsigned int irq, irq_handler_t handler,
________unsigned long irqflags, const char *devname, void *dev_id)
{
____action = kmalloc(sizeof(struct irqaction), GFP_ATOMIC);
......
action->handler = handler;
____action->name = devname;
____action->next = NULL;
____action->dev_id = dev_id;
.......
____retval = setup_irq(irq, action);
}
int setup_irq(unsigned int irq, struct irqaction *new)
{
struct irq_desc *desc = irq_desc + irq;
......
desc->chip->set_type(); /*设置中断引脚*/
......
/*使能中断*/
if (desc->chip->startup)
____desc->chip->startup(irq);
else
____desc->chip->enable(irq);
}