关于中断处理程序和中断服务例程ISR的区别及联系,之前一直搞混,今天抽时间将两者关系弄弄清楚。ok,下面进入主题。
首先中断处理程序(Interrupt Handler)和中断服务例程ISR(Inerrupt Service Routine)是两个不同的概念.
简单来说就是,一条中断线对应一个中断处理程序,而一个中断处理程序再对应若干个中断服务例程,具体看下图所示:
从上图中能很直观的看出所有的中断服务例程挂在中断请求队列中,这个工作是由request_irq()函数来完成的,其实也就是对中断服务例程进行注册,关于这个函数的具体实现在include/linux/interrupt.h中。而中断处理程序就相当于某个中断向量的总的处理程序,比如上图中IRQ0x09_interrupt()是中断号为9(向量为47)的总处理程序,假如这个9号中断由5个设备共享,那么这5个设备都分别有其对应的中断服务例程。
也就是说当有多个设备需要共享某个中断线时,中断处理程序必须要调用ISR,此时会调用handle_IRQ_event()
来运行挂在该中断线上的所有中断服务例程,下图给出了具体的调用关系:
这其实就是中断处理程序的执行过程。其中IRQn_interrupt表示从IRQ0x00_interrupt到IRQ0x0f_interrupt的任意一个中断处理程序。这个中断处理程序需要调用do_IRQ()函数,而do_IRQ()函数对收到的中断请求进行应答,并禁止这条中断线,然后要确保这条中断线上有一个有效的中断服务例程,而且目前这个这个中断服务例程已经启动但未执行。这时do_IRQ()调用handle_IRQ_event()来运行挂在这条中断线上的所有中断服务例程。
最后再补充说明一下在内核中用于让多个设备共享一条中断线而设置的数据结构irqaction(3.7版本的内核):
typedef (*)(int, void *); //声明一个中断服务例程的钩子函数,返回值为irqreturn_tx型
struct {
; //指向一个具体的I/O设备的中断服务程序
void *dev_id; //指定的I/O设备的主设备号和次设备号
void *percpu_dev_id; //用于识别不同cpu设备的资料
struct *; //指向用于共享中断线的下一个irqaction结构
; //指向一个具体的线程化中断的中断服务例程
struct *; //指向线程中断的线程指针
unsigned int ; //所申请的中断号
unsigned int ; //一组用于描述中断线与I/O设备之间关系的中断标志
unsigned long ; //用于描述线程中断的中断标志
unsigned long ; //中断掩码
const char *; //中断设备名称
struct *; //指向IRQn相关的/proc/irq/n目录的描述符
} ;