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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

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

發布時間:2025/3/19 linux 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux设备驱动归纳总结(六):2.分享中断号【转】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
linux設備驅動歸納總結(六):2.分享中斷號

?轉自:http://blog.chinaunix.net/uid-25014876-id-90837.html

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

上一節介紹的內容是,調用接口request_irq(),使中斷號與中斷處理函數對應。但是,有時候會有這樣的情況,如果開發板上按鍵的中斷已經被另外的驅動程序注冊中斷了,而我現在又想再注冊一次這個中斷,這就出現了一個中斷號不止對應一個中斷函數的情況。注意,這里與硬件上的共享中斷不一樣,這里是指,當一個中斷信號來了,基于操作系統,一個中斷的到來可以調用多個中斷處理程序,與硬件無關。

接下來從錯誤的代碼開始講解。

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

?

一、錯誤的產生

?

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

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

看效果:

[root: 1st]# insmod test.ko //某處加載第一個時成功

hello irq

[root: 1st]# key down

key down

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

[test_init]request irq failed!

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

[root: 1st]# cat /proc/interrupts //查看proc時發現,原來早就有人注冊了EINT1中斷號

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

?

這個就是兩男爭一妞的情況了,解決辦法有兩個:

1、動物界的規矩,干掉其中一個,誰贏誰說了算。

2、邪惡做法,和平解決,實現共享。

?

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

?

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

?

二、共享中斷號的標記

?

在上一節的內容,注冊中斷處理函數接口request_irq()的參數irqflags還沒完全介紹完畢,除了IRQ_TIRGGER_FALLING這類指明中斷觸發的條件的標志外,下面還介紹三個:

SA_INTERRUPT:這個標志表明該中斷處理程序是一個快速中斷處理程序。過去,linux系統會區分快速我慢速中斷,但現在這個標志只有這樣的效果:當響應這個中斷時,禁止所有的中斷,是該中斷處理函數不會被其他中斷打斷,迅速執行。

SA_SAMPLE_RANDOM:這個標志表明產生的中斷會對內核的entropy pool有貢獻。Entropy pool負責產生隨機數。

SA_SHIRQ:這個標志表明多個中斷處理程序可以共享一個中斷號。

?

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

?

ARMSA_SHIRQ相當于標志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 }

另外一個一模一樣

