中断API之remove_irq

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;
}

你可能感兴趣的:(Linux,源码分析,kernel常用API源码分析)