struct irqaction *action;
/*
* IRQ lock detection
*/
unsigned int lck_cnt;
unsigned int lck_pc;
unsigned int lck_jif;
};
在具體的ARM芯片中會(huì)有很多的中斷類型,每一種類型的中斷用以上結(jié)構(gòu)來表示:
struct irqdesc irq_desc[NR_IRQS]; /* NR_IRQS根據(jù)不同的MCU會(huì)有所區(qū)別*/
在通過request_irq()函數(shù)注冊(cè)中斷服務(wù)程序的時(shí)候,將會(huì)把中斷向量和中斷服務(wù)程序?qū)?yīng)起來。
我們來看一下request_irq的源碼:
int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
unsigned long irq_flags, const char * devname, void *dev_id)
{
unsigned long retval;
struct irqaction *action;
if (irq >= NR_IRQS || !irq_desc[irq].valid || !handler ||
(irq_flags & SA_SHIRQ && !dev_id))
return -EINVAL;
action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL);
if (!action) /* 生成action結(jié)構(gòu)*/
return -ENOMEM;
action->handler = handler;
action->flags = irq_flags;
action->mask = 0;
action->name = devname;
action->next = NULL;
action->dev_id = dev_id;
retval = setup_arm_irq(irq, action); /*把中斷號(hào)irq和action 對(duì)應(yīng)起來*/
if (retval)
kfree(action);
return retval;
}
其中第一個(gè)參數(shù)irq就是中斷向量,第二個(gè)參數(shù)即是要注冊(cè)的中斷服務(wù)程序。很多同仁可能疑惑的是,我們要注冊(cè)的中斷向量號(hào)是怎么確定的呢?這要根據(jù)具體芯片的中斷控制器,比如三星的S3C2410,需要通過讀取其中的中斷狀態(tài)寄存器,來獲得是哪個(gè)設(shè)備發(fā)生了中斷:
if defined(CONFIG_ARCH_S3C2410)
#include <asm/hardware.h>
.macro disable_fiq
.endm
.macro get_irqnr_and_base, irqnr, irqstat, base, tmp
mov r4, #INTBASE @ virtual address of IRQ registers
ldr irqnr, [r4, #0x8] @ read INTMSK 中斷掩碼寄存器
ldr irqstat, [r4, #0x10] @ read INTPND 中斷寄存器
bics irqstat, irqstat, irqnr
bics irqstat, irqstat, irqnr
beq 1002f
mov irqnr, #0
1001: tst irqstat, #1
bne 1002f @ found IRQ
add irqnr, irqnr, #1
mov irqstat, irqstat, lsr #1
cmp irqnr, #32
bcc 1001b
1002:
.endm
.macro irq_prio_table
.endm
以上代碼也告訴了我們,中斷號(hào)的確定,其實(shí)是和S3C2410手冊(cè)中SRCPND寄存器是一致的,即:
/* Interrupt Controller */
#define IRQ_EINT0 0 /* External interrupt 0 */
#define IRQ_EINT1 1 /* External interrupt 1 */
#define IRQ_EINT2 2 /* External interrupt 2 */
#define IRQ_EINT3 3 /* External interrupt 3 */
#define IRQ_EINT4_7 4 /* External interrupt 4 ~ 7 */
#define IRQ_EINT8_23 5 /* External interrupt 8 ~ 23 */
#define IRQ_RESERVED6 6 /* Reserved for future use */
#define IRQ_BAT_FLT 7
#define IRQ_TICK 8 /* RTC time tick interrupt */
#define IRQ_WDT 9 /* Watch-Dog timer interrupt */
#define IRQ_TIMER0 10 /* Timer 0 interrupt */
#define IRQ_TIMER1 11 /* Timer 1 interrupt */
#define IRQ_TIMER2 12 /* Timer 2 interrupt */
#define IRQ_TIMER3 13 /* Timer 3 interrupt */
#define IRQ_TIMER4 14 /* Timer 4 interrupt */
#define IRQ_UART2 15 /* UART 2 interrupt */
#define IRQ_LCD 16 /* reserved for future use */
#define IRQ_DMA0 17 /* DMA channel 0 interrupt */
#define IRQ_DMA1 18 /* DMA channel 1 interrupt */
#define IRQ_DMA2 19 /* DMA channel 2 interrupt */
#define IRQ_DMA3 20 /* DMA channel 3 interrupt */
#define IRQ_SDI 21 /* SD Interface interrupt */
#define IRQ_SPI0 22 /* SPI interrupt */
#define IRQ_UART1 23 /* UART1 receive interrupt */
#define IRQ_RESERVED24 24
#define IRQ_USBD 25 /* USB device interrupt */
#define IRQ_USBH 26 /* USB host interrupt */
#define IRQ_IIC 27 /* IIC interrupt */
#define IRQ_UART0 28 /* UART0 transmit interrupt */
#define IRQ_SPI1 29 /* UART1 transmit interrupt */
#define IRQ_RTC 30 /* RTC alarm interrupt */
#define IRQ_ADCTC 31 /* ADC EOC interrupt */
#define NORMAL_IRQ_OFFSET 32
這些宏定義在文件irqs.h中,大家可以看到它的定義取自S3C2410的文檔。
總結(jié): linux在初始化的時(shí)候已經(jīng)把每個(gè)中斷向量的地址準(zhǔn)備好了!就是說添加中斷服務(wù)程序的框架已經(jīng)給出,當(dāng)某個(gè)中斷發(fā)生時(shí),將會(huì)到確定的地址處去找指令,所以我們做驅(qū)動(dòng)程序時(shí),只需要經(jīng)過request_irq()來掛接自己編寫的中斷服務(wù)程序即可。
另:對(duì)于快速中斷,linux在初始化時(shí)是空的,所以要對(duì)它掛接中斷處理程序,就需要單獨(dú)的函數(shù)set_fiq_handler()來實(shí)現(xiàn),此函數(shù)在源文件fiq.c中,有興趣的讀者可進(jìn)一步研究。





