linux下怎样看设备的中断号,Linux设备驱动的中断处理
Linux設備驅動中,中斷處理非常重要,尤其是在嵌入式系統中,無時無刻不在與中斷打交道,因此,中斷處理必須要牢牢掌握。
設備在產生某個事件時通知處理器的方法就是中斷。中斷就是一個信號,當硬件需要通知CPU你該處理我的數據或狀態時,就會發出這個信號,而處理器如果發現驅動注冊了該中斷信號,就會保存現場,執行中斷處理程序,然后再恢復現場。中斷處理程序和其他代碼是并行的,因此必須考慮競態問題。
1.注冊中斷
內核維護了一個中斷信號線的注冊表,驅動模塊在使用中斷前要先請求一個中斷通道(或者 IRQ中斷請求),并在使用后釋放它。
int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *dev_name, void *dev_id);
void free_irq(unsigned int irq, void *dev_id);
中斷處理例程可在驅動初始化時或在設備第一次打開時安裝。推薦在設備第一次打開、硬件被告知產生中斷前時申請中斷,因為可以共享有限的中斷資源。這樣調用 free_irq 的位置是設備最后一次被關閉、硬件被告知不用再中斷處理器之后。但這種方式的缺點是必須為每個設備維護一個打開計數。
i386 和 x86_64 體系定義了一個函數來查詢一個中斷線是否可用:
int can_request_irq(unsigned int irq, unsigned long flags); /*當能夠成功分配給定中斷,則返回非零值。但注意,在 can_request_irq 和 request_irq 的調用之間給定中斷可能被占用*/
快速中斷和慢中斷
在現代內核中,快速和慢速中斷的區別已經消失,剩下的只有一個:快速中斷(使用 SA_INTERRUPT )執行時禁止所有在當前處理器上的其他中斷(其他處理器仍然可以響應中斷)。除非你充足的理由在禁止其他中斷情況下來運行中斷處理例程,否則不應當使用SA_INTERRUPT。這個在嵌入式系統中或許用的比較多。
/proc/interrupts:記錄了中斷信息統計
/proc/stat:記錄了系統活動的底層統計信息
2.自動檢測 IRQ 號
驅動初始化時最迫切的問題之一是決定設備要使用的IRQ 線,驅動需要信息來正確安裝處理例程。自動檢測中斷號對驅動的可用性來說是一個基本需求。有時自動探測依賴一些設備具有的默認特性,以下是典型的并口中斷探測程序:
if (short_irq < 0) /* 依靠使并口的端口號,確定中斷*/
switch(short_base) {
case 0x378: short_irq = 7; break;
case 0x278: short_irq = 2; break;
case 0x3bc: short_irq = 5; break;
}
有 2 種方法來進行探測中斷: 調用內核定義的輔助函數和DIY探測。
(1)調用內核定義的輔助函數
unsigned long probe_irq_on(void); /*這個函數返回一個未分配中斷的位掩碼。驅動必須保留返回的位掩碼, 并在后面傳遞給 probe_irq_off。在調用probe_irq_on之后, 驅動應當安排它的設備產生至少一次中斷*/
int probe_irq_off(unsigned long); /*在請求設備產生一個中斷后, 驅動調用這個函數, 并將 probe_irq_on 返回的位掩碼作為參數傳遞給probe_irq_off。probe_irq_off 返回在"probe_on"之后發生的中斷號。如果沒有中斷發生, 返回 0 ;如果產生了多次中斷,probe_irq_off 返回一個負值*/
(2)DIY探測
DIY探測與前面原理相同: 使能所有未使用的中斷, 接著等待并觀察發生什么。
3.實現中斷處理例程
中斷處理例程唯一的特別之處在中斷時運行,它能做的事情受到了一些限制:
(1)中斷處理例程不能與用戶空間傳遞數據, 因為它不在進程上下文執行;
(2)中斷處理例程也不能做任何可能休眠的事情, 例如調用 wait_event, 使用除 GFP_ATOMIC 之外任何東西來分配內存, 或者鎖住一個信號量;
(3)處理者不能調用schedule()。
4.禁用中斷
(1)禁用單個中斷
void disable_irq(int irq);/*禁止給定的中斷, 并等待當前的中斷處理例程結束。如果調用 disable_irq 的線程持有任何中斷處理例程需要的資源(例如自旋鎖), 系統可能死鎖*/
void disable_irq_nosync(int irq);/*禁止給定的中斷后立刻返回(可能引入競態)*/
void enable_irq(int irq);
(2)禁用全部中斷
void local_irq_save(unsigned long flags);/*在保存當前中斷狀態到 flags 之后禁止中斷*/
void local_irq_disable(void);/* 關閉中斷而不保存狀態*/
如果調用鏈中有多個函數可能需要禁止中斷, 應使用 local_irq_save
void local_irq_restore(unsigned long flags); /*打開中斷使用*/
void local_irq_enable(void);
在 2.6 內核, 沒有方法全局禁用整個系統上的所有中斷
5.中斷頂半部和底半部
中斷處理需要很快完成,可通過將中斷處理分為兩部分來解決這個問題:
(1)頂半部,立即執行,實際響應中斷的例程(request_irq 注冊的那個例程)
(2)底版本,被頂半部調度,并在稍后更安全的時間內執行的函數
Linux 內核有 2 個不同的機制可用來實現底半部處理:
(1)tasklet (首選機制),它非常快, 但是所有的 tasklet 代碼必須是原子的。
(2)工作隊列, 它可能有更高的延時,但允許休眠,執行在進程上下文中,但不允許與用戶空間進行數據拷貝。
6.中斷共享
Linux 內核支持在所有總線上中斷共享,Linux大部分中斷都是可以共享的。
在通過request_irq 安裝處理例程時候,有些不同:
(1)當request_irq 時,flags 中必須指定SA_SHIRQ 位;
(2)dev_id 必須唯一。任何指向模塊地址空間的指針都行,但 dev_id 絕不能設置為NULL。
請求一個共享的中斷時,如果滿足下列條件之一,則request_irq 成功:
(1)中斷線空閑;
(2)所有已經注冊該中斷信號線的處理例程也標識了IRQ是共享。
一個共享的處理例程必須能夠識別自己的中斷,并且在自己的設備沒有被中斷時快速退出(返回 IRQ_NONE )。共享處理例程沒有探測函數可用,但使用的中斷信號線是空閑時標準的探測機制才有效。一個使用共享處理例程的驅動需要小心:不能使用 enable_irq 或 disable_irq,否則,對其他共享這條線的設備就無法正常工作了。即便短時間禁止中斷,另一設備也可能產生延時而為設備和其用戶帶來問題,因為這個中斷可能不是你一個驅動模塊在關注。
7.中斷驅動的 IO
當與驅動程序管理的硬件間的數據傳送可能因為某種原因而延遲,驅動編寫者應當實現緩存。
輸入:當新數據到達時并且處理器準備好接受時,設備中斷處理器。
輸出:當設備準備好接受新數據或確認一個成功的數據傳送時,設備產生中斷。
總結
以上是生活随笔為你收集整理的linux下怎样看设备的中断号,Linux设备驱动的中断处理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: sql查找一个范围的值_销售需求丨查找问
- 下一篇: 一道简单却易混淆的高等数学求极限题目