Exploring BeagleBone: LKMs (by Derek Molloy)  V1.0
This project describes how you can build loadable kernel modules (LKMs) on your BeagleBone platform
 All Files Functions Variables Enumerations Enumerator Macros
Macros | Functions | Variables
button.c File Reference

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>
Include dependency graph for button.c:

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
 

Detailed Description

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.

Author
Derek Molloy
Date
19 April 2015
See also
http://www.derekmolloy.ie/

Macro Definition Documentation

#define DEBOUNCE_TIME   200

The default bounce time – 200ms.

Function Documentation

static ssize_t diffTime_show ( struct kobject *  kobj,
struct kobj_attribute *  attr,
char *  buf 
)
static

Display the time difference in the form secs.nanosecs to 9 places.

83  {
84  return sprintf(buf, "%lu.%.9lu\n", ts_diff.tv_sec, ts_diff.tv_nsec);
85 }
static struct timespec ts_last ts_current ts_diff
timespecs from linux/time.h (has nano precision)
Definition: button.c:43
static void __exit ebbButton_exit ( void  )
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.

212  {
213  printk(KERN_INFO "EBB Button: The button was pressed %d times\n", numberPresses);
214  kobject_put(ebb_kobj); // clean up -- remove the kobject sysfs entry
215  gpio_set_value(gpioLED, 0); // Turn the LED off, makes it clear the device was unloaded
216  gpio_unexport(gpioLED); // Unexport the LED GPIO
217  free_irq(irqNumber, NULL); // Free the IRQ number, no *dev_id required in this case
218  gpio_unexport(gpioButton); // Unexport the Button GPIO
219  gpio_free(gpioLED); // Free the LED GPIO
220  gpio_free(gpioButton); // Free the Button GPIO
221  printk(KERN_INFO "EBB Button: Goodbye from the EBB Button LKM!\n");
222 }
static int numberPresses
For information, store the number of button presses.
Definition: button.c:40
static int irqNumber
Used to share the IRQ number within this file.
Definition: button.c:39
static unsigned int gpioButton
Default GPIO is 115.
Definition: button.c:30
static unsigned int gpioLED
Default GPIO is 49.
Definition: button.c:34
static struct kobject * ebb_kobj
Definition: button.c:144
static int __init ebbButton_init ( void  )
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.

Returns
returns 0 if successful

GPIO numbers and IRQ numbers are not the same! This function performs the mapping for us

153  {
154  int result = 0;
155  unsigned long IRQflags = IRQF_TRIGGER_RISING; // The default is a rising-edge interrupt
156 
157  printk(KERN_INFO "EBB Button: Initializing the EBB Button LKM\n");
158  sprintf(gpioName, "gpio%d", gpioButton); // Create the gpio115 name for /sys/ebb/gpio115
159 
160  // create the kobject sysfs entry at /sys/ebb -- probably not an ideal location!
161  ebb_kobj = kobject_create_and_add("ebb", kernel_kobj->parent); // kernel_kobj points to /sys/kernel
162  if(!ebb_kobj){
163  printk(KERN_ALERT "EBB Button: failed to create kobject mapping\n");
164  return -ENOMEM;
165  }
166  // add the attributes to /sys/ebb/ -- for example, /sys/ebb/gpio115/numberPresses
167  result = sysfs_create_group(ebb_kobj, &attr_group);
168  if(result) {
169  printk(KERN_ALERT "EBB Button: failed to create sysfs group\n");
170  kobject_put(ebb_kobj); // clean up -- remove the kobject sysfs entry
171  return result;
172  }
173  getnstimeofday(&ts_last); // set the last time to be the current time
174  ts_diff = timespec_sub(ts_last, ts_last); // set the initial time difference to be 0
175 
176  // Going to set up the LED. It is a GPIO in output mode and will be on by default
177  ledOn = true;
178  gpio_request(gpioLED, "sysfs"); // gpioLED is hardcoded to 49, request it
179  gpio_direction_output(gpioLED, ledOn); // Set the gpio to be in output mode and on
180 // gpio_set_value(gpioLED, ledOn); // Not required as set by line above (here for reference)
181  gpio_export(gpioLED, false); // Causes gpio49 to appear in /sys/class/gpio
182  // the bool argument prevents the direction from being changed
183  gpio_request(gpioButton, "sysfs"); // Set up the gpioButton
184  gpio_direction_input(gpioButton); // Set the button GPIO to be an input
185  gpio_set_debounce(gpioButton, DEBOUNCE_TIME); // Debounce the button with a delay of 200ms
186  gpio_export(gpioButton, false); // Causes gpio115 to appear in /sys/class/gpio
187  // the bool argument prevents the direction from being changed
188 
189  // Perform a quick test to see that the button is working as expected on LKM load
190  printk(KERN_INFO "EBB Button: The button state is currently: %d\n", gpio_get_value(gpioButton));
191 
193  irqNumber = gpio_to_irq(gpioButton);
194  printk(KERN_INFO "EBB Button: The button is mapped to IRQ: %d\n", irqNumber);
195 
196  if(!isRising){ // If the kernel parameter isRising=0 is supplied
197  IRQflags = IRQF_TRIGGER_FALLING; // Set the interrupt to be on the falling edge
198  }
199  // This next call requests an interrupt line
200  result = request_irq(irqNumber, // The interrupt number requested
201  (irq_handler_t) ebbgpio_irq_handler, // The pointer to the handler function below
202  IRQflags, // Use the custom kernel param to set interrupt type
203  "ebb_button_handler", // Used in /proc/interrupts to identify the owner
204  NULL); // The *dev_id for shared interrupt lines, NULL is okay
205  return result;
206 }
static char gpioName[8]
Null terminated default string – just in case.
Definition: button.c:38
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.
Definition: button.c:234
static bool isRising
Rising edge is the default IRQ property.
Definition: button.c:26
static int irqNumber
Used to share the IRQ number within this file.
Definition: button.c:39
static bool ledOn
Is the LED on or off? Used to invert its state (off by default)
Definition: button.c:41
static unsigned int gpioButton
Default GPIO is 115.
Definition: button.c:30
static struct attribute_group attr_group
Definition: button.c:139
static unsigned int gpioLED
Default GPIO is 49.
Definition: button.c:34
static struct kobject * ebb_kobj
Definition: button.c:144
#define DEBOUNCE_TIME
The default bounce time – 200ms.
Definition: button.c:19
static struct timespec ts_last ts_current ts_diff
timespecs from linux/time.h (has nano precision)
Definition: button.c:43
static irq_handler_t ebbgpio_irq_handler ( unsigned int  irq,
void *  dev_id,
struct pt_regs *  regs 
)
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.

