中斷註冊函數 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
第 4 個參數 name 通常是設備驅動程序的名稱。改值用在 /proc/interrupt 系統 (虛擬) 文件上,或內核發生中斷錯誤時使用。
第 5 個參數 dev_id 可作爲共享中斷時的中斷區別參數,也可以用來指定中斷服務函數需要參考的數據地址。
返回值:
函數運行正常時返回 0 ,否則返回對應錯誤的負值。
對於使用open firmware的系統中,驅動程序在執行ruquest_irq之前要先進行軟硬件中斷號的映射,具體通過如下函數實現:
- irq_of_parse_and_map(struct device_node * dev, int index);
以PowerPC中的mpc83xx_sync.c爲例:
- static int sync_ptp_init(void)
- {
- int result;
- struct device_node *np;
- np = of_find_compatible_node(NULL, NULL, "fsl,ucc-ptp");
- if (!np) {
- return -ENODEV;
- }
- ptp_virq = irq_of_parse_and_map(np, 1); /* PTP2 IRQ */
- ptp_rtc_virq = irq_of_parse_and_map(np, 2); /* RTC_IRQ */
- ...
- return result;
- }
通過函數
- struct device_node *of_find_compatible_node(struct device_node *from, const char *type, const char *compatible);
根據compatible屬性,獲得設備結點。遍歷Device Tree中所有的設備結點,看看哪個結點的類型、compatible屬性與本函數的輸入參數匹配,大多數情況下,from、type爲NULL。再進行軟硬中斷號的映射。
- static inline int enable_ptp(int port)
- {
- ...
- result = request_irq(ptp_virq, ptp_intr,
- 0, "ptp", &ptp_reg);
- if(result < 0) {
- printk(KERN_ERR "kjb::%s: register irq failed %d\n",
- __FUNCTION__, result);
- }
- ...
- return result;
- }
完成映射之後進行中斷註冊,這裏以ptp_virq爲例。相應的中斷處理函數
- static irqreturn_t ptp_intr(int irq, void * _ptp)
- {
- u32 events;
- KSYNC_DEBUG("ptp intr\n");
- events = ptp_reg->ptp_tmr_pevent;
- if (events & PTP_QE_TS_TX_FRAME1) {
- struct ptp_ts ts;
- int port = (ucc_port - 1) / 2;
- ts.ts_low = ptp_reg->tmr_ucc_tx_l[port].ts;
- ts.ts_high = ptp_reg->tmr_ucc_tx_h[port].ts;
- tx_push_ts(&ts);
- }
- ptp_reg->ptp_tmr_pevent |= events;
- return IRQ_HANDLED;
疑問:中斷的進入條件是什麼?
參考:
http://www.cnblogs.com/alfredzzj/archive/2012/04/03/2431514.html
http://www.linuxidc.com/Linux/2011-08/40710.htm