日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

linux设备驱动归纳总结(六):2.分享中断号【转】

發(fā)布時(shí)間:2025/3/19 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux设备驱动归纳总结(六):2.分享中断号【转】 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
linux設(shè)備驅(qū)動(dòng)歸納總結(jié)(六):2.分享中斷號(hào)

?轉(zhuǎn)自:http://blog.chinaunix.net/uid-25014876-id-90837.html

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

上一節(jié)介紹的內(nèi)容是,調(diào)用接口request_irq(),使中斷號(hào)與中斷處理函數(shù)對(duì)應(yīng)。但是,有時(shí)候會(huì)有這樣的情況,如果開發(fā)板上按鍵的中斷已經(jīng)被另外的驅(qū)動(dòng)程序注冊(cè)中斷了,而我現(xiàn)在又想再注冊(cè)一次這個(gè)中斷,這就出現(xiàn)了一個(gè)中斷號(hào)不止對(duì)應(yīng)一個(gè)中斷函數(shù)的情況。注意,這里與硬件上的共享中斷不一樣,這里是指,當(dāng)一個(gè)中斷信號(hào)來了,基于操作系統(tǒng),一個(gè)中斷的到來可以調(diào)用多個(gè)中斷處理程序,與硬件無關(guān)。

接下來從錯(cuò)誤的代碼開始講解。

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

?

一、錯(cuò)誤的產(chǎn)生

?

以下的代碼在“6th_irq_2/1st”中。

假設(shè)有這樣的情況,有一個(gè)人,加載了模塊test.ko,模塊注冊(cè)了中斷號(hào)EINT1。接著,我編寫代碼(我并不知道中斷號(hào)已經(jīng)被使用了),加載模塊test1.c(在err目錄下),模塊同樣注冊(cè)了中斷號(hào)EINT1。但這樣的注冊(cè)不成功的。

看效果:

[root: 1st]# insmod test.ko //某處加載第一個(gè)時(shí)成功

hello irq

[root: 1st]# key down

key down

[root: 1st]# insmod err/test1.ko //假設(shè)我并不知道已經(jīng)記載了一次,加載第二次時(shí)失敗

[test_init]request irq failed!

insmod: cannot insert 'err/test1.ko':?Device or resource busy

[root: 1st]# cat /proc/interrupts //查看proc時(shí)發(fā)現(xiàn),原來早就有人注冊(cè)了EINT1中斷號(hào)

CPU0

17: 2 s3c-ext0 key INT_EINT1

30: 20429 s3c S3C2410 Timer Tick

32: 0 s3c s3c2410-lcd

51: 3032 s3c-ext eth0

70: 252 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

?

這個(gè)就是兩男爭(zhēng)一妞的情況了,解決辦法有兩個(gè):

1、動(dòng)物界的規(guī)矩,干掉其中一個(gè),誰贏誰說了算。

2、邪惡做法,和平解決,實(shí)現(xiàn)共享。

?

第一個(gè)解決辦法很簡(jiǎn)單,查閱內(nèi)核代碼,找到注冊(cè)該中斷的模塊,并且想辦法卸載該模塊。但是,如果那個(gè)模塊實(shí)在是太重要的,不能卸載,那只能共享了。

?

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

?

二、共享中斷號(hào)的標(biāo)記

?

在上一節(jié)的內(nèi)容,注冊(cè)中斷處理函數(shù)接口request_irq()的參數(shù)irqflags還沒完全介紹完畢,除了IRQ_TIRGGER_FALLING這類指明中斷觸發(fā)的條件的標(biāo)志外,下面還介紹三個(gè):

SA_INTERRUPT:這個(gè)標(biāo)志表明該中斷處理程序是一個(gè)快速中斷處理程序。過去,linux系統(tǒng)會(huì)區(qū)分快速我慢速中斷,但現(xiàn)在這個(gè)標(biāo)志只有這樣的效果:當(dāng)響應(yīng)這個(gè)中斷時(shí),禁止所有的中斷,是該中斷處理函數(shù)不會(huì)被其他中斷打斷,迅速執(zhí)行。

SA_SAMPLE_RANDOM:這個(gè)標(biāo)志表明產(chǎn)生的中斷會(huì)對(duì)內(nèi)核的entropy pool有貢獻(xiàn)。Entropy pool負(fù)責(zé)產(chǎn)生隨機(jī)數(shù)。

