日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux块设备驱动中断程序,linux设备驱动归纳总结(六):1.中断的实现

發(fā)布時(shí)間:2023/12/1 linux 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux块设备驱动中断程序,linux设备驱动归纳总结(六):1.中断的实现 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

linux設(shè)備驅(qū)動(dòng)歸納總結(jié)(六):1.中斷的實(shí)現(xiàn)

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

一、什么是中斷

中斷分兩種:

1)中斷,又叫外部中斷或異步中斷,它的產(chǎn)生是由于外設(shè)向處理器發(fā)出中斷請(qǐng)求。其中外部中斷也有兩種,這是由配置寄存器設(shè)定的:普通中斷請(qǐng)求(IRQ)和快速中斷請(qǐng)求(FIQ)。一般地,linux下很少使用快速中斷請(qǐng)求。

2)異常,又叫內(nèi)部中斷或同步中斷,它的產(chǎn)生是由于處理器執(zhí)行指令出錯(cuò)。

在以下的內(nèi)容我是要介紹由于外部設(shè)備產(chǎn)生的中斷。

這里我還有兩個(gè)名詞要說清楚

1)中斷請(qǐng)求線:在后面也叫中斷號(hào),每個(gè)中斷都會(huì)通過一個(gè)唯一的數(shù)值來標(biāo)識(shí),而這個(gè)值就稱做中斷請(qǐng)求線

2)在2440芯片中,有些中斷是需要共享一個(gè)中斷寄存器中的一位,如EINT4——EINT7,它們是共享寄存器SRCPEND的第4位。具體可以查看芯片手冊(cè)。

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

二、什么是中斷處理函數(shù)

在相應(yīng)一個(gè)中斷是,內(nèi)核會(huì)執(zhí)行該信號(hào)對(duì)應(yīng)的一個(gè)函數(shù),該函數(shù)就叫做該中斷對(duì)應(yīng)的中斷處理函數(shù)。一般來說,中斷的優(yōu)先級(jí)是最高的,一但接收到中斷,內(nèi)核就會(huì)調(diào)用對(duì)應(yīng)的中斷處理函數(shù)。

中斷處理函數(shù)運(yùn)行在中斷上下文中。中斷上下文與內(nèi)核上下文有一點(diǎn)區(qū)別:

內(nèi)核上下文是指應(yīng)用層調(diào)用系統(tǒng)調(diào)用陷入內(nèi)核執(zhí)行,內(nèi)核代表陷入的進(jìn)程執(zhí)行操作。函數(shù)中可以通過current查看當(dāng)前進(jìn)程(即應(yīng)用層的進(jìn)程)的信息,并且可以睡眠。

中斷上下文中,不能通過current查看調(diào)用它的應(yīng)用層進(jìn)程的信息,同時(shí),處于中斷上下文時(shí),不能睡眠。

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

一、從硬件角度看中斷

中斷的產(chǎn)生到處理器獲得中斷這段過程中,還要通過中斷處理器來篩選信號(hào)。

先溫習(xí)一下S3C2440芯片手冊(cè)的知識(shí):中斷是如何產(chǎn)生的,中斷處理器本身如何處理中斷。先看一下一幅經(jīng)典的圖,這是介紹中斷控制器的工作流程:

從硬件上的分類,有兩種不同的中斷類型:

1)自己占有SORCPND寄存器的一位(without

sub-register)。

2)幾個(gè)中斷共同享用SRCPND寄存器的一位(with

sub-register)。

其實(shí)兩種都差不多,只是多了兩步的檢測。我以自己占用一位的中斷來舉例,如EINT1,在我的開發(fā)板,EINT1上接了一個(gè)按鍵。

1)當(dāng)我按下按鍵產(chǎn)生電平變化,傳到S3C2440的中斷控制器上(即將要進(jìn)入上面圖的流程圖)。

2)首先,信號(hào)要經(jīng)過寄存器SRCPND,SRCPND是用來配置當(dāng)前的處理器要接收什么中斷,如果該寄存器配置成接收EINT1中斷(對(duì)應(yīng)位置一),則允許繼續(xù)下一步。

3)然后,信號(hào)經(jīng)過寄存器MASK,這是用來設(shè)置當(dāng)前系統(tǒng)需要屏蔽的中斷。注意,這里的屏蔽跟上一個(gè)寄存器的不接收中斷是不一樣的。這里的屏蔽是指,中斷是接受了,但是由于某種原因,先暫時(shí)不屏蔽產(chǎn)生的中斷。

