Thursday, October 11, 2012

Compiling a single kernel module

On (the fortunately rare) occasion, the need arises to modify a Linux kernel module/driver.  I finally found a helpful blog-post that gave a walk-through on how to compile a single kernel module without necessitating recompiling the entire Linux kernel.

Following are the steps I took to modify the xpad driver (used by xbox controllers), along with a few clarifications of the original blog post I follgowed.  Anything in bold, you'll want to tweak for your own system.

0. I'm assuming that you've already downloaded Linux source and modified the file(s) you need.  In my case, I was tweaking "/usr/src/linux-source-2.6.32/drivers/input/joystick/xpad.c".

1. Make a working directory to hold your new module when it's compiled, along with overhead needed by the compilation process.  I chose to name my directory "xpad" since I was specifically modifying the xpad driver.

$ sudo mkdir /usr/src/xpad

2. Copy in a few necessary files:

$ cd /usr/src/xpad 
$ sudo cp /boot/config-`uname -r`  .config
$ sudo cp /usr/src/linux-headers-`uname -r`/Module.symvers .

3. Move to your source directory and run some "make" commands to prepare your working directory.

Note that EXTRAVERSION should be whatever follows the first three numbers when you run "uname -r".  For example, if running "uname -r" results in "2.6.32-43-generic", EXTRAVERSION would be "-43-generic".

$ cd /usr/src/linux-source-2.6.32
$ sudo make EXTRAVERSION=-43-generic O=/usr/src/xpad oldconfig
$ sudo make EXTRAVERSION=-43-generic O=/usr/src/xpad prepare
$ sudo make EXTRAVERSION=-43-generic O=/usr/src/xpad outputmakefile
$ sudo make EXTRAVERSION=-43-generic O=/usr/src/xpad archprepare
$ sudo make EXTRAVERSION=-43-generic O=/usr/src/xpad modules SUBDIRS=scripts

4. Make your specific module.

In my case, I tried first to make just the xpad module.  That resulted in an error indicating that there wasn't a Makefile specifically for the xpad module.

First, unsuccessful attempt:

$ sudo make EXTRAVERSION=-43-generic O=/usr/src/xpad modules SUBDIRS=drivers/input/joystick/xpad

/usr/src/linux-source-2.6.32/scripts/ /usr/src/linux-source-2.6.32/drivers/input/joystick/xpad/Makefile: No such file or directory
make[2]: *** No rule to make target `/usr/src/linux-source-2.6.32/drivers/input/joystick/xpad/Makefile'.  Stop.
make[1]: *** [_module_drivers/input/joystick/xpad] Error 2
make: *** [sub-make] Error 2

There WAS, however, a Makefile that built all the joystick drivers at once, so I fell back to using that.

Second, successful attempt:

$ sudo make EXTRAVERSION=-43-generic O=/usr/src/xpad modules SUBDIRS=drivers/input/joystick

This generated, among other files, a .ko file, my modified kernel module.  The new modules will be located in the working directory you created in step 1 (in my case, "/usr/src/xpad/drivers/input/joystick/xpad.ko").

5. Make a backup of the original kernel module, just in case (of course impossible) that there's a bug your new module.

$ sudo cp /lib/modules/`uname -r`/kernel/drivers/input/joystick/xpad.ko /lib/modules/`uname -r`/kernel/drivers/input/joystick/xpad.ko.bak

6. Copy in your new kernel module:

$ sudo cp /usr/src/xpad/drivers/input/joystick/xpad.ko /lib/modules/`uname -r`/kernel/drivers/input/joystick/xpad.ko

7. Reload module dependencies:

$ sudo depmod -a

8. Remove the old module, just in case it's currently loaded:

$ sudo modprobe -r xpad

9. (Unplug and) plug in your device to trigger a load of your new module!

Closing thoughts:

To simplify repeated compiling of the code during development, I dumped the pertinent commands into a script I could run:

cd /usr/src/linux-source-2.6.32
sudo make EXTRAVERSION=-43-generic O=/usr/src/xpad modules SUBDIRS=drivers/input/joystick
sudo cp /usr/src/xpad/drivers/input/joystick/xpad.ko /lib/modules/`uname -r`/kernel/drivers/input/joystick/xpad.ko
sudo depmod -a
sudo modprobe -r xpad