"); //-->
作者:下家山(请尊重原创,转载请注明) http://www.xiajiashan.com
4.1.2.1 desc->chip->unmask(irq)函数来自哪里?其实default_startup和default_enable最终调用的是一个函数desc->chip->unmask(irq);那么这个函数在哪里定义的呢?
在s3c_init_irq中调用了set_irq_chip(irqno, &s3c_irqext_chip);参数s3c_irqext_chip是一个结构体,定义如下:
static struct irq_chip s3c_irqext_chip = {
.mask = s3c_irqext_mask,
.unmask = s3c_irqext_unmaskack,
//.ack = s3c_irqext_maskack,/*old*/
.ack = s3c_irqext_ack,
.set_type = s3c_irqext_type,
.set_wake = s3c_irqext_wake
};因此,在调用set_irq_chip(irqno, &s3c_irqext_chip);这个函数时,就对相应的irq结构体irq_desc进行了回调函数的定义。
4.1.3 关于set_irq_handler函数/*
* Set a highlevel flow handler for a given IRQ:
*/
static inline void
set_irq_handler(unsigned int irq, irq_flow_handler_t handle)
{
__set_irq_handler(irq, handle, 0, NULL);
}(见/include/linux/irq.h)
void
__set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
const char *name) (见/kernel/irq/chip.c)
{
struct irq_desc *desc;
unsigned long flags;
if (irq >= NR_IRQS) {
printk(KERN_ERR
"Trying to install type control for IRQ%d\n", irq);
return;
}
desc = irq_desc + irq;
if (!handle)
handle = handle_bad_irq;
else if (desc->chip == &no_irq_chip) {
printk(KERN_WARNING "Trying to install %sinterrupt handler "
"for IRQ%d\n", is_chained ? "chained " : "", irq);
/*
* Some ARM implementations install a handler for really dumb
* interrupt hardware without setting an irq_chip. This worked
* with the ARM no_irq_chip but the check in setup_irq would
* prevent us to setup the interrupt at all. Switch it to
* dummy_irq_chip for easy transition.
*/
desc->chip = &dummy_irq_chip;
}
spin_lock_irqsave(&desc->lock, flags);
/* Uninstall? */
if (handle == handle_bad_irq) {
if (desc->chip != &no_irq_chip)
mask_ack_irq(desc, irq);
desc->status |= IRQ_DISABLED;
desc->depth = 1;
}
desc->handle_irq = handle;/* 这一句很重要,即定义对应irq结构体irq_desc 的回调函数desc->handle_irq ,这样在函数asm_do_IRQ中调用desc_handle_irq(irq, desc)时就调用到这个句柄函数中来了 */
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->unmask(irq);
}
spin_unlock_irqrestore(&desc->lock, flags);
}
void set_irq_flags(unsigned int irq, unsigned int iflags)/*见arch/arm/kernel/irq.c*/
{
struct irq_desc *desc;
unsigned long flags;
if (irq >= NR_IRQS) {
printk(KERN_ERR "Trying to set irq flags for IRQ%d\n", irq);
return;
}
desc = irq_desc + irq;
spin_lock_irqsave(&desc->lock, flags);
desc->status |= IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
if (iflags & IRQF_VALID)
desc->status &= ~IRQ_NOREQUEST;
if (iflags & IRQF_PROBE)
desc->status &= ~IRQ_NOPROBE;
if (!(iflags & IRQF_NOAUTOEN))
desc->status &= ~IRQ_NOAUTOEN;
spin_unlock_irqrestore(&desc->lock, flags);
}
这个函数主要是初始化irq对应结构体irq_desc的status。这在setup_irq中会涉及到。
4.2 中断发生后,kernel具体做了哪些事情到这里似乎还没有找到我们第二个问题的答案,但至此我们应该有了一个大概的脉络流程,即从中断发生后,kernel具体做了哪些事情:
中断发生——>向量地址0xffff0018——>vector_irq——>handler_irq——>asm_do_IRQ——>desc_handle_irq——>desc->handle_irq——>handle_level_irq
4.3 关于handle_level_irq函数其实,到这里如果你再往下跟一下就会找到答案。
在handle_level_irq函数中其原形如下:(见/kernel/irq/chip.c)
/**
* handle_level_irq - Level type irq handler
* @irq: the interrupt number
* @desc: the interrupt description structure for this irq
*
* Level type interrupts are active as long as the hardware line has
* the active level. This may require to mask the interrupt and unmask
* it after the associated handler has acknowledged the device, so the
* interrupt line is back to inactive.
*/
void fastcall
handle_level_irq(unsigned int irq, struct irq_desc *desc)
{
unsigned int cpu = smp_processor_id();
struct irqaction *action;
irqreturn_t action_ret;
spin_lock(&desc->lock);
mask_ack_irq(desc, irq);
if (unlikely(desc->status & IRQ_INPROGRESS))
goto out_unlock;
desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);
kstat_cpu(cpu).irqs[irq]++;
/*
* If its disabled or no action available
* keep it masked and get out of here
*/
action = desc->action;/*这一句很重要,它从对应irq的结构体irq_desc中取出当前的活动irq,即 desc->action ,而desc->action 即为我们最初在setup_irq 中注册的的那个action */
if (unlikely(!action || (desc->status & IRQ_DISABLED))) {
desc->status |= IRQ_PENDING;
goto out_unlock;
}
desc->status |= IRQ_INPROGRESS;
desc->status &= ~IRQ_PENDING;
spin_unlock(&desc->lock);
action_ret = handle_IRQ_event(irq, action);/*这一句就最重要了,其原形见下面*/
if (!noirqdebug)
note_interrupt(irq, desc, action_ret);
spin_lock(&desc->lock);
desc->status &= ~IRQ_INPROGRESS;
if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
desc->chip->unmask(irq);
out_unlock:
spin_unlock(&desc->lock);
}
4.3.1关于handle_IRQ_event函数/**
* 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
*/
(见kernel/irq/handle.c)
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);/*这一句就是我们要找的最终答案,还记得在register_irq中有 action->handler = handler;这一句吗,这里面的handler就是我们驱动注册的中断函数,而在register_irq中把它赋值给了action,而在setup_irq中又把action赋值给了全局变量irq_desc */
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;
}
2009-2-13 下家山 写于上海.漕河泾
有什么问题可以给我邮件ximenpiaoxue4016@sina.com或加我群198204885
*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。
eleaction01 阅读:4490