专栏中心

EEPW首页 > 专栏 > Linux-2.6.21 S3c6400中断剖析之四 (原创)-上海嵌入式索漫科技培训教材

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

发布人:xiajiashan 时间:2012-10-10 来源:工程师 发布文章

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

专栏文章内容及配图由作者撰写发布,仅供工程师学习之用,如有侵权或者其他违规问题,请联系本站处理。 联系我们

关键词:

相关推荐

低成本仪表放大器该如何设计?

电子科技大学--嵌入式系统应用开发技术36

个用于3.3 V电压轨的简单备份电源

毫米波雷达突破医疗监测痛点:非接触式生命体征传感器破解临床难题

电子科技大学--嵌入式系统应用开发技术35

TSIA今年首度上修 中国台湾半导体产值估逾6.3兆元

成功校准开环DAC信号链的两个方法

电子科技大学--嵌入式系统应用开发技术34

电子科技大学--嵌入式系统应用开发技术37

Nvidia 推迟了颠覆性的新 SOCAMM 内存技术

网络与存储 2025-05-16

整车操作系统何以跻身智能汽车三大件?

越南的半导体封装和测试行业发展势头强劲

电子科技大学--嵌入式系统应用开发技术33

过去24小时 印度电子制造的至暗时刻?

EDA/PCB 2025-05-16

工程师必看!从驱动到热管理:MOSFET选型与应用实战手册

电源与新能源 2025-05-16
更多 培训课堂
更多 焦点
更多 视频

技术专区