分类: LINUX
2008-05-19 16:08:45
(1)系统启动时注册中断:
-----------------------------------
#define IRQ_BATT_FLT S3C2410_IRQ(7)
······························
#define IRQ_LCD S3C2410_IRQ(16) /* 32 */
······························
#define IRQ_ADCPARENT S3C2410_IRQ(31)
/* interrupts generated from the external interrupts sources */
#define IRQ_EINT4 S3C2410_IRQ(32) /* 48 */
#define IRQ_EINT5 S3C2410_IRQ(33)
----------------------------------
MACHINE_START(SMDK2410, "SMDK2410")
··································
.init_irq = smdk2410_init_irq, //中断初始化函数
··································
MACHINE_END
----------------------------------
/*
* Set of macros to define architecture features. This is built into
* a table by the linker.
*/
#define MACHINE_START(_type,_name) \
static const struct machine_desc __mach_desc_##_type \
__attribute_used__ \
__attribute__((__section__(".arch.info.init"))) = { \
.nr = MACH_TYPE_##_type, \
.name = _name,
#define MACHINE_END \
};
----------------------------------
函数smdk2410_init_irq()的调用过程:
<./linux/arch/arm/kernel/head.S>---------------------
/*
* Lookup machine architecture in the linker-build list of architectures.
* Note that we can't use the absolute addresses for the __arch_info
* lists since we aren't running with the MMU on (and therefore, we are
* not in the correct address space). We have to calculate the offset.
*
* r1 = machine architecture number
* Returns:
* r3, r4, r6 corrupted
* r5 = mach_info pointer in physical address space
*/
.type __lookup_machine_type, %function
__lookup_machine_type:
adr r3, 3b
ldmia r3, {r4, r5, r6}
sub r3, r3, r4 @ get offset between virt&phys
add r5, r5, r3 @ convert virt addresses to
add r6, r6, r3 @ physical address space
1: ldr r3, [r5, #MACHINFO_TYPE] @ get machine type
teq r3, r1 @ matches loader number?
beq 2f @ found
add r5, r5, #SIZEOF_MACHINE_DESC @ next machine_desc
cmp r5, r6
blo 1b
mov r5, #0 @ unknown machine
2: mov pc, lr
/*
* This provides a C-API version of the above function.
*/
ENTRY(lookup_machine_type)
stmfd sp!, {r4 - r6, lr}
mov r1, r0
bl __lookup_machine_type
mov r0, r5
ldmfd sp!, {r4 - r6, pc}
--------------------------------
在start_kernel()中:
setup_arch(&command_line):
mdesc = setup_machine(machine_arch_type);
// 此函数将调用head.S中的lookup_machine_type得到对应
// machine_arch_type的machine_desc
init_arch_irq = mdesc->init_irq; //指向smdk2410_init_irq
init_IRQ():
init_arch_irq(); //执行smdk2410_init_irq()
//完成中断初始化
--------------------------------
static void __init smdk2410_init_irq(void)
{
s3c24xx_init_irq();
}
--------------------------------
void __init s3c24xx_init_irq(void)
{
·····················
/* register the main interrupts */
irqdbf("s3c2410_init_irq: registering s3c2410 interrupt handlers\n");
for (irqno = IRQ_BATT_FLT; irqno <= IRQ_ADCPARENT; irqno++) {
/* set all the s3c2410 internal irqs */
switch (irqno) {
/* deal with the special IRQs (cascaded) */
case IRQ_UART0:
case IRQ_UART1:
case IRQ_UART2:
case IRQ_ADCPARENT:
set_irq_chip(irqno, &s3c_irq_level_chip);
set_irq_handler(irqno, do_level_IRQ);
break;
case IRQ_RESERVED6:
case IRQ_RESERVED24:
/* no IRQ here */
break;
default:/* 非级联中断的中断例程相同 */
//irqdbf("registering irq %d (s3c irq)\n", irqno);
set_irq_chip(irqno, &s3c_irq_chip);
set_irq_handler(irqno, do_edge_IRQ);
set_irq_flags(irqno, IRQF_VALID);
}
}
/* setup the cascade irq handlers */
/* 级联中断有各自的中断例程 */
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);
/* external interrupts */
for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) {
irqdbf("registering irq %d (ext int)\n", irqno);
set_irq_chip(irqno, &s3c_irq_eint0t4);
set_irq_handler(irqno, do_edge_IRQ);
set_irq_flags(irqno, IRQF_VALID);
}
for (irqno = IRQ_EINT4; irqno <= IRQ_EINT23; irqno++) {
irqdbf("registering irq %d (extended s3c irq)\n", irqno);
set_irq_chip(irqno, &s3c_irqext_chip);
set_irq_handler(irqno, do_edge_IRQ);
set_irq_flags(irqno, IRQF_VALID);
}
······················
}
其中中断例程do_edge_IRQ() -> __do_irq() 中ret = action->handler(irq, action->dev_id, regs)
完成驱动中的中断处理例程s3c2410fb_irq的调用。
-------------------------------------
(2)驱动申请中断:
ret = request_irq(irq, s3c2410fb_irq, IRQF_DISABLED, pdev->name, info);
其中irq即为IRQ_LCD;
-------------------------------------
int request_irq(unsigned int irq, irqreturn_t (*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;
/* 检查中断号irq是否注册(有效) */
action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL);
if (!action)
return -ENOMEM;
action->handler = handler;
action->flags = irq_flags;
cpus_clear(action->mask);
action->name = devname;
action->next = NULL;
action->dev_id = dev_id;
retval = setup_irq(irq, action);
/ * 关联中断处理例程到对应的中断描述结构体irqdesc */
if (retval)
kfree(action);
return retval;
}
<./linux/include/asm-arm/mach/irq.h>------------------------
struct irqdesc {
irq_handler_t handle;
struct irqchip *chip;
struct irqaction *action;
struct list_head pend;
void *chipdata;
void *data;
unsigned int disable_depth;
unsigned int triggered: 1; /* IRQ has occurred */
unsigned int running : 1; /* IRQ is running */
unsigned int pending : 1; /* IRQ is pending */
unsigned int probing : 1; /* IRQ in use for a probe */
unsigned int probe_ok : 1; /* IRQ can be used for probe */
unsigned int valid : 1; /* IRQ claimable */
unsigned int noautoenable : 1; /* don't automatically enable IRQ */
unsigned int unused :25;
struct proc_dir_entry *procdir;
#ifdef CONFIG_SMP
cpumask_t affinity;
unsigned int cpu;
#endif
/*
* IRQ lock detection
*/
unsigned int lck_cnt;
unsigned int lck_pc;
unsigned int lck_jif;
};