深入淺出 Linux裝置驅動中斷處理介紹

2021-04-13 06:37:11 字數 2787 閱讀 1651

深入淺出 linux裝置驅動中斷處理介紹

與linux裝置驅動中中斷處理相關的首先是申請與釋放irq的api: request_irq()和free_irq()。

request_irq()的原型為:

int request_irq(unsigned int irq,

void (*handler)(int irq, void *dev_id, struct pt_regs *regs),

unsigned long irqflags,

const char * devname,

void *dev_id);

irq是要申請的硬體中斷號;

handler是向系統登記的中斷處理函式,是乙個**函式,中斷發生時,系統呼叫這個函式,dev_id引數將被傳遞;

irqflags是中斷處理的屬性,若設定sa_interrupt,標明中斷處理 程式是快速處理程式,快速處理程式被呼叫時遮蔽所有中斷,慢速處理程式不遮蔽;若設定sa_shirq,則多個裝置共享中斷,dev_id在中斷共享時會 用到,一般設定為這個裝置的device結構本身或者null。

free_irq()的原型為:

void free_irq(unsigned int irq,void *dev_id);

另外,與linux中斷息息相關的乙個重要概念是linux中斷分為兩個半部:上半 部(tophalf)和下半部(bottom half)。上半部的功能是"登記中斷",當乙個中斷發生時,它進行相應地硬體讀寫後就把中斷例程的下半部掛到該裝置的下半部執行佇列中去。因此,上半部 執行的速度就會很快,可以服務更多的中斷請求。但是,僅有"登記中斷"是遠遠不夠的,因為中斷的事件可能很複雜。因此,linux引入了乙個下半部,來完 成中斷事件的絕大多數使命。下半部和上半部最大的不同是下半部是可中斷的,而上半部是不可中斷的,下半部幾乎做了中斷處理程式所有的事情,而且可以被新的 中斷打斷!下半部則相對來說並不是非常緊急的,通常還是比較耗時的,因此由系統自行安排執行時機,不在中斷服務上下文中執行。

linux實現下半部的機制主要有tasklet和工作佇列。

tasklet基於linux softirq,其使用相當簡單,我們只需要定義tasklet及其處理函式並將二者關聯:

void my_tasklet_func(unsigned long); //定義乙個處理函式:

declare_tasklet(my_tasklet,my_tasklet_func,data); //定義乙個tasklet結構my_tasklet,與my_tasklet_func(data)函式相關聯

然後,在需要排程tasklet的時候引用乙個簡單的api就能使系統在適當的時候進行排程執行:

tasklet_schedule(&my_tasklet);

此外,linux還提供了另外一些其它的控制tasklet排程與執行的api:

declare_tasklet_disabled(name,function,data); //與declare_tasklet類似,但等待tasklet被使能 tasklet_enable(struct tasklet_struct *); //使能tasklet tasklet_disble(struct tasklet_struct *); //禁用tasklet tasklet_init(struct tasklet_struct *,void (*func)(unsigned long),unsigned long); //類似declare_tasklet() tasklet_kill(struct tasklet_struct *); // 清除指定tasklet的可排程位,即不允許排程該tasklet

我們先來看乙個tasklet的執行例項,這個例項沒有任何實際意義,僅僅為了演示。它的功能是:在globalvar被寫入一次後,就排程乙個tasklet,函式中輸出"tasklet is executing":

#include … //定義與繫結tasklet函式 void test_tasklet_action(unsigned long t); declare_tasklet(test_tasklet, test_tasklet_action, 0); void test_tasklet_action(unsigned long t) … ssize_t globalvar_write(struct file *filp, const char *buf, size_t len, loff_t *off)  //排程tasklet執行 tasklet_schedule(&test_tasklet);  return sizeof(int); }

由於中斷與真實的硬體息息相關,脫離硬體而空談中斷是毫無意義的,我們還是來舉乙個簡單的例子。這個例子**於samsung s3c2410嵌入式系統例項,看看其中實時鐘的驅動中與中斷相關的部分:

static struct fasync_struct *rtc_async_queue;

static int __init rtc_init(void)

static void __exit rtc_exit(void)

static void rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)

static int rtc_fasync (int fd, struct file *filp, int on)

static void rtc_dropped_irq(unsigned long data)

rtc中斷發生後,激發了乙個非同步訊號,因此本驅動程式提供了對第6節非同步訊號的支援。並不是每個中斷都需要乙個下半部,如果本身要處理的事情並不複雜,可能只有乙個上半部,本例中的rtc驅動就是如此。

深入淺出Linux裝置驅動之字元裝置驅動程式

linux下的裝置驅動程式被組織為一組完成不同任務的函式的集合,通過這些函式使得windows的裝置操作猶如檔案一般。在應用程式看來,硬體裝置只是乙個裝置檔案,應用程式可以象操作普通檔案一樣對硬體裝置進行操作,如open close read write 等。linux主要將裝置分為二類 字元裝置和...

深入淺出Linux裝置驅動之併發控制

在驅動程式中,當多個執行緒同時訪問相同的資源時 驅動程式中的全域性變數是一種典型的共享資源 可能會引發 競態 因此我們必須對共享資源進行併發控制。linux核心中解決併發控制的最常用方法是自旋鎖與訊號量 絕大多數時候作為互斥鎖使用 自旋鎖與訊號量 類似而不類 類似說的是它們功能上的相似性,不類 指代...

深入淺出 Linux裝置驅動非同步通知介紹

結合阻塞與非阻塞訪問 poll函式可以較好地解決裝置的讀寫,但是如果有了非同步通知就更方便了。非同步通知的意思是 一旦裝置就緒,則主動通知應用程式,這樣應用程式根本就不需要查詢裝置狀態,這一點非常類似於硬體上 中斷 地概念,比較準確的稱謂是 訊號驅動 sigio 的非同步i o 我們先來看乙個使用訊...