linux的外部中断分为固定部分和可变部分,固定部分为0~~15号的系统本身定义的中断,而可变部分则是提供给用户自己定义设备驱动的中断相应的,前两天稍微写了一点这方面的分析
外部中断可变部分描述:
以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_id的irqaction结构
(3) 如果找到这样的结构,则将其从队列上摘下,同时释放其原本占用的内存空间
(4) 如果释放后,irq_desc[irq]上已经没有其他的irqaction结构,则释放irq_desc[irq]上的相应域,关掉中断
评论