内核模块中的中断处理:request_irq()返回-22,无效参数

时间:2016-08-09 14:40:38

标签: c linux-kernel interrupt

我正在尝试在内核模块中设置一个由gpio-interrupt触发的中断处理程序,但似乎我没有使用request_irq() - 函数正确... 我通过gpio_to_irq()得到了我的irq号码,这似乎有效。 然后我正在打电话

request_irq(irqNumber, handler, 0, "GPIO_Test", NULL);

但它返回-22,参数无效。 我认为它可能是处理程序函数,因为我不确定它的签名 - 有时它定义为void handler (int irq, void *dev_id, struct pt_regs *regs),有时定义为static irqreturn_t handler(int irq, void *data) - 在这种情况下哪一个是正确的,以及为什么这两种完全不同的变化吗? 我试过了两个,但总是得到相同的Invalid-parameters-error。

编译器给我一个关于我的handler-function的return-type的警告: 使用时:

static irqreturn_t handler(int irq, void *data)
{
    /*interrupt-handling*/

    return IRQ_HANDLED;
}
  

»irq_handler_t«预期,但参数类型为:enum irqreturn_t(*(*)(int,void *))(int,void *)«

......以及使用时:

void handler (int irq, void *dev_id, struct pt_regs *regs){/*interrupt-handling*/}
  

»irq_handler_t«预期,但参数的类型为:void(*)(int,void *,struct pt_regs *)«

感谢您的支持;)

2 个答案:

答案 0 :(得分:1)

问题(-EINVAL)并非由handler引起,因为内核无法在运行时确定其签名。

此外,handler在通过request_irq()请求IRQ时从不被调用(除非定义了CONFIG_DEBUG_SHIRQ_FIXME,并且[带有错误的签名]只会导致参数验证后的未定义行为,而不是之前,所以此时不​​太可能返回-EINVAL

在正确设置IRQ之前,有4个关键点已经过验证:

  • irqflags - 您没有设置,通过了支票。
  • irq_to_desc() - 对irq_desc_tree的{​​{1}}执行查找。如果找不到,将返回irq。否则,返回指向irq描述符结构(-EINVAL
  • 的指针
  • struct irq_desc * - 检查是否可以请求IRQ。您可以在 irq_settings_can_request()之前致电int can_request_irq(unsigned int irq, unsigned long irqflags) ,轻松排除此问题。
  • request_irq() - 会检查handler是否为handler。在你的情况下,它不是。

所以基本上你只有两个可能导致问题的可能检查,其中一个你可以在调用NULL之前使用can_request_irq()排除,但不幸的是,这赢了&# 39;可以在模块下执行,因为request_irq()符号未导出。

但是如果你有耐心和时间,你可以使用内置的代码构建一个新图像,只需查看can_request_irq检查是否通过。如果是,则导致问题的唯一检查是can_request_irq(),这意味着irq_to_desc()无效。

无法更多地延伸这个答案,因为我的问题没有更多信息可以处理,但我希望它可以帮助您走上正确的轨道。

顺便说一句,只是指出irq typedef的情况可能有用:

irq_handler_t(在4.5树上):

include/linux/interrupt.h:92

答案 1 :(得分:0)

request_any_context_irq API (patch) 将在您的中断线嵌套并重新使用线程处理程序时自动处理这种情况。由于您无法从模块访问 irq_settings_can_request,因此在添加检测之前值得使用。

<块引用>

此调用分配中断资源并启用中断线 和 IRQ 处理。它选择硬中断或线程处理 方法取决于上下文。

失败时,它返回一个负值。成功时,它返回 IRQC_IS_HARDIRQ 或 IRQC_IS_NESTED。