Listing 8-5. Loading and Unloading a Module
$ modprobe hello1 <<< Load the driver
Hello Example Init
$ modprobe -r hello1 <<< Unload the driver
Hello Example Exit
$
You should be able to correlate the output with our device driver source code found in Listing 8-1. The module does no work other than printing messages to the kernel log system via printk(), which we see on our console. [64] If you don't see the messages on the console, either disable your syslogd logger or lower the console loglevel. We describe how to do this in Chapter 14, "Kernel Debugging Techniques".
When the module is loaded, the module-initialization function is called. We specify the initialization function that will be executed on module insertion using the module_init() macro. We declared it as follows:
module_init(hello_init);
In our initialization function, we simply print the obligatory hello message and return. In a real device driver, this is where you would perform any initial resource allocation and hardware device initialization. In a similar fashion, when we unload the module (using the modprobe -r command), our module exit routine is called. As shown in Listing 8-1, the exit routine is specified using the module_exit() macro.
That's all there is to a skeletal device driver capable of live insertion in an actual kernel. In the sections to follow, we introduce additional functionality to our loadable device driver module that illustrates how a user space program would interact with a device driver module.
We had a brief introduction to module utilities in Listing 8-5. There we used the module utility modprobe to insert and remove a device driver module from a Linux kernel. A number of small utilities are used to manage device driver modules. This section introduces them. You are encouraged to refer to the man page for each utility, for complete details. In fact, those interested in a greater knowledge of Linux loadable modules should consult the source code for these utilities. Section 8.6.1, "Suggestions for Additional Reading" at the end of this chapter contains a reference for where they can be found.
The insmod utility is the simplest way to insert a module into a running kernel. You supply a complete pathname, and insmod does the work. For example:
$ insmod /lib/modules/2.6.14/kernel/drivers/char/examples/hello1.ko
This loads the module hello1.ko into the kernel. The output would be the same as shown in Listing 8-5 namely, the Hello message. The insmod utility is a simple program that does not require or accept any options. It requires a full pathname because it has no logic for searching for the module. Most often, you will use modprobe, described shortly, because it has many more features and capabilities.
Many device driver modules can accept parameters to modify their behavior. Examples include enabling debug mode, setting verbose reporting, or specifying module-specific options. The insmod utility accepts parameters (also called options in some contexts) by specifying them after the module name. Listing 8-6 shows our modified hello1.c example, adding a single module parameter to enable debug mode.
Listing 8-6. Example Driver with Parameter
/* Example Minimal Character Device Driver */
#include
static int debug_enable = 0; /* Added driver parameter */
module_param(debug_enable, int, 0); /* and these 2 lines */
MODULE_PARM_DESC(debug_enable, "Enable module debug mode.");
static int __init hello_init(void) {
/* Now print value of new module parameter */
printk("Hello Example Init - debug mode is %s\n", debug_enable ? "enabled" : "disabled");
return 0;
}
static void __exit hello_exit(void) {
printk("Hello Example Exit\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_AUTHOR("Chris Hallinan");
MODULE_DESCRIPTION("Hello World Example");
MODULE_LICENSE("GPL");
Three lines have been added to our example device driver module. The first declares a static integer to hold our debug flag. The second line is a macro defined in .../include/linux/moduleparam.h that registers the module parameter with the kernel module subsystem. The third new line is a macro that registers a string description associated with the parameter with the kernel module subsystem. The purpose of this will become clear when we examine the modinfo command later in this chapter.
If we now use insmod to insert our example module, and add the debug_enable option, we should see the resulting output, based on our modified hello1.c module in Listing 8-6.
$ insmod /lib/modules/.../examples/hello1.ko debug_enable=1
Hello Example Init - debug mode is enabled
Or, if we omit the optional module parameter:
$ insmod /lib/modules/.../examples/hello1.ko
Hello Example Init - debug mode is disabled
The lsmod utility is also quite trivial. It simply displays a formatted list of the modules that are inserted into the kernel. Recent versions take no parameters and simply format the output of /proc/modules. [65] /proc/modules is part of the proc file system, which is introduced in Chapter 9, "File Systems".
Listing 8-7 is an example of the output from lsmod.
Listing 8-7. lsmod Example Output Format
$ lsmod
Module Size Used by
ext3 121096 0
jbd 49656 1 ext3
loop 12712 0
hello1 1412 0
$
Notice the rightmost column labeled Used by. This column indicates that the device driver module is in use and shows the dependency chain. In this example, the jbd module (journaling routines for journaling file systems) is being used by the ext3 module, the default journaling file system for many popular Linux desktop distributions. This means that the ext3 device driver depends on the presence of jbd.
This is where the cleverness of modprobe comes into play. In Listing 8-7, we see the relationship between the ext3 and jbd modules. The ext3 module depends on the jbd module. The modprobe utility can discover this relationship and load the dependent modules in the proper order. The following command loads both the jbd.ko and ext3.ko driver modules:
$ modprobe ext3
The modprobe utility has several command line options that control its behavior. As we saw earlier, modprobe can be used to remove modules, including the modules upon which a given module depends. Here is an example of module removal that removes both jbd.ko and ext3.ko :
$ modprobe -r ext3
The modprobe utility is driven by a configuration file called modprobe.conf. This enables a system developer to associate devices with device drivers. For a simple embedded system, modprobe.conf might be empty or might contain very few lines. The modprobe utility is compiled with a set of default rules that establish the defaults in the absence of a valid modprobe.conf. Invoking modprobe with only the -c option displays the set of default rules used by modprobe.
Читать дальше