irqreturn有以下幾種:
enum irqreturn { IRQ_NONE = (0 << 0), // 表示中斷處理程式未處理該中斷,或者沒有發生中斷 IRQ_HANDLED = (1 << 0), // 表示中斷已經被處理 IRQ_WAKE_THREAD = (1 << 1), // 表示中斷處理程式通知核心喚醒一箇中斷執行緒來處理中斷 };
request_threaded_irq 是 Linux 核心中用於註冊中斷處理程式的函式之一。它允許在中斷處理過程中執行較長時間的操作,而不會阻塞其他重要的核心功能。以下是對
request_threaded_irq 函式如下:
int request_threaded_irq(unsigned int irq, irq_handler_t handler, irq_handler_t thread_fn, unsigned long irqflags, const char *devname, void *dev_id); // 引數和返回值說明 unsigned int irq:要註冊的中斷號。 irq_handler_t handler:中斷服務函式,即中斷被觸發時所呼叫的函式。這個函式應該返回一個 irqreturn_t 型別的值。 irq_handler_t thread_fn:中斷執行緒服務函式,用於執行較長時間的操作。中斷執行緒服務函式在中斷服務函式之後執行。這個函式也應該返回一個 irqreturn_t 型別的值。 unsigned long irqflags:中斷標誌,控制中斷的行為。常用的標誌包括 IRQF_SHARED(允許共享中斷)、IRQF_TRIGGER_*(中斷觸發方式,例如上升沿觸發、下降沿觸發等)等。 const char *devname:裝置名稱,用於標識中斷請求所屬的裝置。 void *dev_id:裝置識別符號,將傳遞給中斷服務函式和中斷執行緒服務函式作為引數。 函式返回值為 0 表示註冊成功,否則表示註冊失敗,返回的值是一個負數,表示出錯原因。
request_threaded_irq 函式的工作流程如下:
- 檢查中斷號是否有效,以及指定的中斷服務函式和中斷執行緒服務函式是否為有效函式。
- 分配中斷描述符,併為中斷分配中斷處理程式和中斷執行緒處理程式。
- 將中斷處理程式註冊到核心,以便在中斷被觸發時呼叫。
- 將中斷執行緒處理程式註冊到核心,以便在中斷被觸發時呼叫。
在成功註冊中斷後,中斷被觸發時,首先會呼叫中斷服務函式,然後再呼叫中斷執行緒服務函式。這樣可以確保中斷服務函式儘快返回,而不會阻塞其他重要的核心功能,而長時間的處理操作可以在中斷執行緒服務函式中執行。
request_threaded_irq driver demo:
#include <linux/module.h> #include <linux/kernel.h> #include <linux/interrupt.h> #include <linux/kthread.h> // 包含核心執行緒相關標頭檔案 #define DEMO_IRQ_NUMBER 1 // 定義一個結構體,用於傳遞給中斷處理函式和中斷執行緒處理函式 struct demo_data { irq_handler_t irq_handler; struct task_struct *thread_task; }; static irqreturn_t demo_interrupt_handler(int irq, void *dev_id) { struct demo_data *data = (struct demo_data *)dev_id; // 處理中斷 printk(KERN_INFO "Demo interrupt handled\n"); // 如果有中斷執行緒處理函式,則喚醒執行緒 if (data->thread_task) { wake_up_process(data->thread_task); } // 返回中斷處理結果 return IRQ_HANDLED; } static irqreturn_t demo_threaded_handler(int irq, void *dev_id) { // 處理中斷 printk(KERN_INFO "Demo threaded interrupt handled\n"); // 返回中斷處理結果 return IRQ_HANDLED; } static int demo_thread_fn(void *data) { // 執行長時間的操作,例如複雜計算、檔案操作等 printk(KERN_INFO "Demo threaded handler executing long operation\n"); msleep(1000); // 模擬長時間操作 return 0; } static int __init demo_init(void) { int ret; struct demo_data *data; // 分配記憶體並初始化資料結構 data = kmalloc(sizeof(struct demo_data), GFP_KERNEL); if (!data) { printk(KERN_ERR "Failed to allocate memory for demo data\n"); return -ENOMEM; } data->irq_handler = demo_interrupt_handler; data->thread_task = kthread_create(demo_thread_fn, NULL, "demo_thread_task"); if (IS_ERR(data->thread_task)) { kfree(data); printk(KERN_ERR "Failed to create demo thread\n"); return PTR_ERR(data->thread_task); } // 註冊中斷處理程式和中斷執行緒處理程式 ret = request_threaded_irq(DEMO_IRQ_NUMBER, demo_interrupt_handler, demo_threaded_handler, IRQF_SHARED, "demo_interrupt_threaded", (void *)data); if (ret) { printk(KERN_ERR "Failed to register threaded interrupt handler\n"); kfree(data); return ret; } printk(KERN_INFO "Demo module initialized\n"); return 0; } static void __exit demo_exit(void) { struct demo_data *data = (struct demo_data *)free_irq(DEMO_IRQ_NUMBER, (void *)demo_interrupt_handler); // 釋放中斷資源 if (data) { kfree(data); } printk(KERN_INFO "Demo module exited\n"); } module_init(demo_init); module_exit(demo_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("lethe1203"); MODULE_DESCRIPTION("request_threaded_irq demo");