下面介绍三对管理中断的函数,这些函数都是对第2节中提到的内核中的数据结构进行操作。第一对:request_irq和free_irq一般用于动态注册irq_action结构到内核,在设备驱动中使用;第二对:setup_irq和remove_irq用于静态的注册irq_action,一般用于启动之处的函数的注册和移除;第三对:__setup_irq和__free_irq仅用于内核中断核心代码,一般内核开发人员不能使用。
1.1 rquest_irq
reques_irq的实现是与平台无关的代码,其原型在所有的体系结构上都是相同的,因为这对编写平台无关的驱动来说是一个先决条件。request_irq的调用流程如下:
request_irq
request_threaded_irq
__setup_irq
intrequest_threaded_irq(unsigned int irq, irq_handler_t handler,
irq_handler_t thread_fn, unsigned longirqflags,
const char *devname, void *dev_id)
{
struct irqaction *action;
struct irq_desc *desc;
int retval;
if ((irqflags & IRQF_SHARED)&& !dev_id)
return -EINVAL;
desc =irq_to_desc(irq);
if (!desc)
return -EINVAL;
if (!irq_settings_can_request(desc))
return -EINVAL;
if (!handler) {
if (!thread_fn)
return -EINVAL;
handler =irq_default_primary_handler;
}
action =kzalloc(sizeof(struct irqaction), GFP_KERNEL);
if (!action)
return -ENOMEM;
action->handler = handler;
action->thread_fn = thread_fn;
action->flags = irqflags;
action->name = devname;
action->dev_id = dev_id;
chip_bus_lock(desc);
retval =__setup_irq(irq, desc, action);
chip_bus_sync_unlock(desc);
if (retval)
kfree(action);
…… …….
return retval;
}
request_threaded_irq主要生成一个新的irqaction实例,然后用函数参数填充内容。然后将后续的工作交给__setup_irq来完成。
1.2 __setup_irq
static int
__setup_irq(unsignedint irq, struct irq_desc *desc, struct irqaction *new)
{
if (new->flags & IRQF_SAMPLE_RANDOM) {
rand_initialize_irq(irq);
}
nested = irq_settings_is_nested_thread(desc);
if (nested) {
if (!new->thread_fn)
return -EINVAL;
new->handler =irq_nested_primary_handler;
} else {
if (irq_settings_can_thread(desc))
irq_setup_forced_threading(new);
}
if(new->thread_fn && !nested) {
struct task_struct *t;
t = kthread_create(irq_thread,new, "irq/%d-%s", irq,
new->name);
if (IS_ERR(t))
return PTR_ERR(t);
get_task_struct(t);
new->thread = t;
}
if (!alloc_cpumask_var(&mask,GFP_KERNEL)) {
ret = -ENOMEM;
goto out_thread;
}
/*
*The following block of code has to be executed atomically
*/
raw_spin_lock_irqsave(&desc->lock,flags);
old_ptr = &desc->action;
old = *old_ptr;
if (old) {
/* add new interrupt at end of irq queue */
do {
thread_mask |=old->thread_mask;
old_ptr =&old->next;
old = *old_ptr;
} while (old);
shared = 1;
}
…… ……
register_irq_proc(irq,desc);
new->dir = NULL;
register_handler_proc(irq,new);
free_cpumask_var(mask);
…… ……
return 0;
}
该函数主要完成以下工作:
(1) 如果设置了IRQF_SAMPLE_RANDOM,则该中断将对内核熵池有所贡献。
1.3 setup_irq
intsetup_irq(unsigned int irq, struct irqaction *act)
{
int retval;
struct irq_desc *desc = irq_to_desc(irq);
chip_bus_lock(desc);
retval = __setup_irq(irq, desc, act);
chip_bus_sync_unlock(desc);
return retval;
}
该函数用来在启动之处,静态的注册action到系统中。
1.4 __free_irq
static structirqaction *__free_irq(unsigned int irq, void *dev_id)
{
struct irq_desc*desc = irq_to_desc(irq);
struct irqaction *action, **action_ptr;
unsigned long flags;
WARN(in_interrupt(), "Trying to freeIRQ %d from IRQ context!\n", irq);
if (!desc)
return NULL;
raw_spin_lock_irqsave(&desc->lock,flags);
/*
*There can be multiple actions per IRQ descriptor, find the right
*one based on the dev_id:
*/
action_ptr =&desc->action;
for (;;) {
action = *action_ptr;
if (!action) {
WARN(1, "Trying tofree already-free IRQ %d\n", irq);
raw_spin_unlock_irqrestore(&desc->lock,flags);
return NULL;
}
if (action->dev_id == dev_id)
break;
action_ptr = &action->next;
}
/* Found it - now remove it from the listof entries: */
*action_ptr = action->next;
…… ……
return action;
}
该函数主要完成的工作是,根据irq和dev_id找到对应的irqaction结构,从irq_desc的action链表中删除该结构,然后返回该结构的指针。
1.5 free_irq
voidfree_irq(unsigned int irq, void *dev_id)
{
struct irq_desc *desc = irq_to_desc(irq);
if (!desc)
return;
#ifdefCONFIG_SMP
if (WARN_ON(desc->affinity_notify))
desc->affinity_notify = NULL;
#endif
chip_bus_lock(desc);
kfree(__free_irq(irq, dev_id));
chip_bus_sync_unlock(desc);
}
该函数的功能是调用__free_irq找到irq对应的irq_desc结构,然后释放对应的irq_action结构。但要注意的是该函数不能在中断上下文中使用,以为kfree可能导致睡眠。
1.6 remove_irq
voidremove_irq(unsigned int irq, struct irqaction *act)
{
__free_irq(irq, act->dev_id);
}
remove_irq函数主要调用__free_irq移除中断。和free_irq不同的地方是没有释放irq_action的内存空间,因此该函数只能用来移除在启动之初的时候使用setup_irq静态setup的中断。