在Linux驅動編程中,處理中斷是一個關鍵部分,它允許設備與CPU進行異步通信。以下是處理中斷的基本步驟:
首先,你需要在中斷控制器上注冊你的中斷處理函數。這通常通過request_irq
函數完成。
int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
const char *devname, void *dev_id);
irq
: 中斷號。handler
: 中斷處理函數。flags
: 中斷標志,例如IRQF_SHARED
表示中斷可以與其他設備共享。devname
: 設備名稱。dev_id
: 設備標識符,用于區分共享中斷的不同設備。定義一個中斷處理函數,該函數將在中斷發生時被調用。
irqreturn_t my_irq_handler(int irq, void *dev_id) {
// 處理中斷的代碼
printk(KERN_INFO "Interrupt occurred on IRQ %d\n", irq);
return IRQ_HANDLED;
}
irq
: 中斷號。dev_id
: 傳遞給request_irq
的dev_id
參數。返回值通常是IRQ_HANDLED
或IRQ_NONE
,表示中斷是否已被處理。
以下是一個簡單的示例,展示如何注冊一個中斷處理函數。
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/module.h>
static irqreturn_t my_irq_handler(int irq, void *dev_id) {
printk(KERN_INFO "Interrupt occurred on IRQ %d\n", irq);
return IRQ_HANDLED;
}
static int __init my_module_init(void) {
int ret;
ret = request_irq(IRQ_NUMBER, my_irq_handler, IRQF_SHARED, "my_device", NULL);
if (ret) {
printk(KERN_ALERT "Failed to register IRQ handler\n");
return ret;
}
printk(KERN_INFO "IRQ handler registered successfully\n");
return 0;
}
static void __exit my_module_exit(void) {
free_irq(IRQ_NUMBER, NULL);
printk(KERN_INFO "IRQ handler unregistered\n");
}
module_init(my_module_init);
module_exit(my_module_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple interrupt handling module");
在處理中斷時,有時需要禁用和啟用中斷以確保數據的一致性和安全性。
local_irq_disable(); // 禁用中斷
// 處理中斷的代碼
local_irq_enable(); // 啟用中斷
如果多個設備共享同一個中斷線,可以使用IRQF_SHARED
標志,并在中斷處理函數中通過dev_id
參數區分不同的設備。
int ret = request_irq(IRQ_NUMBER, my_irq_handler, IRQF_SHARED, "my_device", dev_id);
在中斷處理函數中:
irqreturn_t my_irq_handler(int irq, void *dev_id) {
if (dev_id == my_device_id) {
// 處理特定設備的邏輯
}
return IRQ_HANDLED;
}
在模塊卸載時,需要注銷中斷處理函數。
free_irq(IRQ_NUMBER, dev_id);
處理中斷是Linux驅動編程中的一個重要部分。通過注冊中斷處理函數、編寫中斷處理邏輯、禁用和啟用中斷以及處理中斷共享,可以有效地管理設備與CPU之間的異步通信。