所谓技术

-----simple,sometimes naive!
posts - 11, comments - 0, trackbacks - 0, articles - 0
  IT博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

内核中断的注册与申请

Posted on 2008-04-25 16:42 vsolo 阅读(1392) 评论(0)  编辑 收藏 引用 所属分类: LINUX

(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;
};

只有注册用户登录后才能发表评论。