detecting interrupt on GPIO in kernel module
IMO your module lacks some basic kernel module programming prerequisites. At first, you have no includes. For toggling GPIO pins use the following.
#include <linux/init.h> // initialization macros
#include <linux/module.h> // dynamic loading of modules into the kernel
#include <linux/kernel.h> // kernel stuff
#include <linux/gpio.h> // GPIO functions/macros
#include <linux/interrupt.h> // interrupt functions/macros
You should use MODULE_LICENSE("Your license")
otherwise the kernel may get tainted and your initialization and exit functions should be marked with __init
and __exit
macros like:
void __init init_module(void) {...}
void __exit r_int_release(void) {...} // exit code should cleanup all stuff
Furthermore the kernel needs to know which functions to call on module load and exit. Therefore use:
module_init(init_module); // Do some better naming
module_exit(r_int_release);
Now to the IRQ. IRQs must be assigned to GPIOs and you must specify an IRQ handler. So what you need to do within your modules init code is:
static unsigned int yourGPIO = 49; // This is Pin 23 on the P9 header
static unsigned int irqNumber;
static irq_handler_t irqHandler(unsigned int irq, void *dev_id, struct pt_regs *regs);
// This is the IRQ Handler prototype
static int __init init_module(void)
{
int result = 0;
gpio_request(yourGPIO, "fancy label"); // Request a GPIO pin from the driver
// 'yourGPIO' is expected to be an unsigned int, i.e. the GPIO number
gpio_direction_input(yourGPIO); // Set GPIO as input
gpio_set_debounce(yourGPIO, 50); // Set a 50ms debounce, adjust to your needs
gpio_export(yourGPIO); // The GPIO will appear in /sys/class/gpio
...
Without a GPIO pin requested from the driver, the following will fail
...
irqNumber = gpio_to_irq(yourGPIO); // map your GPIO to an IRQ
result = request_irq(irqNumber, // requested interrupt
(irq_handler_t) irqHandler, // pointer to handler function
IRQF_TRIGGER_RISING, // interrupt mode flag
"irqHandler", // used in /proc/interrupts
NULL); // the *dev_id shared interrupt lines, NULL is okay
return result;
}
Last but not least implement your handler function and load the module.
For more reference I recommend reading Derek Molloys Blog on derekmolloy.ie
Siddharth
Updated on July 09, 2022Comments
-
Siddharth almost 2 years
I am toggling the input into a GPIO line on my BeagleBone from high to low every 500 ms using an Atmel uC. I have registered a handler for this in my Linux Kernel Module, but the handler is not being called for some reason.
My module code is -
#define GPIO 54 #define GPIO_INT_NAME "gpio_int" #define GPIO_HIGH gpio_get_value(GPIO) #define GPIO_LOW (gpio_get_value(GPIO) == 0) short int irq_any_gpio = 0; int count =0; enum { falling, rising } type; static irqreturn_t r_irq_handler(int irq, void *dev_id) { count++; printk(KERN_DEBUG "interrupt received (irq: %d)\n", irq); if (irq == gpio_to_irq(GPIO)) { type = GPIO_LOW ? falling : rising; if(type == falling) { printk("gpio pin is low\n"); } else printk("gpio pin is high\n"); } return IRQ_HANDLED; } void r_int_config(void) { if (gpio_request(GPIO, GPIO_INT_NAME )) { printk("GPIO request failure: %s\n", GPIO_INT_NAME ); return; } if ( (irq_any_gpio = gpio_to_irq(GPIO)) < 0 ) { printk("GPIO to IRQ mapping failure %s\n",GPIO_INT_NAME ); return; } printk(KERN_NOTICE "Mapped int %d\n", irq_any_gpio); if (request_irq(irq_any_gpio,(irq_handler_t ) r_irq_handler, IRQF_TRIGGER_HIGH, GPIO_INT_NAME, NULL)) { printk("Irq Request failure\n"); return; } return; } void r_int_release(void) { free_irq(gpio_to_irq(GPIO), NULL); gpio_free(GPIO);; return; } int init_module(void) { printk("<1>Hello World\n"); r_int_config(); return 0; }
On calling insmod interrupt_test.ko, i get the following message
[ 76.594543] Hello World [ 76.597137] Mapped int 214
But now when I start toggling the input into this gpio pin, the interrupt handler doesn't get called and the message (interrupt received is not being displayed).
How do I solve this ? What's causing the problem?