ARM+Linux中断系统详细分析
断是否是本设备的中断,若不是,应迅速返回。这样的说法没有问题,也是我们编程时都遵循的方法。但事实上并不能够说明为什么中断共享必须要设置dev_id。
下面解释一下dev_id参数为什么必须的,而且是必须唯一的。
当调用free_irq注销中断处理函数时(通常卸载驱动时其中断处理函数也会被注销掉),因为dev_id是唯一的,所以可以通过它来判断从共享中断线上的多个中断处理程序中删除指定的一个。如果没有这个参数,那么kernel不可能知道给定的中断线上到底要删除哪一个处理程序。
注销函数定义在Kernel/irq/manage.c中定义:
void free_irq(unsigned int irq, void *dev_id)
4.S3C2410子中断的注册的实现
前面判断中断号的方法,可以看到只是通过S3C2410中断控制器中的INTOFFSET寄存器来判断的。对于INTPND中的EINT4_7、EINT8_23、INT_UART0、INT_ADC等带有子中断的向量,INTOFFSET无法判断出具体的中断号。平台留给我们的注册方法如下:
在include/asm/arch/irqs.h中有类似如下定义:
点击(此处)折叠或打开
- /*interrupts generated from the external interrupts sources*/
- #define IRQ_EINT4 S3C2410_IRQ(32)/*48*/
- #define IRQ_EINT5 S3C2410_IRQ(33)
- #define IRQ_EINT6 S3C2410_IRQ(34)
- #define IRQ_EINT7 S3C2410_IRQ(35)
- #define IRQ_EINT8 S3C2410_IRQ(36)
- #define IRQ_EINT9 S3C2410_IRQ(37)
- #define IRQ_EINT10 S3C2410_IRQ(38)
- #define IRQ_EINT11 S3C2410_IRQ(39)
- #define IRQ_EINT12 S3C2410_IRQ(40)
- #define IRQ_EINT13 S3C2410_IRQ(41)
- #define IRQ_EINT14 S3C2410_IRQ(42)
- #define IRQ_EINT15 S3C2410_IRQ(43)
- #define IRQ_EINT16 S3C2410_IRQ(44)
- #define IRQ_EINT17 S3C2410_IRQ(45)
- #define IRQ_EINT18 S3C2410_IRQ(46)
- #define IRQ_EINT19 S3C2410_IRQ(47)
- #define IRQ_EINT20 S3C2410_IRQ(48)/*64*/
- #define IRQ_EINT21 S3C2410_IRQ(49)
- #define IRQ_EINT22 S3C2410_IRQ(50)
- #define IRQ_EINT23 S3C2410_IRQ(51)
可以看到平台为每种子中断都定义了中断号,如果你想实现EINT10的中断注册,直接按照IRQ_EINT10这个中断号注册都可以了。那么平台代码是如何实现这部分中断注册的呢?
5.S3C2410子中断注册问题的解决
点击(此处)折叠或打开
- /*arch/arm/plat-s3c24xx/irq.c*/
- void __init s3c24xx_init_irq(void)
- {……
- 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);
- ……
- }
平台在初始化时会调用到s3c24xx_init_irq,在此函数中实现了对EINT4_7、EINT8_23、INT_UART0、INT_ADC等中断的注册。下面看看这些带有子中断的中断号对应的处理函数的内容。以IRQ_EINT4t7为例,其它情况类似。
点击(此处)折叠或打开
- /*arch/arm/plat-s3c24xx/irq.c*/
- s3c_irq_demux_extint4t7(unsignedintirq,
- struct irq_desc*desc)
- {
- unsigned long eintpnd=__raw_readl(S3C24XX_EINTPEND);
- unsigned long eintmsk=__raw_readl(S3C24XX_EINTMASK);
- eintpnd&=~eintmsk;
- eintpnd&=0xff;/*only lower irqs*/
- /*eintpnd中可以有多个位同时置1,这一点和intpnd的只能有1个位置1是不一样的*/
- while(eintpnd){//循环执行所有置位的子中断
- irq=__ffs(eintpnd);//算出第一个不为0的位,类似arm v5后的clz前导0的作用
- eintpnd&=~(1
- irq+=(IRQ_EINT4-4);//算出对应的中断号
- desc_handle_irq(irq,irq_desc+irq);//执行对应子中断的注册函数
- }
- }
从上面的函数可以看出子中断是如何注册及被调用到的。有人可能会问为何不在include/asm/arch-s3c2410/entry-macro.s文件中get_irqnr_and_base函数判断中断号时,直接算出对应的子中断号,就可以直接找到子中断处理了呢?
原因是: get_irqnr_and_base是平台给系统提供的函数,对于多个子中断同时置位的情况无法通过一个值返回(因为子中断中,如eintpnd是可以多个位同时置位的))。而intpnd则没有这个问题。
至此,对于s3c2440/10+linux2.6得出以下结论:
①不支持中断嵌套(因为FIQ不支持)
②有明确中断优先级(可编程)
③中断号是根据硬件特性固定的,riq号通过某种转换得到与寄存器相应位,一般在irqs.h文件定义
中断的用法见Ldd3的笔记:http://blog.chinaunix.net/uid-
ARMLinux中断系 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)
