外部中断原理分析

发表于:2007-07-04来源:作者:点击数: 标签:
linux 的外部中断分为固定部分和可变部分,固定部分为0~~15号的系统本身定义的中断,而可变部分则是提供给用户自己定义设备驱动的中断相应的,前两天稍微写了一点这方面的分析 MI LY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-famil
      linux的外部中断分为固定部分和可变部分,固定部分为0~~15号的系统本身定义的中断,而可变部分则是提供给用户自己定义设备驱动的中断相应的,前两天稍微写了一点这方面的分析

MILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">外部中断可变部分描述:

irq_desc[]数组描述

Irq_desc_t:

typedef struct {

       unsigned int status;        /* IRQ status */

       hw_irq_controller *handler;

       struct irqaction *action;  /* IRQ action list */

       unsigned int depth;        /* nested irq disables */

       spinlock_t lock;

} ____cacheline_aligned irq_desc_t;

 

 

Irq状态是由以下各标志组合的:

unsigned int status;        /* IRQ status */

#define IRQ_INPROGRESS 1     /* IRQ handler active - do not enter! */

#define IRQ_DISABLED      2     /* IRQ disabled - do not enter! */

#define IRQ_PENDING       4     /* IRQ pending - replay on enable */

#define IRQ_REPLAY   8     /* IRQ has been replayed but not acked yet */

#define IRQ_AUTODETECT       16    /* IRQ is being autodetected */

#define IRQ_WAITING 32    /* IRQ not yet seen - for autodetection */

#define IRQ_LEVEL     64    /* IRQ level triggered */

#define IRQ_MASKED 128  /* IRQ masked - shouldn't be seen again */

#define IRQ_PER_CPU 256  /* IRQ is per CPU */

 

struct irqaction *action;  /* IRQ action list */

描述外部中断的可变部分,对一个外部中断的所有处理将以irqaction结构挂在action队列上

Interrupt.hàirqaction:

struct irqaction {

       void (*handler)(int, void *, struct pt_regs *);

       unsigned long flags;

       unsigned long mask;

       const char *name;

       void *dev_id;

       struct irqaction *next;

};

Handler中断处理函数,dev_id设备标识,用于标记多个设备共享同一个irq

 

时间中断处理程序为timer_interrupt

 

外部设备的驱动程序在初始化时都要创建自己的irqaction结构

Irq.cà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)

              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);

 

       if (retval)

              kfree(action);

       return retval;

}

 

调用setup_arm_irq向内存申请一块内存填写irqaction结构,返回irq

该函数完成以下工作:

(1)       在数组irq_desc[]中找到程序申请的irq号对应的action队列

(2)       如果该队列不为空,说明该irq号被多个设备共享,检查这种共享是否允许(由老的irqaction结构的flags标识),如果合法,则将新的irqaction结构插到对应的action队列的末尾

(3)       如果队列为空,则将irqaction结构插在对应action队列的头部,填写irq_desc[irq]的其他域

 

至此外部设备驱动向系统注册中断完成

 

中断释放:

void free_irq(unsigned int irq, void *dev_id)

完成以下工作:

(1)       检查irq的合法性

(2)       action队列irq_desc[irq].action上,查找action->dev_id == dev_idirqaction结构

(3)       如果找到这样的结构,则将其从队列上摘下,同时释放其原本占用的内存空间

(4)       如果释放后,irq_desc[irq]上已经没有其他的irqaction结构,则释放irq_desc[irq]上的相应域,关掉中断

原文转自:http://www.ltesting.net