1
0
mirror of https://github.com/bashrc/LKMPG.git synced 2018-06-11 03:06:54 +02:00

Example of bottom half within an interrupt

This commit is contained in:
Bob Mottram
2017-05-16 18:37:40 +01:00
parent 1d38ec9116
commit 9dac267b5f
4 changed files with 955 additions and 440 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -3550,6 +3550,176 @@ MODULE_AUTHOR("Bob Mottram");
MODULE_DESCRIPTION("Handle some GPIO interrupts");
#+END_SRC
** Bottom Half
Suppose you want to do a bunch of stuff inside of an interrupt routine. A common way to do that without rendering the interrupt unavailable for a significant duration is to combine it with a tasklet. This pushes the bulk of the work off into the scheduler.
#+begin_src C file:bottomhalf.c
/*
* bottomhalf.c -
*
* Copyright (C) 2017 by Bob Mottram
* Based upon the Rpi example by Stefan Wendler (devnull@kaltpost.de)
* from:
* https://github.com/wendlers/rpi-kmod-samples
*
* Press one button to turn on a LED and another to turn it off
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
static int button_irqs[] = { -1, -1 };
/* Define GPIOs for LEDs.
Change the numbers for the GPIO on your board. */
static struct gpio leds[] = {
{ 4, GPIOF_OUT_INIT_LOW, "LED 1" }
};
/* Define GPIOs for BUTTONS
Change the numbers for the GPIO on your board. */
static struct gpio buttons[] = {
{ 17, GPIOF_IN, "LED 1 ON BUTTON" },
{ 18, GPIOF_IN, "LED 1 OFF BUTTON" }
};
/* Tasklet containing some non-trivial amount of processing */
static void bottomhalf_tasklet_fn(unsigned long data)
{
printk("Bottom half tasklet starts\n");
/* do something which takes a while */
mdelay(500);
printk("Bottom half tasklet ends\n");
}
DECLARE_TASKLET(buttontask, bottomhalf_tasklet_fn, 0L);
/*
* interrupt function triggered when a button is pressed
*/
static irqreturn_t button_isr(int irq, void *data)
{
/* Do something quickly */
if (irq == button_irqs[0] && !gpio_get_value(leds[0].gpio))
gpio_set_value(leds[0].gpio, 1);
else if(irq == button_irqs[1] && gpio_get_value(leds[0].gpio))
gpio_set_value(leds[0].gpio, 0);
/* Do the rest at leasure via the scheduler */
tasklet_schedule(&buttontask);
return IRQ_HANDLED;
}
int init_module()
{
int ret = 0;
printk(KERN_INFO "%s\n", __func__);
/* register LED gpios */
ret = gpio_request_array(leds, ARRAY_SIZE(leds));
if (ret) {
printk(KERN_ERR "Unable to request GPIOs for LEDs: %d\n", ret);
return ret;
}
/* register BUTTON gpios */
ret = gpio_request_array(buttons, ARRAY_SIZE(buttons));
if (ret) {
printk(KERN_ERR "Unable to request GPIOs for BUTTONs: %d\n", ret);
goto fail1;
}
printk(KERN_INFO "Current button1 value: %d\n",
gpio_get_value(buttons[0].gpio));
ret = gpio_to_irq(buttons[0].gpio);
if (ret < 0) {
printk(KERN_ERR "Unable to request IRQ: %d\n", ret);
goto fail2;
}
button_irqs[0] = ret;
printk(KERN_INFO "Successfully requested BUTTON1 IRQ # %d\n",
button_irqs[0]);
ret = request_irq(button_irqs[0], button_isr,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
"gpiomod#button1", NULL);
if (ret) {
printk(KERN_ERR "Unable to request IRQ: %d\n", ret);
goto fail2;
}
ret = gpio_to_irq(buttons[1].gpio);
if (ret < 0) {
printk(KERN_ERR "Unable to request IRQ: %d\n", ret);
goto fail2;
}
button_irqs[1] = ret;
printk(KERN_INFO "Successfully requested BUTTON2 IRQ # %d\n",
button_irqs[1]);
ret = request_irq(button_irqs[1], button_isr,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
"gpiomod#button2", NULL);
if (ret) {
printk(KERN_ERR "Unable to request IRQ: %d\n", ret);
goto fail3;
}
return 0;
/* cleanup what has been setup so far */
fail3:
free_irq(button_irqs[0], NULL);
fail2:
gpio_free_array(buttons, ARRAY_SIZE(leds));
fail1:
gpio_free_array(leds, ARRAY_SIZE(leds));
return ret;
}
void cleanup_module()
{
int i;
printk(KERN_INFO "%s\n", __func__);
/* free irqs */
free_irq(button_irqs[0], NULL);
free_irq(button_irqs[1], NULL);
/* turn all LEDs off */
for (i = 0; i < ARRAY_SIZE(leds); i++)
gpio_set_value(leds[i].gpio, 0);
/* unregister */
gpio_free_array(leds, ARRAY_SIZE(leds));
gpio_free_array(buttons, ARRAY_SIZE(buttons));
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Bob Mottram");
MODULE_DESCRIPTION("Interrupt with top and bottom half");
#+end_src
* Crypto
At the dawn of the internet everybody trusted everybody completely...but that didn't work out so well. When this guide was originally written it was a more innocent era in which almost nobody actually gave a damn about crypto - least of all kernel developers. That's certainly no longer the case now. To handle crypto stuff the kernel has its own API enabling common methods of encryption, decryption and your favourite hash functions.

View File

@@ -27,6 +27,7 @@ obj-m += example_spinlock.o
obj-m += example_rwlock.o
obj-m += example_atomic.o
obj-m += example_mutex.o
obj-m += bottomhalf.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

View File

@@ -0,0 +1,165 @@
/*
* bottomhalf.c -
*
* Copyright (C) 2017 by Bob Mottram
* Based upon the Rpi example by Stefan Wendler (devnull@kaltpost.de)
* from:
* https://github.com/wendlers/rpi-kmod-samples
*
* Press one button to turn on a LED and another to turn it off
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
static int button_irqs[] = { -1, -1 };
/* Define GPIOs for LEDs.
Change the numbers for the GPIO on your board. */
static struct gpio leds[] = {
{ 4, GPIOF_OUT_INIT_LOW, "LED 1" }
};
/* Define GPIOs for BUTTONS
Change the numbers for the GPIO on your board. */
static struct gpio buttons[] = {
{ 17, GPIOF_IN, "LED 1 ON BUTTON" },
{ 18, GPIOF_IN, "LED 1 OFF BUTTON" }
};
/* Tasklet containing some non-trivial amount of processing */
static void bottomhalf_tasklet_fn(unsigned long data)
{
printk("Bottom half tasklet starts\n");
/* do something which takes a while */
mdelay(500);
printk("Bottom half tasklet ends\n");
}
DECLARE_TASKLET(buttontask, bottomhalf_tasklet_fn, 0L);
/*
* interrupt function triggered when a button is pressed
*/
static irqreturn_t button_isr(int irq, void *data)
{
/* Do something quickly */
if (irq == button_irqs[0] && !gpio_get_value(leds[0].gpio))
gpio_set_value(leds[0].gpio, 1);
else if(irq == button_irqs[1] && gpio_get_value(leds[0].gpio))
gpio_set_value(leds[0].gpio, 0);
/* Do the rest at leasure via the scheduler */
tasklet_schedule(&buttontask);
return IRQ_HANDLED;
}
int init_module()
{
int ret = 0;
printk(KERN_INFO "%s\n", __func__);
/* register LED gpios */
ret = gpio_request_array(leds, ARRAY_SIZE(leds));
if (ret) {
printk(KERN_ERR "Unable to request GPIOs for LEDs: %d\n", ret);
return ret;
}
/* register BUTTON gpios */
ret = gpio_request_array(buttons, ARRAY_SIZE(buttons));
if (ret) {
printk(KERN_ERR "Unable to request GPIOs for BUTTONs: %d\n", ret);
goto fail1;
}
printk(KERN_INFO "Current button1 value: %d\n",
gpio_get_value(buttons[0].gpio));
ret = gpio_to_irq(buttons[0].gpio);
if (ret < 0) {
printk(KERN_ERR "Unable to request IRQ: %d\n", ret);
goto fail2;
}
button_irqs[0] = ret;
printk(KERN_INFO "Successfully requested BUTTON1 IRQ # %d\n",
button_irqs[0]);
ret = request_irq(button_irqs[0], button_isr,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
"gpiomod#button1", NULL);
if (ret) {
printk(KERN_ERR "Unable to request IRQ: %d\n", ret);
goto fail2;
}
ret = gpio_to_irq(buttons[1].gpio);
if (ret < 0) {
printk(KERN_ERR "Unable to request IRQ: %d\n", ret);
goto fail2;
}
button_irqs[1] = ret;
printk(KERN_INFO "Successfully requested BUTTON2 IRQ # %d\n",
button_irqs[1]);
ret = request_irq(button_irqs[1], button_isr,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
"gpiomod#button2", NULL);
if (ret) {
printk(KERN_ERR "Unable to request IRQ: %d\n", ret);
goto fail3;
}
return 0;
/* cleanup what has been setup so far */
fail3:
free_irq(button_irqs[0], NULL);
fail2:
gpio_free_array(buttons, ARRAY_SIZE(leds));
fail1:
gpio_free_array(leds, ARRAY_SIZE(leds));
return ret;
}
void cleanup_module()
{
int i;
printk(KERN_INFO "%s\n", __func__);
/* free irqs */
free_irq(button_irqs[0], NULL);
free_irq(button_irqs[1], NULL);
/* turn all LEDs off */
for (i = 0; i < ARRAY_SIZE(leds); i++)
gpio_set_value(leds[i].gpio, 0);
/* unregister */
gpio_free_array(leds, ARRAY_SIZE(leds));
gpio_free_array(buttons, ARRAY_SIZE(buttons));
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Bob Mottram");
MODULE_DESCRIPTION("Interrupt with top and bottom half");