第一部分獲取中斷(開啟硬件中斷)
一、中斷的申請注銷:
1)中斷的申請
1 2 | int ?request_irq(unsigned? int ?irq, irq_handler_t handler, ????????????????????????? unsigned? long ?irqflags,? const ?char ?*devname,? void ?*dev_id) |
2)中斷的注銷
1 | void ?free_irq(unsigned? int ?irq,? void ?*dev_id) |
3)中斷處理函數
1 | static ?irqreturn_t irq_handle( int ?irq,? void ?*dev__id); |
? ?參數:irq:表示中斷號,這個參數還保留由于歷史遺留問題,往后可能越來越沒用了。由于第二個參數信息更強大
dev__id:就是request_irq()中void *dev_id參數。
二、中斷申請函數參數
1 2 | int ?request_irq(unsigned? int ?irq, irq_handler_t handler, ????????????????????????? unsigned? long ?irqflags,? const ?char ?*devname,? void ?*dev_id) |
? ?1)參數:
? ?irq:是要申請的硬件中斷號。
handler:是向系統注冊的中斷處理函數,是一個回調函數,中斷發生時,系統調用這個函數,dev_id參數將被傳遞給它。
? ? irqflags:是中斷處理的屬性,
? ? ? ?a)若設置了IRQF_DISABLED,則表示中斷處理程序是快速處理程序,快速處理程序被調用時屏蔽所有中斷,慢速處理程序不屏蔽;
? ? ? ?b)若設置了 ? ?IRQF_SHARED,則表示多個設備共享中斷;//在另一篇文章會提到
? ? ? ?c)若設置了IRQF_SAMPLE_RANDOM,表示對系統熵有貢獻,對系統獲取隨機數有好處。
? ? ? ? ? ?Tip:(flag是可以通過或的方式同時使用的)
? ?devname:設置中斷名稱,通常是設備驅動程序的名稱 ?在cat /proc/interrupts中可以看到此名稱。
? ?dev_id:在中斷共享時會用到,一般設置為這個設備的設備結構體或者不使用時為NULL。因為在共享中斷中同一個中斷線(或可以說同一個中斷號)可能掛載好幾個設備,當使用void free_irq(unsigned int irq, void *dev_id)時,根據irq和dev_id可以找到中斷線為irq上的標識為dev_id的某個具體設備。dev_id也經常在不是共享中斷中的驅動傳遞數據
? ?2)返回值:
? ?a)request_irq()返回0表示成功;
? ?b)返回-EINVAL表示無效的參數,如果返回這個值,應該看看傳遞給request_irq()的參數是否正確;
? ?c)返回-EBUSY表示中斷已經被占用且不能共享;
? ?d)返回ENOMEM表示內存不足。嵌入式系統由于內存資源有限,經常會發生這樣的錯誤。
? ?3)擴展---unsigned long irqflags值
? ?在include\linux\interrupt.h中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | /* ? * These correspond to the IORESOURCE_IRQ_* defines in ? * linux/ioport.h to select the interrupt line behaviour.? When ? * requesting an interrupt without specifying a IRQF_TRIGGER, the ? * setting should be assumed to be "as already configured", which ? * may be as per machine or firmware initialisation. ? */ #define IRQF_TRIGGER_NONE??? 0x00000000 #define IRQF_TRIGGER_RISING??? 0x00000001 #define IRQF_TRIGGER_FALLING??? 0x00000002 #define IRQF_TRIGGER_HIGH??? 0x00000004 #define IRQF_TRIGGER_LOW??? 0x00000008 #define IRQF_TRIGGER_MASK??? (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW | \ ????????????????? IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING) #define IRQF_TRIGGER_PROBE??? 0x00000010 /* ? * These flags used only by the kernel as part of the ? * irq handling routines. ? * ? * IRQF_DISABLED - keep irqs disabled when calling the action handler ? * IRQF_SAMPLE_RANDOM - irq is used to feed the random generator ? * IRQF_SHARED - allow sharing the irq among several devices ? * IRQF_PROBE_SHARED - set by callers when they expect sharing mismatches to occur ? * IRQF_TIMER - Flag to mark this interrupt as timer interrupt ? * IRQF_PERCPU - Interrupt is per cpu ? * IRQF_NOBALANCING - Flag to exclude this interrupt from irq balancing ? * IRQF_IRQPOLL - Interrupt is used for polling (only the interrupt that is ? *??????????????? registered first in an shared interrupt is considered for ? *??????????????? performance reasons) ? */ #define IRQF_DISABLED??????? 0x00000020 #define IRQF_SAMPLE_RANDOM??? 0x00000040 #define IRQF_SHARED??????? 0x00000080 #define IRQF_PROBE_SHARED??? 0x00000100 #define IRQF_TIMER??????? 0x00000200 #define IRQF_PERCPU??????? 0x00000400 #define IRQF_NOBALANCING??? 0x00000800 #define IRQF_IRQPOLL??????? 0x00001000 |
? ?Tip:下面是老版本(2.4內核irqflags的值),不要在新版本使用。(2.6 內核及2.6以上內核都為新內核)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* ? * Migration helpers. Scheduled for removal in 9/2007 ? * Do not use for new code !//不要的新版本使用,2.6 內核及2.6以上內核都為新內核 ? */ static ?inline unsigned? long ?__deprecated deprecated_irq_flag(unsigned? long ?flag) { ???? return ?flag; } #define SA_INTERRUPT??????? deprecated_irq_flag(IRQF_DISABLED) #define SA_SAMPLE_RANDOM??? deprecated_irq_flag(IRQF_SAMPLE_RANDOM) #define SA_SHIRQ??????? deprecated_irq_flag(IRQF_SHARED) #define SA_PROBEIRQ??????? deprecated_irq_flag(IRQF_PROBE_SHARED) #define SA_PERCPU??????? deprecated_irq_flag(IRQF_PERCPU) #define SA_TRIGGER_LOW??????? deprecated_irq_flag(IRQF_TRIGGER_LOW) #define SA_TRIGGER_HIGH??????? deprecated_irq_flag(IRQF_TRIGGER_HIGH) #define SA_TRIGGER_FALLING??? deprecated_irq_flag(IRQF_TRIGGER_FALLING) #define SA_TRIGGER_RISING??? deprecated_irq_flag(IRQF_TRIGGER_RISING) #define SA_TRIGGER_MASK??????? deprecated_irq_flag(IRQF_TRIGGER_MASK) |
三、使用模板
? ?使用步驟:以外部中斷為例
a)定義結構體,相當于定義(void *dev_id)中的(void *)
1 2 3 4 5 | struct pin_desc{ //聲明一個引腳描述的結構體pin_desc ??????? unsigned? int ?pin; //引腳值,參考數據手冊及板子電路原理圖 ??????? unsigned? int ?key_val; //值自已隨便定義;看自己的項目需要 ??????? //................... ??? }; |
b)實例化結構體,相當于(void *dev_id)中的 dev_id
1 2 3 4 5 | struct ?pin_desc pins_desc[3] = { //實例化結構體,以jz2440按鍵為列 ??????? {S3C2410_GPF0, 0x01}, //S3C2410_GPFn在內核中定義好了 ??????? {S3C2410_GPF2, 0x02}, ??????? {S3C2410_GPG3, 0x03}, ??? }; |
c)定義中斷處理函數
1 2 3 4 5 | static ?irqreturn_t irq_handle( int ?irq,? void ?*dev__id){ ???? struct pin_desc *pindesc = (struct pin_desc *)dev__id; ???? //................ ???? return ?IRQ_RETVAL(IRQ_HANDLED); //返回IRQ_HANDLED表示中斷已經處理 ???? } |
d)申請中斷
1 2 3 | request_irq(IRQ_EINT0, irq_handle, IRQ_TYPE_EDGE_BOTH,? "s2" , &pins_desc[0]); //IRQ_EINTn在內核中定義好了 ??? request_irq(IRQ_EINT2, irq_handle, IRQ_TYPE_EDGE_BOTH,? "s3" , &pins_desc[1]); ??? request_irq(IRQ_EINT11, irq_handle, IRQ_TYPE_EDGE_BOTH,? "s4" , &pins_desc[2]); |
e)釋放內存
1 2 3 | free_irq(IRQ_EINT0, &pins_desc[0]); ???? free_irq(IRQ_EINT2, &pins_desc[1]); ???? free_irq(IRQ_EINT11, &pins_desc[2]); |
Tip:可以直接將IRQ_EINTn也在pins_desc定義,然后
1 2 3 4 | int ?i =? 0 ; ??? for (i =? 0 ; i <? 3 ; i++){ ??? free_irq(pins_desc[i].irqnum, &pins_desc[i]); ??? } |
? ?實例見[arm驅動]Linux內核開發之阻塞非阻塞IO----輪詢操作?中的實例(按鍵中斷雙邊沿觸發)
本文轉自lilin9105 51CTO博客,原文鏈接:http://blog.51cto.com/7071976/1392439,如需轉載請自行聯系原作者