Linux Device Drivers

From Embedded Workshop
Revision as of 17:55, 5 July 2020 by JMerkle (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Creating (and testing) Linux Device Drivers using the Raspberry Pi

There are plenty of articles / websites devoted to writing a Linux Device Driver. Using some of these (documented below), we'll go over the basics, and then dive into some details. Linux device drivers fall into one of two camps, "Modular" or "Built In", depending on how it's built. It's even possible a device driver can be part of both camps. We'll examine the "Module", since if the driver is written to function well as a "module", it can often function well as a"built in" driver.

We'll start with Hello World example:
Hello World Example

Create a folder, "hello-1", and copy the following to "hello-1.c" withing that folder:

$ mkdir hello-1
$ cd hello-1
$ mousepad hello-1.c &
/*  
 *  hello-1.c - The simplest kernel module.
 */
#include <linux/module.h>	/* Needed by all modules */
#include <linux/kernel.h>	/* Needed for KERN_INFO */

int init_module(void)
{
	printk(KERN_INFO "Hello world 1.\n");

	/* 
	 * A non 0 return means init_module failed; module can't be loaded. 
	 */
	return 0;
}

void cleanup_module(void)
{
	printk(KERN_INFO "Goodbye world 1.\n");
}


Before we can begin to build (and test) this example kernel module, the kernel source code for current version of Linux running on the Pi needs to be installed on the unit. Determine the version of Linux running on the Pi:

$ uname -a

Example
pi@raspberrypi:~ $ uname -a Linux raspberrypi 4.19.118-v7l+ #1311 SMP Mon Apr 27 14:26:42 BST 2020 armv7l GNU/Linux

From the above example, we can see the Raspberry Pi is running 4.19.118-v7l+. This is the version of Linux contained in 2020-05-27-raspios-buster-full-armhf.img. We need to install the source code for 4.19.118-v7l+. https://www.raspberrypi.org/documentation/linux/kernel/building.md

As the Raspberry Pi "Kernel Building" example indicate, we need to install a few tools first (some of these may already be installed):

$ sudo apt install git bc bison flex libssl-dev make

Only a few of the above packages need installation (the others are already installed). The packages are small and install quickly.
The hard part is determining the "git" command needed to bring in the correct source code. (We don't want the latest, since it appears to be 4.19.127)

See:
https://github.com/raspberrypi/linux
https://www.raspberrypi.org/forums/viewtopic.php?t=257155
https://www.kernel.org/doc/Documentation/kbuild/modules.txt
https://www.raspberrypi.org/documentation/linux/kernel/headers.md

According to the above, I'm running 32-bit armv7 with Long Addresses (for the Pi4 increased ram size) If we are not building the kernel itself (building only Modules), we only need to install the kernel header files, without the source files.

Install the kernel header files for the Raspberry Pi

pi@raspberrypi:~ $ sudo apt-get install raspberrypi-kernel-headers
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following package was automatically installed and is no longer required:
  rpi-eeprom-images
Use 'sudo apt autoremove' to remove it.
The following NEW packages will be installed:
  raspberrypi-kernel-headers
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 24.9 MB of archives.
After this operation, 163 MB of additional disk space will be used.
Get:1 http://archive.raspberrypi.org/debian buster/main armhf raspberrypi-kernel-headers armhf 1.20200601-1 [24.9 MB]
Fetched 24.9 MB in 1min 36s (259 kB/s)                                                                
Selecting previously unselected package raspberrypi-kernel-headers.
(Reading database ... 156472 files and directories currently installed.)
Preparing to unpack .../raspberrypi-kernel-headers_1.20200601-1_armhf.deb ...
Unpacking raspberrypi-kernel-headers (1.20200601-1) ...
Setting up raspberrypi-kernel-headers (1.20200601-1) ...

Assuming you copied the above hello-1.c code into the file, "hello-1.c", copy the following into "Makefile":

$ mousepad Makefile &
#Makefile for hello-1 module
obj-m += hello-1.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

Build the hello-1 module

$ make