有一个问题:
在datasheet中清楚的说明s3c6410一共有64个中断,
但是dm9000的驱动中request_irq()的中断号却是108.
如下图所示: cat /proc/interrupts
为什么申请出来的中断号是108呢? ?
从中断引脚的定义可以看出:
- #define IRQ_EINT(x) S3C_EINT(x)
- #define S3C_EINT(x) ((x) + S3C_IRQ_EINT_BASE)
- #define S3C_IRQ_EINT_BASE S3C_IRQ(64+5)
- #define S3C_IRQ(x) ((x) + S3C_IRQ_OFFSET)
- #define S3C_IRQ_OFFSET (32)
EINT(7) = 7+EINT_BASE
EINT_BASE=64+5+32=101
7+64+5+32=108,里面各个数值都是什么意思呢?
要弄明白这个需要详细的了解一下arm中断的各个流程.
1. 系统中断的初始化.
2. 中断产生并进入中断处理函数
一. 中断初始化
从start_kernel开始看起,下面有四个函数跟中断初始化有关系
- asmlinkage void __init start_kernel(void)
- {
- setup_arch(); --> early_trap_init(); //1.中断向量表与中断函数的copy
- trap_init(); //空函数,不管它
- early_irq_init(); //2.初始化irq_desc数组
- init_IRQ(); //3.s3c6410内部64个中断的初始化
- rest_init(); //4. do_initcalls() --> s3c64xx_init_irq_eint();外部中断的初始化
- }
1. 中断向量与中断函数的拷贝
在arch/arm/kernel/traps.c中
- void __init early_trap_init(void)
- {
- //这儿定义了CONFIG_CPU_USE_DOMAINS
- unsigned long vectors = CONFIG_VECTORS_BASE; //BASE=0xffff0000
- extern char __stubs_start[], __stubs_end[];
- extern char __vectors_start[], __vectors_end[];
- extern char __kuser_helper_start[], __kuser_helper_end[];
- int kuser_sz = __kuser_helper_end - __kuser_helper_start;
- //copy中断向量表到0xffff000
- memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);
- //copy中量函数到0xffff000+0x200
- memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);
- //copy中断向量表到0xffff000
- memcpy((void *)vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz);
-
- kuser_get_tls_init(vectors);
-
- memcpy((void *)(vectors + KERN_SIGRETURN_CODE - CONFIG_VECTORS_BASE),
- sigreturn_codes, sizeof(sigreturn_codes));
- memcpy((void *)(vectors + KERN_RESTART_CODE - CONFIG_VECTORS_BASE),
- syscall_restart_code, sizeof(syscall_restart_code));
-
- flush_icache_range(vectors, vectors + PAGE_SIZE);
- modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
- }
2.初始化irq_desc结构体数组
在kernel/irq/irqdesc.c中,其中NR_IRQS=246
start_kernel
--> early_irq_init
- struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {
- [0 ... NR_IRQS-1] = {
- .handle_irq = handle_bad_irq,
- .depth = 1,
- .lock = __RAW_SPIN_LOCK_UNLOCKED(irq_desc->lock),
- }
- };
- int __init early_irq_init(void)
- {
- int count, i, node = first_online_node;
- struct irq_desc *desc;
- init_irq_default_affinity();
- desc = irq_desc;
- count = ARRAY_SIZE(irq_desc);
- for (i = 0; i < count; i++) {
- desc[i].kstat_irqs = alloc_percpu(unsigned int);
- alloc_masks(&desc[i], GFP_KERNEL, node);
- raw_spin_lock_init(&desc[i].lock);
- lockdep_set_class(&desc[i].lock, &irq_desc_lock_class);
- desc_set_defaults(i, &desc[i], node);
- }
- return arch_early_irq_init();
- }
#define ARCH_IRQ_INIT_FLAGS (IRQ_NOREQUEST | IRQ_NOPROBE)
start_kernel
--> early_irq_init
--> desc_set_defaults
- static void desc_set_defaults(unsigned int irq, struct irq_desc *desc, int node)
- {
- int cpu;
- desc->irq_data.irq = irq;
- desc->irq_data.chip = &no_irq_chip;
- desc->irq_data.chip_data = NULL;
- desc->irq_data.handler_data = NULL;
- desc->irq_data.msi_desc = NULL;
- irq_settings_clr_and_set(desc, ~0, _IRQ_DEFAULT_INIT_FLAGS); //初始化为IRQ_NOREQUEST | IRQ_NOPROBE
- irqd_set(&desc->irq_data, IRQD_IRQ_DISABLED);
- desc->handle_irq = handle_bad_irq;
- desc->depth = 1;
- desc->irq_count = 0;
- desc->irqs_unhandled = 0;
- desc->name = NULL;
- for_each_possible_cpu(cpu)
- *per_cpu_ptr(desc->kstat_irqs, cpu) = 0;
- desc_smp_init(desc, node);
- }
3. s3c6410内部64 个中断初始化
- 在arch/arm/kernel/iqr.c中
- void __init init_IRQ(void)
- {
- machine_desc->init_irq();
- }
-
- 在arch/arm/mach-s3c64xx/mach-smdk6410.c中
- MACHINE_START(SMDK6410, "SMDK6410")
- .boot_params = S3C64XX_PA_SDRAM + 0x100,
- .init_irq = s3c6410_init_irq,
- .map_io = smdk6410_map_io,
- .init_machine = smdk6410_machine_init,
- .timer = &s3c24xx_timer,
- MACHINE_END
-
- 在arch/arm/mach-s3c64xx/s3c6410.c中
- void __init s3c6410_init_irq(void)
- {
- /* VIC0 is missing IRQ7, VIC1 is fully populated. */
- s3c64xx_init_irq(~0 & ~(1 << 7), ~0);
- }
-
- //VIC0中的第7号中断是保留的,
-
- 在arch/arm/mach-s3c64xx/iqr.c中
- void __init s3c64xx_init_irq(u32 vic0_valid, u32 vic1_valid)
- {
- /* initialise the pair of VICs */
- vic_init(VA_VIC0, IRQ_VIC0_BASE, vic0_valid, 0);
- vic_init(VA_VIC1, IRQ_VIC1_BASE, vic1_valid, 0);
-
- /* add the timer sub-irqs */
- s3c_init_vic_timer_irq(5, IRQ_TIMER0);
-
- s3c_init_uart_irqs(uart_irqs, ARRAY_SIZE(uart_irqs));
- }
arch/arm/mach-s3c64xx/irq.c:s3c64xx_init_irq[55]: vic0_valid=0xffffff7f, vic1_valid=0xffffffff
arch/arm/mach-s3c64xx/irq.c:s3c64xx_init_irq[56]: VA_VIC0=0xf6000000, IRQ_VIC0_BASE=0x20
arch/arm/mach-s3c64xx/irq.c:s3c64xx_init_irq[57]: VA_VIC1=0xf6010000, IRQ_VIC1_BASE=0x40
#define VA_VIC0 (S3C_VA_IRQ + 0x00)
#define S3C_VA_IRQ S3C_ADDR(0x00000000) /* irq controller(s) */
#define S3C_ADDR(x) (S3C_ADDR_BASE + (x))
#define S3C_ADDR_BASE 0xF6000000
- void __init vic_init(void __iomem *base, unsigned int irq_start,
- u32 vic_sources, u32 resume_sources)
- {
- //读取vid,没有找到0xfe0这个是代表什么,不知道也没有多大影响
- for (i = 0; i < 4; i++) {
- u32 addr = ((u32)base & PAGE_MASK) + 0xfe0 + (i * 4);
- cellid |= (readl(addr) & 0xff) << (8 * i);
- }
- //VIC @f6000000: id 0x00041192, vendor 0x41
- vendor = (cellid >> 12) & 0xff;
- switch(vendor) {
- case AMBA_VENDOR_ST:
- vic_init_st(base, irq_start, vic_sources);
- return;
- default:
- printk(KERN_WARNING "VIC: unknown vendor, continuing anyways\n");
- case AMBA_VENDOR_ARM:
- break;
- }
- vic_disable(base); //3.1 禁止所有的中断
-
- vic_clear_interrupts(base); //PL190???这TMD是什么玩意?
-
- vic_init2(base); //又有PL190?我准备放弃搞懂这个函数
-
- vic_set_irq_sources(base, irq_start, vic_sources); //3.2 设置irq_desc中标志为可用
-
- vic_pm_register(base, irq_start, resume_sources); //3.3
- }
3.1 禁止所有的中断
- static void __init vic_disable(void __iomem *base)
- {
- //32位的寄存器,每一位代表一个中断
- writel(0, base + VIC_INT_SELECT); //将所有的中断都设为IRQ,不是FIQ
- writel(0, base + VIC_INT_ENABLE); //所有的中断都为disable状态
- writel(~0, base + VIC_INT_ENABLE_CLEAR); //写1是要清除VIC_INT_ENABLE的中断使能
- writel(0, base + VIC_IRQ_STATUS); //清除状态寄存器
- writel(0, base + VIC_ITCR); //TMD,VIC test control reg??
- writel(~0, base + VIC_INT_SOFT_CLEAR); //写1是要清除VICSOFTINT寄存器
- }
3.2 对64个内部中断的irq_desc重新设置其标志位
- static void __init vic_set_irq_sources(void __iomem *base, unsigned int irq_start, u32 vic_sources)
- {
- //vic_source是32bit,其中每1位置1的代表启用一个中断源
- //调用时vic0=~0 & ~(1 << 7),即不添加中断源7
- for (i = 0; i < 32; i++) {
- if (vic_sources & (1 << i)) { //只对置1的中断源进行处理
- unsigned int irq = irq_start + i; //vic的中断号是从iqr_start=32或64开始
- //通过中断号找到irq_desc结构体,并设置irq_desc的irq_data.chip与handle_irq
- irq_set_chip_and_handler(irq, &vic_chip, handle_level_irq);
- irq_set_chip_data(irq, base);
- set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); //1.2.1重新设置irq_desc中的标志位为IRQF_VALID
- }
- }
- }
vic0的中断号是32-64;
vic1的中断号是65-96;
3.2.1初始化irq_desc中的标志位state_use_accessors为IRQF_VALID|IRQF_PROBE
- void set_irq_flags(unsigned int irq, unsigned int iflags)
- {
- unsigned long clr = 0, set = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
-
- if (irq >= nr_irqs) {
- printk(KERN_ERR "Trying to set irq flags for IRQ%d\n", irq);
- return;
- }
- //清除在early_irq_init中设置的IRQ_NOREQUEST|IRQ_NOPROBE标志,重新设为
- //IRQ_VALID|IRQ_PROBE
- if (iflags & IRQF_VALID)
- clr |= IRQ_NOREQUEST;
- if (iflags & IRQF_PROBE)
- clr |= IRQ_NOPROBE;
- if (!(iflags & IRQF_NOAUTOEN))
- clr |= IRQ_NOAUTOEN;
-
- irq_modify_status(irq, clr, set & ~clr);
- }
4. 外部中断的初始化
start_kernel
--> do_initcalls()
--> s3c64xx_init_irq_eint()
- static int __init s3c64xx_init_irq_eint(void)
- {
- int irq;
- //6410的外部中断号是从IRQ_EINT(0)=101 到 IRQ_EINT(27)=128
- //对101-128的外部中断,初始化其irq_desc结构体,
- //其中断处理函数是handle_level_irq
- for (irq = IRQ_EINT(0); irq <= IRQ_EINT(27); irq++) {
- irq_set_chip_and_handler(irq, &s3c_irq_eint, handle_level_irq);
- irq_set_chip_data(irq, (void *)eint_irq_to_bit(irq));
- set_irq_flags(irq, IRQF_VALID);
- }
- //对未映射之前的中断号为(0,1,32,33)-->现在的(32,33,64,65)
- //对这四个中断注册其中断处理函数
- irq_set_chained_handler(IRQ_EINT0_3, s3c_irq_demux_eint0_3);
- irq_set_chained_handler(IRQ_EINT4_11, s3c_irq_demux_eint4_11);
- irq_set_chained_handler(IRQ_EINT12_19, s3c_irq_demux_eint12_19);
- irq_set_chained_handler(IRQ_EINT20_27, s3c_irq_demux_eint20_27);
-
- return 0;
- }
在include/linux/irq.h中
start_kernel
--> do_initcalls()
--> s3c64xx_init_irq_eint()
--> irq_set_chained_handler
irq_set_chained_handler(IRQ_EINT4_11, s3c_irq_demux_eint4_11);
- static inline void
- irq_set_chained_handler(unsigned int irq, irq_flow_handler_t handle)
- {
- __irq_set_handler(irq, handle, 1, NULL); //irq=33(33-32=1即INT_EINT1)
- }
start_kernel
--> do_initcalls()
--> s3c64xx_init_irq_eint()
--> irq_set_handler
在kernel/irq/chip.c中
- void __irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, const char *name)
- {
- //其它的省略只看办正事的地方
- desc->handle_irq = handle; //注册中断处理函数
- desc->name = name; //name=NULL
- }
二.以usr_irq为例分析中断调用过程
1. 中断向量表
中断向量表在arch/arm/kernel/entry-armv.S中
- .globl __vectors_start
- __vectors_start:
- ARM( swi SYS_ERROR0 )
- THUMB( svc #0 )
- THUMB( nop )
- W(b) vector_und + stubs_offset
- W(ldr) pc, .LCvswi + stubs_offset
- W(b) vector_pabt + stubs_offset
- W(b) vector_dabt + stubs_offset
- W(b) vector_addrexcptn + stubs_offset
- W(b) vector_irq + stubs_offset
- W(b) vector_fiq + stubs_offset
-
- .globl __vectors_end
- __vectors_end:
a. 当有irq中断发生时,就会调用vector_irq.但是vector_irq在哪呢?
搜一下linux源代码也没有找到一个vector_irq,难道是弄错了?
实际上vector_irq是通过vector_stub这个宏来定义的.
b. 跳转的地址是怎么确定的呢?
以 b vector_irq + stubs_offset 为例
在entry-armv.S中有:
.equ stubs_offset, __vectors_start + 0x200 - __stubs_start
所以 vector_irq + stubs_offset =
vector_irq + __vectors_start + 0x200 - __stubs_start =
(vecor_irq - __stubs_start) + (__vectors_start + 0x200)
即: 相对于中断函数首地址的偏移 + 中断函数首地址
在arch/arm/kernel/entry-armv.S中有
- __stubs_start:
- vector_stub irq, IRQ_MODE, 4 ;马上分析这个宏的作用
- .long __irq_usr @ 0 (USR_26 / USR_32)
- .long __irq_invalid @ 1 (FIQ_26 / FIQ_32)
- .long __irq_invalid @ 2 (IRQ_26 / IRQ_32)
- .long __irq_svc @ 3 (SVC_26 / SVC_32)
- .long __irq_invalid @ 4
- .long __irq_invalid @ 5
2. 用vector_stub 产生中断函数
把vector_stub irq, IRQ_MODE, 4展开后是:
在arch/arm/kernel/entry-armv.S中
- vector_stub irq, IRQ_MODE, 4
- .macro vector_stub, name, mode, correction=0
- vector_irq: ;看到没有vector_irq,它老人家终于出来了
- .if 4
- sub lr, lr, #4
- .endif
-
- ;将r0,lr,spsr压栈
- stmia sp, {r0, lr} ;将r0,lr寄存器压栈
- mrs lr, spsr ;将spsr保存在lr中
- str lr, [sp, #8] ;将lr压栈,即保存spsr
-
- ;将SVC_MODE保存到spsr中,准备切换到svc
- mrs r0, cpsr ;读取cpsr到r0
- eor r0, r0, #(IRQ_MODE ^ SVC_MODE | PSR_ISETSTATE) ;将r0设为SVC_MODE
- msr spsr_cxsf, r0 ;将r0中的SVC_MODE写到spsr中,通过movs就可以切换到SVC模式了
-
- and lr, lr, #0x0f ;usr模式(10000)的低4位==0,SVC模式(10011)的低4位==3,
- THUMB( adr r0, 1f ) ;这几句没有完全弄明白
- THUMB( ldr lr, [r0, lr, lsl #2] ) ;
- mov r0, sp ;
- ARM( ldr lr, [pc, lr, lsl #2] ) ;感觉是要跳到这个宏的下几句进行
- movs pc, lr ;跳转到下一条指令,并cpsr会被spsr覆盖即切换到SVC模式
- ENDPROC(vector_irq)
-
- .align 2
- 1:
- .endm
以spsr中的低四位为索引,对pc值进行调整:
如果上述是从user模式进入,则会跳到__irq_users处执行
如果上述是从svc模式进入,则会跳到 __irq_svc处执行
3. 进入irq_usr
从中断向量表中查找到中断函数,然后进入中断函数的处理过程__irq_usr
在arhc/arm/kernel/entry-armv.S中
- .align 5
- __irq_usr:
- usr_entry
- kuser_cmpxchg_check
- get_thread_info tsk
- irq_handler ;irq_handler继续调用
- mov why, #0
- b ret_to_user_from_irq
- UNWIND(.fnend )
- ENDPROC(__irq_usr)
__irq_usr
--> irq_handler
- 在arch/arm/kernel/entry-armv.S中
- .macro irq_handler
- arch_irq_handler_default
- 9997:
- .endm
__irq_usr
--> irq_handler
--> arch_irq_handler_default
- 在arm/include/asm/entry-macro-multi.S中
- .macro arch_irq_handler_default
- get_irqnr_preamble r5, lr
- 1: get_irqnr_and_base r0, r6, r5, lr ;3.1获取中断号
- movne r1, sp
- adrne lr, BSYM(1b)
- bne asm_do_IRQ ;3.2进入中断处理函数
- 9997:
- .endm
3.1 获取中断号
从寄存器中读取的中断号的范围是(0-64),但是实际上这儿把中断号读取出来之后,都加了一个固定值32
所以真正的中断号的取值范围是(0-64)+32.
在arch/arm/include/asm/entry-macro-vic2.S中
.
macro get_irqnr_preamble
,
base
,
tmp
- ldr \base, =VA_VIC0
- .endm
-
- @base是VA_VIC0
- .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
- mov \irqnr, #IRQ_VIC0_BASE + 31 //为什么这儿要加上31呢?是因为clz这个指令
- ldr \irqstat, [ \base, # VIC_IRQ_STATUS ] //读取VIC_IRQ_STATUS的值,也就是中断号的值(加上"的值"比较确切)
- teq \irqstat, #0 //看irqstat是不是0,如果是0,标志位Z=1
-
- @ otherwise try vic1 //下面的一串eq执行说明vic0没有产生中断irqstat==0
- addeq \tmp, \base, #(VA_VIC1 - VA_VIC0) //
- addeq \irqnr, \irqnr, #(IRQ_VIC1_BASE - IRQ_VIC0_BASE)
- ldreq \irqstat, [ \tmp, # VIC_IRQ_STATUS ]
- teqeq \irqstat, #0 //看irqstat是不是0,如果是0,标志位Z=1
- //下面两句ne执行说明Z=0, 即irqstat不为0,再即有中断产生
- clzne \irqstat, \irqstat //判断是哪一位产生了中断,但是clz是从高向低计数的,实际的中断号是(32-highnr)
- subne \irqnr, \irqnr, \irqstat //irqnr = (IRQ_BASE+31)-highnr = IRQ_BASE+(31-high_nr)也就是加上实际的中断号
- .endm
注意:
a. teq \irqstat, #0 判断irqstat是不是等于0,如果等于0,则cpsr中Z置位.
后面的指令都代着eq,如果Z=1则执行,反之则不执行
b. clz {cond} Rd, Rm
对Rm中leading zeros的个数进行计数,将结果存在Rd中 P { margin-bottom: 0.08in; direction: ltr; color: rgb(0, 0, 0); text-align: justify; }P.western { font-family: "細明體","MingLiU",monospace; font-size: 12pt; }P.cjk { font-family: "細明體","MingLiU",monospace; font-size: 12pt; }P.ctl { font-family: "細明體","MingLiU",monospace; font-size: 12pt; }
(leading zeros: Rm中从高位向低位进行查找,直至遇到1为止,将0的个数统计出来)
例: 0x0000 0000 --> 32;
0x0000 000F --> 24;
0x0F00 0000 --> 4 ;
0x8000 0000 --> 0;
c. 总结一下上面的代码:
如果vic0产生了中断, 读取中断号的值,判断中断号是不是0,不是0,则跳到clz句判断中断号;
3.2 进入c语言的中断处理函数asm_do_IRQ
在arch/arm/kernel/irq.c中
__irq_usr
--> irq_handler
--> arch_irq_handler_default
--> asm_do_IRQ
- asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
- {
- struct pt_regs *old_regs = set_irq_regs(regs);
- irq_enter();
-
- if (unlikely(irq >= nr_irqs)) { //判断中断号是否超出范围
- if (printk_ratelimit())
- printk(KERN_WARNING "Bad IRQ%u\n", irq);
- ack_bad_irq(irq);
- } else {
- generic_handle_irq(irq); //封装,继续调用
- }
-
- /* AT91 specific workaround */
- irq_finish(irq);
-
- irq_exit();
- set_irq_regs(old_regs);
- }
__irq_usr
--> irq_handler
--> arch_irq_handler_default
--> asm_do_IRQ
--> generic_handler_irq
- int generic_handle_irq(unsigned int irq)
- {
- struct irq_desc *desc = irq_to_desc(irq);
-
- if (!desc)
- return -EINVAL;
- generic_handle_irq_desc(irq, desc); //封装,继续调用
- return 0;
- }
- EXPORT_SYMBOL_GPL(generic_handle_irq);
--> asm_do_IRQ
--> generic_handler_irq
--> generic_handler_irq_desc
- static inline void generic_handle_irq_desc(unsigned int irq, struct irq_desc *desc)
- {
- desc->handle_irq(irq, desc); //调用每个中断的中断处理函数
- }
注意,上面的desc->handle_irq是在 s3c64xx_init_irq_eint() 中注册的,
以dm9000的eint(7)为例说明一下:
irq_set_chained_handler(IRQ_EINT4_11, s3c_irq_demux_eint4_11);
即注册 desc->handle_irq= s3c_irq_demux_eint4_11
3.3 分发外部中断
--> asm_do_IRQ
--> generic_handler_irq
--> generic_handler_irq_desc
--> s3c_irq_demux_eint4_11
在arch/arm/mach-s3c64xx/irq-eint.c中
- static void s3c_irq_demux_eint4_11(unsigned int irq, struct irq_desc *desc)
- {
- s3c_irq_demux_eint(4, 11);
- }
--> asm_do_IRQ
--> generic_handler_irq
--> generic_handler_irq_desc
--> s3c_irq_demux_eint4_11
--> s3c_irq_demux_eint
在arch/arm/mach-s3c64xx/irq-eint.c中
- static inline void s3c_irq_demux_eint(unsigned int start, unsigned int end)
- {
- u32 status = __raw_readl(S3C64XX_EINT0PEND);
- u32 mask = __raw_readl(S3C64XX_EINT0MASK);
- unsigned int irq;
- status &= ~mask;
- status >>= start;
- status &= (1 << (end - start + 1)) - 1;
- //当dm9000发生中断时,这儿的status=8=1000b,start=4,end=11
- for (irq = IRQ_EINT(start); irq <= IRQ_EINT(end); irq++) {
- if (status & 1)
- generic_handle_irq(irq); //irq=IRQ_EINT(7)
- status >>= 1;
- }
- }
从IRQ_EINT(4)开始stauts向右移1位,当status==1时,正好是IRQ_EINT(7)
IRQ_EINT(7)正好是在dm9000注册的中断号
3.4 第二次调用generic_handle_irq
- int generic_handle_irq(unsigned int irq)
- {
- struct irq_desc *desc = irq_to_desc(irq);
-
- if (!desc)
- return -EINVAL;
- generic_handle_irq_desc(irq, desc);
- return 0;
- }
- static inline void generic_handle_irq_desc(unsigned int irq, struct irq_desc *desc)
- {
- desc->handle_irq(irq, desc);
- }
这次的desc->handle_irq是谁呢?
注意,上面的desc->handle_irq也是在 s3c64xx_init_irq_eint() 中注册的,
但这次不一样的,要不成死循环了,这次是 desc->handle_irq= handle_level_irq
三.驱动调用request_irq申请中断
dm9000申请中断:
request_irq(dev->irq, dm9000_interrupt, irqflags, dev->name, dev);
其中: dev->irq=EINT(7)=108, irqflags=0x84=IRQF_SAMPLE_RANDOM|IRQF_SHARED
在include/linux/interrupt.h中
- static inline int __must_check
- request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
- const char *name, void *dev)
- {
- return request_threaded_irq(irq, handler, NULL, flags, name, dev);
- }
在kernel/irq/maage.c中
- int request_threaded_irq(unsigned int irq, irq_handler_t handler,
- irq_handler_t thread_fn, unsigned long irqflags,
- const char *devname, void *dev_id)
- {
- struct irqaction *action;
- struct irq_desc *desc;
- int retval;
-
- if ((irqflags & IRQF_SHARED) && !dev_id) //如果是共享中断,缺没有定义dev_id返回错误
- return -EINVAL;
-
- desc = irq_to_desc(irq); //根据中断号在irq_desc数组中找到对应的irq_desc结构体
-
- //这个东东在哪初始化的呢?
- if (!irq_settings_can_request(desc)) //!(status_use_accessors & _IRQ_NOREQUEST)
- return -EINVAL;
-
- if (!handler) { //检查有没有指定中断处理函数
- if (!thread_fn)
- return -EINVAL;
- handler = irq_default_primary_handler;
- }
-
- action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
-
- action->handler = handler;
- action->thread_fn = thread_fn;
- action->flags = irqflags;
- action->name = devname;
- action->dev_id = dev_id;
-
- chip_bus_lock(desc);
- retval = __setup_irq(irq, desc, action);
- chip_bus_sync_unlock(desc);
-
- if (retval)
- kfree(action);
- return retval;
- }
附录:
1. s3c6410的外部中断
section 12.3
s3c6410的外部中断eint0-4,共5个
- NO SOURCES Description Group
- 0 INT_EINT0 External interrupt 0-3 VIC0
- 1 INT_EINT1 External interrupt 4-11 VIC0
- 32 INT_EINT2 External interrupt 12-19 VIC1
- 33 INT_EINT3 External interrupt 20-27 VIC1
- 53 INT_EINT4 External interrupt Group 1-9 VIC1
外部中断0-3会触发0号中断
外部中断4-11会触发1号中断
外部中断12-19会触发32号中断
外部中断20-27会触发33号中断
- XEINT0/GPN0 XEINT1/GPN1 XEINT2/GPN2 XEINT3/GPN3
- XEINT4/GPN4 XEINT5/GPN5 XEINT6/GPN6 XEINT7/GPN7
- XINT8/GPN8 XINT9/GPN9 XEINT10/GPN10 XINT11/GPN11
- XEINT12/GPN12 XEINT13/GPN13 XEINT14/GPN14 XEINT15/GPN15
- EINT16/GPL8 EINT17/GPL9 EINT18/GPL10 EINT19/GPL11
- EINT20/GPL12 EINT21/GPL13 EINT22/GPL14 EINT23/GPM0
- EINT24/GPM1 EINT25/GPM2 EINT26/GPM3 EINT27/GPM4
2. 总结一下s3c6410的中断
- 以IRQ_EINT(7)为例:
- 7+64+5+32 = 108
- 32: 起始偏移
- 64: s3c6410的中断号顺次排列
- 5: 时钟中断
- 7: 外部中断