4)通過INTPND寄存器,查看當(dāng)前是否有相同的中斷已經(jīng)被請(qǐng)求(如果是,INTPND對(duì)應(yīng)位置一)。

5)如果沒有相同的中斷在請(qǐng)求,中斷處理器才會(huì)把這個(gè)信號(hào)傳給處理器,這時(shí)處理器才會(huì)知道有EINT0的中斷真正來了,要對(duì)信號(hào)進(jìn)行處理了。

注:如果設(shè)定了EINT0是快速中斷模式(FIQ),中斷通過SRCPND寄存器后就會(huì)通過MODE寄存器的判斷,確定是FIQ后,中斷控制器優(yōu)先將該中斷傳給CPU處理。

6)對(duì)應(yīng)傳來的中斷類型(IRQ或FIQ),通過CPSR寄存器切換到對(duì)應(yīng)的工作模式(ARM有七種工作模式)。

7)切換工作模式后,進(jìn)入指定的中斷處理入口執(zhí)行中斷處理函數(shù)。

注意:第6、7步在linux下的實(shí)現(xiàn)相對(duì)復(fù)雜,不像在裸板程序,只需要切換一下工作模式,執(zhí)行相應(yīng)的函數(shù)就可以了。遲點(diǎn)會(huì)介紹linux如何實(shí)現(xiàn)。

來個(gè)流程圖比較只在,同時(shí)來個(gè)類比,處理器是老板,中斷處理器是小秘:

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

四、注冊(cè)和釋放中斷處理函數(shù)

上面的介紹只是講解了一個(gè)設(shè)備產(chǎn)生中斷后要經(jīng)過怎么樣的步驟才能讓處理器接收到中斷信號(hào)。傳入處理器后,接下來的工作就是由內(nèi)核來實(shí)現(xiàn)了,那是一個(gè)復(fù)雜的機(jī)制,我們這里先不說。但是,內(nèi)核提供了相關(guān)的接口給我們,我們只要通過接口告訴內(nèi)核,當(dāng)來了指定中斷時(shí),內(nèi)核你該執(zhí)行哪個(gè)中斷處理函數(shù)。

注冊(cè)中斷處理函數(shù):

/*include

*/

int

request_irq(unsigned int irq, irq_handler_t handler,

unsigned

long irqflags, const char *devname, void *dev_id)

使用:

將中斷號(hào)irq與中斷處理函數(shù)handler對(duì)應(yīng)

參數(shù):

irq:指定要分配的中斷號(hào),中斷號(hào)的定義在“include/mach/irqs.h”中。注意,不管是單獨(dú)占有中斷請(qǐng)求線的中斷,還是共享中斷請(qǐng)求線的每個(gè)中斷,都有一個(gè)對(duì)應(yīng)的中斷號(hào)。,所以,調(diào)用該函數(shù)不需要考慮是哪種中斷(是否共享寄存器),你想哪種中斷響應(yīng),你就填對(duì)應(yīng)的中斷號(hào)。

handler:中斷處理函數(shù)指針。

irqflags:中斷處理標(biāo)記,待會(huì)介紹:

devname:該字符串將顯示在/proc/irq和/pro/interrupt中。

dev_id:ID號(hào),待會(huì)會(huì)介紹。

返回值:成功返回0,失敗返回非0。

注冊(cè)函數(shù)需要注意兩件事:

1)該函數(shù)會(huì)睡眠。

2)必須判斷返回值。

中斷處理標(biāo)志irqflags,這里先介紹幾個(gè)待會(huì)要用的:

/*linux-2.6.29/include/linux/interrupt.h*/

29

#define IRQF_TRIGGER_NONE 0x00000000

30

#define IRQF_TRIGGER_RISING 0x00000001 //上升沿觸發(fā)中斷

31

#define IRQF_TRIGGER_FALLING 0x00000002 //下降沿觸發(fā)中斷

32

#define IRQF_TRIGGER_HIGH 0x00000004 //高電平觸發(fā)中斷

33

#define IRQF_TRIGGER_LOW 0x00000008 //低電平觸發(fā)中斷

34

#define IRQF_TRIGGER_MASK (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW | \

35

IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)

36

#define IRQF_TRIGGER_PROBE 0x00000010

釋放中斷處理函數(shù):

void

free_irq(unsigned int irq, void *dev_id)

編寫中斷處理函數(shù):

