中断请求队列的初始化
数据结构
irq通道的控制
struct hw_interrupt_type { const char * typename; unsigned int (*startup)(unsigned int irq); void (*shutdown)(unsigned int irq); void (*enable)(unsigned int irq); void (*disable)(unsigned int irq); void (*ack)(unsigned int irq); void (*end)(unsigned int irq); void (*set_affinity)(unsigned int irq, unsigned long mask); }; typedef struct hw_interrupt_type hw_irq_controller;
1) startup 启动通道 2) ack 响应
irq请求队列头部数据结构
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; extern irq_desc_t irq_desc [NR_IRQS];
1) handler 就是通道级别的操作函数。 2) action 是这个队列的头部,类型是 irqaction。
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; };
1) handler 就是中断服务程序。 2) dev_id 是设备号,因为这个通道是共享的,所以要依赖这个dev_id区分到底是谁产生的中断。 3) next 链表。
队列头irq_desc的初始化
在 init_IRQ -> init_ISA_irqs中
void __init init_ISA_irqs (void) { int i; init_8259A(0); for (i = 0; i < NR_IRQS; i++) { irq_desc[i].status = IRQ_DISABLED; irq_desc[i].action = 0; irq_desc[i].depth = 1; if (i < 16) { irq_desc[i].handler = &i8259A_irq_type; } else { irq_desc[i].handler = &no_irq_type; } } }
1) irq_desc[i].handler = &i8259A_irq_type; 设置队列头 irq_desc中的handler为8259的处理函数。
添加一个 interrupt line 到系统中(外设主动调用把自己的中断服务程序注册到相对的请求队列中)
int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, const char * devname, void *dev_id) { int retval; struct irqaction * action; #if 1 if (irqflags & SA_SHIRQ) { if (!dev_id) printk("Bad boy: %s (at 0x%x) called us without a dev_id!\n", devname, (&irq)[-1]); } #endif if (irq >= NR_IRQS) return -EINVAL; if (!handler) return -EINVAL; action = (struct irqaction *) kmalloc(sizeof(struct irqaction), GFP_KERNEL); if (!action) return -ENOMEM; action->handler = handler; action->flags = irqflags; action->mask = 0; action->name = devname; action->next = NULL; action->dev_id = dev_id; retval = setup_irq(irq, action); if (retval) kfree(action); return retval; }
1) if (!dev_id) 如果没有dev_id则报错。 2) kmalloc(sizeof(struct irqaction), GFP_KERNEL); 从slab分配一个 irqaction 3) action->handler = handler; 设置handler 4) action->dev_id = dev_id; 设置dev_id 5) printk("Bad boy: %s (at 0x%x) called us without a dev_id!\n", devname, (&irq)[-1]); 注意这个printk的技巧:打印出调用者的指令地址。 &irq取出第一个参数在栈上的地址, (&irq)[-1] 在栈上往上找一个,就是函数的返回地址。也就是调用者的地址。
setup_irq 链入请求队列
int setup_irq(unsigned int irq, struct irqaction * new) { int shared = 0; unsigned long flags; struct irqaction *old, **p; irq_desc_t *desc = irq_desc + irq; if (new->flags & SA_SAMPLE_RANDOM) { rand_initialize_irq(irq); } spin_lock_irqsave(&desc->lock,flags); p = &desc->action; if ((old = *p) != NULL) { if (!(old->flags & new->flags & SA_SHIRQ)) { spin_unlock_irqrestore(&desc->lock,flags); return -EBUSY; } do { p = &old->next; old = *p; } while (old); shared = 1; } *p = new; if (!shared) { desc->depth = 0; desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING); desc->handler->startup(irq); } spin_unlock_irqrestore(&desc->lock,flags); register_irq_proc(irq); return 0; }
1) rand_initialize_irq(irq); 借助外设中断的时序来增进随机数。 2) do { p = &old->next; old = *p; } while (old); 找到队列尾端,并插入。