1、中斷註冊方法node
在linux內核中用於申請中斷的函數是request_irq(),函數原型在Kernel/irq/manage.c中定義:linux
int request_irq(unsigned int irq, irq_handler_t handler,
unsigned long irqflags, const char *devname, void *dev_id)編程
irq是要申請的硬件中斷號。dom
handler是向系統註冊的中斷處理函數,是一個回調函數,中斷髮生時,系統調用這個函數,dev_id參數將被傳遞給它。ide
irqflags是中斷處理的屬性,若設置了IRQF_DISABLED (老版本中的SA_INTERRUPT,本版zhon已經不支持了),則表示中斷處理程序是快速處理程序,快速處理程序被調用時屏蔽全部中斷,慢速處理程序不屏蔽;若設置了IRQF_SHARED (老版本中的SA_SHIRQ),則表示多個設備共享中斷,若設置了IRQF_SAMPLE_RANDOM(老版本中的SA_SAMPLE_RANDOM),表示對系統熵有貢獻,對系統獲取隨機數有好處。(這幾個flag是能夠經過或的方式同時使用的)函數
devname設置中斷名稱,一般是設備驅動程序的名稱 在cat /proc/interrupts中能夠看到此名稱。this
dev_id在中斷共享時會用到,通常設置爲這個設備的設備結構體或者NULL。spa
request_irq()返回0表示成功,返回-INVAL表示中斷號無效或處理函數指針爲NULL,返回-EBUSY表示中斷已經被佔用且不能共享。指針
==================================================================================================================================orm
SA_INTERRUPT 表示禁止其餘中斷;(對應於 IRQF_DISABLED )引用/*
* 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_NONE0x00000000
#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
/*#define IRQF_PROBE_SHARED 0x00000100 * IRQF_PROBE_SHARED - set by callers when they expect sharing mismatches to occur
* These flags used only by the kernel as part of the irq handling routines.
* registered first in an shared interrupt is considered for
* performance reasons)
*/
#define IRQF_DISABLED 0x00000020 * IRQF_DISABLED - keep irqs disabled when calling the action handler
#define IRQF_SAMPLE_RANDOM 0x00000040 * IRQF_SAMPLE_RANDOM - irq is used to feed the random generator
#define IRQF_SHARED 0x00000080 * IRQF_SHARED - allow sharing the irq among several devices
#define IRQF_TIMER 0x00000200 * IRQF_TIMER - Flag to mark this interrupt as timer interrupt#define IRQF_PERCPU 0x00000400 * IRQF_PERCPU - Interrupt is per cpu
#define IRQF_NOBALANCING 0x00000800 * IRQF_NOBALANCING - Flag to exclude this interrupt from irq balancing
#define IRQF_IRQPOLL 0x00001000 * IRQF_IRQPOLL - Interrupt is used for polling (only the interrupt that is
早期一點的 2.6 內核這裏通常以 SA_ 前綴開頭,如:
int request_irq(unsigned int irq, irq_handler_t handler,
IRQF_SHARED, const char *devname, void *dev_id)
不少權威資料中都提到,中斷共享註冊時的註冊函數中的dev_id參數是必不可少的,而且dev_id的值必須惟一。那麼這裏提供惟一的dev_id值的到底是作什麼用的?
根據咱們前面中斷模型的知識,能夠看出發生中斷時,內核並不判斷到底是共享中斷線上的哪一個設備產生了中斷,它會循環執行全部該中斷線上註冊的中斷處理函數(即irqaction->handler函數)。所以irqaction->handler函數有責任識別出是不是本身的硬件設備產生了中斷,而後再執行該中斷處理函數。一般是經過讀取該硬件設備提供的中斷flag標誌位進行判斷。那既然kernel循環執行該中斷線上註冊的全部irqaction->handler函數,把識別到底是哪一個硬件設備產生了中斷這件事交給中斷處理函數自己去作,那request_irq的dev_id參數到底是作什麼用的?
不少資料中都建議將設備結構指針做爲dev_id參數。在中斷到來時,迅速地根據硬件寄存器中的信息比照傳入的dev_id參數判斷是不是本設備的中斷,若不是,應迅速返回。這樣的說法沒有問題,也是咱們編程時都遵循的方法。但事實上並不可以說明爲何中斷共享必需要設置dev_id。
下面解釋一下dev_id參數爲何必須的,並且是必須惟一的。
當調用free_irq註銷中斷處理函數時(一般卸載驅動時其中斷處理函數也會被註銷掉),由於dev_id是惟一的,因此能夠經過它來判斷從共享中斷線上的多箇中斷處理程序中刪除指定的一個。若是沒有這個參數,那麼kernel不可能知道給定的中斷線上到底要刪除哪個處理程序。
註銷函數定義在Kernel/irq/manage.c中定義:
void free_irq(unsigned int irq, void *dev_id)
引用irqreturn_t xxx_interrupt (intirq,void*dev_id)
{
...
return (IRQ_HANDLED);
}
int xxx_open (struct inode *inode,structfile*filp)
{
if (!request_irq (XXX_IRQ,xxx_interruppt,IRQF_DISABLED,"xxx",NULL)){
/*正常註冊*/
}
return (0);}