ARM Linux中断机制之中断的初始化
这三个结构体间的关系表示如下
二,中断初始化过程
中断机制的初始化通过 两个函数完成:early_trap_init()和init_IRQ(),在此我们先讨论函数init_IRQ()。
//函数init_IRQ在文件linux/arch/arm/kernel/irq.c中实现。
void __init init_IRQ(void)
{
int irq;
/* 设置 irq_desc 数组的 status 为 IRQ_NOREQUEST | IRQ_NOPROBE(没有请求,没有检测) */
for (irq = 0; irq < NR_IRQS; irq++)
irq_desc[irq].status |= IRQ_NOREQUEST | IRQ_NOPROBE;
#ifdef CONFIG_SMP
cpumask_setall(bad_irq_desc.affinity);
bad_irq_desc.cpu = smp_processor_id();
#endif
/*
init_arch_irq在文件linux/arch/arm/kernel/irq.c中定义如下
void (*init_arch_irq)(void) __initdata = NULL;
该函数指针在 setup_arch()中被赋值,
init_arch_irq = mdesc->init_irq;
指向 machine_desc 中定义的 init_irq 函数。
在平台smdk2440中,该函数在文件linux/arch/arm/plat-s3c24xx/irq.c中实现。
*/
init_arch_irq();
}
//函数s3c24xx_init_irq在文件linux/arch/arm/plat-s3c24xx/irq.c中实现
void __init s3c24xx_init_irq(void)
{
unsigned long pend;
unsigned long last;
int irqno;
int i;
irqdbf("s3c2410_init_irq: clearing interrupt status flags\n");
/* first, clear all interrupts pending... */
last = 0;
for (i = 0; i < 4; i++) {
pend = __raw_readl(S3C24XX_EINTPEND);
if (pend == 0 || pend == last)
break;
__raw_writel(pend, S3C24XX_EINTPEND);//清除外部中断寄存器EINTPEND中的请求标志,
printk("irq: clearing pending ext status %08x\n", (int)pend);
last = pend;
}
last = 0;
。。。。。。
//设置各中断的底层硬件操作函数集desc->chip,中断上层处理函数desc->handle_irq
for (irqno = IRQ_EINT4t7; irqno <= IRQ_ADCPARENT; irqno++) {
/* set all the s3c2410 internal irqs */
switch (irqno) {
/* deal with the special IRQs (cascaded) */
case IRQ_EINT4t7:
case IRQ_EINT8t23:
case IRQ_UART0:
case IRQ_UART1:
case IRQ_UART2:
case IRQ_ADCPARENT:
set_irq_chip(irqno, &s3c_irq_level_chip);
set_irq_handler(irqno, handle_level_irq);
break;
case IRQ_RESERVED6:
case IRQ_RESERVED24:
/* no IRQ here */
break;
default:
//irqdbf("registering irq %d (s3c irq)\n", irqno);
set_irq_chip(irqno, &s3c_irq_chip);
set_irq_handler(irqno, handle_edge_irq);
set_irq_flags(irqno, IRQF_VALID);
}
}
//以下几个中断都有多个中断源,每一个中断源也都有各自的中断号,它们的多个中断源中任意一个产生中断
//该中断都会被触发,而不是直接出发子中断。这几个中断并不处理中断函数,它们的中作是计算子中断的中断号,
//并根据子中断的中断号在数组irq_desc[NR_IRQS]中去找出该中断号对应的irq_desc结构,并调用该结构中的中断处理函数。
set_irq_chained_handler(IRQ_EINT4t7, s3c_irq_demux_extint4t7);
set_irq_chained_handler(IRQ_EINT8t23, s3c_irq_demux_extint8);
set_irq_chained_handler(IRQ_UART0, s3c_irq_demux_uart0);
set_irq_chained_handler(IRQ_UART1, s3c_irq_demux_uart1);
set_irq_chained_handler(IRQ_UART2, s3c_irq_demux_uart2);
set_irq_chained_handler(IRQ_ADCPARENT, s3c_irq_demux_adc);
。。。。。。
for (irqno = IRQ_EINT4; irqno <= IRQ_EINT23; irqno++) {
irqdbf("registering irq %d (extended s3c irq)\n", irqno);
set_irq_chip(irqno, &s3c_irqext_chip);//设置子中断的硬件操作函数集
set_irq_handler(irqno, handle_edge_irq);//设置子中断的上层处理函数
set_irq_flags(irqno, IRQF_VALID);
}
。。。。。。
}
比如此时外部中断10产生了中断,中断号为IRQ_EINT8t23的中断被触发,执行函数s3c_irq_demux_extint8()。
static void
s3c_irq_demux_extint8(unsigned int irq,
struct irq_desc *desc)
{
unsigned long eintpnd = __raw_readl(S3C24XX_EINTPEND);
unsigned long eintmsk = __raw_readl(S3C24XX_EINTMASK);
eintpnd &= ~eintmsk;
eintpnd &= ~0xff;/* ignore lower irqs */
/* we may as well handle all the pending IRQs here */
while (eintpnd) { irq += (IRQ_EINT4 - 4);//根据这个偏移量重新计算中断号 } static inline void generic_handle_irq_desc(
irq = __ffs(eintpnd);//计算该中断在外部中断寄存器EINTPEND中的偏移量
eintpnd &= ~(1
generic_handle_irq(irq);//根据重新计算的中断号获取对应的结构体irq_desc,并调用它的上层中断处理函数。
}
ARMLinux中断机制初始 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)