日期:2014-05-16  浏览次数:20657 次

linux内核分析--中断和中断处理程序

写在前面:

      在前面的这篇文章linux内核分析--中断的分类讲解了关于中断的基本概念,从宏观的角度了解了中断的基本知识。从这篇文章中要明白几点知识

      1、中断是由硬件产生的异步中断,而异常则是处理器产生的同步中断

      2、中断质上是一种特殊的电信号,由硬件设备发向处理器,处理器接收到中断后,会马上向操作系统反应此信号的带来,然后就由OS负责处理这些新到来的数据,中断可以随时发生,才不用操心与处理器的时间同步问题。不同的设备对应的中断不同,他们之间的不同从操作系统级来看,差别就在于一个数字标识-----中断号。专业一点就叫中断请求(IRQ)线,通常IRQ都是一些数值量。有些体系结构上,中断好是固定的,有的是动态分配的,这不是问题所在,问题在于特定的中断总是与特定的设备相关联,并且内核要知道这些信息,这才是最关键的,

     3、中断产生告诉中断控制器,继续告诉操作系统内核,内核总是要处理的,是不?这里内核会执行一个叫做中断处理程序或中断处理例程的函数。这里特别要说明,中断处理程序是和特定中断相关联的,而不是和设备相关联,如果一个设备可以产生很多中断,这时该设备的驱动程序也就需要准备多个这样的函数。一个中断处理程序是设备驱动程序的一部分,在接下来的文章中会介绍关于如何注册中断。前边说过一个问题:中断是可能随时发生的,因此必须要保证中断处理程序也能随时执行,中断处理程序也要尽可能的快速执行,只有这样才能保证尽可能快地恢复中断代码的执行。

     4、为了达到第三步的条件,尽可能让中断处理程序快速执行结束。将中断处理切为两个部分或两半。中断处理程序上半部(top half)---接收到一个中断,它就立即开始开始执行,但只做严格时限的工作,这些工作都是在所有中断被禁止的情况下完成的。同时,能够被允许稍后完成的工作推迟到下半部(bottom half)去,此后,下半部会被执行,通常情况下,下半部都会在中断处理程序返回时立即执行。linux内核分析--为什么把中断分为上半部和下半步这篇文章讲解了其中的原因

下面进入今天的正题:

一、注册中断处理程序

如何注册一个中断处理程序。通过一下函数可注册一个中断处理程序:

int request_irq(unsigned int irq,irqreturn_t (*handler)(int, void *,struct pt_regs *),unsigned long irqflags,const char * devname,void *dev_id)

有关这个中断的一些参数说明,我就不说了,一旦注册了一个中断处理程序,就肯定会有释放中断处理,这是调用下列函数

void free_irq(unsigned int irq, void *dev_id)

这里需要说明的就是要必须要从进程上下文调用free_irq().好了,现在给出一个例子来说明这个过程,首先声明一个中断处理程序:

static irqreturn_t intr_handler(int irq, void *dev_id, struct pt_regs *regs)

注意:这里的类型和前边说到的request_irq()所要求的参数类型是匹配的,参数不说了。对于返回值,中断处理程序的返回值是一个特殊类型,irqrequest_t,可能返回两个特殊的值:IRQ_NONE和IRQ_HANDLED.当中断处理程序检测到一个中断时,但该中断对应的设备并不是在注册处理函数期间指定的产生源时,返回IRQ_NONE;当中断处理程序被正确调用,且确实是它所对应的设备产生了中断时,返回IRQ_HANDLED.C此外,也可以使用宏IRQ_RETVAL(x),如果x非0值,那么该宏返回IRQ_HANDLED,否则,返回IRQ_NONE.利用这个特殊的值,内核可以知道设备发出的是否是一种虚假的(未请求)中断。如果给定中断线上所有中断处理程序返回的都是IRQ_NONE,那么,内核就可以检测到出了问题。最后,需要说明的就是那个static了,中断处理程序通常会标记为static,因为它从来不会被别的文件中的代码直接调用。另外,中断处理程序是无需重入的,当一个给定的中断处理程序正在执行时,相应的中断线在所有处理器上都会被屏蔽掉,以防止在同一个中断上接收另外一个新的中断。通常情况下,所有其他的中断都是打开的,所以这些不同中断线上的其他中断都能被处理,但当前中断总是被禁止的。由此可见,同一个中断处理程序绝对不会被同时调用以处理嵌套的中断。      

       下面要说到的一个问题是和共享的中断处理程序相关的。共享和非共享在注册和运行方式上比较相似的。差异主要有以下几点:

1.request_irq()的参数flags必须设置为SA_SHIRQ标志。
2.对每个注册的中断处理来说,dev_id参数必须唯一。指向任一设备结构的指针就可以满足这一要求。通常会选择设备结构,因为它是唯一的,而且中
   断处理程序可能会用到它,不能给共享的处理程序传递NULL值。
3.中断处理程序必须能够区分它的设备是否真的产生了中断。这既需要硬件的支持,也需要处理程序有相关的处理逻辑。如果硬件不支持这一功能,那中
   断处理程序肯定会束手无策,它根本没法知道到底是否与它对应的设备发生了中断,还是共享这条中断线的其他设备发出了中断。