Driver types
Character devices
Provide a byte-stream interface. Examples: serial ports (
tty), sensors, custom hardware. Registered via cdev_add() and accessed through /dev nodes.Block devices
Transfer data in fixed-size blocks. Examples: storage controllers (NVMe, SATA), SD/MMC. Interact with the block I/O layer via
register_blkdev().Network devices
Present a
net_device to the networking stack. Examples: Ethernet, Wi-Fi, loopback. Registered with register_netdev().Platform drivers
Drive SoC-integrated peripherals described in device tree or ACPI. Use
platform_driver_register() and match by compatible string or device name.PCI drivers
Enumerate PCI/PCIe devices via
pci_register_driver() and a pci_device_id table. Handle BAR mapping, MSI/MSI-X interrupts, and power management.USB drivers
Bind to USB interfaces or devices using
usb_register() and a usb_device_id table. The USB core handles enumeration and bandwidth negotiation.I2C drivers
Communicate over the I2C bus using
i2c_add_driver(). Devices described in the device tree under an I2C controller node.SPI drivers
Full-duplex serial drivers registered via
spi_register_driver(). The SPI core manages chip-select and clock configuration.Essential headers
Every kernel module needs a minimal set of headers. Additional includes depend on the subsystem your driver targets.Module boilerplate
Every loadable kernel module must provide entry and exit points, a license declaration, and optionally author and description metadata.__init marks functions that are discarded from memory after initialization completes. __exit marks functions that are omitted entirely in non-modular (built-in) kernels.MODULE_LICENSE controls which kernel symbols are accessible to the module. Modules declaring "GPL" can use GPL-only exports (marked EXPORT_SYMBOL_GPL). Declaring "Proprietary" restricts access and taints the kernel.
Driver development workflow
Identify the subsystem
Determine which bus or subsystem your device belongs to (platform, PCI, USB, I2C, SPI, etc.). This determines which registration API and probe/remove callbacks to implement.
Define the driver structure
Declare a bus-specific driver struct (e.g.,
struct platform_driver, struct pci_driver) embedding a struct device_driver. Populate the probe, remove, and id_table fields.Implement probe()
The
probe() callback is called by the driver core when a matching device is found. Allocate resources, map I/O memory, request IRQs, and initialize hardware here. Use devm_ prefixed helpers so resources are automatically released on driver detach.Implement remove()
Called when the device is unbound. If you used
devm_ helpers, most cleanup is automatic. Stop hardware activity, unregister any sub-devices, and release manually acquired resources.Register the driver
Call the appropriate registration function (e.g.,
platform_driver_register()) — typically via a convenience macro like module_platform_driver() which generates both module_init and module_exit.Complete minimal character device driver
The following driver creates a single character device that accepts writes and echoes them back on read. It demonstrates all the boilerplate required for a functionalcdev-based driver.
Registering and unregistering drivers
Each bus type exposes its own registration pair. Most drivers use themodule_<bus>_driver() convenience macro, which generates a module_init / module_exit wrapper automatically.
- Platform
- PCI
- USB
- I2C
Building the module
Add the driver to the kernel build system by creating aKconfig entry and a Makefile:
Further reading
Device model
The Linux device model: buses, devices, drivers, probe lifecycle, and sysfs.
DMA API
Coherent and streaming DMA mappings, scatter-gather, and IOMMU considerations.
Power management
Runtime PM, system sleep states, dev_pm_ops, and autosuspend.
