博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
中断API之setup_irq
阅读量:4214 次
发布时间:2019-05-26

本文共 11430 字,大约阅读时间需要 38 分钟。

int setup_irq(unsigned int irq, struct irqaction *act)用于设置irq对应的irqaction.其使用的例程如下:struct irq_domain * __init __init_i8259_irqs(struct device_node *node){	struct irq_domain *domain;	insert_resource(&ioport_resource, &pic1_io_resource);	insert_resource(&ioport_resource, &pic2_io_resource);	init_8259A(0);	domain = irq_domain_add_legacy(node, 16, I8259A_IRQ_BASE, 0,				       &i8259A_ops, NULL);	if (!domain)		panic("Failed to add i8259 IRQ domain");	setup_irq(I8259A_IRQ_BASE + PIC_CASCADE_IR, &irq2);	return domain;}其源码分析如下:int setup_irq(unsigned int irq, struct irqaction *act){	int retval;	struct irq_desc *desc = irq_to_desc(irq);	#中断描述为null,或者设置了_IRQ_PER_CPU_DEVID 标志的话,则直接退出	if (!desc || WARN_ON(irq_settings_is_per_cpu_devid(desc)))		return -EINVAL;	retval = irq_chip_pm_get(&desc->irq_data);	if (retval < 0)		return retval;	#核心代码,设置irq对应的irqaction *act	retval = __setup_irq(irq, desc, act);	if (retval)		irq_chip_pm_put(&desc->irq_data);	return retval;}static int__setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new){	struct irqaction *old, **old_ptr;	unsigned long flags, thread_mask = 0;	int ret, nested, shared = 0;	#中断描述符为null,则退出	if (!desc)		return -EINVAL;	#没有设置irq_data.chip,所以irq_data.chip 会等于no_irq_chip。这属于异常case ,退出.	if (desc->irq_data.chip == &no_irq_chip)		return -ENOSYS;	#增加这个模块的引用计数	if (!try_module_get(desc->owner))		return -ENODEV;	#更新struct irqaction *new 中的irq number	new->irq = irq;	/*	 * If the trigger type is not specified by the caller,	 * then use the default for this interrupt.	 */	 #没有设置中断触发类型的话,则用默认值.	if (!(new->flags & IRQF_TRIGGER_MASK))		new->flags |= irqd_get_trigger_type(&desc->irq_data);	/*	 * Check whether the interrupt nests into another interrupt	 * thread.	 */	#检查这里是否是中断嵌套,正常情况下irq_chip 基本都不支持中断嵌套	nested = irq_settings_is_nested_thread(desc);	if (nested) {		if (!new->thread_fn) {			ret = -EINVAL;			goto out_mput;		}		/*		 * Replace the primary handler which was provided from		 * the driver for non nested interrupt handling by the		 * dummy function which warns when called.		 */		new->handler = irq_nested_primary_handler;	} else {	#这里检查是否为这个中断设置一个thread,也就是说是否支持中断线程化		if (irq_settings_can_thread(desc)) {			ret = irq_setup_forced_threading(new);			if (ret)				goto out_mput;		}	}	/*	 * Create a handler thread when a thread function is supplied	 * and the interrupt does not nest into another interrupt	 * thread.	 */	#在没有支持中断嵌套且用户用设置中断线程的情况下,这里会创建一个中断线程	if (new->thread_fn && !nested) {		ret = setup_irq_thread(new, irq, false);		if (ret)			goto out_mput;		#中断线程化时是否支持第二个线程。如果支持的话,再创建一个中断线程.		if (new->secondary) {			ret = setup_irq_thread(new->secondary, irq, true);			if (ret)				goto out_thread;		}	}	/*	 * Drivers are often written to work w/o knowledge about the	 * underlying irq chip implementation, so a request for a	 * threaded irq without a primary hard irq context handler	 * requires the ONESHOT flag to be set. Some irq chips like	 * MSI based interrupts are per se one shot safe. Check the	 * chip flags, so we can avoid the unmask dance at the end of	 * the threaded handler for those.	 */	#有设置oneshot 标志的话,则清掉这个标志.	if (desc->irq_data.chip->flags & IRQCHIP_ONESHOT_SAFE)		new->flags &= ~IRQF_ONESHOT;	/*	 * Protects against a concurrent __free_irq() call which might wait	 * for synchronize_irq() to complete without holding the optional	 * chip bus lock and desc->lock.	 */	mutex_lock(&desc->request_mutex);	/*	 * Acquire bus lock as the irq_request_resources() callback below	 * might rely on the serialization or the magic power management	 * functions which are abusing the irq_bus_lock() callback,	 */	chip_bus_lock(desc);	/* First installed action requests resources. */	#中断描述符的action为null的话,则通过irq_request_resources 来申请中断资源.	if (!desc->action) {		ret = irq_request_resources(desc);		if (ret) {			pr_err("Failed to request resources for %s (irq %d) on irqchip %s\n",			       new->name, irq, desc->irq_data.chip->name);			goto out_bus_unlock;		}	}	/*	 * The following block of code has to be executed atomically	 * protected against a concurrent interrupt and any of the other	 * management calls which are not serialized via	 * desc->request_mutex or the optional bus lock.	 */	raw_spin_lock_irqsave(&desc->lock, flags);	old_ptr = &desc->action;	old = *old_ptr;	#如果这个中断号对应的中断描述符中的action 不为null,说明这个中断号之前可能已经申请过中断了	#这里同样可以得出结论,同一个中断好,可以重复申请中断,但是可能会继承前一次的中断触发类型.	if (old) {		/*		 * Can't share interrupts unless both agree to and are		 * the same type (level, edge, polarity). So both flag		 * fields must have IRQF_SHARED set and the bits which		 * set the trigger type must match. Also all must		 * agree on ONESHOT.		 */		unsigned int oldtype;		/*		 * If nobody did set the configuration before, inherit		 * the one provided by the requester.		 */		if (irqd_trigger_type_was_set(&desc->irq_data)) {			oldtype = irqd_get_trigger_type(&desc->irq_data);		} else {			oldtype = new->flags & IRQF_TRIGGER_MASK;			irqd_set_trigger_type(&desc->irq_data, oldtype);		}		if (!((old->flags & new->flags) & IRQF_SHARED) ||		    (oldtype != (new->flags & IRQF_TRIGGER_MASK)) ||		    ((old->flags ^ new->flags) & IRQF_ONESHOT))			goto mismatch;		/* All handlers must agree on per-cpuness */		if ((old->flags & IRQF_PERCPU) !=		    (new->flags & IRQF_PERCPU))			goto mismatch;		/* add new interrupt at end of irq queue */		do {			/*			 * Or all existing action->thread_mask bits,			 * so we can find the next zero bit for this			 * new action.			 */			thread_mask |= old->thread_mask;			old_ptr = &old->next;			old = *old_ptr;		} while (old);		shared = 1;	}	/*	 * Setup the thread mask for this irqaction for ONESHOT. For	 * !ONESHOT irqs the thread mask is 0 so we can avoid a	 * conditional in irq_wake_thread().	 */	if (new->flags & IRQF_ONESHOT) {		/*		 * Unlikely to have 32 resp 64 irqs sharing one line,		 * but who knows.		 */		if (thread_mask == ~0UL) {			ret = -EBUSY;			goto out_unlock;		}		/*		 * The thread_mask for the action is or'ed to		 * desc->thread_active to indicate that the		 * IRQF_ONESHOT thread handler has been woken, but not		 * yet finished. The bit is cleared when a thread		 * completes. When all threads of a shared interrupt		 * line have completed desc->threads_active becomes		 * zero and the interrupt line is unmasked. See		 * handle.c:irq_wake_thread() for further information.		 *		 * If no thread is woken by primary (hard irq context)		 * interrupt handlers, then desc->threads_active is		 * also checked for zero to unmask the irq line in the		 * affected hard irq flow handlers		 * (handle_[fasteoi|level]_irq).		 *		 * The new action gets the first zero bit of		 * thread_mask assigned. See the loop above which or's		 * all existing action->thread_mask bits.		 */		new->thread_mask = 1UL << ffz(thread_mask);	} else if (new->handler == irq_default_primary_handler &&		   !(desc->irq_data.chip->flags & IRQCHIP_ONESHOT_SAFE)) {		/*		 * The interrupt was requested with handler = NULL, so		 * we use the default primary handler for it. But it		 * does not have the oneshot flag set. In combination		 * with level interrupts this is deadly, because the		 * default primary handler just wakes the thread, then		 * the irq lines is reenabled, but the device still		 * has the level irq asserted. Rinse and repeat....		 *		 * While this works for edge type interrupts, we play		 * it safe and reject unconditionally because we can't		 * say for sure which type this interrupt really		 * has. The type flags are unreliable as the		 * underlying chip implementation can override them.		 */		pr_err("Threaded irq requested with handler=NULL and !ONESHOT for irq %d\n",		       irq);		ret = -EINVAL;		goto out_unlock;	}	#非共享中断	if (!shared) {		#初始化一个等待队列,这个等待队列包含在中断描述符中		init_waitqueue_head(&desc->wait_for_threads);		/* Setup the type (level, edge polarity) if configured: */		if (new->flags & IRQF_TRIGGER_MASK) {			ret = __irq_set_trigger(desc,						new->flags & IRQF_TRIGGER_MASK);			if (ret)				goto out_unlock;		}		/*		 * Activate the interrupt. That activation must happen		 * independently of IRQ_NOAUTOEN. request_irq() can fail		 * and the callers are supposed to handle		 * that. enable_irq() of an interrupt requested with		 * IRQ_NOAUTOEN is not supposed to fail. The activation		 * keeps it in shutdown mode, it merily associates		 * resources if necessary and if that's not possible it		 * fails. Interrupts which are in managed shutdown mode		 * will simply ignore that activation request.		 */		 #激活这个中断		ret = irq_activate(desc);		if (ret)			goto out_unlock;		desc->istate &= ~(IRQS_AUTODETECT | IRQS_SPURIOUS_DISABLED | \				  IRQS_ONESHOT | IRQS_WAITING);		irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS);		#是不是percpu中断		if (new->flags & IRQF_PERCPU) {			irqd_set(&desc->irq_data, IRQD_PER_CPU);			irq_settings_set_per_cpu(desc);		}		if (new->flags & IRQF_ONESHOT)			desc->istate |= IRQS_ONESHOT;		/* Exclude IRQ from balancing if requested */		#不用设置irq balance		if (new->flags & IRQF_NOBALANCING) {			irq_settings_set_no_balancing(desc);			irqd_set(&desc->irq_data, IRQD_NO_BALANCING);		}		#开始中断		if (irq_settings_can_autoenable(desc)) {			irq_startup(desc, IRQ_RESEND, IRQ_START_COND);		} else {			/*			 * Shared interrupts do not go well with disabling			 * auto enable. The sharing interrupt might request			 * it while it's still disabled and then wait for			 * interrupts forever.			 */			WARN_ON_ONCE(new->flags & IRQF_SHARED);			/* Undo nested disables: */			desc->depth = 1;		}	} else if (new->flags & IRQF_TRIGGER_MASK) {		unsigned int nmsk = new->flags & IRQF_TRIGGER_MASK;		unsigned int omsk = irqd_get_trigger_type(&desc->irq_data);		if (nmsk != omsk)			/* hope the handler works with current  trigger mode */			pr_warn("irq %d uses trigger mode %u; requested %u\n",				irq, omsk, nmsk);	}	*old_ptr = new;	#设置power相关	irq_pm_install_action(desc, new);	/* Reset broken irq detection when installing new handler */	desc->irq_count = 0;	desc->irqs_unhandled = 0;	/*	 * Check whether we disabled the irq via the spurious handler	 * before. Reenable it and give it another chance.	 */	if (shared && (desc->istate & IRQS_SPURIOUS_DISABLED)) {		desc->istate &= ~IRQS_SPURIOUS_DISABLED;		__enable_irq(desc);	}	raw_spin_unlock_irqrestore(&desc->lock, flags);	chip_bus_sync_unlock(desc);	mutex_unlock(&desc->request_mutex);	irq_setup_timings(desc, new);	/*	 * Strictly no need to wake it up, but hung_task complains	 * when no hard interrupt wakes the thread up.	 */	# 如果有中断线程的话,则wakeup线程	if (new->thread)		wake_up_process(new->thread);	if (new->secondary)		wake_up_process(new->secondary->thread);	#注册irq在proc中的接口	register_irq_proc(irq, desc);	new->dir = NULL;	register_handler_proc(irq, new);	return 0;mismatch:	if (!(new->flags & IRQF_PROBE_SHARED)) {		pr_err("Flags mismatch irq %d. %08x (%s) vs. %08x (%s)\n",		       irq, new->flags, new->name, old->flags, old->name);#ifdef CONFIG_DEBUG_SHIRQ		dump_stack();#endif	}	ret = -EBUSY;#一下都是异常caseout_unlock:	raw_spin_unlock_irqrestore(&desc->lock, flags);	if (!desc->action)		irq_release_resources(desc);out_bus_unlock:	chip_bus_sync_unlock(desc);	mutex_unlock(&desc->request_mutex);out_thread:	if (new->thread) {		struct task_struct *t = new->thread;		new->thread = NULL;		kthread_stop(t);		put_task_struct(t);	}	if (new->secondary && new->secondary->thread) {		struct task_struct *t = new->secondary->thread;		new->secondary->thread = NULL;		kthread_stop(t);		put_task_struct(t);	}out_mput:	module_put(desc->owner);	return ret;}

转载地址:http://fgjmi.baihongyu.com/

你可能感兴趣的文章
libgdx: 2D Particle Editor工具使用
查看>>
eclipse 给jar库添加源码
查看>>
3.0正式版环境搭建(4)-- 运行(3)创建的工程
查看>>
C++ 枚举声明 enum 和 enum class
查看>>
Python optionParser模块的使用方法
查看>>
android 消灭星星出错
查看>>
PyCharm 教程(三)Hello world!
查看>>
PyCharm: 显示源码行号
查看>>
cocos2dx使用第三方字库.ttf,需要注意的事项
查看>>
cocos2dx 音频模块分析(4): 音效部分
查看>>
cocos2dx 音频模块分析(5): 音效部分
查看>>
19、Cocos2dx 3.0游戏开发找小三之Action:流动的水没有形状,漂流的风找不到踪迹、、、
查看>>
cocos2.X版本lua端使用定时器的方法
查看>>
lua math.fmod使用注意小数问题
查看>>
lua 时间转化
查看>>
lua学习笔记之五(Lua中的数学库)
查看>>
dos: tree命令生成目录结构
查看>>
Managing Projects from the Command Line(android官网文档)
查看>>
Android项目自动生成build.xml,用Ant打包
查看>>
CCLayer注册lua回调函数setTouchPriority失效
查看>>