新闻  |   论坛  |   博客  |   在线研讨会
Linux-2.6.21 S3c6400中断剖析之五 (原创)-上海嵌入式索漫科技培训教材
xiajiashan | 2012-10-10 14:34:30    阅读:1917   发布文章

作者:下家山(请尊重原创,转载请注明)  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

 

*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。

参与讨论
登录后参与讨论
02年接触ARM和ucos,开发过有线和无线图像报警器,IPCamera,人脸识别系统,OCR识别系统,指纹识别系统,05年开始从事Linux及Rtems下WiFi,camera,Ethernet等驱动开发工作,专做嵌入式linux培训,致力于把我十年来的研发经验传授给每一个学员,招人的可以找我,ximenpiaoxue4016@sina.com
推荐文章
最近访客