中断API之irq_set_chained_handler

irq_set_chained_handler(unsigned int irq, irq_flow_handler_t handle)用于修改通过request_irq 注册中断号的handle
其使用的例程如下:
static int mvebu_pic_probe(struct platform_device *pdev)
{
	struct device_node *node = pdev->dev.of_node;
	struct mvebu_pic *pic;
	struct irq_chip *irq_chip;
	struct resource *res;

	pic = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_pic), GFP_KERNEL);
	if (!pic)
		return -ENOMEM;

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	pic->base = devm_ioremap_resource(&pdev->dev, res);
	if (IS_ERR(pic->base))
		return PTR_ERR(pic->base);

	irq_chip = &pic->irq_chip;
	irq_chip->name = dev_name(&pdev->dev);
	irq_chip->irq_mask = mvebu_pic_mask_irq;
	irq_chip->irq_unmask = mvebu_pic_unmask_irq;
	irq_chip->irq_eoi = mvebu_pic_eoi_irq;

	pic->parent_irq = irq_of_parse_and_map(node, 0);
	if (pic->parent_irq <= 0) {
		dev_err(&pdev->dev, "Failed to parse parent interrupt\n");
		return -EINVAL;
	}

	pic->domain = irq_domain_add_linear(node, PIC_MAX_IRQS,
					    &mvebu_pic_domain_ops, pic);
	if (!pic->domain) {
		dev_err(&pdev->dev, "Failed to allocate irq domain\n");
		return -ENOMEM;
	}
	#通过irq_set_chained_handler 来修改pic->parent_irq 中断号的handle
	irq_set_chained_handler(pic->parent_irq, mvebu_pic_handle_cascade_irq);
	irq_set_handler_data(pic->parent_irq, pic);

	on_each_cpu(mvebu_pic_enable_percpu_irq, pic, 1);

	platform_set_drvdata(pdev, pic);

	return 0;
}
其源码分析如下:
static inline void
irq_set_chained_handler(unsigned int irq, irq_flow_handler_t handle)
{
	__irq_set_handler(irq, handle, 1, NULL);
}
继续调用__irq_set_handler
void
__irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
		  const char *name)
{
	unsigned long flags;
	#通过irq number获取中断描述符的时候需要通过irq_get_desc_buslock/irq_put_desc_busunlock 这一对函数来保护
	struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, 0);

	if (!desc)
		return;
	#继续调用__irq_do_set_handler 来修改irq对应的handle
	__irq_do_set_handler(desc, handle, is_chained, name);
	irq_put_desc_busunlock(desc, flags);
}
static void
__irq_do_set_handler(struct irq_desc *desc, irq_flow_handler_t handle,
		     int is_chained, const char *name)
{
	#handle 为null的话,就会被赋值handle_bad_irq,这种情况一般不会存在。如果不想删掉irq,可以通过这种方式来替换irq原本的handle,从而让irq取消执行
	#原来的功能
	if (!handle) {
		handle = handle_bad_irq;
	} else {
		struct irq_data *irq_data = &desc->irq_data;
#一般不开这个宏		
#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
		/*
		 * With hierarchical domains we might run into a
		 * situation where the outermost chip is not yet set
		 * up, but the inner chips are there.  Instead of
		 * bailing we install the handler, but obviously we
		 * cannot enable/startup the interrupt at this point.
		 */
		while (irq_data) {
			if (irq_data->chip != &no_irq_chip)
				break;
			/*
			 * Bail out if the outer chip is not set up
			 * and the interrrupt supposed to be started
			 * right away.
			 */
			if (WARN_ON(is_chained))
				return;
			/* Try the parent */
			irq_data = irq_data->parent_data;
		}
#endif
		#如果irq_data为null或者没有之指定irq_chip的话,则退出
		if (WARN_ON(!irq_data || irq_data->chip == &no_irq_chip))
			return;
	}

	/* Uninstall? */
	#如果当前irq 的handle 是handle_bad_irq,则把irq的state设置为disable,这个case 一般也不会成立
	if (handle == handle_bad_irq) {
		if (desc->irq_data.chip != &no_irq_chip)
			mask_ack_irq(desc);
		irq_state_set_disabled(desc);
		if (is_chained)
			desc->action = NULL;
		desc->depth = 1;
	}
	#这里才是核心代码,给irq对应的中断描述符设置为新的handler
	desc->handle_irq = handle;
	#设置name,通过这种方式的name强制为null.
	desc->name = name;
	#通过irq_set_chained_handler 设置的时候,is_chained 会为1,所以这个if条件一般成立
	if (handle != handle_bad_irq && is_chained) {
		#得到中断触发类型,例如边沿,电平等
		unsigned int type = irqd_get_trigger_type(&desc->irq_data);

		/*
		 * We're about to start this interrupt immediately,
		 * hence the need to set the trigger configuration.
		 * But the .set_type callback may have overridden the
		 * flow handler, ignoring that we're dealing with a
		 * chained interrupt. Reset it immediately because we
		 * do know better.
		 */
		 #这里有重新设置一遍中断的类型和handle,因为is_chained为1,所以这里的handle 等于被设置了两次 
		if (type != IRQ_TYPE_NONE) {
			__irq_set_trigger(desc, type);
			desc->handle_irq = handle;
		}
		#设置中断描述符的flag
		irq_settings_set_noprobe(desc);
		irq_settings_set_norequest(desc);
		irq_settings_set_nothread(desc);
		desc->action = &chained_action;
		#重新激活和开始中断
		irq_activate_and_startup(desc, IRQ_RESEND);
	}
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值