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 (unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long frags, const char *device, void *dev_id);
  • 2.6 內核
request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev);
參數說明:
在發生對應於第 1個參數 irq 的中斷時,則調用第 2 個參數 handler 指定的中斷服務函數(也就是把 handler() 中斷服務函數注冊到內核中 )。
第 3 個參數 flags 指定了快速中斷或中斷共享等中斷處理屬性。在 2.6 教新的內核里(我的是 2.6.27 ~ 2.6.31 ),在 linux/interrupt.h 中定義操作這個參數的宏如下:

引用

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


早期一點的 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 可作為共享中斷時的中斷區別參數,也可以用來指定中斷服務函數需要參考的數據地址。
返回值:
函數運行正常時返回 0 ,否則返回對應錯誤的負值。
示例代碼片段:

引用

irqreturn_t xxx_interrupt (int irq, void *dev_id)
{
...
return (IRQ_HANDLED);
}
int xxx_open (struct inode *inode, struct file *filp)
{
if (!request_irq (XXX_IRQ, xxx_interruppt, IRQF_DISABLED, "xxx", NULL)) {
/*正常注冊*/
}
return (0);
}

============================================================================

內核中的中斷處理模型

內核版本: Linux 2.6.19

Kernel中斷處理模型結構圖如下:

內核中的中斷處理模型

下面簡單介紹一下:

1. Linux定義了名字為irq_desc的中斷例程描述符表:(include/linux/irq.h)

struct irqdesc irq_desc[NR_IRQS];

NR_IRQS表示中斷源的數目。

2. irq_desc[]是一個指向irq_desc結構的數組, irq_desc結構是各個設備中斷服務例程的描述符。

struct irq_desc {
irq_flow_handler_t handle_irq;
struct irq_chip *chip;
void *handler_data;
void *chip_data;
struct irqaction *action;
unsigned int status;

unsigned int depth;
unsigned int wake_depth;
unsigned int irq_count;
unsigned int irqs_unhandled;
spinlock_t lock;
#ifdef CONFIG_SMP
cpumask_t affinity;
unsigned int cpu;
#endif
#if defined(CONFIG_GENERIC_PENDING_IRQ) || defined(CONFIG_IRQBALANCE)
cpumask_t pending_mask;
#endif
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *dir;
#endif
const char *name;
} ____cacheline_aligned;

Irq_desc結構體中的成員action指向該中斷號對應的irqaction結構體鏈表。Irqaction結構體定義如下:

// include/linux/interrupt.h
struct irqaction {
irq_handler_t handler; // 指向中斷服務程序
unsigned long flags; // 中斷標志
unsigned long mask; // 中斷掩碼
const char *name; // I/O設備名

void *dev_id; // 設備標識
struct irqaction *next; // 指向下一個描述符

int irq; // IRQ線
struct proc_dir_entry *dir; // 指向IRQn相關的/proc/irq/n目錄的描述符
};

其中關鍵的handler成員指向了該設備的中斷服務程序,由執行request_irq時建立。

3. 在驅動程序初始化時,若使用到中斷,通常調用函數request_irq()建立該驅動程序對應的irqaction結構體,並把它登記到irq_desc [irq_num]->action鏈表中。Iqr_num為驅動程序申請的中斷號。

request_irq()函數的原型如下:

// kernel/irq/manage.c
int request_irq(unsigned int irq,
irqreturn_t (*handler)(int, void *, struct pt_regs *),
unsigned long irqflags,
const char *devname,
void *dev_id);

參數irq是設備中斷求號,在向irq_desc []數組登記時,它做為數組的下標。把中斷號為irq的irqaction結構體的首地址寫入irq_desc [irq]->action。這樣就把設備的中斷請求號與該設備的中斷服務例程irqaction聯系在一起了。

這樣當CPU接收到中斷請求后,就可以根據中斷號通過irq_desc []找到該設備的中斷服務程序。流程如上圖所示。

4. 關於共享中斷

共享中斷的不同設備的iqraction結構體都會添加進該中斷號對應的irq_desc結構體的action成員所指向的irqaction鏈表內。當內核發生中斷時,它會依次調用該鏈表內所有的handler函數。因此,若驅動程序需要使用共享中斷機制,其中斷處理函數必須有能力識別是否是自己的硬件產生了中斷。通常是通過讀取該硬件設備提供的中斷flag標志位進行判斷。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM