How to Compile Just One Kernel Module

I received two C.H.I.P computers in 2016. They come with Linux kernel 4.4.13, but the kernel had limited features. When I needed to use the fuse kernel module, I had to re-compile the entire kernel, which took a whole day. Two years later, I upgraded to a newer 4.4.138 kernel, built by community member kaplan2539. The kernel comes with more modules including fuse, which is a better situation than the original kernel.

DM9601 USB Ethernet adapter plugged into a C.H.I.P computer

Recently I acquired a cheap USB Ethernet adapter. When I plugged it in, the kernel recognizes a USB device:

chip@chip-b:~$ lsusb | grep Ethernet
Bus 002 Device 002: ID 0fe6:9700 Kontron (Industrial Computer Source / ICS Advent) DM9601 Fast Ethernet Adapter

But there's no new NIC showing up in ip link command. A quick Google search of the USB ID 0fe6:9700 indicates that I need the dm9601 kernel module. But:

chip@chip-b:~$ sudo modprobe dm9601
modprobe: FATAL: Module dm9601 not found.

Do I have to spend a whole day re-compiling the kernel? It turns out that, I can build a single kernel module individually. After some trial and error, I figured out the exact procedure of doing so.

  1. Obtain the kernel headers and the compiler, and download the kernel sources:

    sudo apt install build-essential libncurses-dev linux-headers-4.4.138-chip
    curl -L | tar xz

    It's important that the header package and kernel sources both match the running kernel, which can be seen with uname -r command.

  2. Copy the kernel "config" file into the kernel source directory. This file records how the kernel was configured when it was originally built, which serves as a starting point of the new compilation process.

    cd ntc-linux-ntc-stable-mlc-4.4.138
    cp /boot/config-4.4.138-chip ./.config
  3. Copy the kernel "symbol" file into the kernel source directory as well. This file records what function names exist in the running kernel, so that our new module can link to them.

    cp /usr/src/linux-headers-4.4.138-chip/Module.symvers ./
  4. Load the original config file, and modify it.

    make oldconfig
    make menuconfig

    The make menuconfig command brings up an interactive dialog, allowing me to select what kernel features I want. I followed the dialogs into "Device Drivers" - "Network device support" - "USB Network Adapters" menu, and changed "Davicom DM96xx based USB 10/100 ethernet devices" to "M", indicating this feature would be built as a module.

  5. Since the running kernel version is 4.4.138-chip, I need to modify Makefile and set EXTRAVERSION = -chip. After that, make kernelversion should say 4.4.138-chip, exactly matching the output of uname -r command.

  6. Build the module.

    make scripts prepare modules_prepare
    make -C . M=drivers/net/usb

    In this command, drivers/net/usb is the directory containing the dm9601 kernel module source code. This command would build all enabled kernel modules in that directory, not just dm9601.

  7. Install the module.

    sudo cp drivers/net/usb/dm9601.ko /lib/modules/4.4.138-chip/kernel/drivers/net/usb/
    sudo depmod

At this point, I'm ready to load the module with modprobe. In fact, the module would be loaded automatically when I plug in the USB Ethernet adapter.

chip@chip-b:~$ dmesg | grep -i dm9601
[270352.048643] dm9601 2-1:1.0 eth0: register 'dm9601' at usb-1c14400.usb-1, Davicom DM96xx USB 10/100 Ethernet, 00:e0:4c:53:44:58
[270352.070843] usbcore: registered new interface driver dm9601
[270352.923157] dm9601 2-1:1.0 eth0: link up, 100Mbps, full-duplex, lpa 0xFFFF

The whole process took less than an hour, which is a lot less than re-compiling the entire kernel.

Reference: Oleg Kokorin's answer to "How to recompile just a single kernel module?"