irq_set_chained_handler_and_data和devm_request_irq区别

1、irq_set_chained_handler_and_data一般用来设置中断级联处理函数(一般GPIO控制器驱动上用的多,需要级联判断具体哪个gpio触发的中断,一组gpio共享一个硬件中断号)

函数声明

void irq_set_chained_handler_and_data(unsigned int irq, irq_flow_handler_t handle,  void *data)
{
	unsigned long flags;
	struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, 0);

	if (!desc)
		return;

	desc->irq_common_data.handler_data = data;
	__irq_do_set_handler(desc, handle, 1, NULL);//这函数里面赋值

	irq_put_desc_busunlock(desc, flags);
}

irq_set_chained_handler_and_data直接赋值 desc->handle_irq = handle;
中断来的时候会调用以下函数


int generic_handle_irq(unsigned int irq)
{
	struct irq_desc *desc = irq_to_desc(irq);

	if (!desc)
		return -EINVAL;
	generic_handle_irq_desc(desc);
	return 0;
}
static inline void generic_handle_irq_desc(struct irq_desc *desc)
{
	desc->handle_irq(desc);//这里直接调用通过该函数注册的中断处理函数
}

2 devm_request_irq注册中断处理函数治最后通过action->handler(irq, action->dev_id)调用

函数声明

static inline int __must_check
devm_request_irq(struct device *dev, unsigned int irq, irq_handler_t handler,
		 unsigned long irqflags, const char *devname, void *dev_id)
{
	return devm_request_threaded_irq(dev, irq, handler, NULL, irqflags,
					 devname, dev_id);
}

调用request_threaded_irq赋值	action->handler = handler;
int request_threaded_irq(unsigned int irq, irq_handler_t handler,
			 irq_handler_t thread_fn, unsigned long irqflags,
			 const char *devname, void *dev_id)
{
	struct irqaction *action;
	struct irq_desc *desc;
	int retval;
	<...>
	action->handler = handler;//赋值中断处理函数
	action->thread_fn = thread_fn;
	action->flags = irqflags;
	action->name = devname;
	action->dev_id = dev_id;
		<...>
}
//中断发生的时候调用的地方
irqreturn_t __handle_irq_event_percpu(struct irq_desc *desc, unsigned int *flags)
{
	irqreturn_t retval = IRQ_NONE;
	unsigned int irq = desc->irq_data.irq;
	struct irqaction *action;
//通过irq_desc找到对应action
	for_each_action_of_desc(desc, action) {
		irqreturn_t res;

		trace_irq_handler_entry(irq, action);
		res = action->handler(irq, action->dev_id);//执行中断处理函数
		trace_irq_handler_exit(irq, action, res);

		if (WARN_ONCE(!irqs_disabled(),"irq %u handler %pF enabled interrupts\n",
			      irq, action->handler))
			local_irq_disable();

		switch (res) {
		case IRQ_WAKE_THREAD:
			/*
			 * Catch drivers which return WAKE_THREAD but
			 * did not set up a thread function
			 */
			if (unlikely(!action->thread_fn)) {
				warn_no_thread(irq, action);
				break;
			}

			__irq_wake_thread(desc, action);

			/* Fall through to add to randomness */
		case IRQ_HANDLED:
			*flags |= action->flags;
			break;

		default:
			break;
		}

		retval |= res;
	}

	return retval;
}

在这里插入图片描述

在这里插入图片描述
这里直接调用devm_request_irq注册中断处理函数,第一个gpio控制器调用的desc->handle_irq(desc)这个就用中断控制器注册的函数handle_fasteoi_irqs
gpio中断处理函数中调用的handle_edge_irq是在初始化的时候注册struct irq_chip指定的irq_set_type函数设置desc->handle_irq,request_irq的时候会调用该函数设置desc->handle_irq

