天天看點

[LDD3速記]_中斷處理一、安裝中斷處理二、中斷處理例程三、頂半部和底半部(上半部和下半部)

一、安裝中斷處理

1. 申請中斷

int request_irq(unsigned int irq,
                irqreturn_t (*handler)(int, void *, struct pt_regs *),
                unsigned long flags,
                const char *dev_name,
                void *dev_id);
/*
申請中斷通道(成功傳回0)
irq中斷号;handler中斷處理函數的指針;flag與中斷管理有關的位掩碼;
dev_id用于共享的中斷信号線,可用于指向驅動程式自己的私有資料區,用來識别裝置
*/

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

int can_request_irq(unsigned int irq, unsigned long flags);
/* 查詢某個中斷線是否可用,可用傳回非零 */
           

        flags:

        SA_INTERRUPT:快速中斷處理例程,運作于中斷的禁用狀态下(目前處理器上的其他所有中斷都被禁止)

        SA_SHIRQ:中斷可在裝置間共享

        SA_SAMPLE_RANDOM:中斷能對/dev/random裝置和/dev/urandom裝置使用的熵池(entropy pool)有貢獻。熵池用來收集來自裝置驅動程式和其它來源的環境噪音。add_interrupt_randomness()函數利用裝置兩次中斷的間隔時間作為噪聲源将随機資料加入熵池。

2. /proc接口

        /proc/interrupt:硬體中斷産生時内部計數器遞增,産生的報告顯示在/proc/interrupt,隻顯示已安裝了中斷處理例程的中斷,且在檔案快照時沒使用的話也不會出現。不依賴于體系結構。

        /proc/stat:記錄了一些系統活動的底層統計資訊(包括從系統啟動開始接收到的中斷數量)。所有中斷線都會顯示,字段的數量依賴于核心之下的硬體。

3. 自動檢測IRQ号

        有些裝置(如PCI标準)會聲明打算使用的中斷線,而另一些裝置則需自動檢測進行一些探測工作,決定使用哪條IRQ以便正确安裝處理例程。

        裝載時配置設定中斷号:insmod xxx.ko irq=x

        核心輔助函數:

//1.配置設定中斷的位掩碼
unsigned long probe_irq_on(void);
/* 需儲存傳回的位掩碼,且調用後需至少産生一次中斷再調用下一個函數 */

//2.裝置産生中斷

//3.适當延時(留給中斷探測)

//4.傳回上述産生中斷的編号
int probe_irq_off(unsigned long);
/* 若無中斷發生則傳回0,若産生了多次中斷則傳回負值 */
           

       DIY探測: 

       啟用所有未被占用的中斷,觀察會發生什麼(若不能預知可能的IRQ值,則需要探測0 - NR_IRQS-1所有中斷)

二、中斷處理例程

1. 限制

        不是在程序上下文運作,是以不能向空間發送或接收資料,不能休眠(wait_event、使用不帶GFP_ATOMIC的記憶體配置設定操作、鎖住一個信号量),不能調用schdule函數

2. 功能

        将有關中斷接收的資訊回報給裝置,根據中斷不同含義對資料進行讀寫

        清除中斷挂起位(有些裝置沒有,可在第一步也可在最後執行)

        通知程序事件已經發生(喚醒在該裝置上休眠的程序)

static irqreturn_t sample_interrupt(int irq, void *dev_id, struct pt_regs *regs)
/*
中斷處理例程
irq:中斷号
dev_id:區分共享中斷線上的不同裝置(中斷處理程式)?
regs:可有可無?儲存了處理器進入中斷前的環境?
*/
           

        傳回值:irqreturn_t:IRQ_HANDLED(确實需要處理);IRQ_NONE

        也可以用宏來産生傳回值:IRQ_RETVAL(handled),如果需要處理該中斷,則handled取非零,給核心使用以抑制假中斷

3. 啟用和禁用中斷

void disable_irq(int irq);//禁用中斷線,可嵌套調用,會等待正在執行的處理例程完成
void disable_irq_nosync(int irq);//立即傳回,但可能會導緻競态
void enable_irq(int irq);//啟用

void local_irq_save(unsigned long flags);
void local_irq_disable(void);
void local_irq_restore(unsigned long flags);
void local_irq_enable(void);
/* 禁用和啟動所有中斷 */
           

三、頂半部和底半部(上半部和下半部)

        頂半部:中斷處理例程

        底半部:tasklet、工作隊列

繼續閱讀