Hardware drivers on linux need to fit to the running kernel. When drivers you need are not part of the distribution in use you need to build and install them yourself. While this may be ok to do once or twice it soon becomes tedious doing it after every kernel update.
The Dynamic Kernel Module Support (DKMS) may help in such a situation: The module source code is installed on the target machine and can be rebuilt and installed automatically when a new kernel is installed. While veterans may be willing to manually maintain their hardware drivers with DKMS end user do not care about the underlying system that keeps their hardware working. They want to manage their software updates using the tools of their distribution and everything should be working automagically.
I want to show you how to package a kernel driver as an RPM package hiding all of the complexities of DKMS from the user. This requires several steps:
- Preparing/patching the driver (aka kernel module) to include
dkms.conf
and follow the required conventions of DKMS - Creating a RPM spec-file to install the source, tool chain and integrate the module source with DKMS
While there is native support for RPM packaging in DKMS I found the following procedure more intuitive and flexible.
Preparing the module source
You need at least a small file called dkms.conf to describe the module source to the DKMS system. It usually looks like that:
PACKAGE_NAME="menable" PACKAGE_VERSION=3.9.18.4.0.7 BUILT_MODULE_NAME[0]="menable" DEST_MODULE_LOCATION[0]="/extra" AUTOINSTALL="yes"
Also make sure that the source tarball extracts into the directory /usr/src/$PACKAGE_NAME-$PACKAGE_VERSION
! If you do not like /usr/src
as a location for your kernel modules you can configure it in /etc/dkms/framework.conf
.
Preparing the spec file
Since we are not building a binary and package it but install source code, register, build and install it on the target machine the spec file looks a bit different than usual: We have no build step, instead we just install the source tree and potentially additional files like udev rules or documentation and perform all DKMS work in the postinstall and preuninstall scripts. All that means, that we build a noarch
-RPM an depend on dkms, kernel sources and a compiler.
Preparation section
Here we unpack and patch the module source, e.g.:
Source: %{module}-%{version}.tar.bz2 Patch0: menable-dkms.patch Patch1: menable-fix-for-kernel-3-8.patch %prep %setup -n %{module}-%{version} -q %patch0 -p0 %patch1 -p1
Install section
Basically we just copy the source tree to /usr/src
in our build root. In this example we have to install some additional files, too.
%install rm -rf %{buildroot} mkdir -p %{buildroot}/usr/src/%{module}-%{version}/ cp -r * %{buildroot}/usr/src/%{module}-%{version} mkdir -p %{buildroot}/etc/udev/rules.d/ install udev/10-siso.rules %{buildroot}/etc/udev/rules.d/ mkdir -p %{buildroot}/sbin/ install udev/men_path_id udev/men_uiq %{buildroot}/sbin/
Post-install section
In the post-install script of the RPM we add our module to the DKMS system build and install it:
occurrences=/usr/sbin/dkms status | grep "%{module}" | grep "%{version}" | wc -l if [ ! occurrences > 0 ]; then /usr/sbin/dkms add -m %{module} -v %{version} fi /usr/sbin/dkms build -m %{module} -v %{version} /usr/sbin/dkms install -m %{module} -v %{version} exit 0
Pre-uninstall section
We need to remove our module from DKMS if the user uninstalls our package to leave the system in a clean state. So we need a pre-uninstall script like this:
/usr/sbin/dkms remove -m %{module} -v %{version} --all exit 0
Conclusion
Packaging kernel modules using DKMS and RPM is not really hard and provides huge benefits to your users. There are some little quirks like the post-install and pre-uninstall scripts but after you got that working you (and your users) are rewarded with a great, fully integrated experience. You can use the full spec file of the driver in the above example as a template for your driver packages.