diff --git a/demo_module/Makefile b/demo_module/Makefile new file mode 100644 index 0000000..a080c80 --- /dev/null +++ b/demo_module/Makefile @@ -0,0 +1,23 @@ +# This is a standard makefile for building a kernel module. +# It looks a bit backwards compared to a normal makefile, but that's because +# the kernel supplies its own sub-makefile that we use to build the module. +# +# The M= option tells the kernel's makefile where to find the module's source +# files, and the -C option sets the context directory for make. +# +# The obj-m variable tells the kernel's makefile what the module's object file +# should be called. In this case, it's demo_module.o. This is how the sub-makefile +# infers the name of the module's source file. +# +# This build is highly sensitive to compiler version, and requires the system gcc +# to be the same version as the gcc that built the current kernel. +# +# For more info, see: https://www.kernel.org/doc/html/latest/kbuild/modules.html + +obj-m = demo_module.o + +all: + make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) modules + +clean: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean diff --git a/demo_module/demo_module.c b/demo_module/demo_module.c new file mode 100644 index 0000000..85598ab --- /dev/null +++ b/demo_module/demo_module.c @@ -0,0 +1,74 @@ +#include +#include +#include +#include + +/* + * Last compiled with Linux 6.14.5-300.fc42.x86_64 + */ + +/* Meta Info */ +MODULE_DESCRIPTION("Demo kernel module."); +MODULE_VERSION("0.0.1"); +MODULE_AUTHOR("Imbus"); +MODULE_LICENSE("GPL"); + +/* + * Hard coded for RPI3 + * Usually retrieved via device tree + */ +#define IO_LED 21 +#define IO_BUTTON 20 +#define IO_OFFSET 0 + +static struct gpio_desc *led, *button; + +/** + * @brief Called on load + */ +static int __init demo_mod_init(void) { + printk(KERN_INFO "Demo module loaded successfully..."); + + int status; + + led = gpio_to_desc(IO_LED + IO_OFFSET); + if (!led) { + printk("gpioctrl - Error getting pin 21\n"); + return -ENODEV; + } + + button = gpio_to_desc(IO_BUTTON + IO_OFFSET); + if (!button) { + printk("gpioctrl - Error getting pin 20\n"); + return -ENODEV; + } + + status = gpiod_direction_output(led, 0); + if (status) { + printk("gpioctrl - Error setting pin 20 to output\n"); + return status; + } + + status = gpiod_direction_input(button); + if (status) { + printk("gpioctrl - Error setting pin 21 to input\n"); + return status; + } + + gpiod_set_value(led, 1); + + printk("gpioctrl - Button is %spressed\n", + gpiod_get_value(button) ? " " : "not "); + + return 0; +} + +/** + * @brief Called on unload + */ +static void __exit demo_mod_exit(void) { + printk(KERN_INFO "Demo module unloaded successfully..."); +} + +module_init(demo_mod_init); +module_exit(demo_mod_exit);