SA_SHIRQ:這個(gè)標(biāo)志表明多個(gè)中斷處理程序可以共享一個(gè)中斷號(hào)。

?

相對(duì)其他兩個(gè),SA_SHIRQ是常用的標(biāo)記。也就是說,我的中斷注冊(cè)失敗,原因是我沒有共享標(biāo)記。也就是說,我需要在我的注冊(cè)中斷函數(shù)添加共享標(biāo)記。但再回想一下兩男爭(zhēng)一妞的場(chǎng)景,需要共享前提是兩個(gè)男的都同意共享,所以,原來的中斷注冊(cè)函數(shù)也需要共享標(biāo)記。需要修改原來的函數(shù)test.c和我新寫的test1.c,都加上共享標(biāo)記SA_SHIRQ,表示它們兩都同意共享。

?

ARMSA_SHIRQ相當(dāng)于標(biāo)志IRQF_SHARED

/*iclude/linux/interrupt.h*/

53 #define IRQF_DISABLED 0x00000020 //SA_INTERRUPT

54 #define IRQF_SAMPLE_RANDOM 0x00000040 //SA_SAMPLE_RANDOM

55 #define IRQF_SHARED 0x00000080 //SA_SHIRQ

?

看修改后的代碼:

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

30 ret = request_irq(IRQ_EINT1, irq_handler,

31 IRQF_TRIGGER_FALLING |?IRQF_SHARED, "key INT_EINT1", NULL);

32 if(ret){

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

34 return ret;

35 }

另外一個(gè)一模一樣

/*6th_irq_2/1st/err/test1.c*/

30 ret = request_irq(IRQ_EINT1, irq_handler,

31 IRQF_TRIGGER_FALLING |?IRQF_SHARED, "key INT_EINT1", NULL);

32 if(ret){

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

34 return ret;

35 }

?

再加載一次,發(fā)現(xiàn)還是不行。

[root: /]# cd review_driver/6th_irq/6th_irq_2/2nd/

[root: 2nd]# insmod test.ko //加載第一個(gè)時(shí)就已經(jīng)不行了

[test_init]request irq failed!

insmod: cannot insert 'test.ko':?invalid parameter //提示參數(shù)錯(cuò)誤

[root: 2nd]# insmod err/test1.ko

[test_init]request irq failed!

insmod: cannot insert 'err/test1.ko': invalid parameter

?

那到底是哪個(gè)參數(shù)錯(cuò)了?

?

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

?

三、設(shè)備號(hào)ID——dev_id

?

話說兩個(gè)難得已經(jīng)同意共享,但為什么還是只能加載一個(gè)呢?女的說:“你們是同意了,但我不能分辨不你們吖!”

中斷函數(shù)同時(shí)一樣的道理,實(shí)現(xiàn)共享中斷號(hào)的情況下,在調(diào)用free_irq()時(shí),通過對(duì)應(yīng)的標(biāo)記,內(nèi)核才會(huì)知道該釋放哪個(gè)中斷處理函數(shù)。

此時(shí),最有一個(gè)沒講的參數(shù)dev_id就有他的用處了——內(nèi)核通過dev_id對(duì)應(yīng)中斷處理函數(shù)handler。另外,也可以通過它來傳參給中斷處理函數(shù)。

?

再次修改兩個(gè)程序,給每個(gè)程序就加上一個(gè)不同的dev_id

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

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

14 {

15 printk("key down, dev_id[%d]\n", *(int *)dev_id);

16 return IRQ_HANDLED;

17 }

18

19 int id = 321;

20

。。。。

32 ret = request_irq(IRQ_EINT1, irq_handler,

33 IRQF_TRIGGER_FALLING | IRQF_SHARED, "key INT_EINT1",?&id);

。。。。

44 free_irq(IRQ_EINT1,?&id);

另外一個(gè)一模一樣

6th_irq_2/1st/err/test.c

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

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

14 {

15 printk("hello xiaobai!, dev_id[%d]\n", *(int *)dev_id);

16 return IRQ_HANDLED;

17 }

18

19 int id = 123;

20

。。。。

32 ret = request_irq(IRQ_EINT1, irq_handler,

33 IRQF_TRIGGER_FALLING | IRQF_SHARED, "key INT_EINT1",?&id);

