linux中断API

来源:互联网 发布:四个字母cn未注册域名 编辑:程序博客网 时间:2024/06/06 02:28

来自:linux内核修炼之道

内核提供了一组 API 接口用于控制系统上的中断状态,了解并掌握这些接口的使用是我们进行驱动开发的基本功。主要是内容:驱动程序的注册和释放函数,激活和禁止函数,通常禁止是不需要的,允许抢占。

注册和释放
IRQ 线是一个非常宝贵的资源,驱动程序在使用前必须要先注册申请,不再使用时必须要释放申请的IRQ。
request_irq 函数和 free_irq 函数分别用来注册和释放 IRQ,它们在 include/linux/interrupt.h 文件中声明如下。

/*** @irq:要申请的 IRQ 号。很多设备使用的 IRQ 号通常都是预先分配好的,比如系统时钟和键盘。* @handler:要注册的中断服务程序。* @irqflags:中断的类型标志。它可以取下面三个值之一,或者它们的“|”:* IRQF_SHARED:表示可以与其他设备共享同一条中断线。* IRQF_DISABLED:在本地 CPU 上,中断处理程序在禁止所有中断的情况下执行,***可以不受其他中断干扰。如果没有设置这个标志,则只有该中断处理程序对应的那条中断线被屏蔽,而其他中断都是激活的。IRQF_SAMPLE_RANDOM:表明这个中断能够用来产生内核熵。* @dev_name:中断源的名称,可以在/proc/interrupts 文件中看到。* @dev_id:传递给中断服务程序 handler 的参数,必须全局唯一,通常都是用来指向设备* 的私有数据结构,以便标识具体是哪个设备产生了中断。如果不与其他设备共享中断线,* 则可以指定为 NULL。*/int request_irq(unsigned int irq, irq_handler_t handler,unsigned long irqflags, const char *devname, void *dev_id);void free_irq(unsigned int irq, void *dev_id);

使用前通过request_irq激活,使用完通过free_irq禁止。

1.request_irq 函数
request_irq 的主要任务是为 IRQ 线的中断请求队列创建 irqaction 节点。因为中断请求队列在中断子系统的初始化过程中被初始化为空,所以如果设备没有使用 request_irq 函数为其填充节点,即使设备产生了中断,也得不到任何真正的处理。

参数 irqflags 在旧的内核版本中,使用的是 SA_SHIRQ、SA_INTERRUPT 和 SA_SAMPLE_RANDOM,但是在 2007 年 9 月,它们分别被 IRQF_SHARED、IRQF_DISABLED 和 IRQF_SAMPLE_RANDOM 所取代。为了保持兼容,旧的标志仍然能够使用,但新的代码建议使用新的标志。

request_irq 返回 0 表示成功,此时该 IRQ 被激活。返回非 0 值,表示发生了错误,常见的错误为-EBUSY,表示指定的 IRQ 已经被占用,或者是没有设置 IRQF_SHARED 标志(与其他设备共享同一条中断线时)。
内核接收一个中断后,将依次调用在该中断线上注册的每一个中断服务程序。设备驱动程序必须知道它是否应该为这个中断请求负责。因此,一个中断服务程序如果判断与它相关的设备并没有产生该中断请求,那么它应该立即退出。通常硬件设备都会提供状态寄存器(或类似机制),以供中断服务程序进行检查。
为了避免中断处理程序在设备初始化完成之前就开始执行,初始化硬件和调用 request_irq 注册 IRQ 线的顺序必须正确。

2.free_irq 函数
卸载设备驱动程序时,必须调用 free_irq 函数删除中断请求队列中的相应 irqaction 节点,并释放中断线。
如果 IRQ 线不是共享的,则 free_irq 删除 irqaction 节点之后,禁止该 IRQ 线。否则,free_irq 只删除参数 dev_id 指定的 irqaction 节点,而该 IRQ 线在中断请求队列中的所有 irqaction 节点都已经被删除时,才会被禁止。
free_irq 直到该 IRQ 线上的所有中断服务程序都执行完毕时才返回。

激活和禁止
我们通常需要通过禁止中断线来确保某个中断服务程序不会抢占当前的代码,以免数据的并发访问产生问题。但是对于 MP 系统,我们只能防止来自当前 CPU 的其他中断服务程序的并发访问,对于来自其他CPU 的则需要通过锁机制进行保护。
如表 6.4 所示,内核提供了一组函数用于操作中断的状态,比如禁止当前 CPU 上的中断处理,或者仅仅禁止某个指定的中断线

对于 X86 来说,local_irq_disable 函数仅仅是通过 cli 指令将当前 CPU 标志寄存器中的中断标志位 IF清 0,使该 CPU 不响应来自 INTR 引脚的中断请求。而 local_irq_enable 函数则是通过 sti 指令将当前 CPU标志寄存器中的中断标志位 IF 置 1,允许该 CPU 响应来自 INTR 引脚的中断请求。
disable 、 enable_irq 与 disable_irq_nosync 可 以 嵌 套 调 用 , 但 必 须 注 意 , 每 次 调 用 disable 和disable_irq_nosync,都必须相应调用一次 enable_irq。通 常 情 况 下 禁 止 多 个 设 备 共 享 的 中 断 线 是 不 合 适 的 , 所 以 我 们 一 般 都 不 需 要 使 用 disable 和disable_irq_nosync。

如表 6.5 所示为内核提供的其他一些 API 函数。

表 6.5
其他 API 函数 

API 函数                               描述
in_irq()                  判断内核是否正在执行中断服务程序
in_softirq()           判断内核是否正在处理软中断
in_interrupt()       判断内核是否处于中断上下文,如果内核正在执行中断服务程序或下半部处理程序,则返回非 0


0 0
原创粉丝点击