Part of what makes linux what it is, is active kernel development. This means that any description of how to write extensions to the kernel will need to be frequently updated (which is not likely for this document). These notes are not intended to be a tutorial. They are my personal condensed cheat-sheet (which I hope may be useful to others) for an activity that I get involved in only sporatically.
A device driver is part of the linux kernel. You could install a device driver by writing it, then compiling it into the kernel (i.e. compiling a custom kernel that included the device driver). Nobody in their right mind does this, they use modules. It used to be done this way in the days of yore with unix kernels. You still could do it this way if you just wanted to make things hard on yourself. Mentioning just one huge advantage of using modules ought to convince you. You can test multiple versions of a module without having to reboot your system each time.
Whole books can, should, and have been written about modules and device drivers. The classic is LINUX Device Drivers by Alessandro Rubini. At the time of this writing (2009), this is in its third edition which is frighteningly out of date for specific details. Any book on this topic is doomed to instant obsolescence. For example in 2009, I am running a 2.6.27 kernel, and the third edition is up to date as of 2.6.10 kernels. Nonetheless, this book is very much worth having and you just have to go online for the big details. The book itself is available online at:
2.6.23.15-137.fc8 2.6.24.3-34.fc8 2.6.25.14-69.fc8 2.6.26.6-79.fc9.x86_64 2.6.27.5-37.fc9.x86_64 2.6.27.5-41.fc9.x86_64The kernel I am currently running is (from uname -a) 2.6.27.5-41.fc9.x86_64 so the modules for that kernel will be found in the subdirectory /lib/modules/2.6.27.5-41.fc9.x86_64 Each directory holds a quite complex arrangement of files and directories.
The file modules.dep is created by the depmod utility to indicate module interdependencies. I find I do not need to deal with this or to run this command by hand, but it is good to know about if you start fiddling with a module or subsystem that has dependency issues. If the dependencies in modules.dep are not set up right, you will have no end of grief.
cat /proc/modulesThe lsmod utility reads this file and gives you a nicer listing.
insmod onion.koand your system would run forever.
Since the world is not so perfect, you also end up needing rmmod. After you fix your driver bug and want to test the new version, you will need to use this to "unload" the previously loaded driver module via rmmod onion.ko or just rmmod onion. modprobe is a higher level interface to insmod, rmmod, and more. For modules that have dependencies it is probably the tool of choice to install and remove modules, but for my simple tastes I do not use it.
A module should only ever include files in /usr/include/linux or /usr/include/asm as things will be arranged so that these are files that correspond to the current running kernel. This is done via symbolic link trickery (or something) to files in /usr/src/kernels/2.6.27.5-41.fc9.x86_64/include/linux, which is exactly what you want. Actually there are other directories that are set up in this way, but none that I have had to be concerned with for simple drivers.
If you do not see files like this in /usr/src you probably need to load the kernel-devel rpm to get the kernel headers. On a fedora system you would do this:
yum install kernel-devel
On a fedora system, you need to locate the source rpm for the kernel you are running (just the same as you would need to locate the source rpm for any other package you wanted to study the source from. For my current kernel this would be:
kernel-2.6.27.5-41.fc9.src.rpmWhat I actually found however (on our fedora mirror in fedora/updates/9/SRPMS was: kernel-2.6.27.24-78.2.53.fc9.src.rpm - a more recent version than I am actually running. But I don't intend to actually build a kernel from this, just look at the files, so this will be fine for study purposes:
rpm -Uvh kernel-2.6.27.24-78.2.53.fc9.src.rpmThis seems to dump the whole shooting match into /usr/src/redhat/SOURCES as a bunch of patch files and the all important pristine file: linux-2.6.27.tar.bz2. You might just as well go to www.kernel.org (or one of its mirrors) and download this or any other kernel source snapshot. However you get it, you then pick a convenient spot (with 400M or so of free space) and do:
tar xjvf /usr/src/redhat/SOURCES/linux-2.6.27.tar.bz2
Voila - the entire linux kernel source tree! You now have the source to hundreds, if not thousands of device drivers at your very fingertips. I am loathe to recommend any particular starting point since there is so much variation among drivers. Just cd to linux-2.6.27/drivers and start poking around.
#include <linux/module.h> #include <linux/version.h>These provide the macros for MOD_INC_USE_COUNT, EXPORT_SYMBOL, and more.
If you are reading a tutorial that tells you that you need something called linux/modversions.h, it is way out of date and you should find other sources of information.
printk ( "<1>hello world\n" ); or: printk ( KERN_INFO "hello world\n" );Note that there is no comma in the second form. These things are defined in the include file linux/kernel.h - low numbers are more urgent. Values range from 0 (KERN_EMERG) to 7 (KERN_DEBUG). Level 7 may not even make it to /var/log/messages. KERN_INFO is level 6. KERN_NOTICE is level 5.
In any linux system, drivers are accessed via a special file in the /dev directory. Once upon a time, you would just use the mknod command to create such entries and life was good. In the current scheme of things (i.e with 2.6 kernels and later) this directory gets created fresh on every reboot! This means you will have to arrange for mknod to be properly invoked on every reboot, or learn how the new scheme (called udev) works.
Under the udev scheme, the files in the /dev directory are created fresh and new on every reboot. You can still use mknod to create entries in /dev, but they will vanish on every reboot, so this is not the way to do things. One of the points of the udev scheme is to allow /dev entries come and go as hot pluggable devices come and go. Another point is that the /dev directory holds only files representing devices (or drivers anyway) actually present in a given system.
Kernel events are sent to the udevd daemon, which gets notified of netlink uevents (by the kernel), and runs in user space in order to make or destroy /dev nodes as needed.
Files in /etc/udev and /lib/udev make this whole business go. If you read udev documents on the web, you will find many references to /sbin/hotplug which no longer exists. The things that used to be done by hotplug are now all done by udev.
It would seem that what you want to do is to create your own udev rules in a file like /etc/udev/rules.d/10-local.rules. What just might work is to have a single entry created for a given driver via:
DRIVER=="dingus" NAME="frisbee"This would create /dev/frisbee when the dingus driver was seen.
Have any comments? Questions? Drop me a line!
Adventures in Computing / [email protected]