Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Interrupt-handling within kernel-module: request_irq() returns -22, Invalid Parameter

I'm trying to set up an interrupt-handler within a kernel-module that gets triggered by a gpio-interrupt, but it seems that I don't use the request_irq()-function right... I'm getting my irq-number via gpio_to_irq() and this seems to work. Then I'm calling

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

but It returns -22, Invalid parameters. I think it might be the handler-function because I'm not sure about it's signature - Sometimes it's defined as void handler (int irq, void *dev_id, struct pt_regs *regs), sometimes as static irqreturn_t handler(int irq, void *data) - Which one is the correct one to use in this case and why are there these two totally different variations? I tried both, but always got the same Invalid-parameters-error.

The compiler gives me a warning about the return-type of my handler-function: when using:

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

    return IRQ_HANDLED;
}

»irq_handler_t« expected, but argument has type »enum irqreturn_t (* (*)(int, void *))(int, void *)«

...and when using:

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

»irq_handler_t« expected, but argument has type »void (*)(int, void *, struct pt_regs *)«

Thank you for your support ;)

like image 913
DocValle Avatar asked Aug 09 '16 14:08

DocValle


1 Answers

The issue (-EINVAL) isn't being caused by the handler, as there's no way for the kernel to determine its signature at runtime.

Also, handler is never called while requesting an IRQ via request_irq() (unless CONFIG_DEBUG_SHIRQ_FIXME is defined, and [with the wrong signature] that would only lead to undefined behaviour AFTER parameter validation, not before, so it would be very unlikely to return an -EINVAL at this point).

There are 4 key points that are validated before an IRQ is properly setup:

  • irqflags - You've none set, that passes the check.
  • irq_to_desc() - Will perform a lookup over irq_desc_tree for irq. Will return -EINVAL if not found. Otherwise, returns a pointer to an irq descriptor structure (struct irq_desc *)
  • irq_settings_can_request() - Check if the IRQ can be requested. You can easily rule out this by calling int can_request_irq(unsigned int irq, unsigned long irqflags) before request_irq().
  • handler - Will check if handler is NULL. In your case, it is not.

So basically you've only two possible checks that may be causing the issue, and one of them you can rule out using can_request_irq() before calling request_irq(), but, unfortunately, this won't be possible to do under a module, because can_request_irq symbol isn't exported.

But if you've the patience and the time, you can build a new image with that code built-in, just see if can_request_irq() check passes. If it does, the only check that is causing the issue is irq_to_desc(), meaning that irq is invalid.

Can't extend this answer much more, as there's no more information I can work with from your question, but I hope it helps you to get in the right track.

By the way, just to point out the typedef of irq_handler_t in the case it may be useful:

include/linux/interrupt.h:92 (on 4.5 tree):

typedef irqreturn_t (*irq_handler_t)(int, void *);
like image 120
pah Avatar answered Sep 28 '22 01:09

pah