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

作者:下家山(请尊重原创,转载请注明)  http://www.xiajiashan.com 

 

四:当中断发生时,kernel是怎么找到这个句柄

第二个问题,我们调用register_irq 函数时注册的句柄,当中断发生时,kernel是怎么找到这个句柄,继而执行我们驱动里的函数的???

      4.1 关于s3c_init_irq函数

在asm_do_IRQ执行时,调用了desc_handle_irq(irq, desc);此函数调用了一个回调函数irq_desc->handle_irq,这一回调函数是在s3c_init_irq(位于/arch/arm/plat-s3c24xx/irq-pl192.c中)中设置的,其原型为:

/* --------------------------------------------------

 *  s3c_init_irq

 *

 *  Initialise s3c6400 IRQ system

 * --------------------------------------------------

 */

/*这个函数是在内核启动时被执行的,通过它来初始化irq_desc结构体数组,这样后续的驱动如果要注册中断就填充到这个数组中来*/

void __init s3c_init_irq(void)

{

       int irqno;

       int irqindex = 0;

 

       irqdbf("s3c_init_irq: clearing interrupt status flags\n");

 

       /* first, clear all interrupts pending... */

 

       /* clear external interrupts */

       __raw_writel(0xFFFFFFFF, S3C_EINTPEND);

 

       /* clear all vector interrupts */

       __raw_writel(0x00000000, S3C_VIC0ADDRESS);

       __raw_writel(0x00000000, S3C_VIC1ADDRESS);

 

 

       /* For writing the IRQ number into the VICVECTADDR */

       for (irqno = IRQ_EINT0_3; irqno <= IRQ_LCD_SYSTEM; irqno++) {

              __raw_writel(irqno, S3C_VIC0VECTADDR0 + irqindex);

              irqindex = irqindex + 4;

       }/*初始化第一组(0~31)中断源的向量地址*/

 

       irqindex = 0;

       for (irqno = IRQ_EINT12_19; irqno <= IRQ_ADC; irqno++) {

              __raw_writel(irqno, S3C_VIC1VECTADDR0 + irqindex);

              irqindex = irqindex + 4;

       }/*初始化第二组(32~63)中断源的向量地址*/

 

       /* register the main interrupts */

       irqdbf("s3c6400_init_irq: registering mDirac-III interrupt handlers\n");

       /*下面的for循环设置63个中断源的中断服务例程(中断服务函数或中断句柄),状态,标志,中断服务例程处理时的回调函数*/

       for (irqno = IRQ_EINT0_3; irqno <= IRQ_ADC; irqno++) {

              switch (irqno) {

                     /* deal with the special IRQs in ext (cascaded) */

              case IRQ_EINT0_3:

                     set_irq_chained_handler(IRQ_EINT0_3, s3c_irq_demux_eint0_3);

                     break; /*设置第一组外部中断中断源的中断服务例程(中断服务函数或中断句柄) */

 

 

              case IRQ_EINT4_11:

                     set_irq_chained_handler(IRQ_EINT4_11, s3c_irq_demux_eint4_11);

                     break; /*设置第二组外部中断中断源的中断服务例程(中断服务函数或中断句柄) */

 

              case IRQ_EINT12_19:

                     set_irq_chained_handler(IRQ_EINT12_19, s3c_irq_demux_eint12_19);

                     break; /*设置第三组外部中断中断源的中断服务例程(中断服务函数或中断句柄) */

 

              case IRQ_EINT20_27:

                     set_irq_chained_handler(IRQ_EINT20_27, s3c_irq_demux_eint20_27);

                     break; /*设置第四组外部中断中断源的中断服务例程(中断服务函数或中断句柄) */

 

              default:

                     irqdbf("registering irq %d (s3c irq)\n", irqno);

                     set_irq_chip(irqno, &s3c_irq_level_chip);/* 设置内部中断中断源的irq_desc结构体回调函数*/

                     //set_irq_handler(irqno, do_level_IRQ);

                     set_irq_handler(irqno, handle_level_irq); /*设置内部中断中断源的中断服务例程(中断服务函数或中断句柄) */

                     set_irq_flags(irqno, IRQF_VALID); /*设置内部中断中断源的irq_desc结构体中断标志*/

                     break;

              }

       }

 

       for (irqno = IRQ_EINT0; irqno <= IRQ_EINT27; irqno++) {

              irqdbf("registering irq %d (extended s3c irq)\n", irqno);

              set_irq_chip(irqno, &s3c_irqext_chip); /* 设置外部中断中断源的irq_desc结构体回调函数*/

              //set_irq_handler(irqno, do_level_IRQ);

              set_irq_handler(irqno, handle_level_irq); /*设置外部中断中断源的中断服务例程(中断服务函数或中断句柄) */             

set_irq_flags(irqno, IRQF_VALID); /*设置外部中断中断源的irq_desc结构体中断标志*/

 

       }

 

       irqdbf("s3c6400: registered interrupt handlers\n");

}

下面对

              set_irq_chip();//见kernel/irq/chip.c

              set_irq_handler();//见include/linux/irq.h->见kernel/irq/chip.c

              set_irq_flags();//见arch/arm/kernel/irq.c

这三个函数分别展开

4.1.1 关于 set_irq_chip()函数

/**

 *    set_irq_chip - set the irq chip for an irq

 *    @irq:      irq number

 *    @chip:    pointer to irq chip description structure

 */

int set_irq_chip(unsigned int irq, struct irq_chip *chip)

{

       struct irq_desc *desc;

       unsigned long flags;

 

       if (irq >= NR_IRQS) {

              printk(KERN_ERR "Trying to install chip for IRQ%d\n", irq);

              WARN_ON(1);

              return -EINVAL;

       }

 

       if (!chip)

              chip = &no_irq_chip;

 

       desc = irq_desc + irq;

       spin_lock_irqsave(&desc->lock, flags);

       irq_chip_set_defaults(chip);/*会调用到irq_chip_set_defaults函数*/

       desc->chip = chip;

       spin_unlock_irqrestore(&desc->lock, flags);

 

       return 0;

}

4.1.2 关于 irq_chip_set_defaults函数

 

下面是irq_chip_set_defaults函数的原型(见当前页)

/*

 * Fixup enable/disable function pointers

 */

void irq_chip_set_defaults(struct irq_chip *chip)

{

       if (!chip->enable)

              chip->enable = default_enable;/* 见当前页*/

       if (!chip->disable)

              chip->disable = default_disable; /* 见当前页*/

       if (!chip->startup)

              chip->startup = default_startup; /* 见当前页*/

       if (!chip->shutdown)

              chip->shutdown = chip->disable; /* 见当前页*/

       if (!chip->name)

              chip->name = chip->typename;

       if (!chip->end)

              chip->end = dummy_irq_chip.end;

}

2009-2-13   下家山     写于上海.漕河泾

                                   有什么问题可以给我邮件ximenpiaoxue4016@sina.com或加我群198204885

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

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