0% found this document useful (0 votes)
21 views8 pages

Chapter 3

Uploaded by

duyhuy362003
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
21 views8 pages

Chapter 3

Uploaded by

duyhuy362003
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 8

3

The Simplest Drivers


A key concept in the design of an embedded Linux system is the separation of user applications
from the underlying hardware. User space applications are not allowed to access peripheral
registers, storage media or even RAM memory directly. Instead, the hardware is accessed via
kernel drivers, and RAM memory is managed by the memory management unit (MMU), with
applications operating on virtual addresses.
This separation provides robustness. If it is assumed that the Linux kernel is operating correctly,
then allowing only the kernel to interact with underlying hardware keeps applications from
accidentally or maliciously misconfiguring hardware peripherals and placing them in unknown
states.
This separation also provides portability. If only the kernel drivers manage the hardware specific
code, only these drivers need to be modified in order to port a system from one hardware platform
to another. Applications access a set of driver APIs that is consistent across hardware platforms,
allowing applications to be moved from one platform to another with little or no modification to
the source code.
Device drivers can be kernel modules or statically built into the kernel image. The default kernel
builds most drivers into the kernel statically, so they are started automatically. A kernel module is
not necessarily a device driver; it is an extension of the kernel. The kernel modules are loaded into
virtual memory of the kernel. Building a device driver as a module makes the development easier,
since it can be loaded, tested and unloaded without rebooting the kernel. The kernel modules are
usually located in /lib/modules/<kernel_version>/ on the root filesystem.
Every Linux kernel module has an init() and an exit() function. The init() function is called once
when the driver is loaded, and the exit() function is called when the driver is removed. The init()
function lets the OS know what the driver is capable of and which of its function must be called
when a certain event takes place (for example, register a driver to the bus or register a char device).
The exit() function must free all the resources that were requested by the init() function.
Macros module_init() and module_exit() export the symbols for the init() and exit() functions such that
the kernel code that loads your module can identify these entry points.

[ 61 ]
The Simplest Drivers Chapter 3

There is a collection of macros used to identify various attributes of a module. These strings get
packaged into the module and can be accessed by various tools. The most important module
description macro is the MODULE_LICENSE macro. If this macro is not set to some sort of GPL
license tag, then the kernel will become tainted when you load your module. When the kernel
is tainted, it means that it is in a state that is not supported by the community. Most kernel
developers will ignore bug reports involving tainted kernels, and community members may ask
that you correct the tainting condition before they can proceed with diagnosing problems related
to the kernel. In addition, some debugging functionality and API calls may be disabled when the
kernel is tainted.

Licensing
The Linux kernel is licensed under the GNU General Public License version 2. This license gives
you the right to use, study, modify and share the software freely. However, when the software is
redistributed, modified or unmodified, the GPL requires that you redistribute the software under
the same license, with the source code. If modifications are made to the Linux kernel (for example
to adapt it to your hardware), it is a derivative work of the kernel and therefore must be released
under GPLv2. However, you're only required to do so at the time the device starts to be distributed
to your customers, not to the entire world.
The kernel modules provided in this book are released under the GPL license. For more
information on open source software licenses, please see http://opensource.org/licenses.

LAB 3.1: "helloworld" module


In your first kernel module, you will simply send some info to the Raspberry Pi console every
time you load and unload the module. The hello_init() and hello_exit() functions include a pr_info()
function. This is much like the printf syntax you use in user applications, except that pr_info() is
used to print log messages in kernel space. If you look into the real kernel code, you will always
see something like:
printk(KERN_ERR "something went wrong, return code: %d\n",ret);

Where KERN_ERR is one of the eight different log levels defined in include/linux/kern_levels.h in
the kernel source tree and specifies the severity of the error message. The pr_* macros (defined in
include/linux/printk.h in the kernel source tree) are simple shorthand definitions for their respective
printk calls and should be used in newer drivers.
In the home folder of your host PC, you will create the linux_5.4_rpi3_drivers folder, where you are
going to store all the drivers and applications developed through this book.
~$ mkdir linux_5.4_rpi3_drivers

[ 62 ]
Chapter 3 The Simplest Drivers

Create the helloworld_rpi3.c and Makefile files using your favorite text editor, and save them in
the linux_5.4_rpi3_drivers folder. Write the Listing 3-1 code and the Listing 3-2 code to these files.
Secure Copy (SCP) will be added to the Makefile to transfer the modules from the host PC to the
Raspberry Pi filesystem via Ethernet:
scp *.ko root@10.0.0.10:

The same Makefile will be reused for many of the labs by simply adding the new <module name>.o
to the Makefile variable obj-m.
Compile the helloworld_rpi3.c driver, and deploy it to the Raspberry Pi:
~/linux_5.4_rpi3_drivers$ make
~/linux_5.4_rpi3_drivers$ make deploy

Listing 3-1: helloworld_rpi3.c


#include <linux/module.h>

static int __init hello_init(void)


{
pr_info("Hello world init\n");
return 0;
}

static void __exit hello_exit(void)


{
pr_info("Hello world exit\n");
}