Parameters
irqthe IRQ number that is associated with the GPIO – useful for logging.
dev_idthe *dev_id that is provided – can be used to identify which device caused the interrupt Not used in this example as NULL is passed.
regsh/w specific register values – only really ever used for debugging. return returns IRQ_HANDLED if successful – should return IRQ_NONE otherwise.
234  {
235  ledOn = !ledOn; // Invert the LED state on each button press
236  gpio_set_value(gpioLED, ledOn); // Set the physical LED accordingly
237  getnstimeofday(&ts_current); // Get the current time as ts_current
238  ts_diff = timespec_sub(ts_current, ts_last); // Determine the time difference between last 2 presses
239  ts_last = ts_current; // Store the current time as the last time ts_last
240  printk(KERN_INFO "EBB Button: The button state is currently: %d\n", gpio_get_value(gpioButton));
241  numberPresses++; // Global counter, will be outputted when the module is unloaded
242  return (irq_handler_t) IRQ_HANDLED; // Announce that the IRQ has been handled correctly
243 }
static int numberPresses
For information, store the number of button presses.
Definition: button.c:40
static bool ledOn
Is the LED on or off? Used to invert its state (off by default)
Definition: button.c:41
static unsigned int gpioButton
Default GPIO is 115.
Definition: button.c:30
static unsigned int gpioLED
Default GPIO is 49.
Definition: button.c:34
static struct timespec ts_last ts_current ts_diff
timespecs from linux/time.h (has nano precision)
Definition: button.c:43
static ssize_t isDebounce_show ( struct kobject *  kobj,
struct kobj_attribute *  attr,
char *  buf 
)
static

Displays if button debouncing is on or off.

88  {
89  return sprintf(buf, "%d\n", isDebounce);
90 }
static bool isDebounce
Use to store the debounce state (on by default)
Definition: button.c:42
static ssize_t isDebounce_store ( struct kobject *  kobj,
struct kobj_attribute *  attr,
const char *  buf,
size_t  count 
)
static

Stores and sets the debounce state.

