每个中断向量都有自己的irq_desc_t描述符,所有的这些描述符组织在一起形成irq_desc数组。
typedef struct irq_desc {
hw_irq_controller *handler;指向pic对象(hw_irq_controller描述符),服务于irq线
void *handler_data;指向pic方法所使用的数据
struct irqaction *action; /* IRQ action list */标识当出现irq时要调用的中断服务例程。该字段指向irq的irqaction描述符链表的第一个元素。
unsigned int status; /* IRQ status */描述irq线状态的一组标志
unsigned int depth; /* nested irq disables */如果irq线被激活,则显示0;如果irq线被禁止了不止一次,则显示一个正数
unsigned int irq_count; /* For detecting broken interrupts */中断计数器,统计irq线上发生的中断计数
unsigned int irqs_unhandled;中断计数器,统计irq线上发生的无法处理的中断进行计数
spinlock_t lock;用于串行访问irq描述符和pic的自旋锁。
} ____cacheline_aligned irq_desc_t;
extern irq_desc_t irq_desc [NR_IRQS];
/*
* IRQ line status.
*/
#define IRQ_INPROGRESS 1 /* IRQ handler active - do not enter! */IRQ的一个处理程序正在执行
#define IRQ_DISABLED 2 /* IRQ disabled - do not enter! */由一个设备驱动程序故意地禁用irq线
#define IRQ_PENDING 4 /* IRQ pending - replay on enable */一个irq已经出现在线上,它的出现也已对pic做出应答,但是内核还没有为它提供服务
#define IRQ_REPLAY 8 /* IRQ has been replayed but not acked yet */irq线已被禁用,但是前一个出现的irq还没有对pic做出应答
#define IRQ_AUTODETECT 16 /* IRQ is being autodetected */内核在执行硬件设备探测时使用irq线
#define IRQ_WAITING 32 /* IRQ not yet seen - for autodetection */内核在执行硬件设备探测时使用irq线;此外,相应的中断还没有产生
#define IRQ_LEVEL 64 /* IRQ level triggered */在80x86结构上没有使用
#define IRQ_MASKED 128 /* IRQ masked - shouldn't be seen again */未使用
#define IRQ_PER_CPU 256 /* IRQ is per CPU */在80x86结构上没有使用
在初始化期间,下面的函数把每个irq主描述符的status字段设置成IRQ_DISABLED。此外,init_IRQ()通过替换由setup_idt()所建立的中断门来更新idt,通过其中的for循环来完成。
void __init init_IRQ(void)
{
int i;
/* all the set up before the call gates are initialised */
pre_intr_init_hook();
/*Cover the whole vector space, no vector can escape us. (some of these will be overridden and become 'special' SMP interrupts)*/
for (i = 0; i < (NR_VECTORS - FIRST_EXTERNAL_VECTOR); i++) {
int vector = FIRST_EXTERNAL_VECTOR + i;
if (i >= NR_IRQS)
break;
if (vector != SYSCALL_VECTOR)
set_intr_gate(vector, interrupt[i]);
}
/* setup after call gates are initialised (usually add in the architecture specific gates)*/
intr_init_hook();
/* Set the clock to HZ Hz, we already have a valid vector now:*/
setup_pit_timer();
/*External FPU? Set up irq13 if so, for original braindamaged IBM FERR coupling.*/
if (boot_cpu_data.hard_math && !cpu_has_fpu)
setup_irq(FPU_IRQ, &fpu_irq);
irq_ctx_init(smp_processor_id());
}
其中interrupt数组中,有用于建立中断门的中断处理程序地址。其中的第n项中存放irqn的中断处理程序的地址。这里不包括与128号中断向量相关的中断门,因为它用于系统调用的编程异常。
在linux中,驱动程序不必关注安装在系统中的pic种类。每个驱动程序可见的中断源透明第连接到适当的控制器。定义pic对象的数据结构叫做hw_interrupt_type(也叫hw_irq_controller)。
static struct hw_interrupt_type i8259A_irq_type = {
"XT-PIC",pic的名字
startup_8259A_irq,启动芯片的irq线
shutdown_8259A_irq,关闭芯片的irq线
enable_8259A_irq,启用irq线
disable_8259A_irq,禁用irq线
mask_and_ack_8259A,函数通过把适当的字节发往8259A i/o端口来应答所接收到的irq.
end_8259A_irq,函数在irq的中断处理程序终止时被调用
NULL设置为空,用在多处理器系统中以声明特定irq所在cpu的“亲和力”。也就是说,那些cpu被启用来处理特定的irq.
};
unsigned int startup_8259A_irq(unsigned int irq)
{
enable_8259A_irq(irq);
return 0; /* never anything pending */
}
static void end_8259A_irq (unsigned int irq)
{
if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)) && irq_desc[irq].action)
enable_8259A_irq(irq);
}
void enable_8259A_irq(unsigned int irq)
{
unsigned int mask = ~(1 << irq);
unsigned long flags;
spin_lock_irqsave(&i8259A_lock, flags);
cached_irq_mask &= mask;
if (irq & 8)
outb(cached_slave_mask, PIC_SLAVE_IMR);
else
outb(cached_master_mask, PIC_MASTER_IMR);
spin_unlock_irqrestore(&i8259A_lock, flags);
}