Linux裝置驅動程式設計之中斷處理

2021-04-27 19:00:32 字數 2682 閱讀 1988

與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);}

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字元裝置驅動之中斷按鍵

驅動程式 include 模組有關的 include 核心有關的 include 檔案系統有關的 include include include include include include linux中斷 include include include include copy to user ...

Linux字元裝置驅動之中斷按鍵

驅動程式 include 模組有關的 include 核心有關的 include 檔案系統有關的 include include include include include include linux中斷 include include include include copy to user ...

linux驅動程式設計之裝置註冊

linux下編寫驅動時有註冊裝置這一步,裝置註冊有兩種方法,一種是直接以平台的形式新增,平時都是用這種方式實現,另一種則是編譯成.c檔案,通過ko檔案新增進去,其實就是將以平台的方式新增的過程通過自己的 實現出來,如下是這兩種的實現過程 1.以平台的形式新增 a.新增裝置的結構體 b.將裝置新增到裝...