If you are starting a free Linux kernel development course or working through a free Linux device drivers course, the very first mental model you need is the Linux Device Model (LDM). Every character driver, block driver, network driver, and platform driver you will ever write sits on top of this model. Once you understand how buses, devices, and drivers cooperate inside the kernel, writing your own drivers becomes far less mysterious.
In this lecture of our free embedded systems course, we rebuild the Linux Device Model from first principles, using the current kernel source tree (6.12 and later) instead of outdated references, and we visualize every relationship using clean inline diagrams — no screenshots, no external images, just concepts you can actually study and remember.
What You Will Learn
- What the Linux Device Model actually is, and why the kernel is organized around it
- Why “every device must live on a bus,” including logical and pseudo-buses
- How
/sys/bus,/sys/devices, and/sys/classrelate to each other - How device discovery triggers
probe()andremove()in a driver - The difference between registering with a bus and registering with a kernel framework
- What changed in the Linux Device Model on modern 6.x kernels
- Common mistakes beginners make when reasoning about bus/device/driver binding
Prerequisites
This lecture assumes basic familiarity with:
- C programming fundamentals (structs, function pointers)
- Basic Linux command-line usage
- A general idea of what a kernel module is (covered in our earlier free Linux kernel development course lectures on loadable kernel modules)
You do not need any prior driver-writing experience — this is where that journey begins.
What Is the Linux Device Model?
The Linux Device Model is the internal bookkeeping system the kernel uses to track every piece of hardware (and some purely logical devices) present on a running system, along with the drivers responsible for them. Instead of every subsystem inventing its own way to represent hardware, the kernel provides one unified core — commonly called the driver core — that all bus types plug into.
This unification is what makes /sys possible. Whether you plug in a USB webcam, a PCIe network card, or an I2C temperature sensor, the resulting device object ends up represented the same structural way internally, even though the underlying hardware protocols are completely different.
Why Every Device Must Live on a Bus
A foundational rule of the Linux Device Model is simple to state: every device must be attached to a bus. This is intuitive for physical buses — a USB mouse obviously sits on the USB bus, an NVMe SSD sits on the PCIe bus. But the rule also covers hardware that has no real electrical bus at all.
For SoC-integrated peripherals that are wired directly into the processor with no discoverable bus protocol, the kernel uses a pseudo-bus called the platform bus. This lets even “busless” hardware follow the same registration pattern as everything else, which keeps the driver model consistent across the entire kernel.
Each bus folder under /sys/bus/ is maintained by a bus driver, which is either compiled into the kernel image or auto-loaded during boot. The bus driver’s job is to enumerate hardware that appears on it and match each device to a compatible driver.
The Bus, Device, and Driver Triad
The Linux Device Model revolves around three cooperating entities. Understanding their separate responsibilities removes most of the early confusion beginners face in this free Linux device drivers course.
| Entity | Responsibility | Example |
|---|---|---|
| Bus | Discovers hardware and matches it with a registered driver | USB, I2C, PCI, Platform |
| Device | Represents one physical or logical hardware instance | An I2C RTC chip at address 0x68 |
| Driver | Provides the code that operates a specific class of device | An RTC driver implementing read/set-time |
How Device Discovery Works: probe() and remove()
When a bus driver detects a new device and successfully pairs it with a registered driver, the kernel invokes that driver’s probe() callback. This is where the driver allocates resources, requests interrupts, maps memory, and initializes the hardware. When the device is removed, or the module is unloaded, the matching remove() (sometimes disconnect()) callback runs to release everything cleanly.
Registering with a Kernel Framework vs Registering with a Bus
A well-designed modern driver typically does two separate registrations, and mixing these up is one of the most common sources of confusion in any free Linux device drivers course:
| Registration Type | Purpose | Example API |
|---|---|---|
| Kernel framework | Plugs your driver into a subsystem-specific API (RTC, network, misc, input, etc.) so you get ready-made helper routines | rtc_register_device(), register_netdev() |
| Bus registration | Tells the kernel which bus your driver should be matched against for device discovery | i2c_register_driver(), pci_register_driver() |
Some of the simplest drivers — like the misc character device driver we build in the next lecture — only need the framework registration and skip bus registration entirely, because they operate on logical resources rather than real bus-attached hardware.
What’s New in the Linux Device Model on Kernel 6.12+
Older driver books and tutorials often reference APIs whose signatures have since changed. If you are following this free Linux kernel development course to write real, buildable drivers on a current kernel, keep these updates in mind:
class_create()no longer takes anownermodule pointer as of kernel 6.4 — it now takes only the class name.- Device tree overlays are now the standard way most platform devices are described on ARM SoCs, rather than hand-written platform device registration in board files.
devm_*managed resource APIs (devm_kzalloc(),devm_request_irq(), and similar) are now the preferred way to allocate resources insideprobe(), since they are automatically released when the device is unbound.- Many bus subsystems increasingly rely on
fwnodeabstractions so the same driver logic can work whether the platform description comes from device tree or ACPI.
Real-World Use Cases
Almost every embedded Linux product you interact with relies on this model:
- A Wi-Fi module on an SDIO bus, bound automatically when the SoC boots
- A touchscreen controller on I2C, probed the moment its device tree node is parsed
- An SoC’s built-in UART or timer block, registered on the platform bus
- A USB-to-serial adapter, bound the instant it is plugged in
Common Mistakes and Troubleshooting
| Mistake | Why It Breaks Things |
|---|---|
| Assuming every device needs bus registration | Logical drivers like misc devices don’t sit on a real bus at all |
Doing hardware setup outside probe() |
Resources may not be ready yet, or you break hot-plug support |
Forgetting remove() cleanup |
Leaks memory/IRQs and can crash the kernel on module unload |
Best Practices
- Always check
/sys/bus/<bus>/devices/and/sys/bus/<bus>/drivers/while debugging binding issues - Prefer
devm_*managed APIs over manual allocation/free pairs inprobe()/remove() - Keep
probe()fast — defer heavy initialization with workqueues if needed - Log meaningful context using
pr_fmt()sodmesgoutput is traceable
Performance and Security Considerations
Performance: Because probe() can run during boot for many devices in parallel (asynchronous probing), keep it non-blocking wherever possible to avoid extending boot time.
Security: Device nodes created through this model often end up world-accessible under /dev. Always set correct permissions and validate any user-supplied data your driver later accepts through its file operations.
Summary / Key Takeaways
- The Linux Device Model unifies how the kernel represents buses, devices, and drivers
- Every device, even logical ones, is conceptually attached to a bus — real or pseudo (platform)
probe()andremove()drive the device lifecycle- Modern drivers often register with both a specialized kernel framework and a bus
- Simple logical drivers, like the misc driver in the next lecture, can skip bus registration entirely
Conclusion
The Linux Device Model can look intimidating from the outside, but it boils down to a small number of consistent rules repeated across every subsystem in the kernel. Once this mental model clicks, reading unfamiliar driver source code becomes dramatically easier, because you already know what probe(), remove(), and bus registration are trying to accomplish. In the next lecture of this free Linux device drivers course, we put this theory into practice by writing a real, working misc character device driver from scratch.
Frequently Asked Questions
Q1. What is the Linux Device Model in simple terms?
It is the kernel’s unified system for tracking hardware buses, the devices on them, and the drivers that operate those devices.
Q2. Why does every device need to be on a bus?
It keeps device discovery and driver matching consistent, even for hardware without a real physical bus, via the platform pseudo-bus.
Q3. What is the platform bus?
A pseudo-bus used for SoC-integrated peripherals that have no discoverable physical bus of their own.
Q4. What triggers a driver’s probe() function?
The bus driver invokes it once a device is successfully matched to a registered driver.
Q5. Do all drivers need to register with a bus?
No. Simple logical drivers, such as misc character device drivers, often only register with a kernel framework.
Q6. Where can I inspect bus and device relationships on a running system?
Under /sys/bus/, /sys/devices/, and /sys/class/.
Q7. What changed with class_create() in recent kernels?
From kernel 6.4 onward, class_create() takes only the class name, dropping the older owner-module argument.
Next up: writing your first real driver using the misc framework.
Next Lecture » Back to Course Index
2 Comments