中断注册
中断,传统的中断信号线式的中断需要注册才可以用。信号线是各设备分时复用或者共享的,具体哪个设备使用哪个信号线是硬件连线决定的。
1 | // 注册中断信号线,返回非0值表示成功 |
推荐在打开设备的时候注册中断,而不是模块初始化的时候,这样可以提高中断信号线的复用效率。同时,还应在设备关闭时反注册中断。
flag可以有多个不同的取值,列表如下
值 | 含义 |
---|---|
SA_INTERRUPT | 表明这个是一个“快速”中断处理例程,快速中断处理例程会被置于中断禁用状态下运行,一般情况下不要用 |
SA_SHIRQ | 表示中断可以在设备之间共享 |
SA_SAMPLE_RANDOM | 设置该位表示要不要将该设备的中断作为/dev/random 等的输入 |
/proc
/proc/interrupts文件表征了当前OS的中断注册情况。第一列是中断号,有些不连续的情况,说明该中断号没有注册中断处理例程或者说没有目标设备。以CPUx为标题的列,表示某个CPU上中断处理次数情况。后面几列是处理中断的PIC信息和设备信息,共享中断号的设备会在此并列。

还有个/proc/stat文件,该文件intr行统计各号中断触发的次数。第一列是总中断触发次数,后面各列是不同中断号触发中断的次数。
中断探测
中断线形式触发的中断,必须告知驱动设备的中断号。这个事情可以让驱动用户来做,也可以让驱动编写者来做。但事实上他们都可能不知道具体某个设备的中断号。LDD3提到一种探测技术,其思路就是将现阶段所有未被使用的中断号都打开,然后静候设备触发中断,最后看设备用的是几号中断。内核提供了API来完成这件事(但是在最新的内核中没有找到),其实也可以手动实现该功能(将可能的中断号,注册上自定义的中断处理例程)。但是注意,这种探测对于那种共享中断信号线的设备时无效的。
1 | // 返回当前未被使用的中断的掩码 |
处理例程
中断处理例程有三个参数,irq、dev_id以及regs
1 | irqreturn_t (*handler)(int irq, void * dev_id, struct pt_regs *regs) |
启用和禁用中断
内核提供禁用单个或者全部中断的接口,使用这些接口时应有以下注意事项。
- 共享的中断线是不能禁用的
- 部分接口禁用和开启可以嵌套,禁用接口调用了多少次,对应的开启接口也需要调用相同次数才可以复原状态。
1 | void disable_irq(int irq); // 禁用某个中断同时,等待该中断处理例程结束,如果调用者持有中断例程需要的资源,系统会发生死锁 |
中断顶半部和底半部(Top and Bottom Halves)
中断处理例程需要做的事情可以分为两类,快速的控制面处理和耗时的数据面处理。内核将这两类事务分成两个部分处理,分别叫顶半部和底半部。一般而言,顶半部主要负责填装调度任务然后启用底半部,底半部可以运行在workqueue、tasklet等机制中。tasklet和workqueu的工作机制和相关接口,阅读第七章笔记。