module_init(hello_init);
module_exit(hello_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Alberto Liberal <aliberal@arroweurope.com>");

MODULE_DESCRIPTION("This is a print out Hello World module");

Listing 3-2: Makefile


obj-m := helloworld.o

KERNEL_DIR ?= $(HOME)/linux_rpi3/linux

all:
make -C $(KERNEL_DIR) \
ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- \
M=$(PWD) modules

[ 63 ]
The Simplest Drivers Chapter 3

clean:
make -C $(KERNEL_DIR) \
ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- \
M=$(PWD) clean

deploy:
scp *.ko root@10.0.0.10:/home/pi

helloworld_rpi3.ko demonstration
Load the module:
root@raspberrypi:/home/pi# insmod helloworld_rpi3.ko
Hello world init
See the MODULE macros defined in your module:
root@raspberrypi:/home/pi# modinfo helloworld_rpi3.ko
filename: /home/pi/helloworld_rpi3.ko
description: This is a print out Hello World module
author: Alberto Liberal <aliberal@arroweurope.com>
license: GPL
srcversion: F329256EE5AE6A9F62F65DF
depends:
name: helloworld_rpi3
vermagic: 5.4.83-v7+ SMP mod_unload modversions ARMv7 p2v8
An externally-built (“out-of-tree”) untainted module has been loaded:
root@raspberrypi:/home/pi# cat /sys/module/helloworld_rpi3/taint
O
Remove the module:
root@raspberrypi:/home/pi# rmmod helloworld_rpi3.ko
Hello world exit
Comment out the MODULE_LICENSE macro in the helloworld_rpi3.c file. Build, deploy and load the
module again. Reboot the Pi!. Work with your tainted module (PO):
root@raspberrypi:/home/pi# reboot
root@raspberrypi:/home/pi# insmod helloworld_rpi3.ko
helloworld_rpi3: module license 'unspecified' taints kernel.
Disabling lock debugging due to kernel taint
Hello world init
root@raspberrypi:/home/pi# cat /proc/sys/kernel/tainted
PO
root@raspberrypi:/home/pi# cat /proc/modules
helloworld_rpi3 16384 0 - Live 0x7f1b6000 (PO)
Find your module in the sysfs:
root@raspberrypi:/home/pi# find /sys -name "*helloworld*"
/sys/module/helloworld_rpi3

[ 64 ]
Chapter 3 The Simplest Drivers

root@raspberrypi:/home/pi# ls /sys/module/helloworld_rpi3/
coresize initsize notes sections taint
holders initstate refcnt srcversion uevent
Remove the module:
root@raspberrypi:/home/pi# rmmod helloworld_rpi3.ko
Hello world exit

LAB 3.2: "helloworld with parameters" module


Many Linux loadable kernel modules (LKMs) have parameters that can be set at load time, boot
time and sometimes at run-time. In this kernel module, you are going to pass a parameter in the
command line that will be set during the module loading. You can also read the parameters via the
sysfs filesystem.
As you saw in the section "The sysfs filesystem" of Chapter 2, the sysfs is a virtual filesystem
provided by the Linux kernel that exports information about the various kernel subsystems,
hardware devices and associated device drivers from the kernel's device model to the user space
through virtual files. In addition to providing information about various devices and kernel
subsystems, exported virtual files are also used for their configuration.
The definition of module parameters is done via the macro module_param():
/*
* the perm argument specifies the permissions
* of the corresponding file in sysfs.
*/
module_param(name, type, perm);

The main code sections of the driver will now be described:


1. After the #include statements, declare a new num variable, and use the module_param() on it:
static int num = 5;
/* S_IRUG0: everyone can read the sysfs entry */
module_param(num, int, S_IRUG0);

2. Write the pr_info statement in the hello_init() function, as shown below:


pr_info("parameter num = %d.\n", num);

3. Create a new helloword_rpi3_with_parameters.c file in the linux_5.4_rpi3_drivers folder,


and add helloworld_rpi3_with_parameters.o to your Makefile obj-m variable, then build and
deploy the module to the Raspberry Pi:
~/linux_5.4_rpi3_drivers$ make

~/linux_5.4_rpi3_drivers$ make deploy

[ 65 ]
The Simplest Drivers Chapter 3

Listing 3-3: helloworld_rpi3_with_parameters.c


#include <linux/module.h>

static int num = 5;

module_param(num, int, S_IRUGO);

static int __init hello_init(void)


{
pr_info("parameter num = %d\n", num);
return 0;
}

static void __exit hello_exit(void)


{
pr_info("Hello world with parameter exit\n");
}

module_init(hello_init);
module_exit(hello_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Alberto Liberal <aliberal@arroweurope.com>");
MODULE_DESCRIPTION("This is a module that accepts parameters");

Listing 3-4: Makefile


obj-m := helloworld.o helloworld_rpi3_with_parameters.o

KERNEL_DIR ?= $(HOME)/linux_rpi3/linux

all:
make -C $(KERNEL_DIR) \
ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- \
M=$(PWD) modules

clean:
make -C $(KERNEL_DIR) \
ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- \
M=$(PWD) clean

deploy:
scp *.ko root@10.0.0.10:/home/pi

[ 66 ]
Chapter 3 The Simplest Drivers

helloworld_rpi3_with_parameters.ko demonstration
Load the module:
root@raspberrypi:/home/pi# insmod helloworld_rpi3_with_parameters.ko
parameter num = 5
Remove the module:
root@raspberrypi:/home/pi# rmmod helloworld_rpi3_with_parameters.ko
Hello world with parameter exit
Load the module with a parameter:
root@raspberrypi:/home/pi# insmod helloworld_rpi3_with_parameters.ko num=10
parameter num = 10
root@raspberrypi:/home/pi# cat /sys/module/helloworld_rpi3_with_parameters/param
eters/num
10
Remove the module:
root@raspberrypi:/home/pi# rmmod helloworld_rpi3_with_parameters.ko
Hello world with parameter exit

[ 67 ]

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy