本文共 5537 字,大约阅读时间需要 18 分钟。
request_irq 是内核中用来注册中断服务函数的重要函数。它位于 kernel/irq/management.c 中,函数原型如下:
int request_irq(unsigned int irq, irq_handler_t handler, unsigned long irqflags, const char *devname, void *dev_id);
request_irq 函数主要完成以下步骤:
代码实现如下:
int request_irq(unsigned int irq, irq_handler_t handler, unsigned long irqflags, const char *devname, void *dev_id) { struct irqaction *action; if (!action = kmalloc(sizeof(struct irqaction), GFP_ATOMIC)) { return -ENOMEM; } action->handler = handler; action->flags = irqflags; cpus_clear(action->mask); action->name = devname; action->next = NULL; action->dev_id = dev_id; select_smp_affinity(irq); return setup_irq(irq, action);} setup_irq 是 request_irq 的一个辅助函数,主要负责将 action 加入中断描述符的 action 链表中,并初始化中断引脚。
代码实现如下:
int setup_irq(unsigned int irq, struct irqaction *new) { struct irq_desc *desc = irq_desc + irq; struct irqaction *old = &desc->action; unsigned int shared = 0; if (old) { if (((old->flags & new->flags) & IRQF_SHARED) || ((old->flags ^ new->flags) & IRQF_TRIGGER_MASK)) { shared = 1; } else { old_name = old->name; goto mismatch; } if (config_intx) { do { old = *p; } while (old); } shared = 1; } *p = new; if (!shared) { if (desc->chip && desc->chip->set_type) { desc->chip->set_type(irq, new->flags & IRQF_TRIGGER_MASK); } else { printk(KERN_WARNING "No IRQF_TRIGGER set_type function for IRQ %d (%s)\n", irq, desc->chip ? desc->chip->name : "unknown"); } if (!(desc->status & (IRQ_AUTODETECT | IRQ_WAITING | IRQ_INPROGRESS))) { desc->depth = 0; desc->status &= ~IRQ_DISABLED; if (desc->chip->startup) { desc->chip->startup(irq); } else { desc->chip->enable(irq); } } else { desc->depth = 1; } }} 通过 setup_irq 函数,中断引脚的初始化主要通过 desc->chip->set_type 方法完成。以外部中断0为例,函数 s3c_irqext_type 会根据中断类型设置相应的寄存器模式。
代码实现如下:
unsigned int s3c_irqext_type(unsigned int irq, unsigned int type) { void __iomem *extint_reg; void __iomem *gpcon_reg; unsigned long gpcon_offset, extint_offset; if ((irq >= IRQ_EINT0) && (irq < IRQ_EINT3)) { gpcon_reg = S3C2410_GPFCON; extint_reg = S3C24XX_EXTINT0; gpcon_offset = (irq - IRQ_EINT0) * 2; extint_offset = (irq - IRQ_EINT0) * 4; } else if (...) { // 其他中断类型的处理 } value = __raw_readl(gpcon_reg); value = (value & ~(3 << gpcon_offset)) | (0x02 << gpcon_offset); switch (type) { case IRQT_NOEDGE: printk(KERN_WARNING "No edge setting!\n"); break; case IRQT_RISING: newvalue = S3C2410_EXTINT_RISEEDGE; break; case IRQT_FALLING: newvalue = S3C2410_EXTINT_FALLEDGE; break; case IRQT_BOTHEDGE: newvalue = S3C2410_EXTINT_BOTHEDGE; break; case IRQT_LOW: newvalue = S3C2410_EXTINT_LOWLEV; break; case IRQT_HIGH: newvalue = S3C2410_EXTINT_HILEV; break; default: } value = __raw_readl(extint_reg); value = (value & ~(7 << extint_offset)) | (newvalue << extint_offset); __raw_writel(value, extint_reg); return 0;} free_irq 是用来卸载中断服务函数的函数,位于同一文件中,函数原型如下:
void free_irq(unsigned int irq, void *dev_id);
free_irq 函数主要完成以下步骤:
代码实现如下:
void free_irq(unsigned int irq, void *dev_id) { struct irq_desc *desc = irq_desc + irq; struct irqaction **p; unsigned long flags; WARN_ON(in_interrupt()); if (irq >= NR_IRQS) { return; } spin_lock_irqsave(&desc->lock, flags); p = &desc->action; for (;;) { struct irqaction *action = *p; if (!action) { spin_unlock_irqrestore(&desc->lock, flags); return; } if (action->dev_id != dev_id) { *p = action->next; continue; } *p = action->next; if (desc->chip->release) { desc->chip->release(irq, dev_id); } if (!desc->action) { desc->status |= IRQ_DISABLED; if (desc->chip->shutdown) { desc->chip->shutdown(irq); } else { desc->chip->disable(irq); } } spin_unlock_irqrestore(&desc->lock, flags); unregister_handler_proc(irq, action); synchronize_irq(irq); if (action->flags & IRQF_SHARED) { handler = action->handler; } kfree(action); return; } printk(KERN_ERR "Trying to free already-free IRQ %d\n", irq); spin_unlock_irqrestore(&desc->lock, flags); return;} 通过以上分析,可以清晰地了解 request_irq 和 free_irq 的工作原理,以及如何在内核中注册和卸载中断服务函数。
转载地址:http://zqiyz.baihongyu.com/