。。。。

44 free_irq(IRQ_EINT1,?&id);

?

驗(yàn)證一下,共享成功!

[root: 3rd]# insmod test.ko //加載第一個(gè)成功

hello irq

[root: 3rd]# key down, dev_id[321]

key down, dev_id[321]

key down, dev_id[321]

[root: 3rd]# insmod err/test1.ko //加載第二個(gè)也成功

hello irq

[root: 3rd]# key down, dev_id[321] //當(dāng)我按下按鍵時(shí),兩個(gè)中斷處理函數(shù)都調(diào)用了。

hello xiaobai!, dev_id[123]

key down, dev_id[321]

hello xiaobai!, dev_id[123]

key down, dev_id[321]

hello xiaobai!, dev_id[123]

?

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

?

四、介紹完了中斷接口函數(shù),下面簡(jiǎn)單講一下一個(gè)中斷產(chǎn)生后的流程:

?

以下的圖是《linux內(nèi)核設(shè)計(jì)與實(shí)現(xiàn)》上的插圖,基于x86體系的,所以有些函數(shù)我在ARM下找不到。

?

先看前三步,這三步是我在《linux設(shè)備驅(qū)動(dòng)歸納總結(jié)(六):1.中斷的實(shí)現(xiàn)的“從硬件角度看中斷”有詳細(xì)描述,當(dāng)硬件(Hardware)產(chǎn)生中斷,傳給中斷處理器(Interrupt controller),經(jīng)過中斷處理器的一輪篩選后,把中斷傳給處理器(Processer)。

?

接下來就要講解處理器接收到中斷之后干什么:

1、處理器中斷內(nèi)核(processor interrupts the kernel):這步驟如下:

1.1、處理器會(huì)立即停止它正在進(jìn)行的事情。

1.2、處理器關(guān)閉中斷。

1.3、保存原來寄存器的值(這些值屬于中斷的任務(wù)),切換工作模式至IRQS3C24407種工作模式,芯片手冊(cè)有講解,切換工作模式之前需要保存原來部分寄存器上的值,具體請(qǐng)看S3C2440芯片手冊(cè))。

?

2、do_IRQ:(這個(gè)部分說得可能有錯(cuò),因?yàn)槲野褍?nèi)核的源代碼仔細(xì)看過,這部分主要是為了引出下一個(gè)的函數(shù)handle_IRQ_event()

ARM相關(guān)的內(nèi)核代碼我沒找到do_IRQ函數(shù),但我找到一個(gè)相關(guān)的——asm_do_IRQ。看看大概做了些什么事情:

2.1、把中斷號(hào)和一個(gè)在內(nèi)核中存放對(duì)應(yīng)的相關(guān)數(shù)據(jù)的結(jié)構(gòu)體(這個(gè)結(jié)構(gòu)體就是存放處理器中寄存器的值)作為參數(shù),傳參給asm_do_IRQ。

/*linux-2.6.29/arch/arm/kernel/entry-armv.S*/

29 .macro irq_handler

30 get_irqnr_preamble r5, lr

31 1: get_irqnr_and_base r0, r6, r5, lr

32 movne r1, sp

33 @

34 @ routine called with?r0 = irq number, r1 = struct pt_regs *

35 @?//獲得中斷號(hào)和一個(gè)結(jié)構(gòu)體,作為參數(shù)傳給asm_do_IRQ

36 adrne lr, 1b

37 bne?asm_do_IRQ

2.2asm_do_IRQ進(jìn)行一系列的準(zhǔn)備工作之后,調(diào)用函數(shù)generic_handle_irq()

/*linux-2.6.29/arch/arm/kernel/irq.c*/

112 asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs)

113 {

114 struct pt_regs *old_regs = set_irq_regs(regs);?//保存并設(shè)置寄存器上的值,還沒弄懂操作的原因

115

116 irq_enter(); //一系列準(zhǔn)備操作,沒細(xì)看

117

118 /*

119 * Some hardware gives randomly wrong interrupts. Rather

120 * than crashing, do something sensible.

121 */

122 if (irq >= NR_IRQS)

123 handle_bad_irq(irq, &bad_irq_desc);

124 else

125?generic_handle_irq(irq); //調(diào)用該函數(shù),開始處理中斷。

126

127 /* AT91 specific workaround */

128 irq_finish(irq);

129

130 irq_exit();

131 set_irq_regs(old_regs);

132 }

