Sitemap
We develop

We develop

Write your first Linux device driver

5 min readNov 24, 2024

--

The computing world has changed rapidly. In the beginning, we used bare-metal programming with simple embedded processors. As processors improved, we moved on to using Real-Time Operating Systems (RTOS). Eventually, even faster processors allowed us to run Linux directly on our core systems.

Press enter or click to view image in full size
Photo by Gabriel Heinzer on Unsplash
Photo by Gabriel Heinzer on Unsplash

For embedded applications, we often need to connect multiple devices. The operating system must communicate with these devices. Just as we use different drivers for keyboards and mice connected to our laptops, we need to create and use drivers that allow the OS to communicate with custom devices. These drivers must be “injected” into the existing kernel so that the kernel can access them whenever it needs to interact with the custom device. This is the main purpose of writing a device driver in Linux.

The Kernel is responsible for communicating with the hardware, and it does this through device drivers. On top of the kernel layer, there’s a system interface that connects with the user space, where our applications run.

The structure of the components in a Linux environment

When you write a device driver, you need to integrate that with Kernel. It can be done in two ways.

  • Put device driver into Kernel source and recompile the Kernel
  • Dynamically loading the driver files (Loadable Kernel Modules or LKM) into the running kernel

The second method is more efficient one and will save a lot of development time.

However, there can be critical issues. If a driver has a problem, it could disrupt the kernel. Therefore, it’s recommended to test Loadable Kernel Modules (LKMs) in a sandbox or virtual machine with Linux OS. You can use Multipass for this purpose. For setting up a Multipass instance in Windows, you can refer to this article.

Connect to virtual instance

After setting up Multipass, you can connect Visual Studio Code (VS Code) to the virtual instance. Once connected, use the VS Code terminal to run the following commands:

sudo apt update
sudo apt upgrade

To compile code for a Linux device driver, you’ll need some tools provided by the build-essential package. This package includes everything you need to compile the code. Additionally, you will need the Linux header files that match your Linux kernel version. The kmod package is used to handle loading kernel modules.

sudo apt install -y build-essential linux-headers-$(uname -r) kmod

Basics on Kernel

The kernel manages software processes and hardware peripherals connected to the machine. It consists of files stored on the HDD/SSD. When the system boots up, these files are loaded into DRAM/RAM so the CPU can fetch and execute instructions as needed.

Linux boot process

  1. Machine powered ON
  2. ROM code executes and check for basic peripherals intact
  3. Bootloader is copied from internal storage (SSD/HDD) to memory (DRAM)
  4. Bootloader copies dtb (device tree blob) into DRAM
  5. Kernel is copied into memory from internal storage

The kernel includes abstracted sets of instructions that execute as needed. For example, when a Bluetooth headset is connected, the corresponding driver file is executed from the kernel. Therefore, the kernel needs to know the hardware details provided by the dtb.

The kernel operates in privileged mode, with direct access to hardware peripherals. In contrast, user applications (user space) run in non-privileged mode and must request the kernel to perform hardware-specific operations. These requests are made using system calls, and the device drivers must have functions to handle these calls.

Linux treats everything as a file, meaning basic file operations (open, close, read, write, seek) apply to all hardware operations. For instance, if a user tries to read data from a UART port, the kernel accesses /dev/ttyACM0 and performs the read() function to get the UART port data for the user.

Get We develop’s stories in your inbox

Join Medium for free to get updates from this writer.

There are three types of drivers in Linux:

  • Character drivers
  • Block drivers (eg: file system, storage related)
  • Network drivers (eg: ethernet)

Write a linux driver

write a C source file (ldriver.c) with init and exit function

#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Vdevelop");
MODULE_DESCRIPTION("Our first kernel module");
static int opening_function (void)
{
printk("You have injected your first kernel module\n");
return 0;
}
static void closing_function (void)
{
printk("You have removed your kernel module\n");
}
module_init(opening_function);
module_exit(closing_function);

Write a Makefile to build above source code

obj-m += ldriver.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

Note: If you’re copying and pasting above code to create your Makefile, you may get error Makefile:4: *** missing separator. Stop. Therefore, after copying you should replace spaces in line 4 and line 6 with one tab each.

Build the source file using following command

make

This process will create several files within the folder, including the kernel module file with the .ko extension. To test your module, you need to inject it into the kernel using the following command.

sudo insmod ldd.ko

You can check now if above process works well

echo $?

If this outputs 0 then you were able to inject your module into kernel successfully.

sudo dmesg

This will provide the log where at the end you will be able to see “Hello world”.

If the log is full of junk messages, you can clear that using

sudo dmesg -c

You can remove the module from kernel now and you will be seeing the

sudo rmmod ldriver

The information of the module can be viewed using

modinfo ldd.ko

Press enter or click to view image in full size

Conclusion

You have created and tested a simple character driver in the Linux kernel. This is the first step into the world of writing your own device drivers. In upcoming articles, we will explore even more topics. If you encounter any issues with the steps above, please let me know in the comments.

--

--