6

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 ;)

DocValle
  • 125
  • 2
  • 10
  • 1
    Handler return type `void` hasn't been valid since the 2.4 kernel series (or sometime in the 2.5 development series). Kernel versions 2.6.0 to 2.6.18 inclusive used `irqreturn_t (*handler)(int, void *, struct pt_regs *)`. Kernel versions 2.6.19 onwards use `irqreturn_t (*handler)(int, void *)`. – Ian Abbott Aug 09 '16 at 16:10
  • Thank you for the explanation. So I will continue to use the latest version - But the problem with the invalid parameters still exists. Any ideas? – DocValle Aug 09 '16 at 16:27
  • As @lan mentioned you should change your irq handler signature to `irqreturn_t (*handler)(int, void *, struct pt_regs *)`.. – Sridhar Nagarajan Aug 09 '16 at 18:42
  • @Sridhar Thanks again - I changed my code to match the signature, but still getting the same error as I said... My current code looks like: `static irqreturn_t handler (int irq, void *dev_id, struct pt_regs *regs) { /*handle interrupt */ return IRQ_HANDLED; }` And the function call: `request_irq(irqNumber, handler, 0, "GPIO_Test", NULL);` ...I can't spot any obvious mistakes - you? Thanks so far ;) – DocValle Aug 09 '16 at 21:59

2 Answers2

4

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 *);
pah
  • 4,700
  • 6
  • 28
  • 37
  • Thank you @pah, this explanation is extremely helpful! - I tried using `can_request_irq()`, but It seems that I can't use it because I'm on an arm-typed architecture and this function is only defined on the i386 and x86_64 architectures. (_Unknown symbol can_request_irq (err 0)_) ...Sorry that I forgot to tell you about the architecture in my question. Is there any other way to find out which of these functions causes the problem? Looks like I can't call `irq_to_desc()` or `irq_settings_can_request()` directly. – DocValle Aug 10 '16 at 11:22
  • @DocValle What's the kernel version you're working on? – pah Aug 10 '16 at 11:41
  • I'm using the CHIP [https://getchip.com/](https://getchip.com/) with CHIP-OS 4.4.11. It's a custom linux based on debian. I'm not sure how to find the underlaying kernel-version: `uname -a` gives me `Linux chip 4.4.11-ntc #1 SMP Sat May 28 00:27:07 UTC 2016 armv7l GNU/Linux` and `cat /proc/version` shows: `Linux version 4.4.11-ntc (bamboo@ip-172-31-17-100) (gcc version 5.2.1 20151010 (Ubuntu 5.2.1-22ubuntu1) ) #1 SMP Sat May 28 00:27:07 UTC 2016` – DocValle Aug 10 '16 at 12:12
  • `can_request_irq()` is generic, but the problem is that it is not exported to modules, so there's no way to use it there... My bad, forgot about the question title `kernel-module`. Anyway, I'll see if there's an alternative way to test that from a module. – pah Aug 10 '16 at 12:26
  • Okay, looks like 4.4.11 is the actual kernel-version it's using - my fault, thought this was just the version of there CHIP-OS... – DocValle Aug 10 '16 at 12:41
  • Unfortunately, I'm not being able to find a way to distinguish a *failed irq lookup* from a *non-requestable irq* under a kernel module code, only as kernel *built-in* code as stated on the answer (I'll edit the answer to point that out). Meanwhile, can you provide a snippet around your `gpio_to_irq()` code? – pah Aug 10 '16 at 13:27
  • currently it looks like: `for (i = 0; i < 8; i = i + 1) { error = gpio_to_irq(gpios[i].gpio); if (error < 0) { printk (KERN_ERR "GPIO_Test: Unable to request IRQ-Number: %d\n", error); goto fail1; } inputIrqs[i] = error; error = request_irq(inputIrqs[i], handler, 0, "GPIO_Test", NULL); if(error) { printk(KERN_ERR "GPIO_Test: Unable to set up IRQ: %d\n", error); goto fail1; } }` inputIrqs[] is an int array to store all 8 irqNumbers I want to set up... – DocValle Aug 10 '16 at 13:47
  • Can you try to use `free_irq(inputIrqs[i], NULL)` before `request_irq()`? Also, is it failing for every IRQ ? Or just only one? – pah Aug 10 '16 at 14:19
  • `free_irq(inputIrqs[i])` didn't change anything. It fails for the first IRQ (i=0) and stops. None of my error-checks gets triggered. I load the module with `insmod GPIO_Test.ko` and this gives me this message in the terminal: `insmod: ERROR: could not insert module GPIO_Test.ko: Invalid parameters` -> `dmesg shows GPIO_Test: Unable to set up IRQ: -22` ...I test-printed the irqNumber received from the `gpio_to_irq()`-function, it was 106, seems ok. Thanks so far for your help! ;) – DocValle Aug 10 '16 at 14:30
  • Humm... This is becoming a mystery for me. If I were you, I would debug it directly in the kernel code instead of a module, as there are plenty of other interfaces that would help to get to the root cause. One other thing that crossed my mind was trying to set the irq type before `request_irq()` with something similar to `set_irq_type(inputIrqs[i], IRQ_TYPE_EDGE_RISING);` (or any other appropriate type for your case), but I'm not aware that irq type is evaluated during IRQ handler setup, so the precedence should not matter. – pah Aug 10 '16 at 15:12
  • For some reason my compiler doesn't know the `set_irq_type()`-function: `Implicit declaration of function »set_irq_type« [-Werror=implicit-function-declaration]` ...I think I don't know enough about the linux kernel to work outside a module. What I wanted to do was an input-device which uses some Buttons on the GPIO-Pins as "keyboard". If Interrupts don't want to work I will poll the values 50 times a second or something like this to get it working... Not very elegant though. :/ – DocValle Aug 10 '16 at 15:49
  • You need to include `linux/irq.h` when using `set_irq_type()`. Anyway, yes, not a very elegant solution when GPIO can be IRQ mapped and handled. I'm sorry, but I don't really know what's happening there without doing some extensive debugging. Maybe some other SO user can help you better, so I recommend you to clear the 'accepted answer' tick from this answer, as if it is marked as accepted, few users will ever open and look at it again. – pah Aug 10 '16 at 15:54
  • 1
    I actually did include `linux/irq.h` - Thanks for your time anyway ;) – DocValle Aug 10 '16 at 15:59
0

The request_any_context_irq API (patch) will automatically handle the case if your interrupt line is nested and reuest a threaded handler. Since you cannot access irq_settings_can_request from a module this is worth using before adding instrumentation.

This call allocates interrupt resources and enables the interrupt line and IRQ handling. It selects either a hardirq or threaded handling method depending on the context.

On failure, it returns a negative value. On success, it returns either IRQC_IS_HARDIRQ or IRQC_IS_NESTED.

Lucas
  • 661
  • 1
  • 10
  • 22