arm linux 下中断流程简要分析初始化
esc = irq_esc + irq;/*获取保存该中断的中断描述符*/
spin_lock_irqsave(&desc->lock, flags);
irq_chip_set_defaults(chip); /*为chip设置一些默认的enable,disable函数*/
desc->chip = chip;/*为中断保存chip对象*/
/*
* For compatibility only:
*/
desc->chip = chip;
spin_unlock_irqrestore(&desc->lock, flags);
return 0;
}
为特定中断号初始化好chip对象,表示该中断号由这个chip控制,后面会调用到该中断号所属chip的相关函数,各个中断的chip是不同的,以IRQ_WDT为例,它的chip是s3c_irq_chip。
arch/arm/mach-s3c2410/Irq.c:
static struct irqchip s3c_irq_chip = {
.ack= s3c_irq_ack,
.mask= s3c_irq_mask,
.unmask= s3c_irq_unmask,
.set_wake= s3c_irq_wake
};
在看irq_chip_set_defaults
kernel/irq/Chip.c:
/*
* Fixup enable/disable function pointers
*/
void irq_chip_set_defaults(struct irq_chip *chip)
{
if (!chip->enable)
chip->enable = default_enable;
if (!chip->disable)
chip->disable = default_disable;
if (!chip->startup)
chip->startup = default_startup;
if (!chip->shutdown)
chip->shutdown = chip->disable;
if (!chip->name)
chip->name = chip->typename;
}
很显然,如果chip没有相应的操作函数,则就给chip赋默认的操作函数。
我们接着看set_irq_handler()
include/linux/Irq.h:
static inline void
set_irq_handler(unsigned int irq,
void fastcall (*handle)(unsigned int, struct irq_desc *,
struct pt_regs *))
{
__set_irq_handler(irq, handle, 0);
}
kernel/irq/Chip.c:
void
__set_irq_handler(unsigned int irq,
void fastcall (*handle)(unsigned int, irq_desc_t *,
struct pt_regs *),
int is_chained)
{
struct irq_desc *desc;
unsigned long flags;
if (irq >= NR_IRQS) { /*参数检查*/
printk(KERN_ERR
"Trying to install type control for IRQ%d/n", irq);
return;
}
desc = irq_desc + irq; /*获取中断描述符的存储地址*/
if (!handle)
handle = handle_bad_irq;/*赋默认的中断handle*/
if (desc->chip == &no_irq_chip) {
printk(KERN_WARNING "Trying to install %sinterrupt handler "
"for IRQ%d/n", is_chained ? "chained " : " ", irq);
/*
* Some ARM implementations install a handler for really dumb
* interrupt hardware without setting an irq_chip. This worked
* with the ARM no_irq_chip but the check in setup_irq would
* prevent us to setup the interrupt at all. Switch it to
* dummy_irq_chip for easy transition.
*/
desc->chip = &dummy_irq_chip;/*赋默认的chip*/
}
spin_lock_irqsave(&desc->lock, flags);
/* Uninstall? */
if (handle == handle_bad_irq) {
if (desc->chip != &no_irq_chip) {
desc->chip->mask(irq);
desc->chip->ack(irq);
}
desc->status |= IRQ_DISABLED;/*没有中断例程则disable掉该中断*/
desc->depth = 1;
}
desc->handle_irq = handle;/*保存中断例程,对于IRQ_WDT来说则是do_edge_IRQ */
/*由上面的调用可知,is_chained始终等于0*/
if (handle != handle_bad_irq && is_chained) {
desc->status &= ~IRQ_DISABLED;
desc->status |= IRQ_NOREQUEST | IRQ_NOPROBE;
desc->depth = 0;
desc->chip->unmask(irq);
}
spin_unlock_irqrestore(&desc->lock, flags);
}
上面这个函数就是为特定的中断设置好一个中断处理例程(这里的例程可不是我们request_irq注册的例程喔)。
接着看set_irq_flags()
arch/arm/kernel/Irq.c:
void set_irq_flags(unsigned int irq, unsigned int iflags)
{
struct irqdesc *desc;
unsigned long flags;
if (irq >= NR_IRQS) {
printk(KERN_ERR "Trying to set irq flags for IRQ%d/n", irq);
return;
}
desc = irq_desc + irq;
spin_lock_irqsave(&desc->lock, flags);
desc->status |= IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
if (iflags & IRQF_VALID)
desc->status &= ~IRQ_NOREQUEST;/*清掉IRQ_NOREQUEST标记*/
if (iflags & IRQF_PROBE)
desc->status &= ~IRQ_NOPROBE;
if (!(iflags & IRQF_NOAUTOEN))
desc->status &= ~IRQ_NOAUTOEN;
spin_unlock_irqrestore(&desc->lock, flags);
}
该函数主要是为特定的中断设置相应的状态标记, 而这里我们调用它的目的就是清掉IRQ_NOREQUEST标记,告诉系统该中断已经可以被申请使用了,中断在申请的时候会查看是否有IRQ_NOREQUEST标记,如有则表面该中断还不能使用。而初始化的时候
armlinux中断流程初始 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)