Linux驅(qū)動(dòng)實(shí)踐:一起來(lái)梳理【中斷】的前世今生
目錄
· Linux 中斷的知識(shí)點(diǎn)梳理
中斷的分類
中斷號(hào)和中斷向量
中斷服務(wù)程序ISR
上半部分和下半部分
· 中斷處理的注冊(cè)和注銷 API
· 實(shí)操:捕獲鍵盤中斷
示例代碼
驅(qū)動(dòng)程序傳參
IO編址:IO端口和IO內(nèi)存
編譯、測(cè)試、驗(yàn)證
別人的經(jīng)驗(yàn),我們的階梯!
大家好,我是道哥,今天我為大伙兒解說(shuō)的技術(shù)知識(shí)點(diǎn)是:【Linux 中斷的注冊(cè)和處理】。
在前兩篇文章中,描述的是在應(yīng)用層如何調(diào)用驅(qū)動(dòng)函數(shù)來(lái)控制GPIO,以及在驅(qū)動(dòng)中如何發(fā)送發(fā)送信號(hào)給應(yīng)用層。
假如存在這樣一個(gè)需求:應(yīng)用程序需要監(jiān)控某個(gè)硬件GPIO口的電平狀態(tài),當(dāng)發(fā)生變化時(shí),應(yīng)用程序就做出相應(yīng)的動(dòng)作。
利用之前已經(jīng)介紹的知識(shí),是可以完成這個(gè)需求的。
比如:在驅(qū)動(dòng)程序中不停的讀取GPIO口的狀態(tài),一旦發(fā)生變化,就把新的電平狀態(tài)通過(guò)信號(hào)發(fā)送到應(yīng)用層。
這樣的方式稱作:輪詢。
輪詢方式的缺點(diǎn)顯而易見(jiàn):輪詢的時(shí)間間隔應(yīng)該是多少毫秒(or 微秒),才比較合適呢?
輪詢太慢:可能會(huì)丟失信號(hào);輪詢太快:消耗 CPU 資源!
因此,在實(shí)際的產(chǎn)品中,用中斷觸發(fā)的方式才是更切合實(shí)際的選擇!
本文所有的描述和測(cè)試,都是在 x86 平臺(tái)上完成的;
Linux 中斷的知識(shí)點(diǎn)梳理
中斷的分類
Linux 的版本在持續(xù)更新,對(duì)中斷的處理方式也在不停的發(fā)生變化。
下面幾張圖,是以前在學(xué)習(xí)時(shí)畫(huà)的思維導(dǎo)圖。
這幾張圖比較清晰地描述了在Linux操作系統(tǒng)中,關(guān)于中斷的一些基本概念。
這張圖的結(jié)構(gòu)還是比較清晰的,基本上概括了Linux系統(tǒng)中的中斷分類。
另外,在很多關(guān)于中斷的書(shū)籍中,大部分都是從基礎(chǔ)的 PIC(可編程中斷控制器)開(kāi)始講解的。
如果您想非常具體、專業(yè)、深入的了解關(guān)于中斷的相關(guān)內(nèi)容,有一篇文章《Interrupt in Linux.pdf》講得非常好(文章的后面部分我也沒(méi)有看懂)。
在文末有下載鏈接,感興趣的小伙伴可以學(xué)習(xí)一下。
中斷號(hào)和中斷向量
這張圖只要記住中斷號(hào)與中斷向量的關(guān)系就可以了:
1. 中斷號(hào)與中斷控制器(PIC/APIC)相關(guān);
2. 中斷向量與 CPU 相關(guān),用來(lái)查找中斷處理函數(shù)的入口地址;
中斷服務(wù)例程 ISR
中斷服務(wù)程序,就是針對(duì)每一個(gè)中斷如何進(jìn)行處理。
如果您了解Linux中斷的相關(guān)內(nèi)容,一定會(huì)看到這樣的描述:中斷處理分為上半部分和下半部分。
上半部分不能消耗太多的時(shí)間,主要處理與硬件相關(guān)的重要工作;其他不重要的工作,都放在下半部分去做。
從上面這張圖中可以看出,用來(lái)完成下半部分工作有好幾種機(jī)制可以選擇,每一種方式都是針對(duì)不同的需求場(chǎng)景。
在每一種下半部分機(jī)制中,Linux都設(shè)計(jì)了非常方便的接口函數(shù)。
作為開(kāi)發(fā)者的我們來(lái)說(shuō),使用這些下半部分的機(jī)制很簡(jiǎn)單,只需要幾個(gè)函數(shù)調(diào)用即可。
例如:如果使用工作隊(duì)列來(lái)實(shí)現(xiàn)下半部分的工作,只需要2步動(dòng)作:
1. 定義處理函數(shù)
2. 在中斷處理函數(shù)中,注冊(cè)注冊(cè)函數(shù)
INIT_WORK(&mywork, mywork_h(yuǎn)andler);
schedule_work(&mywork);
下面幾張圖,是針對(duì)每一種“下半部分”處理機(jī)制的一些特點(diǎn),注意:有些機(jī)制在新版本中已經(jīng)廢棄不用了,了解即可。
中斷處理的注冊(cè)和注銷 API
所謂的中斷注冊(cè),就是告訴操作系統(tǒng):我對(duì)哪個(gè)中斷感興趣。
當(dāng)這些中斷發(fā)生的時(shí)候,請(qǐng)通知我。通知的方式就是:調(diào)用一個(gè)預(yù)先注冊(cè)好的回調(diào)函數(shù)。
驅(qū)動(dòng)程序可以通過(guò)函數(shù) request_irq(),向操作系統(tǒng)注冊(cè),并且激活指定的中斷線:
參數(shù)說(shuō)明:
irq: 申請(qǐng)的硬件中斷號(hào);
handler: 中斷處理函數(shù)。一旦中斷發(fā)生,這個(gè)函數(shù)就被調(diào)用;
flags: 中斷的屬性,例如:IRQF_DISABLED,IRQF_TIMER,IRQF_SHARED;
devname: 中斷驅(qū)動(dòng)程序的名稱,在 /proc/interrupts 文件中看到對(duì)應(yīng)的內(nèi)容;
dev_id: 中斷程序的唯一標(biāo)識(shí),比如:在共享中斷中,可以用來(lái)區(qū)分不同的中斷處理程序;
驅(qū)動(dòng)程序通過(guò)函數(shù) free_irq(),向操作系統(tǒng)注銷一個(gè)中斷處理函數(shù):
void free_irq(unsigned int irq, void *dev_id);
參數(shù)說(shuō)明:
irq: 硬件中斷號(hào);
dev_id: 中斷程序的唯一標(biāo)識(shí);
實(shí)操:捕獲鍵盤中斷 示例代碼
有了上面的知識(shí)鋪墊,下面就來(lái)實(shí)操一下,實(shí)現(xiàn)的功能是:
捕獲鍵盤的中斷,在中斷處理函數(shù)中,打印出按鍵的掃描碼,如果是 ESC 鍵被按下,就打印出指定的信息。
與往常一樣,操作的目錄位于:tmp/linux-4.15/drivers 目錄下。
$ mkdir my_driver_interrupt
$ touch driver_interrupt.c
文件內(nèi)容:
上面的代碼,有兩個(gè)小的知識(shí)點(diǎn)。
向驅(qū)動(dòng)程序傳參
示例代碼中,在調(diào)用 request_irq 時(shí),需要指定中斷號(hào)和驅(qū)動(dòng)程序的名稱。
這兩個(gè)參數(shù)是在加載驅(qū)動(dòng)模塊的時(shí)候,從命令行傳入的。
在驅(qū)動(dòng)程序中,通過(guò)下面兩行代碼即可實(shí)現(xiàn)參數(shù)的接收:
module_param(irq, int, 0644);
module_param(devname, charp, 0644);
module_param 是一個(gè)宏定義,定義在 include/linux/moduleparam.h 文件中,具體定義如下:
#define module_param(name, type, perm)
module_param_named(name, name, type, perm);
name: 存儲(chǔ)參數(shù)的變量名;
type: 變量的類型;
perm: 訪問(wèn)參數(shù)的權(quán)限,表示此參數(shù)在sysfs文件系統(tǒng)中所對(duì)應(yīng)的文件節(jié)點(diǎn)的屬性;
IO地址:IO端口和IO內(nèi)存
這是讀取 IO 外設(shè)的兩種不同方式。
IO 端口有兩種編址方式:統(tǒng)一編址和獨(dú)立編址。
統(tǒng)一編制
把主存單元所在的地址空間,劃出一部分出來(lái),專門用來(lái)把IO外設(shè)寄存器的地址映射到這部分劃出來(lái)的地址空間中。
統(tǒng)一編址的好處是:讀取IO外設(shè)的時(shí)候,就好像讀取普通的內(nèi)存地址空間中的數(shù)據(jù)一樣。
獨(dú)立編址
IO 外設(shè)的地址空間,與主存單元的地址空間是兩個(gè)獨(dú)立的地址空間,此時(shí),IO地址一般稱作: IO端口。
我們?cè)谧x寫IO外設(shè)的時(shí)候,從這些 “IO端口” 中讀寫就可以了。不同的外設(shè),被分配了不同的 IO 端口號(hào)。
CPU 提供了一些列函數(shù)來(lái)讀寫 IO 端口,例如:
// 讀寫一個(gè)字節(jié)
unsigned inb(unsigned port);
void outb(unsigned char byte, unsigned port);
// 讀寫一個(gè)字
unsigned inw(unsigned port);
void outw(unsigned short word, unsigned port);
編譯、驗(yàn)證
編譯驅(qū)動(dòng)模塊:
$ make
輸出文件:driver_interrupt.ko
因?yàn)槲覀儾东@的是鍵盤中斷(中斷號(hào):1),先看一下在加載驅(qū)動(dòng)模塊之前的中斷驅(qū)動(dòng)程序 head /proc/interrupts:
可以把 demsg 的輸出也清理一下:dmesg -c
執(zhí)行下面指令來(lái)加載驅(qū)動(dòng)模塊(傳遞2個(gè)參數(shù)):
insmod driver_interrupt.ko irq=1 devname=myirq
再次執(zhí)行一下指令 head /proc/interrupts 查看驅(qū)動(dòng)程序:
在中斷號(hào) 1 的右側(cè),是不是看到了我們的驅(qū)動(dòng)程序:my_irq?
再來(lái)看一下 dmesg 的輸出信息:
成功注冊(cè)了中斷號(hào)1的處理函數(shù)!
此時(shí),按幾次鍵盤左上角的 ESC 鍵,然后再查看 dmesg 的輸出信息:
以上,就是最簡(jiǎn)單的中斷注冊(cè)和相應(yīng)的中斷處理函數(shù)!
在實(shí)際的項(xiàng)目中,如果要把中斷信息通知到應(yīng)用層,可以通過(guò)上一篇文章介紹的發(fā)送信號(hào)來(lái)實(shí)現(xiàn),或者通過(guò)其他的回調(diào)機(jī)制也可以。
下一篇文章,我們?cè)谶@個(gè)示例代碼上進(jìn)行擴(kuò)展,看一下:中斷處理中每一個(gè)“下半部分”機(jī)制應(yīng)該如何編程。
發(fā)表評(píng)論
請(qǐng)輸入評(píng)論內(nèi)容...
請(qǐng)輸入評(píng)論/評(píng)論長(zhǎng)度6~500個(gè)字
最新活動(dòng)更多
-
即日-12.26立即報(bào)名>>> 【在線會(huì)議】村田用于AR/VR設(shè)計(jì)開(kāi)發(fā)解決方案
-
1月8日火熱報(bào)名中>> Allegro助力汽車電氣化和底盤解決方案優(yōu)化在線研討會(huì)
-
即日-1.14火熱報(bào)名中>> OFweek2025中國(guó)智造CIO在線峰會(huì)
-
即日-1.16立即報(bào)名>>> 【在線會(huì)議】ImSym 開(kāi)啟全流程成像仿真時(shí)代
-
即日-1.24立即參與>>> 【限時(shí)免費(fèi)】安森美:Treo 平臺(tái)帶來(lái)出色的精密模擬
-
即日-2025.8.1立即下載>> 《2024智能制造產(chǎn)業(yè)高端化、智能化、綠色化發(fā)展藍(lán)皮書(shū)》
推薦專題
-
2
- 1 人形機(jī)器人核心零部件,誰(shuí)是盈利最強(qiáng)企業(yè)?
- 2 AI Agent現(xiàn)狀如何?聊聊近期國(guó)內(nèi)的智能體市場(chǎng)動(dòng)向
- 3 5nm重大突破,研祥智能助力半導(dǎo)體企業(yè)高效發(fā)展!
- 4 人形機(jī)器人引爆“PEEK材料”!概念股梳理(名單)
- 5 馬云沒(méi)回牌桌,但重注全壓在了
- 6 7 豆包AI登頂國(guó)內(nèi)第一!概念股梳理(名單)
- 8 押注AI王者歸來(lái),歌爾股份“智能體”在下一盤“大棋”
- 9 AI超級(jí)應(yīng)用什么時(shí)候才能出現(xiàn)?
- 10 英偉達(dá)迎來(lái)當(dāng)頭一棒
- 高級(jí)軟件工程師 廣東省/深圳市
- 自動(dòng)化高級(jí)工程師 廣東省/深圳市
- 光器件研發(fā)工程師 福建省/福州市
- 銷售總監(jiān)(光器件) 北京市/海淀區(qū)
- 激光器高級(jí)銷售經(jīng)理 上海市/虹口區(qū)
- 光器件物理工程師 北京市/海淀區(qū)
- 激光研發(fā)工程師 北京市/昌平區(qū)
- 技術(shù)專家 廣東省/江門市
- 封裝工程師 北京市/海淀區(qū)
- 結(jié)構(gòu)工程師 廣東省/深圳市
OFweek人工智能網(wǎng)
獲取更多精彩內(nèi)容