ARM+Linux中断系统详细分析
- struct pt_regs*regs)
- {
- struct pt_regs*old_regs=set_irq_regs(regs);
- struct irq_desc*desc=irq_desc+irq;//根据中断号,找到响应的irq_desc
- /*
- *Some hardware gives randomly wrong interrupts.Rather
- *than crashing,dosomething sensible.
- */
- if(irq>=NR_IRQS)
- desc=&bad_irq_desc;
- irq_enter();
- desc_handle_irq(irq,desc);//根据irq和desc进入中断处理
- /*AT91 specific workaround*/
- irq_finish(irq);
- irq_exit();
- set_irq_regs(old_regs);
- }
- static inline void desc_handle_irq(unsignedintirq,struct irq_desc*desc)
- {
- desc->handle_irq(irq,desc);//中断处理
- }
上述asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs)使用了asmlinkage标识。那么这个标识的含义如何理解呢?
该符号定义在kernel/include/linux/linkage.h中,如下所示:
点击(此处)折叠或打开
- #ifdef __cplusplus
- #define CPP_ASMLINKAGE extern"C"
- #else
- #define CPP_ASMLINKAGE
- #endif
- #ifndef asmlinkage//如果以前没有定义asmlinkage
- #define asmlinkage CPP_ASMLINKAGE
- #endif
对于ARM处理器的,没有定义asmlinkage,所以没有意义(不要以为参数是从堆栈传递的,对于ARM平台来说还是符合ATPCS过程调用标准,通过寄存器传递的)。
但对于X86处理器的中是这样定义的:
#define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0)))
表示函数的参数传递是通过堆栈完成的。
中断处理过程代码就跟到这了,那么最后一个问题desc->handle_irq(irq, desc);是怎么跟我们注册的中断函数相关联的呢?再从中断模型注册入手:
中断相关的数据结构:在include/asm/arch/irq.h中定义。
irq_desc[]是一个指向irq_desc_t结构的数组,irq_desc_t结构是各个设备中断服务例程的描述符。Irq_desc_t结构体中的成员action指向该中断号对应的irqaction结构体链表。Irqaction结构体定义在include/linux/interrupt.h中,如下:
点击(此处)折叠或打开
- truct irqaction{
- irq_handler_t handler;//中断处理函数,注册时提供
- unsigned long flags;//中断标志,注册时提供
- cpumask_t mask;//中断掩码
- constchar*name;//中断名称
- void*dev_id;//设备id,本文后面部分介绍中断共享时会详细说明这个参数的作用
- struct irqaction*next;//如果有中断共享,则继续执行,
- intirq;//中断号,注册时提供
- struct proc_dir_entry*dir;//指向IRQn相关的/proc/irq/n目录的描述符
- };
在注册中断号为irq的中断服务程序时,系统会根据注册参数封装相应的irqaction结构体。并把中断号为irq的irqaction结构体写入irq_desc [irq]->action。这样就把设备的中断请求号与该设备的中断服务例程irqaction联系在一起了。当CPU接收到中断请求后,就可以根据中断号通过irq_desc []找到该设备的中断服务程序。
3.中断共享的处理模型
共享中断的不同设备的iqraction结构体都会添加进该中断号对应的irq_desc结构体的action成员所指向的irqaction链表内。当内核发生中断时,它会依次调用该链表内所有的handler函数。因此,若驱动程序需要使用共享中断机制,其中断处理函数必须有能力识别是否是自己的硬件产生了中断。通常是通过读取该硬件设备提供的中断flag标志位进行判断。也就是说不是任何设备都可以做为中断共享源的,它必须能够通过的它的中断flag判断出是否发生了中断。
中断共享的注册方法是:
int request_irq(unsigned int irq, irq_handler_t handler,IRQF_SHARED, const char *devname, void *dev_id)
很多权威资料中都提到,中断共享注册时的注册函数中的dev_id参数是必不可少的,并且dev_id的值必须唯一。那么这里提供唯一的dev_id值的究竟是做什么用的?
根据我们前面中断模型的知识,可以看出发生中断时,内核并不判断究竟是共享中断线上的哪个设备产生了中断,它会循环执行所有该中断线上注册的中断处理函数(即irqaction->handler函数)。因此irqaction->handler函数有责任识别出是否是自己的硬件设备产生了中断,然后再执行该中断处理函数。通常是通过读取该硬件设备提供的中断flag标志位进行判断。那既然kernel循环执行该中断线上注册的所有irqaction->handler函数,把识别究竟是哪个硬件设备产生了中断这件事交给中断处理函数本身去做,那request_irq的dev_id参数究竟是做什么用的?
很多资料中都建议将设备结构指针作为dev_id参数。在中断到来时,迅速地根据硬件寄存器中的信息比照传入的dev_id参数判
ARMLinux中断系 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)
