Embedded Linux Device Driver Module:1

In my previous tutorial i have shown how to run Simple Hello World application on target Qemu using  Virtual Embedded Linux System  setup. In this tutorial we will try to understand how to write Simple Linux Device Driver Module, cross-compiling using Makefile and finally running on target.

The Simple Linux Device Driver module is as shown below.

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

static int __init hello_init(void)
{
pr_alert("Hi All Welcome to Linux Device driver module \n");
return 0;
}

static void __exit hello_exit(void)
{
pr_alert("Goobye to Device driver module \n");
}

module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Welcome module");
MODULE_AUTHOR("Vinay Hunachyal");

Save above file as hello.c.

#include <linux/module.h> :
This module.h mainly contains definitions of symbols and functions needed by loadable modules.

#include <linux/init.h> :
This header required for specify your initialization and cleanup functions.

Initialization and Shutdown:

An initialization function:

This function called when the module is loaded, returns an error code (0 on success, negative value on failure).Its declared by the module_init() macro: the name of the function doesn’t matter, even though <modulename>_init() (e.g hello_init) is a convention.

static int __init initialization_function(void)
{
/* Initialization code here */
}

hello_init  (initialization_function);

static int  __init hello_init(void):
static :
static needs to be declared for Initialization functions, static makes function not meant to be visible outside the specific file. There is no hard rule using static, though, as no function is exported to the rest of the kernel unless explicitly requested.

__init:
It is a hint to the kernel that the given function is used only at initialization time The module loader drops the initialization function after the module is loaded, making its memory available for other user.

hello_init:
This macro adds a special section to the module’s object code stating where the module’s initialization function is to be found. Without this definition, your initialization function is never called.

The Cleanup Function:  This is called when the module is unloaded.

static void __exit cleanup_function(void)
{
/* Cleanup code here */
}

hello_exit(cleanup_function):
The cleanup function has no value to return, so it is declared void.

__exit modifier:
Marks the code as being for module unload only. If your module is built directly into the kernel, or if your kernel is configured to disallow the unloading of modules, functions marked __exit are simply discarded. For this reason, a function marked __exit can be called only at module unload or system shutdown time; any other use is an error. Once again, the module_exit declaration is necessary to enable to kernel to find your cleanup function.

Metadata information:

MODULE_LICENSE(“GPL”); : It is not strictly necessary, but your module really should specify which license applies to its code. (GPL:- GNU General Public License).
MODULE_AUTHOR: who wrote the module.
MODULE_DESCRIPTION : A human-readable statement of what the module does

pr_alert:

The pr_alert function is defined in the Linux kernel and made available to modules; it behaves similarly to the standard C library function printf. The kernel needs its own printing function because it runs by itself, without the help of the C library.  The alert in pr_alert is the priority of the message.here its specified a high priority in this module.

Compiling a Module
There are 2 solutions for compiling a module
1. Out of kernel tree
2. Inside the kernel tree

We will stick to out of kernel tree since it might be easier to handle than modifications to the kernel itself.

Makefile

# If KERNELRELEASE is defined, we've been invoked from the
# kernel build system and can use its language.
ifneq ($(KERNELRELEASE),)
obj-m := hello.o
# Otherwise we were called directly from the command
# line; invoke the kernel build system.
else
KERNELDIR ?=/home/Vinay/Embedded_Linux_Virtual_Setup/linux
PWD := $(shell pwd)
default:
<TAB> $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
<TAB> rm -rvf *.ko *.mod.c *.mod.o *.o modules.order Module.symvers endif

Save above file as Makefile.

Note: TAB followed by command.

The module Makefile is interpreted with KERNELRELEASE undefined, so it calls the kernel Makefile, passing the module directory in the M variable The kernel Makefile knows how to compile a module and M variable knows where the Makefile for our module is. This module Makefile is then interpreted with KERNELRELEASE defined, so the kernel sees the obj-m definition.

KERNELDIR : This is the path where your compiled linux kernel exist.

Building/ Compiling Module:

make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi-

Create a directory in nfs rootfs  /NFS_rootfs/lib/modules/linux_version/.
e.g /NFS_rootfs/lib/modules/4.9.0/.

Copy built driver to nfs rootfs

cp -a  *  /NFS_rootfs/lib/modules/4.9.0/.

Boot Linux with nfs as rootfs.

qemu-system-arm -M vexpress-a9 -dtb linux/arch/arm/boot/dts/vexpress-v2p-ca9.dtb -kernel linux/arch/arm/boot/zImage -append "root=/dev/nfs nfsroot=10.0.2.2:/NFS_rootfs rw ip=10.0.2.15::10.0.2.1:255.255.255.0 init=/linuxrc console=ttyAMA0" -serial stdio

Once Qemu boots up execute below command in target Console.

modprobe hello

Most common usage of modprobe: tries to load all the modules the given module depends on, and then this module.modprobe automatically looks in /lib/modules/<version>/ for the object file corresponding to the given module name.

lsmod: Displays the list of loaded modules Compare its output with the contents of /proc/modules

modprobe  -r hello : Tries to remove the given module and all dependent modules.

dd

Let me know if you have any questions or comments.

Reference:

  1. LLD3
  2. free-electron

 

Advertisements

About VinayMahadev

I am passionate about Embedded Linux systems . I believe in "If you want to learn something, read about it. If you want to understand something, write about it. If you want to master something, teach it". Here I am just trying to connect the Dots.
Gallery | This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s