Linux经过以下函数来注册中止以及中止相关的进口函数handle,只要先注册IRQ,才干正常运用。
- intset_irq_chip(unsignedintirq,structirq_chip*chip)
- staticinlinevoidset_irq_handler(unsignedintirq,irq_flow_handler_thandle)
- staticinlinevoidset_irq_chained_handler(unsignedintirq,irq_flow_handler_thandle)
完结的代码如下:
- for(irqno=IRQ_EINT4t7;irqno<=IRQ_ADCPARENT;irqno++){
- /*setallthes3c2410internalirqs*/
- switch(irqno){
- /*dealwiththespecialIRQs(cascaded)*/
- caseIRQ_EINT4t7:
- caseIRQ_EINT8t23:
- caseIRQ_UART0:
- caseIRQ_UART1:
- caseIRQ_UART2:
- caseIRQ_ADCPARENT:
- set_irq_chip(irqno,&s3c_irq_level_chip);
- set_irq_handler(irqno,handle_level_irq);//电平触发型
- break;
- caseIRQ_RESERVED6:
- caseIRQ_RESERVED24:
- /*noIRQhere*/
- break;
- default:
- //irqdbf(“registeringirq%d(s3cirq)\n”,irqno);
- set_irq_chip(irqno,&s3c_irq_chip);
- set_irq_handler(irqno,handle_edge_irq);//边际触发型
- set_irq_flags(irqno,IRQF_VALID);
- }
- /*级联中止的注册*/
- set_irq_chained_handler(IRQ_EINT4t7,s3c_irq_demux_extint4t7);
- set_irq_chained_handler(IRQ_EINT8t23,s3c_irq_demux_extint8);
- set_irq_chained_handler(IRQ_UART0,s3c_irq_demux_uart0);
- set_irq_chained_handler(IRQ_UART1,s3c_irq_demux_uart1);
- set_irq_chained_handler(IRQ_UART2,s3c_irq_demux_uart2);
- set_irq_chained_handler(IRQ_ADCPARENT,s3c_irq_demux_adc);
- /*externalinterrupts*/
- for(irqno=IRQ_EINT0;irqno<=IRQ_EINT3;irqno++){
- irqdbf(“registeringirq%d(extint)\n”,irqno);
- set_irq_chip(irqno,&s3c_irq_eint0t4);
- set_irq_handler(irqno,handle_edge_irq);
- set_irq_flags(irqno,IRQF_VALID);
- }
- for(irqno=IRQ_EINT4;irqno<=IRQ_EINT23;irqno++){
- irqdbf(“registeringirq%d(extendeds3cirq)\n”,irqno);
- set_irq_chip(irqno,&s3c_irqext_chip);
- set_irq_handler(irqno,handle_edge_irq);
- set_irq_flags(irqno,IRQF_VALID);
- }
- /*registertheuartinterrupts*/
- irqdbf(“s3c2410:registeringexternalinterrupts\n”);
- for(irqno=IRQ_S3CUART_RX0;irqno<=IRQ_S3CUART_ERR0;irqno++){
- irqdbf(“registeringirq%d(s3cuart0irq)\n”,irqno);
- set_irq_chip(irqno,&s3c_irq_uart0);
- set_irq_handler(irqno,handle_level_irq);
- set_irq_flags(irqno,IRQF_VALID);
- }
- for(irqno=IRQ_S3CUART_RX1;irqno<=IRQ_S3CUART_ERR1;irqno++){
- irqdbf(“registeringirq%d(s3cuart1irq)\n”,irqno);
- set_irq_chip(irqno,&s3c_irq_uart1);
- set_irq_handler(irqno,handle_level_irq);
- set_irq_flags(irqno,IRQF_VALID);
- }
- for(irqno=IRQ_S3CUART_RX2;irqno<=IRQ_S3CUART_ERR2;irqno++){
- irqdbf(“registeringirq%d(s3cuart2irq)\n”,irqno);
- set_irq_chip(irqno,&s3c_irq_uart2);
- set_irq_handler(irqno,handle_level_irq);
- set_irq_flags(irqno,IRQF_VALID);
- }
- for(irqno=IRQ_TC;irqno<=IRQ_ADC;irqno++){//详细注册IRQ_TC、IRQ_ADC
- irqdbf(“registeringirq%d(s3cadcirq)\n”,irqno);
- set_irq_chip(irqno,&s3c_irq_adc);
- set_irq_handler(irqno,handle_edge_irq);
- set_irq_flags(irqno,IRQF_VALID);
- }
从以上代码中能够看出,注册中止主要是注册中止服务程序进口。Linux中将一切的中止号用一个stuctirq_desc数据结构进行统一管理,每个中止号或许一组中止号(如级联的中止),对应一个structirq_desc, 所以依据相应的中止号,能够获取对应的中止描绘结构irq_desc:
- structirq_desc*desc=irq_to_desc(irq);
- irq_desc数据结构如下:
- structirq_desc{
- unsignedintirq;//中止号
- …
- irq_flow_handler_thandle_irq;//体系中止处理的进口函数
- structirq_chip*chip;//对应的irq_chip结构,界说了与中止处理有关的函数
- …
- structirqaction*action;//用户的中止处理函数,调用request_irq时增加
- unsignedintstatus;//IRQ的状况
- …
- spinlock_tlock;
- …
- constchar*name;
- }____cacheline_internodealigned_in_smp;
irq_chip结构界说了各种中止相关的处理行为,如舱位或制止中止以及中止服务完结的之后对相关的中止寄存器进行处理。关于电平触发型和边际型触发中止进口函数能够从irq_chip结构中的看出只要ack函数的处理不同:
- structirq_chips3c_irq_level_chip={
- .name=”s3c-level”,
- .ack=s3c_irq_maskack,
- .mask=s3c_irq_mask,
- .unmask=s3c_irq_unmask,
- .set_wake=s3c_irq_wake
- };
- structirq_chips3c_irq_chip={
- .name=”s3c”,
- .ack=s3c_irq_ack,
- .mask=s3c_irq_mask,
- .unmask=s3c_irq_unmask,
- .set_wake=s3c_irq_wake
- };
在s3cirq_maskack中多了以下代码:
mask = __raw_readl(S3C2410_INTMSK);
__raw_writel(mask|bitval, S3C2410_INTMSK);
完结的功用是,屏蔽相应的中止。
在early_trap_init()中现已进行了中止(反常)向量的初始化,将反常向量表从物理地址0x00000000拷贝到虚拟0xffff0000的虚拟地址处。反常向量在arch/arm/kernel/entry-armv.S中界说:
- .globl__vectors_start
- rs_start:
- swiSYS_ERROR0
- bvector_und+stubs_offset
- ldrpc,.LCvswi+stubs_offset
- bvector_pabt+stubs_offset
- bvector_dabt+stubs_offset
- bvector_addrexcptn+stubs_offset
- bvector_irq+stubs_offset
- bvector_fiq+stubs_offset
- .globl__vectors_end
那么当有中止发生时:
- /*
- *Interrupthandling.Preservesr7,r8,r9
- */
- .macroirq_handler
- get_irqnr_preambler5,lr
- 1:get_irqnr_and_baser0,r6,r5,lr
- movner1,sp
- @
- @routinecalledwithr0=irqnumber,r1=structpt_regs*
- @
- adrnelr,1b
- bneasm_do_IRQ//跳转到这儿中止的总进口函数
这儿的asm_do_IRQ对应arch/arm/kernel/irq.c中:
- asmlinkagevoid__exceptionasm_do_IRQ(unsignedintirq,structpt_regs*regs)
所以这是Linux中一切中止的总进口函数。asm_doIRQ()调用generic_handle_irq()再后调用
generic_handle_irq_desc(),最终到各个irq_desc的处理。
- staticinlinevoidgeneric_handle_irq_desc(unsignedintirq,structirq_desc*desc)
- {
- #ifdefCONFIG_GENERIC_HARDIRQS_NO__DO_IRQ
- desc->handle_irq(irq,desc);
- #else
- if(likely(desc->handle_irq))
- desc->handle_irq(irq,desc);
- else
- __do_IRQ(irq);
- #endif
- }
从总进口到用户的中止处理函数的流程:
asm_do_IRQ() –-> generic_handle_irq() –->irq_dsc->handle() à handle_IRQ_event() à irq_des->action()
最终对中止处理流程进行简略总结:
(1)总进口函数asm_do_IRQ,获取中止号irq
(2)asm_do_IRQ依据中止号调用各中止号所注册的中止进口函数irq_desc[irq]->handle_irq
(3)最终在中止进口函数中调用handle_IRQ_event()顺次碑文用户的中止处理函数action