中斷處理函數(shù)聲明如下:

static

irqreturn_t intr_handler(int irq, void *dev_id)

先看第一個(gè)參數(shù)irq,這是調(diào)用中斷處理函數(shù)時(shí)傳給它的中斷號(hào),對(duì)于新版本的內(nèi)核,這個(gè)參數(shù)已經(jīng)用處不大,一般只用于打印。

第二個(gè)參數(shù)dev_id,這個(gè)參數(shù)與request_irq()的參數(shù)dev_id一致,由于待會(huì)的程序我并不需要用這個(gè)參數(shù),所以先不介紹。

再看返回值,中斷處理函數(shù)的返回值有三個(gè):

/*linux-2.6.29/include/linux/interrupt..h*/

21

#define IRQ_NONE (0) //如果產(chǎn)生的中斷并不會(huì)執(zhí)行該中斷處理函數(shù)時(shí)返回該值

22

#define IRQ_HANDLED (1) //中斷處理函數(shù)正確調(diào)用會(huì)返回

23

#define IRQ_RETVAL(x) ((x) != 0) //指定返回的數(shù)值,如果非0,返回IRQ_HADLER,否則

26

#ifndef IRQ_NONE //返回IRQ_NONE。

接下來就要寫函數(shù)了,在我的開發(fā)板中,有一個(gè)按鍵是對(duì)應(yīng)EINT1,我要實(shí)現(xiàn)的操作是,當(dāng)我按下按鍵,終端打印”key

down”。在這個(gè)程序中,我并沒有使用dev_id。這將在會(huì)以后的章節(jié)介紹。

/*6th_irq_1/1st/test.c*/

1

#include

2

#include

3

4

#include

5

。。。省略。。。

13

irqreturn_t irq_handler(int irqno, void *dev_id) //中斷處理函數(shù)

14

{

15

printk("key down\n");

16

return IRQ_HANDLED;

17

}

18

19

static int __init test_init(void) //模塊初始化函數(shù)

20

{

21

int ret;

22

23

/*注冊(cè)中斷處理函數(shù),必須查看返回值

24

* IRQ_EINT1:中斷號(hào),定義在"include/mach/irqs.h"中

25

* irq_handler:中斷處理函數(shù)

26

* IRQ_TIRGGER_FALLING:中斷類型標(biāo)記,下降沿觸發(fā)中斷

27

* ker_INT_EINT1:中斷的名字,顯示在/proc/interrupts等文件中

28

*NULL;現(xiàn)在我不使用dev_id,所以這里不傳參數(shù)

29

*/

30

ret = request_irq(IRQ_EINT1, irq_handler, IRQF_TRIGGER_FALLING,

31

"key INT_EINT1", NULL);

32

if(ret){

33

P_DEBUG("request irq failed!\n");

34

return -1;

35

}

36

printk("hello irq\n");

37

return 0;

38

}

39

40

static void __exit test_exit(void) //模塊卸載函數(shù)

41

{

42

free_irq(IRQ_EINT1, NULL);

43

printk("good bye irq\n");

44

}

45

46

module_init(test_init);

47

module_exit(test_exit);

48

49

MODULE_LICENSE("GPL");

50

MODULE_AUTHOR("xoao bai");

51

MODULE_VERSION("v0.1");

接下來驗(yàn)證一下:

[root:

1st]# insmod test.ko

hello

irq

[root:

1st]# key down //按下按鍵顯示

key

down

key

down

key

down

[root:

1st]# cat /proc/interrupts

CPU0

17:

11 s3c-ext0 key INT_EINT1顯示我注冊(cè)和中斷名字

30:

423482 s3c S3C2410 Timer Tick

32:

0 s3c s3c2410-lcd

51:

2782 s3c-ext eth0

70:

49 s3c-uart0 s3c2440-uart

71:

69 s3c-uart0 s3c2440-uart

79:

0 s3c-adc s3c2410_action

80:

0 s3c-adc adc, s3c2410_action

83:

0 - s3c2410-wdt

Err:

0

[root:

key INT_EINT1]# rmmod test //卸載

good

bye irq

[root:

key INT_EINT1]# cat /proc/interrupts //卸載后,我的中斷名字消失了

CPU0

30:

828977 s3c S3C2410 Timer Tick

32:

0 s3c s3c2410-lcd

51:

3202 s3c-ext eth0

70:

192 s3c-uart0 s3c2440-uart

71:

