void remove_irq(unsigned int irq, struct irqaction *act)用于卸载IRQ链表中于输入参数act中devid相等的
irqaction 描述符。
其使用的源码如下:
void remove_irq(unsigned int irq, struct irqaction *act)
{
struct irq_desc *desc = irq_to_desc(irq);
#删除irqaction 描述符的条件是通过irq_to_desc得到的中断描述符不能为null
if (desc && !WARN_ON(irq_settings_is_per_cpu_devid(desc)))
#调用__free_irq来进行具体的操作
__free_irq(irq, act->dev_id);
}
static struct irqaction *__free_irq(unsigned int irq, void *dev_id)
{
#根据irq 号得到中断描述符
struct irq_desc *desc = irq_to_desc(irq);
struct irqaction *action, **action_ptr;
unsigned long flags;
#不能在中断环境中调用__free_irq
WARN(in_interrupt(), "Trying to free IRQ %d from IRQ context!\n", irq);
#中断描述符为null,则退出
if (!desc)
return NULL;
#锁保护
mutex_lock(&desc->request_mutex);
chip_bus_lock(desc);
raw_spin_lock_irqsave(&desc->lock, flags);
/*
* There can be multiple actions per IRQ descriptor, find the right
* one based on the dev_id:
*/
#得到这个中断号对应的irqaction
action_ptr = &desc->action;
for (;;) {
action = *action_ptr;
#这个中断号对应的irqaction如果为null的话,则退出
if (!action) {
WARN(1, "Trying to free already-free IRQ %d\n", irq);
raw_spin_unlock_irqrestore(&desc->lock, flags);
chip_bus_sync_unlock(desc);
mutex_unlock(&desc->request_mutex);
return NULL;
}
#一个中断号下的所有irqaction 是连成一个链表的。例如中断share的情况下,就是根据dev_id来区分是
#哪个device对应的处理函数irqaction。
if (action->dev_id == dev_id)
break;
action_ptr = &action->next;
}
/* Found it - now remove it from the list of entries: */
#通过指向下一个来删除这个链表节点
*action_ptr = action->next;
#电源管理相关
irq_pm_remove_action(desc, action);
/* If this was the last handler, shut down the IRQ line: */
#如果这是这个中断线上最有一个处理函数,则关掉这个中断
if (!desc->action) {
irq_settings_clr_disable_unlazy(desc);
irq_shutdown(desc);
}
#ifdef CONFIG_SMP
/* make sure affinity_hint is cleaned up */
#smp的case 要把irq的亲和性的hint清空
if (WARN_ON_ONCE(desc->affinity_hint))
desc->affinity_hint = NULL;
#endif
raw_spin_unlock_irqrestore(&desc->lock, flags);
/*
* Drop bus_lock here so the changes which were done in the chip
* callbacks above are synced out to the irq chips which hang
* behind a slow bus (I2C, SPI) before calling synchronize_irq().
*
* Aside of that the bus_lock can also be taken from the threaded
* handler in irq_finalize_oneshot() which results in a deadlock
* because synchronize_irq() would wait forever for the thread to
* complete, which is blocked on the bus lock.
*
* The still held desc->request_mutex() protects against a
* concurrent request_irq() of this irq so the release of resources
* and timing data is properly serialized.
*/
chip_bus_sync_unlock(desc);
#删除掉proc中的接口
unregister_handler_proc(irq, action);
/* Make sure it's not being used on another CPU: */
#同步irq
synchronize_irq(irq);
#debug的case 不考虑
#ifdef CONFIG_DEBUG_SHIRQ
/*
* It's a shared IRQ -- the driver ought to be prepared for an IRQ
* event to happen even now it's being freed, so let's make sure that
* is so by doing an extra call to the handler ....
*
* ( We do this after actually deregistering it, to make sure that a
* 'real' IRQ doesn't run in * parallel with our fake. )
*/
if (action->flags & IRQF_SHARED) {
local_irq_save(flags);
action->handler(irq, dev_id);
local_irq_restore(flags);
}
#endif
#这个中断号对应的dev_id 如果有中断线程的话,则停掉这个线程。因为这个dev_id 对应的中断
#处理函数都没有了,也就没有必要保留中断线程
if (action->thread) {
kthread_stop(action->thread);
put_task_struct(action->thread);
if (action->secondary && action->secondary->thread) {
kthread_stop(action->secondary->thread);
put_task_struct(action->secondary->thread);
}
}
/* Last action releases resources */
#如果要删除的irqaction是最后一个,则释放相关资源.
if (!desc->action) {
/*
* Reaquire bus lock as irq_release_resources() might
* require it to deallocate resources over the slow bus.
*/
chip_bus_lock(desc);
irq_release_resources(desc);
chip_bus_sync_unlock(desc);
irq_remove_timings(desc);
}
#解锁
mutex_unlock(&desc->request_mutex);
irq_chip_pm_put(&desc->irq_data);
#减少模块的禁用计数
module_put(desc->owner);
#释放action->secondary 所占用的资源,即使为null,也可以调用kfree释放.
kfree(action->secondary);
return action;
}
中断API之remove_irq
最新推荐文章于 2024-03-16 21:20:44 发布