2.3、generic_handle_irq中調(diào)用函數(shù)_do_IRQ

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

309 static inline void generic_handle_irq_desc(unsigned int irq, struct irq_desc *desc)

310 {

311 #ifdef CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ

312 desc->handle_irq(irq, desc);

313 #else

314 if (likely(desc->handle_irq))

315 desc->handle_irq(irq, desc);

316 else

317 __do_IRQ(irq);

318 #endif

319 }

320

321 static inline void generic_handle_irq(unsigned int irq)

322 {

323 generic_handle_irq_desc(irq, irq_to_desc(irq));

324 }

2.4、在__do_IRQ中,會(huì)判斷該中斷號(hào)是否已經(jīng)注冊(cè)了中斷處理函數(shù),如果沒有則退出中斷,切換至原來的工作模式。如果有,__do_IRQ會(huì)調(diào)用函數(shù)handle_IRQ_event()

?

3、irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)?干了些什么:

上面說的內(nèi)容可能都不太詳細(xì),因?yàn)槲乙膊惶靼子行┖瘮?shù)的作用和具體的內(nèi)核代碼,但下面的函數(shù)大家應(yīng)該都會(huì)看得懂:

/*linux-2.6.29/kernel/irq/handle.c*/

326 irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)

327 {

328 irqreturn_t ret, retval = IRQ_NONE;

329 unsigned int status = 0;

330

331 if (!(action->flags &?IRQF_DISABLED)) //在切換工作模式時(shí)內(nèi)核是禁止了中斷的,如果

332 local_irq_enable_in_hardirq(); //注冊(cè)時(shí)使用標(biāo)記IRQF_DISABLED,則開啟中斷

333

334 do {

335 ret = action->handler(irq, action->dev_id); //調(diào)用我們注冊(cè)的中斷處理函數(shù)

336 if (ret == IRQ_HANDLED)

337 status |= action->flags;

338 retval |= ret;

339 action = action->next;

340 } while (action); //這是個(gè)循環(huán),那就說,如果我們使用的IRQF_SHARED標(biāo)識(shí),

341 //它會(huì)輪流執(zhí)行該中斷號(hào)對(duì)應(yīng)的所有注冊(cè)的中斷處理函數(shù)

342 if (status & IRQF_SAMPLE_RANDOM) //如果使用該標(biāo)記時(shí)相應(yīng)的操作

343 add_interrupt_randomness(irq);

344?local_irq_disable(); //再次關(guān)上中斷

345

346 return retval;

347 }

?

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

?

五、總結(jié)

?

總結(jié)一下中斷注冊(cè)的幾個(gè)注意事項(xiàng):

1、調(diào)用request_irq必須通過返回值判斷是否成功。

2、共享中斷號(hào)時(shí),所有共享這個(gè)中斷號(hào)的request_irq都必須添加標(biāo)記IRQF_SHARED,另外還需要使用一個(gè)獨(dú)特的設(shè)備好dev_id,讓內(nèi)核能夠通過dev_id對(duì)應(yīng)注冊(cè)時(shí)的中斷處理函數(shù)。

?

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

源代碼:?6th_irq_2.rar???

【作者】張昺華 【出處】http://www.cnblogs.com/sky-heaven/ 【博客園】 http://www.cnblogs.com/sky-heaven/ 【新浪博客】 http://blog.sina.com.cn/u/2049150530 【知乎】 http://www.zhihu.com/people/zhang-bing-hua 【我的作品---旋轉(zhuǎn)倒立擺】 http://v.youku.com/v_show/id_XODM5NDAzNjQw.html?spm=a2hzp.8253869.0.0&from=y1.7-2 【我的作品---自平衡自動(dòng)循跡車】 http://v.youku.com/v_show/id_XODM5MzYyNTIw.html?spm=a2hzp.8253869.0.0&from=y1.7-2 【新浪微博】 張昺華--sky 【twitter】 @sky2030_ 【facebook】 張昺華 zhangbinghua 本文版權(quán)歸作者和博客園共有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責(zé)任的權(quán)利.

總結(jié)

以上是生活随笔為你收集整理的linux设备驱动归纳总结(六):2.分享中断号【转】的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

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