注册 登录
电子工程世界-论坛 返回首页 EEWORLD首页 频道 EE大学堂 下载中心 Datasheet 专题
xiajiashan的个人空间 https://home.eeworld.com.cn/space-uid-440873.html [收藏] [复制] [分享] [RSS]
日志

Linux-2.6.21 S3c6400中断剖析<四>(原创)-上海嵌入式索漫科技培训教材

已有 1157 次阅读2012-10-10 13:40 |个人分类:嵌入式|

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

评论 (0 个评论)

facelist doodle 涂鸦板

您需要登录后才可以评论 登录 | 注册

热门文章