277 s3c-uart0 s3c2440-uart

79:

0 s3c-adc s3c2410_action

80:

0 s3c-adc adc, s3c2410_action

83:

0 - s3c2410-wdt

Err:

0

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

五、proc/interrupt

接下來,稍稍介紹一下proc/interrupt

[root:

1st]# cat /proc/interrupts

CPU0

17:

11 s3c-ext0 key INT_EINT1顯示我注冊(cè)和中斷名字

首先,第一列是中斷號(hào),之前的程序應(yīng)該有人會(huì)有疑問:

中斷號(hào)在哪里找的?

在S3C2440中,這些中斷號(hào)定義在文件"include/mach/irqs.h"中,在這里,可以找到對(duì)應(yīng)的中斷:

25

/* main cpu interrupts */

26

#define IRQ_EINT0 S3C2410_IRQ(0) /* 16 */

27

#define IRQ_EINT1 S3C2410_IRQ(1)

28

#define IRQ_EINT2 S3C2410_IRQ(2)

29

#define IRQ_EINT3 S3C2410_IRQ(3)

30

#define IRQ_EINT4t7 S3C2410_IRQ(4) /* 20 */

在這里我標(biāo)了兩處紅筆:

第一處:可以看到,S3C2440所有的中斷號(hào)在原來的基值上加了16構(gòu)成中斷號(hào),但不同的芯片或許有不同的定義方法。

第二處:有些中斷號(hào)是共享的。在S3C2440中,EINT4---EINT7是共享寄存器SRCPND中的一位,所以,linux系統(tǒng)給這樣的中斷分配了一個(gè)共享的中斷號(hào)。那就是說,如果你使用IRQ_EINT4t7,當(dāng)收到這些中斷時(shí),都會(huì)調(diào)用對(duì)應(yīng)的中斷處理函數(shù)。這就需要在中斷處理函數(shù)中通過第一個(gè)傳參irq來辨別中斷并執(zhí)行相應(yīng)的操作。如:

13

irqreturn_t irq_handler(int irqno, void *dev_id) //中斷處理函數(shù)

14

{

15switch(irqno){

16。。。。}

17

}

那肯定有人會(huì)說,這太麻煩了吧,有沒有更好的辦法處理共享中斷號(hào)?

那當(dāng)然是有,繼續(xù)看文件"include/mach/irqs.h":

61

/* interrupts generated from the external interrupts sources */

62

#define IRQ_EINT4 S3C2410_IRQ(32) /* 48 */

63

#define IRQ_EINT5 S3C2410_IRQ(33)

64

#define IRQ_EINT6 S3C2410_IRQ(34)

65

#define IRQ_EINT7 S3C2410_IRQ(35)

66

#define IRQ_EINT8 S3C2410_IRQ(36)

看到了吧?內(nèi)核把共享的中斷分離出來,只要使用這些標(biāo)記就可以了。

其實(shí)上面我只是想說明:無論在硬件上ARM是怎么實(shí)現(xiàn)中斷的(是否共享),在內(nèi)核看來所有的中斷都是一樣的,都可以獨(dú)自獲得一個(gè)中斷號(hào)。

第二列“11”是對(duì)應(yīng)處理器響應(yīng)該中斷的次數(shù)。

第三列“s3c-ext0”是處理這個(gè)中斷的中斷控制器

第四列一看就知道調(diào)用irq_request()時(shí)定義的中斷名字。

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

六、總結(jié)

其實(shí)要實(shí)現(xiàn)中斷,大部分的工作已經(jīng)給內(nèi)核包了,我們只需要做的就是告訴內(nèi)核,當(dāng)來了什么中斷要執(zhí)行怎么樣的函數(shù),這也是今天介紹的重點(diǎn),其實(shí)步驟很簡單:

1)調(diào)用兩個(gè)函數(shù):requesr_irq和free_irq。

2)實(shí)現(xiàn)中斷處理函數(shù):irq_handler()。

還有沒講的知識(shí):

1)還有幾個(gè)irqflag沒介紹。

2)沒有介紹dev_id。

可能有人會(huì)加載上面的模塊失敗,這也是我今天沒介紹的只是,共享中斷號(hào)。這里說的共享和硬件的共享不一樣性質(zhì),下節(jié)會(huì)介紹。

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

總結(jié)

以上是生活随笔為你收集整理的linux块设备驱动中断程序,linux设备驱动归纳总结(六):1.中断的实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。