linux中断机制及中断注册1(韦东山的视频总结及针对linux-2.6.30.4)
2013-05-19 16:43
176 查看
自己的总结有错误请评论,我们共同进步。
下面的以天嵌 用户模式下 按下按键k1 产生中断EINT1为例进行分析的,内核代码只是摘录中断相关的。
下面为流程图,
traps.c中early_trap_init(void)被用来设置各种异常向量,通俗的说就是把有关异常代码放到固定位置,当发生异常时,CPU会自动找到相关异常的代码进行执行。
void __init early_trap_init(void){
unsigned long vectors = CONFIG_VECTORS_BASE;
/*CONFIG_VECTORS_BASE配置项,vi .config可以查看其值,此值为异常向量基址*/
memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);
/*从__vectors_start到 __vectors_end 复制到vectors中去*/
}
__vectors_start异常代码,(在kernel\entry-armv.S中,下面只是分析中断)
__vectors_start:
b vector_irq + stubs_offset /*vector_irq是宏,就在此文件中stubs_offset */
/*与vector_irq 相关代码*/
__stubs_start:
/*
* Interrupt dispatcher
*/
vector_stub
irq, IRQ_MODE, 4 (1)
.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
/*
*Common stub entry macro:
* Enter in IRQ mode, spsr = SVC/USR CPSR, lr = SVC/USR PC
*/
在此文件中有上面一句话,意思大概是宏的共同的入口函数(英语不怎么地,只能知道大概意思)
/*上面的 vector_stub irq, IRQ_MODE, 4 跟这个结构好像呢
.macro
vector_stub, name, mode, correction=0 (2)
.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]
movspc, lr@ branch to handler in SVC mode
ENDPROC(vector_\name)
.endm
有(1)和(2)就可以把宏vector_irq展开(更改的用红色字体已标出)。
.macro
vector_stub, irq, IRQ_MODE, 4
.align
5
vector_irq:
.if 4
sub lr, lr, #4/*计算返回值*/
.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
ENDPROC(vector_irq)
.endm
用户模式下发生中断进入__irq_usr
__irq_usr:
usr_entry
/*主要是保存返回的寄存器的值*/
irq_handler/*在kernel\entry-armv.S定义的宏*/
/*********************展开irq_handler****************/
/*
*Interrupt handling. Preserves r7, r8, r9
*/
.macroirq_handler//最终调用asm_do_IRQ(中断处理)
bneasm_do_IRQ
/****************************************************/
asm_do_IRQ主要的功能1.分辨中断,2.调用中断处理函数,3.清中断。
下面分析asm_do_IRQ函数(在\kernel\irq.c中定义)
asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
{
generic_handle_irq(irq); /*主要的中断都是调用它,在linux\irq.h中定义*/
}
/************把generic_handle_irq(irq)展开*********************/
generic_handle_irq( irq)
{
generic_handle_irq_desc(irq, irq_to_desc(irq));/*被调用也在linux \irq.h中定义*/
/********irq_to_desc(irq)展开(在irq\handle.c中定义)*********/
struct irq_desc *irq_to_desc(unsigned int irq)
{
return (irq < NR_IRQS) ? irq_desc + irq : NULL;
}
返回以中断号irq为下标的中断描述项的指针 即:dev=irq_desc+irq
中断描述的数组(在irq\handle.c中定义)为:
struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {
[0 ... NR_IRQS-1] = {
.status = IRQ_DISABLED,
.chip = &no_irq_chip,
.handle_irq = handle_bad_irq,
.depth = 1,
.lock = __SPIN_LOCK_UNLOCKED(irq_desc->lock),
}
/**************************************************/
}
/*******************************************************************/
/************把generic_handle_irq_desc展开************/
/*irq_desc + irq 分辨出中断,就是确定了中断源,调用->handle_irq()*/
generic_handle_irq_desc(unsigned int irq, irq_desc + irq )
{
desc->handle_irq(irq, desc);
}
/*****************************************************************/
/****desc->handle_irq(irq, desc);相关的*****/
/*在irq/chip.c中定义*/
__set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,const char *name)
{
desc->handle_irq = handle;
}
/*
* Set a highlevel flow handler for a given IRQ:
*/
/*linux\irq.h中定义*/
set_irq_handler(unsigned int irq, irq_flow_handler_t handle)
{
__set_irq_handler(irq, handle, 0, NULL);
}
/* s3c24xx_init_irq
*
* Initialise S3C2410 IRQ system
*/
/*在plat-s3c24xx\irq.c中定义*/
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_chip(irqno, &s3c_irq_eint0t4)展开***/
int set_irq_chip(irq, &s3c_irq_eint0t4)
{
struct irq_desc *desc = irq_to_desc(irq);
irq_chip_set_defaults(chip);
desc->chip = chip;
}
结果为设置了desc中的chip域
/*************************************************/
set_irq_handler(irqno, handle_edge_irq); /*设置中断事件处理函数 即dev->handle_irqhandle_edge_irq*/
set_irq_flags(irqno, IRQF_VALID);
}
}
/************ handle_edge_irq展开****************/
handle_edge_irq(unsigned int irq, struct irq_desc *desc){
/* Start handling the irq */
if (desc->chip->ack)
desc->chip->ack(irq); /*清中断,查看s3c_irq_eint0t4可查看ack*/
action_ret = handle_IRQ_event(irq, action); /*中断处理*/
}
/***********************************************/
/****************** 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(irqirq, action)
{
do {
trace_irq_handler_entry(irq, action);
ret = action->handler(irq, action->dev_id); /*我们定义的中断处理函数执行*/
trace_irq_handler_exit(irq, action, ret);
switch (ret) {
case IRQ_WAKE_THREAD:
/*
* Set result to handled so the spurious check
* does not trigger.
*/
ret = IRQ_HANDLED;
/*
* Catch drivers which return WAKE_THREAD but
* did not set up a thread function
*/
if (unlikely(!action->thread_fn)) {
warn_no_thread(irq, action);
break;
}
/*
* Wake up the handler thread for this
* action. In case the thread crashed and was
* killed we just pretend that we handled the
* interrupt. The hardirq handler above has
* disabled the device interrupt, so no irq
* storm is lurking.
*/
if (likely(!test_bit(IRQTF_DIED,
&action->thread_flags))) {
set_bit(IRQTF_RUNTHREAD, &action->thread_flags);
wake_up_process(action->thread);
}
/* Fall through to add to randomness */
case IRQ_HANDLED:
status |= action->flags;
break;
default:
break;
}
retval |= ret;
action = action->next; //为NULL跳出,
} while (action);
return retval;
}
结果为调用action->handler(irq, action->dev_id)处理中断,就是我们定义在驱动中的中断处理函数
/************************************************************************/
下面的以天嵌 用户模式下 按下按键k1 产生中断EINT1为例进行分析的,内核代码只是摘录中断相关的。
下面为流程图,
traps.c中early_trap_init(void)被用来设置各种异常向量,通俗的说就是把有关异常代码放到固定位置,当发生异常时,CPU会自动找到相关异常的代码进行执行。
void __init early_trap_init(void){
unsigned long vectors = CONFIG_VECTORS_BASE;
/*CONFIG_VECTORS_BASE配置项,vi .config可以查看其值,此值为异常向量基址*/
memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);
/*从__vectors_start到 __vectors_end 复制到vectors中去*/
}
__vectors_start异常代码,(在kernel\entry-armv.S中,下面只是分析中断)
__vectors_start:
b vector_irq + stubs_offset /*vector_irq是宏,就在此文件中stubs_offset */
/*与vector_irq 相关代码*/
__stubs_start:
/*
* Interrupt dispatcher
*/
vector_stub
irq, IRQ_MODE, 4 (1)
.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
/*
*Common stub entry macro:
* Enter in IRQ mode, spsr = SVC/USR CPSR, lr = SVC/USR PC
*/
在此文件中有上面一句话,意思大概是宏的共同的入口函数(英语不怎么地,只能知道大概意思)
/*上面的 vector_stub irq, IRQ_MODE, 4 跟这个结构好像呢
.macro
vector_stub, name, mode, correction=0 (2)
.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]
movspc, lr@ branch to handler in SVC mode
ENDPROC(vector_\name)
.endm
有(1)和(2)就可以把宏vector_irq展开(更改的用红色字体已标出)。
.macro
vector_stub, irq, IRQ_MODE, 4
.align
5
vector_irq:
.if 4
sub lr, lr, #4/*计算返回值*/
.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
ENDPROC(vector_irq)
.endm
用户模式下发生中断进入__irq_usr
__irq_usr:
usr_entry
/*主要是保存返回的寄存器的值*/
irq_handler/*在kernel\entry-armv.S定义的宏*/
/*********************展开irq_handler****************/
/*
*Interrupt handling. Preserves r7, r8, r9
*/
.macroirq_handler//最终调用asm_do_IRQ(中断处理)
bneasm_do_IRQ
/****************************************************/
asm_do_IRQ主要的功能1.分辨中断,2.调用中断处理函数,3.清中断。
下面分析asm_do_IRQ函数(在\kernel\irq.c中定义)
asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
{
generic_handle_irq(irq); /*主要的中断都是调用它,在linux\irq.h中定义*/
}
/************把generic_handle_irq(irq)展开*********************/
generic_handle_irq( irq)
{
generic_handle_irq_desc(irq, irq_to_desc(irq));/*被调用也在linux \irq.h中定义*/
/********irq_to_desc(irq)展开(在irq\handle.c中定义)*********/
struct irq_desc *irq_to_desc(unsigned int irq)
{
return (irq < NR_IRQS) ? irq_desc + irq : NULL;
}
返回以中断号irq为下标的中断描述项的指针 即:dev=irq_desc+irq
中断描述的数组(在irq\handle.c中定义)为:
struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {
[0 ... NR_IRQS-1] = {
.status = IRQ_DISABLED,
.chip = &no_irq_chip,
.handle_irq = handle_bad_irq,
.depth = 1,
.lock = __SPIN_LOCK_UNLOCKED(irq_desc->lock),
}
/**************************************************/
}
/*******************************************************************/
/************把generic_handle_irq_desc展开************/
/*irq_desc + irq 分辨出中断,就是确定了中断源,调用->handle_irq()*/
generic_handle_irq_desc(unsigned int irq, irq_desc + irq )
{
desc->handle_irq(irq, desc);
}
/*****************************************************************/
/****desc->handle_irq(irq, desc);相关的*****/
/*在irq/chip.c中定义*/
__set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,const char *name)
{
desc->handle_irq = handle;
}
/*
* Set a highlevel flow handler for a given IRQ:
*/
/*linux\irq.h中定义*/
set_irq_handler(unsigned int irq, irq_flow_handler_t handle)
{
__set_irq_handler(irq, handle, 0, NULL);
}
/* s3c24xx_init_irq
*
* Initialise S3C2410 IRQ system
*/
/*在plat-s3c24xx\irq.c中定义*/
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_chip(irqno, &s3c_irq_eint0t4)展开***/
int set_irq_chip(irq, &s3c_irq_eint0t4)
{
struct irq_desc *desc = irq_to_desc(irq);
irq_chip_set_defaults(chip);
desc->chip = chip;
}
结果为设置了desc中的chip域
/*************************************************/
set_irq_handler(irqno, handle_edge_irq); /*设置中断事件处理函数 即dev->handle_irqhandle_edge_irq*/
set_irq_flags(irqno, IRQF_VALID);
}
}
/************ handle_edge_irq展开****************/
handle_edge_irq(unsigned int irq, struct irq_desc *desc){
/* Start handling the irq */
if (desc->chip->ack)
desc->chip->ack(irq); /*清中断,查看s3c_irq_eint0t4可查看ack*/
action_ret = handle_IRQ_event(irq, action); /*中断处理*/
}
/***********************************************/
/****************** 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(irqirq, action)
{
do {
trace_irq_handler_entry(irq, action);
ret = action->handler(irq, action->dev_id); /*我们定义的中断处理函数执行*/
trace_irq_handler_exit(irq, action, ret);
switch (ret) {
case IRQ_WAKE_THREAD:
/*
* Set result to handled so the spurious check
* does not trigger.
*/
ret = IRQ_HANDLED;
/*
* Catch drivers which return WAKE_THREAD but
* did not set up a thread function
*/
if (unlikely(!action->thread_fn)) {
warn_no_thread(irq, action);
break;
}
/*
* Wake up the handler thread for this
* action. In case the thread crashed and was
* killed we just pretend that we handled the
* interrupt. The hardirq handler above has
* disabled the device interrupt, so no irq
* storm is lurking.
*/
if (likely(!test_bit(IRQTF_DIED,
&action->thread_flags))) {
set_bit(IRQTF_RUNTHREAD, &action->thread_flags);
wake_up_process(action->thread);
}
/* Fall through to add to randomness */
case IRQ_HANDLED:
status |= action->flags;
break;
default:
break;
}
retval |= ret;
action = action->next; //为NULL跳出,
} while (action);
return retval;
}
结果为调用action->handler(irq, action->dev_id)处理中断,就是我们定义在驱动中的中断处理函数
/************************************************************************/
相关文章推荐
- linux中断机制及中断注册2(韦东山的视频总结及针对linux-2.6.30.4)
- POLL机制分析(韦东山的视频总结及针对linux-2.6.30.4)
- 输入服务子系统框架代码分析(韦东山的视频总结及针对linux-2.6.30.4)
- arm驱动程序——手动设备节点 (韦东山的视频总结及针对linux-2.6.30.4)
- 输入服务子系统实例分析(韦东山的视频总结及针对linux-2.6.30.4)
- arm驱动程序——按键程序3_定时器消抖(韦东山的视频总结及针对linux-2.6.30)
- arm驱动程序——按键程序6_互斥1—原子操作(韦东山的视频总结及针对linux-2.6.30)
- arm驱动程序——按键程序6_互斥—信号量(韦东山的视频总结及针对linux-2.6.30)
- arm驱动程序——按键程序4_poll(韦东山的视频总结及针对linux-2.6.30)
- arm驱动程序——按键程序6_互斥—信号量(韦东山的视频总结及针对linux-2.6.30)
- arm驱动程序——自动创建设备节点 (韦东山的视频总结及针对linux-2.6.30)
- arm驱动程序——点亮led(韦东山的视频总结及针对linux-2.6.30)
- arm驱动程序——按键程序2(韦东山的视频总结及针对linux-2.6.30)
- arm驱动程序——点亮led-利用次设备号(韦东山的视频总结及针对linux-2.6.30)
- arm驱动程序——按键程序6_互斥1—原子操作(韦东山的视频总结及针对linux-2.6.30)
- arm驱动程序——按键程序1(韦东山的视频总结及针对linux-2.6.30)
- arm驱动程序——按键程序5_异步通信(韦东山的视频总结及针对linux-2.6.30)
- arm驱动程序——按键程序2(韦东山的视频总结及针对linux-2.6.30)
- 韦东山Linux视频驱动第2期》学习总结之第17课(USB设备驱动程序)
- linux的中断注册机制分析