-
Notifications
You must be signed in to change notification settings - Fork 1
helloworld
Introduce the basic concepts and a simple driver "skeleton" with typical functions used to write a device driver and how to compile it.
As the name says, this driver just "prints" (sends to syslog) a "hello, world" message. This a very simple piece of code that shows the very basic of the Linux device drivers development. First we include the necessary header files:
#include <linux/init.h>
#include <linux/module.h>
The next spet is to include the driver entry and exit point to the Kernel:
static int hello_init(void)
{
pr_alert("Hello, world\n");
return 0;
}
static void hello_exit(void)
{
pr_alert("Goodbye, cruel world\n");
}
As we can see we use the printk
function to print the hello, world
message. The argument KERN_ALERT
is used to inform how important the message to be printed is. The table bellow list all values:
Name | Value | Description |
---|---|---|
KERN_EMERG | 0 | system is unusable |
KERN_ALERT | 1 | action must be taken immediately |
KERN_CRIT | 2 | critical conditions |
KERN_ERR | 3 | error conditions |
KERN_WARNING | 4 | warning conditions |
KERN_NOTICE | 5 | normal but significant condition |
KERN_INFO | 6 | informational |
KERN_DEBUG | 7 | debug-level messages |
The printk
funcion can be found in the file include/linux/printk.h
and kernel/printk.c
. In fact the kernel developers use macros as wrappers for printk
, according to the message severity, e.g. pr_debug
, pr_info
, pr_notice
and so on.
And in order to tell the Kernel the device driver's entry and exit point, we use the following macros:
module_init(hello_init);
module_exit(hello_exit);
And their corresponding declaration and implementation can be found at include/linux/module.h
and kernel/module.c
.
After compiling the driver, you execute sudo insmod helloworld.ko
and you shall see at the syslog the hello, world
message. To unload the driver from memory execute sudo rmmod helloworld.ko
and you shall see the message Goodbye, cruel world
.
And in order to compile the driver code the following Makefile is used:
TARGET = helloworld
ifneq ($(KERNELRELEASE),)
# call from kernel build system
obj-m := $(TARGET).o
else
KERNELDIR ?= ~/src/linux
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules
endif
clean:
rm -rf *.o *.ko *~ core .depend *.mod.c .*.cmd .tmp_versions .*.o.d \
*.order *.symvers
depend .depend dep:
$(CC) $(CFLAGS) -M *.c > .depend
ins: default rem
insmod $(TARGET).ko debug=1
rem:
@if [ -n "`lsmod | grep -s $(TARGET)`" ]; then \
rmmod $(TARGET); \
echo "rmmod $(TARGET)"; \
fi
ifeq (.depend,$(wildcard .depend))
include .depend
endif
Run make
to compile it. Run sudo make ins
or sudo insmod helloworld.ko
to insert the driver (AKA module) in the Linux Kernel memory space. Then take a look at the kernel log and you should see the following lines:
Jun 16 21:09:19 localhost kernel: [42127.560470] Hello, world
Jun 16 21:09:25 localhost kernel: [42133.989496] Goodbye, cruel world