Linux kernel drivers live either as loadable kernel modules (Documentation Index
Fetch the complete documentation index at: https://mintlify.com/DeelerDev/linux/llms.txt
Use this file to discover all available pages before exploring further.
.ko files inserted at runtime) or as code compiled directly into the kernel image. Both share the same APIs and follow the same driver model; the distinction is purely about when the code is linked and whether it can be removed while the system is running. Understanding this split is the first step toward building any driver, because it determines your build process, your deployment strategy, and which lifecycle hooks matter to you.
Kernel modules vs. built-in drivers
A loadable module is an ELF shared object that the kernel caninsmod at any time after boot. It is unloaded with rmmod and can be auto-loaded by modprobe based on device aliases recorded in the module’s .ko file. A built-in driver is linked into vmlinux during the kernel build; it starts with the rest of the kernel and cannot be removed.
The choice comes down to flexibility versus startup time. Embedded systems with a fixed hardware set often prefer built-in drivers to avoid a root filesystem at early boot. Desktop and server distributions use modules so that a single kernel binary can support thousands of different devices.
Anatomy of a kernel module
Every module must define an init function and optionally an exit function, and must declare its license.| Macro | Purpose |
|---|---|
module_init() | Registers the function called when the module is inserted |
module_exit() | Registers the function called when the module is removed |
MODULE_LICENSE() | Declares the license; "GPL" enables access to GPL-only kernel symbols |
MODULE_AUTHOR() | Recorded in the .ko and visible via modinfo |
MODULE_DESCRIPTION() | Human-readable description shown by modinfo |
__init annotation places the function in a special section that the kernel frees after init completes; __exit is discarded entirely for built-in drivers.
Compiling an out-of-tree module
Out-of-tree modules are built against an installed kernel header tree using a smallMakefile:
make in the source directory. The kernel build system reads obj-m and produces hello.ko.
You need the kernel headers or full kernel source tree for the running kernel. On Debian/Ubuntu, install
linux-headers-$(uname -r). On Fedora/RHEL, install kernel-devel.Loading and unloading modules
Insert a module manually
insmod loads the exact file you specify. It does not resolve dependencies; if your module requires another module, load that one first.Check the kernel log
pr_info() messages appear here. Use pr_err() and pr_warn() for errors and warnings.Character devices
Character devices expose a file-like interface in/dev. User space opens the device node and calls read(), write(), and ioctl() as with any file. The driver registers a set of file_operations callbacks that the kernel invokes for each syscall.
Major and minor numbers
Every character device is identified by a major number (which driver handles the device) and a minor number (which instance within that driver). The pair is encoded as adev_t value. You can allocate a major number statically or dynamically:
udev rules so the node appears automatically.
Overview of driver types
Character drivers
Expose a byte-stream interface via
/dev nodes. Used for serial ports, input devices, sensors, and most custom hardware. Implement file_operations callbacks.Block drivers
Expose fixed-size block I/O, typically for storage. The kernel queues and merges requests before dispatching them. Implement
block_device_operations and a request queue.Network drivers
Manage
net_device structs and transmit/receive packets. Do not appear in /dev; user space interacts through sockets and ioctl. Implement net_device_ops.Platform drivers
For SoC-integrated peripherals described in Device Tree or ACPI tables. Use
platform_driver and platform_device; the kernel’s platform bus matches them automatically.