一、什麼是request_threaded_irq
request_threaded_irq是一個Linux內核函數,用於請求指定IRQ(Interrupt Request)並安裝處理程序。它可以使設備驅動無需關心硬體IRQ號及中斷處理函數,同時避免了中斷處理時間過長導致的系統掛起。相比較request_irq函數,request_threaded_irq還增加了線程的支持,可以在一個獨立的線程中處理中斷。
二、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);
其中,參數的含義如下:
- irq:被請求的中斷號
- handler:中斷處理函數
- thread_fn:中斷線程函數
- irqflags:中斷處理標誌
- devname:設備名稱(不是必須的)
- dev_id:傳遞給中斷處理函數的設備特定指針
三、handler和thread_fn函數
handler是具有如下原型的函數:
irqreturn_t (*irq_handler_t)(int irq, void *dev_id);
它接收兩個參數:irq表示發生中斷的IRQ號,dev_id是傳遞給request_threaded_irq函數的設備特定指針。handler函數應該迅速處理中斷,然後返回IRQ_HANDLED(中斷已處理)或IRQ_NONE(中斷未處理)。
thread_fn函數是具有如下原型的函數:
irqreturn_t (*irq_handler_t)(int irq, void *dev_id);
它接收兩個參數:irq表示發生中斷的IRQ號,dev_id是傳遞給request_threaded_irq函數的設備特定指針。和handler一樣,thread_fn函數應該迅速處理中斷,然後返回IRQ_HANDLED(中斷已處理)或IRQ_NONE(中斷未處理)。線程函數通常用於完成一些佔用時間較長的操作,例如接收網路數據等。
四、irqflags參數
irqflags參數用於設置中斷處理標誌,不同的標誌會影響中斷處理方式。常見的標誌如下:
- IRQF_DISABLED:禁止中斷(已棄用)
- IRQF_SAMPLE_RANDOM:用於實時時鐘中斷(fast path)
- IRQF_TRIGGER_NONE:不處理中斷
- IRQF_TRIGGER_RISING:上升沿觸發
- IRQF_TRIGGER_FALLING:下降沿觸發
- IRQF_TRIGGER_HIGH:高電平觸發
- IRQF_TRIGGER_LOW:低電平觸發
- IRQF_TRIGGER_MASK:設置中斷方式的掩碼
- IRQF_ONESHOT:在第一次中斷髮生後禁用中斷(line line)
- IRQF_SHARED:共享中斷
- IRQF_PROBE_SHARED:檢查中斷是否可共享
五、指定設備名稱和設備特定指針
request_threaded_irq函數還接收兩個其他參數:devname和dev_id(通常設置為驅動程序使用的設備結構)。設備名稱作為一個字元串傳遞,它不是必須的,當IRQ使用的具體硬體設備已知時,建議傳遞設備名稱以便於調試。設備特定指針可以存儲指向驅動程序使用的設備結構的指針,用於在中斷處理程序中引用。
六、request_threaded_irq函數示例
下面是一個簡單的request_threaded_irq函數的示例,它為IRQ 20安裝了一個中斷處理程序和線程函數:
#include <linux/irq.h> static int irq_number; //IRQ號碼 irqreturn_t handler_func(int irq, void *dev_id) //中斷處理函數 { printk(KERN_INFO "IRQ %d occurred\n", irq_number); return IRQ_HANDLED; } irqreturn_t thread_func(int irq, void *dev_id) //中斷線程函數 { printk(KERN_INFO "IRQ %d thread is running\n", irq_number); return IRQ_HANDLED; } int init_module() { if (request_threaded_irq(irq_number, handler_func, thread_func, IRQF_SHARED, "my_device", NULL) == -EBUSY) { printk(KERN_ERR "Request IRQ %d failed\n", irq_number); return -EBUSY; } else { printk(KERN_INFO "Request IRQ %d succeeded\n", irq_number); return 0; } } void cleanup_module() { free_irq(irq_number, NULL); printk(KERN_INFO "Free IRQ %d succeeded\n", irq_number); }
在此示例中,中斷處理函數和線程函數都輸出到內核日誌中,以便於調試。request_threaded_irq函數的返回值是0表示中斷請求成功,-EBUSY表示IRQ已被佔用。在模塊卸載時,要使用free_irq函數釋放IRQ號碼。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/242150.html