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

作者:下家山(请尊重原创,转载请注明) 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
推荐文章
最近访客