Section 18.2. Loadable Device Drivers

Traditionally, device drivers have been included as part of the kernel. There are several reasons for this. First of all, nearly all device drivers require the special hardware access provided by being part of the kernel code. Such hardware access can't be obtained easily through a user program. Also, device drivers are much easier to implement as part of the kernel; such drivers have complete access to the data structures and other routines in the kernel and can call them freely.

A conglomerate kernel containing all drivers in this manner presents several problems. First of all, it requires the system administrator to rebuild the kernel in order to selectively include device drivers, as we saw in the previous section. Also, this mechanism lends itself to sloppy programming on the part of the driver writers: there's nothing stopping a programmer from writing code that is not completely modularcode which, for example, directly accesses data private to other parts of the kernel. The cooperative nature of the Linux kernel development compounds this problem, and not all parts of the code are as neatly contained as they should be. This can make it more difficult to maintain and debug the code.

In an effort to move away from this paradigm, the Linux kernel supports loadable device drivers device drivers that are added to or removed from memory at runtime, with a series of commands. Such drivers are still part of the kernel, but they are compiled separately and enabled only when loaded. Loadable device drivers, or modules, are generally loaded into memory using commands in one of the boot-time rc scripts.

Modules provide a cleaner interface for writing drivers. To some extent, they require the code to be somewhat modular and to follow a certain coding convention. (Note that this doesn't actually prevent a programmer from abusing the convention and writing nonmodular code. Once the module has been loaded, it is just as free to wreak havoc as if it were compiled directly into the kernel.) Using modules makes drivers easier to debug; you can simply unload a module, recompile it, and reload it without having to reboot the system or rebuild the kernel as a whole. Modules can be used for other parts of the kernel, such as filesystem types, in addition to device drivers.

Most device drivers, and a lot of other kernel functionality under Linux, are implemented as modules. One of them is the parallel port driver for PCs (or parport_pc driver), for devices that connect to the parallel port (there are also additional drivers for special devices such as printers that report back status to the computer). If you plan to use this driver on your system, it is good to know how to build, load, and unload modules. Although nothing is stopping you from compiling this module statically into your kernel, a parallel port driver is something that you need only rarely (whenever you print to a directly connected printer, maybe a couple of times a day), and its driver shouldn't occupy valuable RAM during the times it is not needed. See the Linux Printing HOWTO for more about parallel port printing.

18.2.1. Installing the Kernel

Now we'll talk about how to load and unload modules from the kernel. The first thing you'll need is the module-init-tools package, which contains the commands used to load and unload modules from the kernel. On the FTP archive sites, this is usually found as module-init-tools-versionnumber.tar.bz2 in the directory where the kernel sources are kept. This package contains the sources to the commands insmod, modprobe, rmmod, and lsmod. All reasonably recent Linux distributions include these commands (found in sbin) already, so if you already have these commands installed, you probably don't need to get the modules package. However, it can't hurt to get the package and rebuild these commands to be sure that you have the most up-to-date version.

To rebuild these commands, unpack module-init-tools-versionnumber.tar.bz2 (say, in a subdirectory of /usr/src). Follow the installation instructions contained there; usually all you have to do is execute make followed by make install (as root). The three commands will now be installed in /sbin and will be ready to use.

18.2.2. Compiling Modules

A module is simply a single object file containing all the code for the driver. For example, the parport_pc module might be called parport_pc.ko. On most systems, the modules themselves are stored in a directory tree below /lib/modules /kernelversion, where you can find different directories for the various types of modules. For example, the modules compiled for the 2.6.8 kernel would be below /lib/modules/2.6.8. You might already have a number of modules on your system; check the appropriate directory. Notice that kernel modules, unlike other compiled object files, have the filename extension .ko to show their status as kernel modules. If you are running an older version of Linux, your modules might still have the extension .o.

Modules can be either in the kernel sources or external to it. The former is the case for those device drivers, filesystems, and other functionality that are used most often and are maintained as part of the official kernel sources. Using these modules is very easy: during the make config, make menuconfig, or make xconfig step, select to build a certain feature as a module. Repeat this for everything you want to compile as a module. Then, after the make bzImage step, execute the following commands:

# make modules
# make modules_install

This will compile the modules and install them in /lib/modules/kernelversion.

New modules that are not yet integrated into the official kernel sources, or those that are simply too esoteric to be put into the kernel sources (e.g., a device driver for some custom-built hardware that is not publicly available) can be available as stand-alone, external modules. Unpack the archive of the module, compile it according to the instructions that are hopefully included, and copy the resulting module file to the appropriate subdirectory of /lib/modules/kernelversion. Some modules might have an install script or allow you to issue the command make install to perform the last step.

18.2.3. Loading a Module

Once you have a compiled module (either from the kernel sources or external), you can load it using the command:

insmod module

where module is the name of the module object file. For example:

insmod /lib/modules/2.6.11.4/kernel/drivers/parport/parport_pc.ko

installs the parport_pc driver if it is found in that file.

Once a module is installed, it may display some information to the console (as well as to the system logs), indicating that it is initialized. For example, the ftape driver might display the following:

Jul 26 13:08:41 tigger kernel: pnp: Device 00:09 activated.
Jul 26 13:08:41 tigger kernel: parport: PnPBIOS parport detected.
Jul 26 13:08:41 tigger kernel: parport0: PC-style at 0x378, irq 7 [PCSPP,TRISTATE]

The exact messages printed depend on the module, of course. Each module should come with ample documentation describing just what it does and how to debug it if there are problems.

It is likely that insmod will tell you it could not load the module into the kernel because there were "symbols missing ." This means that the module you want to load needs functionality from another part of the kernel that is neither compiled into the kernel nor contained in a module already loaded. In particular, the parport_pc module that we have been using as an example depends on the parport module that provides the general parallel port functionality. You could now try to find out which module contains those functions, load that module first with insmod, and try again. You will eventually succeed with this method, but it can be cumbersome, and this would not be Linux if there weren't a better way.

You first need a module database in the file /lib/modules/kernelversion/modules.dep. You can create this database by calling:

depmod -a

This goes through all the modules you have and records whether they need any other modules. With this database in place, you can simply replace the insmod command with the modprobe command, which checks the module database and loads any other modules that might be needed before loading the requested module. For example, our modules.dep file containsamong othersthe following line:

/lib/modules/2.6.8/kernel/drivers/isdn/i4l/isdn.ko:/lib/modules/2.6.8/
kernel/drivers/net/slhc.ko

This means that in order to load the isdn module (a device driver for ISDN support), the slhc module (containing one of the ISDN protocol implementations) must be loaded. If we now load the isdn module with modprobe (this example is slightly simplified because the isdn module needs additional parameters):

modprobe hisax

modprobe will detect the dependency and load the slhc module. If you have compiled a module for the current kernel, you first need to run depmod -a, though, so that modprobe can find it.

Some modules need so-called module parameters. For example, a device driver might need to be assigned an IRQ. You can pass those parameters in the form parameter_name=parameter_value with both the insmod and the modprobe command. In the following example, several parameters are passed to the hisax module, which is a particular (and somewhat outdated) driver for a family of ISDN boards:

tigger # modprobe hisax type=3 protocol=2 io=0x280 irq=10

The documentation for each module should tell you which parameters the module supports. If you are too lazy to read the documentation, a nifty tool you can use is modinfo, which tells youamong other thingswhich parameters are accepted by the module you specify.

One caveat about modules if you use the Debian distribution: Debian uses a file called /etc/modules that lists the modules that should be loaded at boot time. If a module that you do not want keeps reappearing, check whether it is listed here.

You can list the drivers that are loaded with the command lsmod:

rutabaga$ lsmod
Module        Size  Used by
parport       40392 1 parport_pc

The memory usage of the module in bytes is displayed as well. The parport driver here is using about 40 KB of memory. If any other modules are dependent on this module, they are shown in the third column.

A module can be unloaded from memory using the rmmod command, as long as it is not in use. For example:

rmmod parport_pc

The argument to rmmod is the name of the driver as it appears in the lsmod listing.

Once you have modules working to your satisfaction, you can include the appropriate insmod commands in one of the rc scripts executed at boot time. One of your rc scripts might already include a place where insmod commands can be added, depending on your distribution.

One feature of the current module support is that you must rebuild a module any time you upgrade your kernel to a new version or patch level. (Rebuilding your kernel while keeping the same kernel version doesn't require you to do this.) This is done to ensure that the module is compatible with the kernel version you're using. If you attempt to load a module with a kernel that is newer or older than that for which it was compiled, insmod will complain and not allow the module to be loaded. When rebuilding a module, you must be running the kernel under which it will be used. Therefore, when upgrading your kernel, upgrade and reboot the new kernel first, then rebuild your modules and load them. There is an option that allows you to keep your modules when switching kernels, but a number of problems are associated with it, and we recommend against using it.




Part I: Enjoying and Being Productive on Linux
Part II: System Administration