ARM Linux中断机制之中断的申请
//分配一个中断服务例程结构体action并初始化它的各字段。
action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
if (!action)
return -ENOMEM;
action->handler = handler;
action->thread_fn = thread_fn; //为NULL
action->flags = irqflags;
action->name = devname;
//对于共享中断 , 此特定值用来区分各中断,以便从共享中断线的诸多中断处理程序中删除指定的那一个。
action->dev_id = dev_id;
//将该例程添加到单向链表desc->action上,并启动该例程。
retval = __setup_irq(irq, desc, action);
if (retval)
kfree(action);
。。。。。。
return retval;
}
static int
__setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
{
struct irqaction *old, **old_ptr;
const char *old_name = NULL;
unsigned long flags;
int shared = 0;
int ret;
。。。。。。
old_ptr = &desc->action;//获取中断处理例程单向链表上的第一个例程,如果它为NULL说明该中断线是第一次被触发。
old = *old_ptr;
if (old) { //
。。。。。。
//如果该中断线上存在中断服务例程则让old_ptr指向该例程链表的尾部,以便加入新的服务例程
do {
old_ptr = &old->next;
old = *old_ptr;
} while (old);
shared = 1;
}
if (!shared) {
//将操作函数集desc->chip的一些未设置的字段设为默认值。
irq_chip_set_defaults(desc->chip);
init_waitqueue_head(&desc->wait_for_threads);
/*
函数__irq_set_trigger()的主要工作是调用函数chip->set_type(irq, flags);设置外部中断的触发方式。
中断触发方式在文件linux\include\irq.h中定义
#define IRQ_TYPE_NONE0x00000000/* Default, unspecified type */
#define IRQ_TYPE_EDGE_RISING0x00000001/* Edge rising type */
#define IRQ_TYPE_EDGE_FALLING0x00000002/* Edge falling type */
#define IRQ_TYPE_EDGE_BOTH (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)
#define IRQ_TYPE_LEVEL_HIGH0x00000004/* Level high type */
#define IRQ_TYPE_LEVEL_LOW0x00000008/* Level low type */
#define IRQ_TYPE_SENSE_MASK0x0000000f/* Mask of the above */
IRQF_TRIGGER_MASK在文件interrupt.h中定义
#define IRQF_TRIGGER_NONE0x00000000
#define IRQF_TRIGGER_RISING0x00000001
#define IRQF_TRIGGER_FALLING0x00000002
#define IRQF_TRIGGER_HIGH0x00000004
#define IRQF_TRIGGER_LOW0x00000008
#define IRQF_TRIGGER_MASK(IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW | \
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)
可以看出只要外部中断设置了触发方式函数__irq_set_trigger()就会执行。
*/
if (new->flags & IRQF_TRIGGER_MASK)
ret = __irq_set_trigger(desc, irq,new->flags & IRQF_TRIGGER_MASK);
if (ret)
goto out_thread;
} else
compat_irq_chip_set_default_handler(desc);
// desc->status的标志IRQ_NOAUTOEN 在中断初始化函数 s3c24xx_init_irq()中调用函数set_irq_flags()设置。
if (!(desc->status & IRQ_NOAUTOEN)) {
desc->depth = 0;
desc->status &= ~IRQ_DISABLED;
desc->chip->startup(irq);//开启中断线
} else
desc->depth = 1;
。。。。。。
}
*old_ptr = new; //将新加入的中断处理例程添加到链表中
。。。。。。
//在proc文件系统中创建目录。
new->irq = irq;
register_irq_proc(irq, desc);
new->dir = NULL;
register_handler_proc(irq, new);
。。。。。。
return ret;
}
中断卸载函数free_irq().。
如果指定的中断线不是共享的 , 那么 , 该函数删除处理程序的同时将禁用这条中断线 。 如果
中断线是共享的,则仅删除 dev_id 所对应的处理程序,而这条中断线本身只有在删除了最
后一个处理程序时才会被禁用。由此可以看出为什么惟一的 dev_ id 如此重要。对于共享的
中断线,需要一个惟一的信息来区分其上面的多个处理程序,并让 free_irq() 仅仅删除指定
的处理程序。如果 dev_id 非空,它都必须与需要删除的处理程序相匹配。非共享中断,该
域可以为空,但需要和注册时使用的指针一致。
static struct irqaction *__free_irq(unsigned int irq, void *dev_id)
{
struct irq_desc *desc = irq_to_desc(irq);
struct irqaction *action, **action_ptr;
struct task_struct *irqthread;
unsigned long flags;
if (!desc)
return NULL;
action_ptr = &desc->action;
for (;;) {
action = *action_ptr;
/*
根据 dev_id在中断处理例程单项链表中找出一个要卸载的中断例程。
在单项链表中如果卸
ARMLinux中断机制申 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)