static struct irq_chip pl061_irqchip = {
	.name		= "pl061",
	.irq_ack	= pl061_irq_ack,
	.irq_mask	= pl061_irq_mask,
	.irq_unmask	= pl061_irq_unmask,
	.irq_set_type	= pl061_irq_type,
	.irq_set_wake	= pl061_irq_set_wake,
};
static int pl061_irq_type(struct irq_data *d, unsigned trigger)
{
	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
	struct pl061_gpio *chip = gpiochip_get_data(gc);
	int offset = irqd_to_hwirq(d);
	unsigned long flags;
	u8 gpiois, gpioibe, gpioiev;
	u8 bit = BIT(offset);
《。。。。irq_set_handler_locked(d, handle_edge_irq);通过该函数赋值》
	if (trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
		bool polarity = trigger & IRQ_TYPE_LEVEL_HIGH;

		/* Disable edge detection */
		gpioibe &= ~bit;
		/* Enable level detection */
		gpiois |= bit;
		/* Select polarity */
		if (polarity)
			gpioiev |= bit;
		else
			gpioiev &= ~bit;
		irq_set_handler_locked(d, handle_level_irq);
		dev_dbg(gc->parent, "line %d: IRQ on %s level\n",
			offset,
			polarity ? "HIGH" : "LOW");
	} else if ((trigger & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) {
		/* Disable level detection */
		gpiois &= ~bit;
		/* Select both edges, setting this makes GPIOEV be ignored */
		gpioibe |= bit;
		irq_set_handler_locked(d, handle_edge_irq);
		dev_dbg(gc->parent, "line %d: IRQ on both edges\n", offset);
	} else if ((trigger & IRQ_TYPE_EDGE_RISING) ||
		   (trigger & IRQ_TYPE_EDGE_FALLING)) {
		bool rising = trigger & IRQ_TYPE_EDGE_RISING;

		/* Disable level detection */
		gpiois &= ~bit;
		/* Clear detection on both edges */
		gpioibe &= ~bit;
		/* Select edge */
		if (rising)
			gpioiev |= bit;
		else
			gpioiev &= ~bit;
		irq_set_handler_locked(d, handle_edge_irq);
		dev_dbg(gc->parent, "line %d: IRQ on %s edge\n",
			offset,
			rising ? "RISING" : "FALLING");
	} else {
		/* No trigger: disable everything */
		gpiois &= ~bit;
		gpioibe &= ~bit;
		gpioiev &= ~bit;
		irq_set_handler_locked(d, handle_bad_irq);
		dev_warn(gc->parent, "no trigger selected for line %d\n",
			 offset);
	}
《。。。。》
}


中断流处理程序(无论是预定义的还是架构特定的)由架构在启动期间或设备初始化期间分配给 特定中断。
handle_level_irq()
handle_edge_irq()
handle_fasteoi_irq()
handle_simple_irq()
handle_percpu_irq()
handle_edge_eoi_irq()
handle_bad_irq()

电平触发型IRQ流处理器
handle_level_irq为电平触发型的中断提供了一个通用实现。
实现的控制流如下(简化摘录):
desc->irq_data.chip->irq_mask_ack();
handle_irq_event(desc->action);
desc->irq_data.chip->irq_unmask();

默认的需回应IRQ流处理器
handle_fasteoi_irq为中断提供了一个通用的实现,它只需要在处理程序的末端有一个EOI。
实现的控制流如下(简化摘录):
handle_irq_event(desc->action);
desc->irq_data.chip->irq_eoi();

默认的边沿触发型IRQ流处理器
handle_edge_irq为边沿触发型的中断提供了一个通用的实现。
实现的控制流如下(简化摘录):
if (desc->status & running) {
desc->irq_data.chip->irq_mask_ack();
desc->status |= pending | masked;
return;
}
desc->irq_data.chip->irq_ack();
desc->status |= running;
do {
if (desc->status & masked)
desc->irq_data.chip->irq_unmask();
desc->status &= ~pending;
handle_irq_event(desc->action);
} while (status & pending);
desc->status &= ~running;

默认的简单型IRQ流处理器
handle_simple_irq提供了一个简单型中断的通用实现。(简单型的流处理程序不调用任何处理程序/芯片基元。)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值