中断是一种电信号,由硬件设备生成,并直接送入中断控制器的输入引脚上。如果中断线是被激活的,由中断控制器向处理器发送相应的信号。处理器一经检测到此信号,便中断自己的当前工作转而处理中断。此后,处理器会通知操作系统已经产生中断,这样,操作系统就可以对这个中断进行适当的处理了。
一、 核心结构
llinux中断机制的核心数据结构是 irq_desc,irq_desc数组的每一项对应一个中断或者一组中断使用同一个中断号, 它完整地描述了一条中断线。其中包括俩个重要的结构struct irq_chip *chip和 struct irqaction *action。
irq_chip结构: 里面基本上是一些回调函数,其中大多用于操作底层硬件,设置寄存器,其中包括设置GPIO为中断输入就是其中的一个回调函数。
irqaction结构:里面包括用户注册的中断处理函数irq_handler_t handler。用户注册的中断名字const char *name。irqaction结构链,一个共享中断可以有多个中断处理函数struct irqaction *next。中断号int irq。用户传递的参数或者用来区分共享中断参数void *dev_id等
二、流程分析
1.中断初始化流程 设置寄存器等等问题都是内核启动的时候就已经初始化了,这个阶段做很多工作,其中最重要的就是初始化了irq_chip结构。使得其中的众多函数已经设置好了,可以被调用了。注意这里只是实现了irq_chip结构的函数,要响应中断还有很多事情要做。
2.中断注册流程 request_irq首先生成一个irqaction结构,其次根据中断号找到irq_desc数组项,然后将irqaction结构添加到irq_desc中的action链表中。当然还做一些其他的工作,注册完成后,中断函数就可以发生并被处理了。
3.中断的处理流程 这个流程主要是产生中断后调用irq_chip中的函数来屏蔽,清除中断等,然后调用irqaction结构中用户注册的中断函数处理中断。
1)首先异常向量表,保存一条跳转指令,一般存放在0x00000000或者0xffff000地址,linux使用后者,中断发生后CPU进入异常模式,将跳转到相应的异常向量表处执行,异常向量表保存跳转指令,它会跳到一个os规定的内存地址,然后开始执行那边的代码。这段代码完成的主要是把IRQ号保存到栈中,然后保存当前的寄存器的值(这个值包含了中断的任务)。
2)调用do_IRQ(),计算出中断号后(通过中断号可以找出中断对应的irq_desc结构),对所接受到的中断进行应答,禁止这条线上的中断传递。接下来do_IRQ()需要确保在这条中断线上有一个有效的中断处理程序,而且这个程序已经启动,但是当前并没有执行。如果是这样的话do_IRQ()就调用handle_IRQ_event(irq, action),这个函数中会调用中断处理程序( action->handler(irq, action->dev_id))。
3)ret_from_intr()函数