This document provides a consolidated introduction to Linux device drivers, serving as a centralized knowledge base. Since Linux driver documentation is often fragmented across various sources, this guide aims to provide a clear, cohesive overview — with a particular focus on platform, I2C, misc, and character drivers.
Checkout our historic linear growth! I am so grateful for every one of these stars and hope this repository proves helpful. Please feel free to contribute as we achieve new records in Linux device driver helpfulness.
Keep scrolling for a short summary on large topics; click these content links for a lot more information. This repository contains example drivers and related documentation in subdirectories:
- Character Drivers
- Misc Drivers
- I2C Drivers
- Platform Drivers
- WSL Notes
- What is a kobject?
- What about Rust?
If this documentation has proven helpful to you,
A misc driver is a simple type of character driver used to expose hardware functionality to user space. These drivers are often used alongside platform or I2C drivers to provide userspace interfaces via /dev.
-
Registered using
misc_register() -
Allocated a single minor number from the misc major (no need to manually allocate major numbers)
-
Typically exposes
read,write,ioctl, andpollfile operations -
Lives under:
drivers/char/misc.c— registration APIdrivers/misc/— actual drivers that don’t fit other categories
A misc driver can be registered inside a platform driver's probe() function to expose the device to user space.
⚠️ Note: Don't confusemisc_register(API) with thedrivers/misc/directory — they are related but not the same.
I2C devices communicate over a two-wire bus (SDA + SCL) and are typically not discoverable in the same way USB or PCI devices are. In Linux, I2C devices are treated as platform devices — meaning the system must already know they exist (via device tree or static registration).
To inspect the system for available I2C buses and devices, use the i2cdetect tool:
i2cdetect -l # list I2C buses
i2cdetect -y <bus> # scan for devices on a specific busPlatform devices represent hardware that cannot self-describe or announce their presence to the operating system. Examples include on-chip peripherals (UART, I2C, GPIO), especially common in embedded systems and SoCs.
Generally, they are a foundation for running software and a crucial part of a system's architecture, providing the basic functionality needed for other software and hardware to operate. Platform devices are typically integrated into a system-on-chip (SoC) and can be directly addressed by the CPU.
-
Not dynamically discovered — must be known at compile-time
-
Registered via:
- Device Tree (preferred for ARM/embedded):
.dtsfiles - Static code registration:
platform_device_register()
- Device Tree (preferred for ARM/embedded):
-
Bound to a driver using name matching (
compatiblein DT or.namein code)
- A device must be registered using
platform_device_register()or Device Tree - A driver must be registered using
platform_driver_register() - The names must match via
compatiblestrings or driver.name
lkmc_platform_device@101e9000 {
compatible = "lkmc_platform_device";
reg = <0x101e9000 0x1000>;
interrupts = <18>;
interrupt-controller;
#interrupt-cells = <2>;
clocks = <&pclk>;
clock-names = "apb_pclk";
lkmc-asdf = <0x12345678>;
};
- Device memory regions, IRQs, and clocks are hardcoded via Device Tree
- These devices cannot be hotplugged
- The correct driver is matched via the
compatiblestring in the Device Tree and the driver's.of_match_table
Devices like PCI, USB, and virtio are discoverable — meaning the OS can detect them at runtime without prior knowledge.
-
Auto-discovered by hardware buses (PCI, USB)
-
Register and interrupt addresses are dynamically assigned
-
Devices are matched to drivers using:
- PCI Vendor:Device ID
- USB Vendor/Product ID
-
Device hotplug is supported (can be added or removed at runtime)
- PCI core enumerates the device and matches the IDs with a driver table (
pci_device_id) - Driver is probed automatically when a match is found
- Devices can be dynamically rescanned with:
echo 1 > /sys/bus/pci/rescanstatic const struct pci_device_id my_pci_ids[] = {
{ PCI_DEVICE(0x1234, 0x5678) }, // Vendor ID, Device ID
{ 0, }
};
MODULE_DEVICE_TABLE(pci, my_pci_ids);| Feature | Platform Device | Non-Platform Device (PCI/USB) |
|---|---|---|
| Discovery | Static (manual) | Automatic (hotplug capable) |
| Typical Use Case | SoC peripherals | Add-in cards, USB peripherals |
| Address Assignment | Hardcoded (Device Tree) | Dynamic (PCI/USB assigns) |
| Driver Matching | Name / compatible | Vendor:Device ID |
| Hotplug Support | ❌ Not possible | ✅ Yes |