/*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 }

?

再加載一次,發現還是不行。

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

[root: 2nd]# insmod test.ko //加載第一個時就已經不行了

[test_init]request irq failed!

insmod: cannot insert 'test.ko':?invalid parameter //提示參數錯誤

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

[test_init]request irq failed!

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

?

那到底是哪個參數錯了?

?

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

?

三、設備號ID——dev_id

?

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

中斷函數同時一樣的道理,實現共享中斷號的情況下,在調用free_irq()時,通過對應的標記,內核才會知道該釋放哪個中斷處理函數。

此時,最有一個沒講的參數dev_id就有他的用處了——內核通過dev_id對應中斷處理函數handler。另外,也可以通過它來傳參給中斷處理函數。

?

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

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

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

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);

另外一個一模一樣

6th_irq_2/1st/err/test.c

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

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

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);

?

驗證一下,共享成功!

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

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 //加載第二個也成功

hello irq

[root: 3rd]# key down, dev_id[321] //當我按下按鍵時,兩個中斷處理函數都調用了。

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

?

四、介紹完了中斷接口函數,下面簡單講一下一個中斷產生后的流程:

?

以下的圖是《linux內核設計與實現》上的插圖,基于x86體系的,所以有些函數我在ARM下找不到。

?

先看前三步,這三步是我在《linux設備驅動歸納總結(六):1.中斷的實現的“從硬件角度看中斷”有詳細描述,當硬件(Hardware)產生中斷,傳給中斷處理器(Interrupt controller),經過中斷處理器的一輪篩選后,把中斷傳給處理器(Processer)。

?

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

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

1.1、處理器會立即停止它正在進行的事情。

1.2、處理器關閉中斷。

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

?

2、do_IRQ:(這個部分說得可能有錯,因為我把內核的源代碼仔細看過,這部分主要是為了引出下一個的函數handle_IRQ_event()

ARM相關的內核代碼我沒找到do_IRQ函數,但我找到一個相關的——asm_do_IRQ??纯创蟾抛隽诵┦裁词虑?#xff1a;

2.1、把中斷號和一個在內核中存放對應的相關數據的結構體(這個結構體就是存放處理器中寄存器的值)作為參數,傳參給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 @?//獲得中斷號和一個結構體,作為參數傳給asm_do_IRQ

36 adrne lr, 1b

37 bne?asm_do_IRQ

2.2、asm_do_IRQ進行一系列的準備工作之后,調用函數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);?//保存并設置寄存器上的值,還沒弄懂操作的原因

115

116 irq_enter(); //一系列準備操作,沒細看

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); //調用該函數,開始處理中斷。

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中調用函數_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中,會判斷該中斷號是否已經注冊了中斷處理函數,如果沒有則退出中斷,切換至原來的工作模式。如果有,__do_IRQ會調用函數handle_IRQ_event()。

?

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

上面說的內容可能都不太詳細,因為我也不太明白有些函數的作用和具體的內核代碼,但下面的函數大家應該都會看得懂:

/*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)) //在切換工作模式時內核是禁止了中斷的,如果

332 local_irq_enable_in_hardirq(); //注冊時使用標記IRQF_DISABLED,則開啟中斷

333

334 do {

335 ret = action->handler(irq, action->dev_id); //調用我們注冊的中斷處理函數

336 if (ret == IRQ_HANDLED)

337 status |= action->flags;

338 retval |= ret;

339 action = action->next;

340 } while (action); //這是個循環,那就說,如果我們使用的IRQF_SHARED標識,

341 //它會輪流執行該中斷號對應的所有注冊的中斷處理函數

342 if (status & IRQF_SAMPLE_RANDOM) //如果使用該標記時相應的操作

343 add_interrupt_randomness(irq);

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

345

346 return retval;

347 }

?

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

?

五、總結

?

總結一下中斷注冊的幾個注意事項:

1、調用request_irq必須通過返回值判斷是否成功。

2、共享中斷號時,所有共享這個中斷號的request_irq都必須添加標記IRQF_SHARED,另外還需要使用一個獨特的設備好dev_id,讓內核能夠通過dev_id對應注冊時的中斷處理函數。

?

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 【我的作品---旋轉倒立擺】 http://v.youku.com/v_show/id_XODM5NDAzNjQw.html?spm=a2hzp.8253869.0.0&from=y1.7-2 【我的作品---自平衡自動循跡車】 http://v.youku.com/v_show/id_XODM5MzYyNTIw.html?spm=a2hzp.8253869.0.0&from=y1.7-2 【新浪微博】 張昺華--sky 【twitter】 @sky2030_ 【facebook】 張昺華 zhangbinghua 本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利.

總結

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

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 中文字幕在线一区 | 变态另类一区二区 | 97精品 | 成人免费片 | 免费观看污视频 | 婷婷视频网 | 超碰人人人人人人人 | 日韩中文字幕影院 | 爱爱91| 草草视频在线免费观看 | 亚洲欧洲精品一区二区 | 蜜桃av噜噜一区二区三区 | 97成人精品 | 午夜影院网站 | 国产三级国产精品国产国在线观看 | 免费国产黄色 | 精品国产一区二区三区日日嗨 | 女同久久另类69精品国产 | 青青色在线观看 | 欧洲精品一区 | 阿v视频免费在线观看 | 久久亚洲一区二区三区四区五区 | 欧美人与动物xxxxx | av卡一卡二 | 91久久精品国产91久久 | bt天堂新版中文在线地址 | 有码视频在线观看 | 玖玖色资源 | 国产aⅴ爽av久久久久成人 | 日本中文字幕影院 | 久久久久久久久久久久久女国产乱 | 国产免费麻豆 | 99久久精品免费看国产四区 | 制服.丝袜.亚洲.另类.中文 | 色婷婷视频在线 | 亚洲福利一区二区三区 | 亚洲成年人在线观看 | 无码人妻av免费一区二区三区 | 麻豆免费下载 | 亚洲第一网站 | 欧美日韩精选 | 国产一区二区精品在线 | 人人干干 | 男人的天堂av片 | 尼姑福利影院 | 草草影院在线免费观看 | 日韩尤物| 在线高清观看免费观看 | 中文天堂 | 午夜久久网站 | 日本国产一区二区三区 | 一本之道av | 日韩成人专区 | 天天操操| 欧美日韩性视频 | 国产ts三人妖大战直男 | 97偷拍视频| 人妻一区二区在线 | av噜噜色| 九七久久| 国产综合在线视频 | 成人免费在线小视频 | 成人毛片100免费观看 | 蜜臀av性久久久久蜜臀av麻豆 | 伊人免费在线观看 | 精精国产xxxx视频在线播放 | 青青操在线观看 | 99自拍偷拍 | 国产精品亚洲精品 | 一个人看的www日本高清视频 | 久久国产成人精品av | xx久久| 毛片内射 | 欧美日韩高清在线播放 | 天天操天天射天天爱 | 大尺度av | 二区不卡| 伊人久久久久久久久 | 日本a在线免费观看 | 九九九九精品 | 丁香色网| 女生扒开腿让男生操 | www.99re7.com| 日韩激情毛片 | 久久久久久国产精品免费播放 | 青青五月天| 手机在线免费观看av | 青草99| 91jk制服白丝超短裙大长腿 | 免费看av毛片 | av天堂一区二区三区 | 超碰91人人 | 91高潮大合集爽到抽搐 | av无码精品一区二区三区宅噜噜 | 风韵少妇性饥渴推油按摩视频 | 91资源在线播放 | 日韩黄色在线视频 | 天堂99| 99久久久无码国产精品不卡 |