93  {
94  unsigned int temp;
95  sscanf(buf, "%du", &temp); // use a temp varable for correct int->bool
96  gpio_set_debounce(gpioButton,0);
97  isDebounce = temp;
98  if(isDebounce) { gpio_set_debounce(gpioButton, DEBOUNCE_TIME);
99  printk(KERN_INFO "EBB Button: Debounce on\n");
100  }
101  else { gpio_set_debounce(gpioButton, 0); // set the debounce time to 0
102  printk(KERN_INFO "EBB Button: Debounce off\n");
103  }
104  return count;
105 }
static unsigned int gpioButton
Default GPIO is 115.
Definition: button.c:30
#define DEBOUNCE_TIME
The default bounce time – 200ms.
Definition: button.c:19
static bool isDebounce
Use to store the debounce state (on by default)
Definition: button.c:42
static ssize_t lastTime_show ( struct kobject *  kobj,
struct kobj_attribute *  attr,
char *  buf 
)
static

Displays the last time the button was pressed – manually output the date (no localization)

77  {
78  return sprintf(buf, "%.2lu:%.2lu:%.2lu:%.9lu \n", (ts_last.tv_sec/3600)%24,
79  (ts_last.tv_sec/60) % 60, ts_last.tv_sec % 60, ts_last.tv_nsec );
80 }
static ssize_t ledOn_show ( struct kobject *  kobj,
struct kobj_attribute *  attr,
char *  buf 
)
static

Displays if the LED is on or off.

72  {
73  return sprintf(buf, "%d\n", ledOn);
74 }
static bool ledOn
Is the LED on or off? Used to invert its state (off by default)
Definition: button.c:41
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 ssize_t numberPresses_show ( struct kobject *  kobj,
struct kobj_attribute *  attr,
char *  buf 
)
static

A callback function to output the numberPresses variable.

Parameters
kobjrepresents a kernel object device that appears in the sysfs filesystem
attrthe pointer to the kobj_attribute struct
bufthe buffer to which to write the number of presses
Returns
return the total number of characters written to the buffer (excluding null)
54  {
55  return sprintf(buf, "%d\n", numberPresses);
56 }
static int numberPresses
For information, store the number of button presses.
Definition: button.c:40
static ssize_t numberPresses_store ( struct kobject *  kobj,
struct kobj_attribute *  attr,
const char *  buf,
size_t  count 
)
static

A callback function to read in the numberPresses variable.

Parameters
kobjrepresents a kernel object device that appears in the sysfs filesystem
attrthe pointer to the kobj_attribute struct
bufthe buffer from which to read the number of presses (e.g., reset to 0).
countthe number characters in the buffer
Returns
return should return the total number of characters used from the buffer
66  {
67  sscanf(buf, "%du", &numberPresses);
68  return count;
69 }
static int numberPresses
For information, store the number of button presses.
Definition: button.c:40

Variable Documentation

struct attribute_group attr_group
static
Initial value:
= {
.name = gpioName,
.attrs = ebb_attrs,
}
static char gpioName[8]
Null terminated default string – just in case.
Definition: button.c:38
static struct attribute * ebb_attrs[]
Definition: button.c:126

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.

struct kobj_attribute count_attr = __ATTR(numberPresses, 0666, numberPresses_show, numberPresses_store)
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

struct kobj_attribute debounce_attr = __ATTR(isDebounce, 0666, isDebounce_show, isDebounce_store)
static
struct kobj_attribute diff_attr = __ATTR_RO(diffTime)
static

the difference in time attr

struct attribute* ebb_attrs[]
static
Initial value:
= {
&count_attr.attr,
&ledon_attr.attr,
&time_attr.attr,
&diff_attr.attr,
&debounce_attr.attr,
NULL,
}
static struct kobj_attribute diff_attr
the difference in time attr
Definition: button.c:121
static struct kobj_attribute time_attr
the last time pressed kobject attr
Definition: button.c:120
static struct kobj_attribute count_attr
Definition: button.c:112
static struct kobj_attribute debounce_attr
Definition: button.c:113
static struct kobj_attribute ledon_attr
the ledon kobject attr
Definition: button.c:119

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

struct kobject* ebb_kobj
static
unsigned int gpioButton = 115
static

Default GPIO is 115.

unsigned int gpioLED = 49
static

Default GPIO is 49.

char gpioName[8] = "gpioXXX"
static

Null terminated default string – just in case.

int irqNumber
static

Used to share the IRQ number within this file.

bool isDebounce = 1
static

Use to store the debounce state (on by default)

bool isRising = 1
static

Rising edge is the default IRQ property.

bool ledOn = 0
static

Is the LED on or off? Used to invert its state (off by default)

struct kobj_attribute ledon_attr = __ATTR_RO(ledOn)
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.

int numberPresses = 0
static

For information, store the number of button presses.

struct kobj_attribute time_attr = __ATTR_RO(lastTime)
static

the last time pressed kobject attr

struct timespec ts_last ts_current ts_diff
static

timespecs from linux/time.h (has nano precision)