![]() |
Exploring BeagleBone: LKMs (by Derek Molloy)
V1.0
This project describes how you can build loadable kernel modules (LKMs) on your BeagleBone platform
|
A kernel module for controlling a button (or any signal) that is connected to a GPIO. It has full support for interrupts and for sysfs entries so that an interface can be created to the button or the button can be configured from Linux userspace. The sysfs entry appears at /sys/ebb/gpio115. More...
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/kobject.h>
#include <linux/time.h>
Macros | |
#define | DEBOUNCE_TIME 200 |
The default bounce time – 200ms. More... | |
Functions | |
MODULE_LICENSE ("GPL") | |
MODULE_AUTHOR ("Derek Molloy") | |
MODULE_DESCRIPTION ("A simple Linux GPIO Button LKM for the BBB") | |
MODULE_VERSION ("0.1") | |
module_param (isRising, bool, S_IRUGO) | |
Param desc. S_IRUGO can be read/not changed. More... | |
MODULE_PARM_DESC (isRising," Rising edge = 1 (default), Falling edge = 0") | |
parameter description More... | |
module_param (gpioButton, uint, S_IRUGO) | |
Param desc. S_IRUGO can be read/not changed. More... | |
MODULE_PARM_DESC (gpioButton," GPIO Button number (default=115)") | |
parameter description More... | |
module_param (gpioLED, uint, S_IRUGO) | |
Param desc. S_IRUGO can be read/not changed. More... | |
MODULE_PARM_DESC (gpioLED," GPIO LED number (default=49)") | |
parameter description More... | |
static irq_handler_t | ebbgpio_irq_handler (unsigned int irq, void *dev_id, struct pt_regs *regs) |
Function prototype for the custom IRQ handler function – see below for the implementation. More... | |
static ssize_t | numberPresses_show (struct kobject *kobj, struct kobj_attribute *attr, char *buf) |
A callback function to output the numberPresses variable. More... | |
static ssize_t | numberPresses_store (struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) |
A callback function to read in the numberPresses variable. More... | |
static ssize_t | ledOn_show (struct kobject *kobj, struct kobj_attribute *attr, char *buf) |
Displays if the LED is on or off. More... | |
static ssize_t | lastTime_show (struct kobject *kobj, struct kobj_attribute *attr, char *buf) |
Displays the last time the button was pressed – manually output the date (no localization) More... | |
static ssize_t | diffTime_show (struct kobject *kobj, struct kobj_attribute *attr, char *buf) |
Display the time difference in the form secs.nanosecs to 9 places. More... | |
static ssize_t | isDebounce_show (struct kobject *kobj, struct kobj_attribute *attr, char *buf) |
Displays if button debouncing is on or off. More... | |
static ssize_t | isDebounce_store (struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) |
Stores and sets the debounce state. More... | |
static int __init | ebbButton_init (void) |
The LKM initialization function The static keyword restricts the visibility of the function to within this C file. The __init macro means that for a built-in driver (not a LKM) the function is only used at initialization time and that it can be discarded and its memory freed up after that point. In this example this function sets up the GPIOs and the IRQ. More... | |
static void __exit | ebbButton_exit (void) |
The LKM cleanup function Similar to the initialization function, it is static. The __exit macro notifies that if this code is used for a built-in driver (not a LKM) that this function is not required. More... | |
module_init (ebbButton_init) | |
module_exit (ebbButton_exit) | |
Variables | |
static bool | isRising = 1 |
Rising edge is the default IRQ property. More... | |
static unsigned int | gpioButton = 115 |
Default GPIO is 115. More... | |
static unsigned int | gpioLED = 49 |
Default GPIO is 49. More... | |
static char | gpioName [8] = "gpioXXX" |
Null terminated default string – just in case. More... | |
static int | irqNumber |
Used to share the IRQ number within this file. More... | |
static int | numberPresses = 0 |
For information, store the number of button presses. More... | |
static bool | ledOn = 0 |
Is the LED on or off? Used to invert its state (off by default) More... | |
static bool | isDebounce = 1 |
Use to store the debounce state (on by default) More... | |
static struct timespec ts_last ts_current | ts_diff |
timespecs from linux/time.h (has nano precision) More... | |
static struct kobj_attribute | count_attr = __ATTR(numberPresses, 0666, numberPresses_show, numberPresses_store) |
static struct kobj_attribute | debounce_attr = __ATTR(isDebounce, 0666, isDebounce_show, isDebounce_store) |
static struct kobj_attribute | ledon_attr = __ATTR_RO(ledOn) |
the ledon kobject attr More... | |
static struct kobj_attribute | time_attr = __ATTR_RO(lastTime) |
the last time pressed kobject attr More... | |
static struct kobj_attribute | diff_attr = __ATTR_RO(diffTime) |
the difference in time attr More... | |
static struct attribute * | ebb_attrs [] |
static struct attribute_group | attr_group |
static struct kobject * | ebb_kobj |
A kernel module for controlling a button (or any signal) that is connected to a GPIO. It has full support for interrupts and for sysfs entries so that an interface can be created to the button or the button can be configured from Linux userspace. The sysfs entry appears at /sys/ebb/gpio115.
#define DEBOUNCE_TIME 200 |
The default bounce time – 200ms.
|
static |
|
static |
The LKM cleanup function Similar to the initialization function, it is static. The __exit macro notifies that if this code is used for a built-in driver (not a LKM) that this function is not required.
|
static |
The LKM initialization function The static keyword restricts the visibility of the function to within this C file. The __init macro means that for a built-in driver (not a LKM) the function is only used at initialization time and that it can be discarded and its memory freed up after that point. In this example this function sets up the GPIOs and the IRQ.
GPIO numbers and IRQ numbers are not the same! This function performs the mapping for us
|
static |
Function prototype for the custom IRQ handler function – see below for the implementation.
The GPIO IRQ Handler function This function is a custom interrupt handler that is attached to the GPIO above. The same interrupt handler cannot be invoked concurrently as the interrupt line is masked out until the function is complete. This function is static as it should not be invoked directly from outside of this file.
irq | the IRQ number that is associated with the GPIO – useful for logging. |
dev_id | the *dev_id that is provided – can be used to identify which device caused the interrupt Not used in this example as NULL is passed. |
regs | h/w specific register values – only really ever used for debugging. return returns IRQ_HANDLED if successful – should return IRQ_NONE otherwise. |
|
static |
Displays if button debouncing is on or off.
|
static |
Stores and sets the debounce state.
|
static |
|
static |
MODULE_AUTHOR | ( | "Derek Molloy" | ) |
MODULE_DESCRIPTION | ( | "A simple Linux GPIO Button LKM for the BBB" | ) |
module_exit | ( | ebbButton_exit | ) |
module_init | ( | ebbButton_init | ) |
MODULE_LICENSE | ( | "GPL" | ) |
module_param | ( | isRising | , |
bool | , | ||
S_IRUGO | |||
) |
Param desc. S_IRUGO can be read/not changed.
module_param | ( | gpioButton | , |
uint | , | ||
S_IRUGO | |||
) |
Param desc. S_IRUGO can be read/not changed.
module_param | ( | gpioLED | , |
uint | , | ||
S_IRUGO | |||
) |
Param desc. S_IRUGO can be read/not changed.
MODULE_PARM_DESC | ( | isRising | , |
" Rising | edge = 1 (default) |
||
) |
parameter description
MODULE_PARM_DESC | ( | gpioButton | , |
" GPIO Button number (default=115)" | |||
) |
parameter description
MODULE_PARM_DESC | ( | gpioLED | , |
" GPIO LED number (default=49)" | |||
) |
parameter description
MODULE_VERSION | ( | "0.1" | ) |
|
static |
A callback function to output the numberPresses variable.
kobj | represents a kernel object device that appears in the sysfs filesystem |
attr | the pointer to the kobj_attribute struct |
buf | the buffer to which to write the number of presses |
|
static |
A callback function to read in the numberPresses variable.
kobj | represents a kernel object device that appears in the sysfs filesystem |
attr | the pointer to the kobj_attribute struct |
buf | the buffer from which to read the number of presses (e.g., reset to 0). |
count | the number characters in the buffer |
|
static |
The attribute group uses the attribute array and a name, which is exposed on sysfs – in this case it is gpio115, which is automatically defined in the ebbButton_init() function below using the custom kernel parameter that can be passed when the module is loaded.
|
static |
Use these helper macros to define the name and access levels of the kobj_attributes The kobj_attribute has an attribute attr (name and mode), show and store function pointers The count variable is associated with the numberPresses variable and it is to be exposed with mode 0666 using the numberPresses_show and numberPresses_store functions above
|
static |
|
static |
the difference in time attr
|
static |
The ebb_attrs[] is an array of attributes that is used to create the attribute group below. The attr property of the kobj_attribute is used to extract the attribute struct
|
static |
|
static |
Default GPIO is 115.
|
static |
Default GPIO is 49.
|
static |
Null terminated default string – just in case.
|
static |
Used to share the IRQ number within this file.
|
static |
Use to store the debounce state (on by default)
|
static |
Rising edge is the default IRQ property.
|
static |
Is the LED on or off? Used to invert its state (off by default)
|
static |
the ledon kobject attr
The __ATTR_RO macro defines a read-only attribute. There is no need to identify that the function is called _show, but it must be present. __ATTR_WO can be used for a write-only attribute but only in Linux 3.11.x on.
|
static |
For information, store the number of button presses.
|
static |
the last time pressed kobject attr
|
static |
timespecs from linux/time.h (has nano precision)