Writing “hello world” driver for the Linux Kernel

Kumar Gaurav
4 min readOct 4, 2019

--

Before jumping to writing code; Let’s know the basics first.

what is a Linux driver?

I think I can’t give any better definition than the one from the official site:

“Device drivers take on a special role in the Linux kernel. They are distinct “black boxes” that make a particular piece of hardware respond to a well-defined internal programming interface; they hide completely the details of how the device works. User activities are performed by means of a set of standardized calls that are independent of the specific driver; mapping those calls to device-specific operations that act on real hardware is then the role of the device driver. This programming interface is such that drivers can be built separately from the rest of the kernel, and “plugged in” at runtime when needed. This modularity makes Linux drivers easy to write, to the point that there are now hundreds of them available.”

Why do we create drivers?

To make it easy; through device drivers Linux Kernel provides a way to communicate from user-space to device’s chips like WiFi, Bluetooth etc otherwise it’ll not be an easy task to do.

How to write a driver?

The driver should be written in C programming language using only Kernel library which has very limited set of APIs and data types.

Let’s see what all we need. One driver file which will have the code written in C programming language and a Makefile with the default levels like all, clean or any custom one.
Note: That driver file is called Module; Going forward I’ll use this word instead. Also a driver may have more than one modules.

For every driver, two methods are mandatory; one which will get executed at the time of loading the driver and other when driver gets exited. Both are called module_init() and module_exit(). To write code we need set of kernel libraries which are:

#include<linux/module.h>
#include<linux/init.h>
#include<linux/kernel.h>

Now we will write the method to init the driver:

static int hello_init(void){
printk(KERN_ALERT “Hello TheLittleNaruto; it’s your first driver which doesn’t do shit :/\n”);
return 0;
}

And the method when the driver exiting like I mentioned above:

static void hello_exit(void){
printk(KERN_INFO “Goodbye TheLittleNaruto; No point in keeping this driv er running.\n”);
}

Now we are ready with the both methods. Let’s pass these to the init and exit apis:

module_init(hello_init);
module_exit(hello_exit);

Few more things we need to tell in the driver code which is optional; we may skip it; but I think it is necessary. They are Author, Licence and Description. To add these; below is the sample code:

MODULE_AUTHOR(“TheLittleNaruto”);
MODULE_LICENSE(“GPL”);
MODULE_DESCRIPTION(“TheLittleNaruto’s first driver with GPL licence.”);

We are done with writing code for the hello driver; Here is the complete for the same:

How to compile and build:

In order to compile and build the hello module; we need to create a Makefile which will have default level i.e. “all” and level “clean”. In level “all” we will ask to create modules present in current drive directory; and in level “clean” we will ask to cleanup current drive directory to remove compiled files. Below is the code snippet of Makefile.

Note: the make file should be named as “Makefile” else when running “make” command it’ll complain “no file named Makefile”

I told about “all” and “clean” level. Now what is “-C” and “M” are doing here?
“-C” needs the path of kernel module build from where it’ll pick the Makefile and compile as per the definition of the level. “M” needs the absolute path to the driver where all its modules are present.

Note: Modules must be compiled withe kernel version of the Linux system in order to run on the given system. That is why we used the “$(shell uname -r)” which will dynamically pick the current kernel version of the system on which we will be going to run the driver.

Now run the “make” in the driver directory. After running the command; the console should look like this:

Picture 1.0 Output of make command

It should generate object, kernel object files. We are only interested in kernel object file(.ko) for loading the driver module; and if we’ll ls to the same directory; it’ll list all generated files; here is a screenshot:

Picture 1.1 Generated object files

So I think that’s all about it. Let’s run the the driver and see what happens. To load, list and unload the driver we use insmod, lsmod and rmmod respectively . To load the driver run this command:

insmod hello.ko

This will throw error if code has any error else it won’t give any output. And to exiting from running the driver module; run this command:

rmmod hello

To verify whether it worked properly or not; run the following command

dmesg | tail

The output should look like this:

[11489656.503306] Hello TheLittleNaruto; it’s your first driver which doesn’t do shit :/
[11489667.099461] Goodbye TheLittleNaruto; No point in keeping this driver running.

So We learned how to run basic hello driver and exiting today. It;s time to celebrate.

Celebration Time.

--

--

Kumar Gaurav

Android Developer, Otaku and well known with my secondary name “TheLittleNaruto” on internet.