Linux 中断注册的核心机制
在 Linux 内核中,中断是硬件与操作系统交互的重要方式,它允许硬件在需要时暂停当前进程的处理,转而请求内核响应,中断注册则是内核管理硬件中断的关键步骤,涉及中断号的申请、中断处理函数的绑定以及中断资源的释放等操作,正确理解中断注册的流程和注意事项,对于驱动开发者和内核开发者至关重要。

中断的基本概念
中断分为硬件中断和软件中断,硬件中断由外部设备(如键盘、网卡)触发,通过中断控制器(如 APIC)传递给 CPU;软件中断则由程序通过指令(如 int 0x80)触发,本文主要讨论硬件中断的注册流程。
Linux 内核通过中断描述符表(IDT)管理中断,每个中断号对应一个处理函数,当硬件触发中断时,CPU 会根据中断号查找 IDT,并执行相应的处理函数,驱动开发者需要通过内核提供的 API,将自定义的中断处理函数注册到指定的中断号上。
中断注册的主要 API
Linux 内核提供了多种中断注册的 API,以适应不同的场景需求,最常用的函数是 request_irq(),其原型如下:
int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
const char *name, void *dev);
irq:要注册的中断号,通常通过设备树或平台资源获取。handler:中断处理函数,类型为irq_handler_t,其原型为irqreturn_t (*handler)(int, void *)。flags:中断标志位,如IRQF_SHARED(共享中断)、IRQF_TRIGGER_RISING(上升沿触发)等。name:中断名称,用于/proc/interrupts等文件显示,便于调试。dev:设备标识符,用于共享中断时的区分,通常为设备结构体指针。
内核还提供了 devm_request_irq() 函数,它通过设备管理资源,可以在设备移除时自动释放中断,避免内存泄漏。
中断处理函数的设计
中断处理函数是中断注册的核心,其设计需遵循以下原则:

- 执行效率高:中断处理函数应尽量简短,避免耗时操作(如休眠、内存分配),复杂操作应通过
tasklet、workqueue等机制延迟执行。 - 可重入性:中断可能被嵌套或重复触发,处理函数需确保在并发执行时的安全性。
- 返回值规范:返回
IRQ_NONE表示中断未处理,返回IRQ_HANDLED表示已处理。
一个简单的中断处理函数如下:
static irqreturn_t my_interrupt_handler(int irq, void *dev_id) {
// 读取硬件状态,确认中断来源
if (/* 中断条件满足 */) {
// 处理中断事件
return IRQ_HANDLED;
}
return IRQ_NONE;
}
中断标志位的配置
flags 参数决定了中断的行为,常见的标志位包括:
IRQF_TRIGGER_NONE:电平触发(默认)。IRQF_TRIGGER_RISING/IRQF_TRIGGER_FALLING:边沿触发。IRQF_SHARED:允许多个设备共享同一中断线,需配合dev参数使用。
标志位的配置必须与硬件规格一致,否则可能导致中断无法正常触发或系统不稳定,PCI 设备通常使用边沿触发,而 ISA 设备多用电平触发。
中断的共享机制
多个设备可以共享同一中断线,此时需设置 IRQF_SHARED 标志,并为每个设备提供唯一的 dev 标识符,内核会按顺序调用所有注册的中断处理函数,直到某个函数返回 IRQ_HANDLED,共享中断的典型场景包括 PCI 设备,多个设备可能连接到同一个中断引脚。
中断的释放
当设备不再需要中断时,需调用 free_irq() 释放资源:

void free_irq(unsigned int irq, void *dev);
对于 devm_request_irq() 注册的中断,内核会在设备卸载时自动释放,无需手动调用。
中断注册的注意事项
- 中断号的合法性:在注册前需确认中断号未被其他设备占用,可通过
/proc/interrupts查看当前中断分配情况。 - 上下文环境:中断处理函数运行在中断上下文,不能调用休眠或调度相关的函数(如
kmalloc(GFP_KERNEL))。 - 错误处理:
request_irq()可能返回错误码(如-EBUSY),需检查返回值并处理异常情况。
实际应用示例
以下是一个简化的中断注册流程:
- 获取中断号:通过
platform_get_irq()从平台设备中获取中断号。 - 注册中断:调用
request_irq()注册处理函数。 - 中断处理:在中断处理函数中读取硬件状态并触发后续操作。
- 释放资源:在设备移除时调用
free_irq()。
int my_driver_probe(struct platform_device *pdev) {
int irq = platform_get_irq(pdev, 0);
if (irq < 0) {
return irq;
}
return request_irq(irq, my_interrupt_handler, IRQF_SHARED,
"my_device", pdev);
}
int my_driver_remove(struct platform_device *pdev) {
int irq = platform_get_irq(pdev, 0);
free_irq(irq, pdev);
return 0;
}
Linux 中断注册是驱动开发的基础环节,涉及中断号的申请、处理函数的绑定、标志位的配置以及资源的释放,开发者需严格遵循内核规范,确保中断处理的高效性和安全性,通过合理使用 request_irq() 和 devm_request_irq() 等接口,结合硬件特性配置中断标志,可以实现稳定可靠的中断管理,在实际开发中,还需结合调试工具(如 /proc/interrupts 和 /proc/irq)排查中断相关问题,提升系统的健壮性。
















