request_irq() | 註冊中斷服務

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

request_irq() | 註冊中斷服務

 
 
在 2.4 內核和 2.6內核中都使用  request_irq() 函數來註冊中斷服務函數。在 2.4 內核中,須要包含的頭文件是 #include <linux/sched.h> ,2.6 內核中須要包含的頭文件則是
#include <linux/interrupt.h> 。函數原型以下:

  • 2.4 內核
int request_irq ( unsignedintirq, void (*handler)( int, void*, structpt_regs*), unsignedlongfrags, constchar*device, void*dev_id);

  • 2.6 內核
request_irq( unsignedintirq,irq_handler_thandler, unsignedlongflags, constchar*name, void*dev);

參數說明

在發生對應於第 1個參數  irq 的中斷時,則調用第 2 個參數 handler 爲要註冊的中斷服務函數(也就是把 handler() 中斷服務函數註冊到內核中 )。

第 3 個參數  flags 指定了 快速中斷或中斷共享等中斷處理屬性。在 2.6 教新的內核裏(個人是 2.6.27 ~ 2.6.31 ),在 linux/interrupt.h 中定義操做這個參數的宏以下:
引用
/*
 * 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
/*
* 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_PROBE_SHARED       0x00000100 * IRQF_PROBE_SHARED - set by callers when they expect sharing mismatches to occur
#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_ 前綴開頭,如:
SA_INTERRUPT   表示禁止其餘中斷;(對應於 IRQF_DISABLED )
SA_SHIRQ             表示共享相同的中斷號 (對應於 IRQF_SHARED )
SA_SAMPLE_RANDOM   此宏會影響到 RANDOM 的處理( 對應於 IRQF_SAMPLE_RANDOM )。

第 4 個參數 name,一般是 設備驅動程序的名稱。改值用在 /proc/interrupt 系統 (虛擬) 文件上,或內核發生中斷錯誤時使用。

第 5 個參數  dev_id 中斷名稱 可做爲共享中斷時的中斷區別參數,也能夠用來指定中斷服務函數須要參考的數據地址。建議將設備結構指針做爲dev_id參數

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)


返回值
函數運行正常時返回 0 ,不然返回對應錯誤的負值。

示例代碼片斷
引用

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

相關文章
相關標籤/搜索