2012年(1008)
分类:
2012-08-01 10:57:11
原文地址:Linux内核驱动之中断处理 作者:luozhiyong131
中断线是一个宝贵且常常有限的资源, 特别当它们只有 15 或者 16 个时. 内核保持了中断线的一个注册, 类似于 I/O 端口的注册. 一个模块被希望来请求一个中断通道(或者 IRQ, 对于中断请求), 在使用它之前, 并且当结束时释放它. 在很多情况下, 也希望模块能够与其他驱动共享中断线, 如同我们将看到的. 下面的函数, 声明在 , 实现中断注册接口:
从 request_irq 返回给请求函数的返回值 0 指示成功, 或者是一个负的错误码, 如同平常. 函数返回 -EBUSY 来指示另一个驱动已经使用请求的中断线是不寻常的.
函数的参数如下:
unsigned int irq //请求的中断号
irqreturn_t (*handler) // 安装的处理函数指针.
unsigned long flags //一个与中断管理相关的选项的位掩码(后面描述).
const char *dev_name //这个传递给 request_irq 的字串用在 /proc/interrupts 来显示中断的拥有者(下一节看到)
void *dev_id //用作共享中断线的指针. 它是一个独特的标识, 用在当释放中断线时以及可能还被驱动用来指向它自己的私有数据区(来标识哪个设备在中断). 如果中断没有被共享, dev_id 可以设置为 NULL,
flags 中可以设置的位如下:
SA_INTERRUPT //当置位了, 这表示一个"快速"中断处理. 快速处理在当前处理器上禁止中断来执行(这个主题在"快速和慢速处理"一节涉及).
SA_SHIRQ //这个位表示中断可以在设备间共享. 共享的概念在"中断共享"一节中略述.
一个处理实现注意
至今, 我们已学习了注册一个中断处理, 但是没有编写一个. 实际上, 对于一个处理者, 没什么不寻常的 -- 它是普通的 C 代码.
唯一的特别之处是一个处理者在中断时运行, 因此, 它能做的事情遭受一些限制. 这些限制与我们在内核定时器上看到的相同. 一个处理者不能传递数据到或者从用户空间, 因为它不在进程上下文执行. 处理者也不能做任何可能睡眠的事情,
一个中断处理的典型任务是唤醒睡眠在设备上的进程, 如果中断指示它们在等待的事件, 例如新数据的到达.
程序员应当小心编写一个函数在最小量的时间内执行, 不管是一个快速或慢速处理者. 如果需要进行长时间计算, 最好的方法是使用一个 tasklet 或者 workqueue 来调度计算在一个更安全的时间
有时(但是很少!)一个驱动需要禁止一个特定中断线的中断递交. 内核提供了 3 个函数为此目的, 所有都声明在 . 这些函数是内核 API 的一部分, 因此我们描述它们, 但是它们的使用在大部分驱动中不鼓励:
disable_irq 不仅禁止给定的中断, 还等待一个当前执行的中断处理结束
强力推介阅读:.·中断处理