Why Linux Uses a Bus‑Device‑Driver Model for High Cohesion, Low Coupling
The article explains how Linux separates board‑level information from drivers using a bus‑device‑driver model, illustrating high cohesion and low coupling with concrete code examples, matching mechanisms, and the evolution toward device trees for scalable hardware abstraction.
Device Driver Model Requirements
Understanding the relationship between buses, devices, and drivers can be clarified with everyday analogies: a wall socket (bus) remains fixed while various devices (phones, laptops) plug in without needing the socket to change. This mirrors the software engineering principle of high cohesion and low coupling.
High cohesion means elements within a module are tightly related, while low coupling means modules interact minimally. Applying this to drivers, the driver should remain isolated from specific board details, enabling reuse across many hardware platforms.
Illustrative Example: GITCHAT Network Card
Consider a hypothetical network card GITCHAT that connects to the CPU via address, data, and control buses, plus an interrupt pin. Its driver must define a base address and interrupt number, e.g.:
#define GITCHAT_BASE 0x0001
#define GITCHAT_INTERRUPT 2
int gitchat_send() {
writel(GITCHAT_BASE + REG, 1);
...
}
int gitchat_init() {
request_init(GITCHAT_INTERRUPT, ...);
...
}If the same driver is used on dozens of boards with different base addresses and interrupts, the hard‑coded constants would have to change, defeating reuse. The solution is a driver model that abstracts board‑specific data.
Implementing the Driver Model
Linux solves this by introducing a bus layer that binds devices and drivers while keeping board‑level information separate. The board supplies its hardware resources to the bus, and the driver queries the bus for those resources.
Typical steps:
Define the board’s resources (memory ranges, IRQs) in a resource array.
Create a platform_device structure that references those resources.
Register the device on the appropriate platform bus.
In the driver’s probe function, obtain the resources via platform_get_resource().
Example of board‑side registration:
static struct resource gitchat_resource[] = {
{ .start = ..., .end = ..., .flags = IORESOURCE_MEM },
...
};
static struct platform_device gitchat_device = {
.name = "gitchat",
.id = 0,
.num_resources = ARRAY_SIZE(gitchat_resource),
.resource = gitchat_resource,
};
static struct platform_device *ip0x_device __initdata = { &gitchat_device, ... };
static int __init ip0x_init(void) {
platform_add_devices(ip0x_device, ARRAY_SIZE(ip0x_device));
return 0;
}Driver‑side probe function retrieving resources:
static int gitchat_probe(struct platform_device *pdev)
{
db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
db->irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 2);
...
return 0;
}The bus matches devices to drivers primarily by name, falling back to ID tables, OF (Device Tree) matches, or ACPI matches. A simplified matching function looks like:
static int platform_match(struct device *dev, struct device_driver *drv)
{
struct platform_device *pdev = to_platform_device(dev);
struct platform_driver *pdrv = to_platform_driver(drv);
if (pdev->driver_override)
return !strcmp(pdev->driver_override, drv->name);
if (of_driver_match_device(dev, drv))
return 1;
if (acpi_driver_match_device(dev, drv))
return 1;
if (pdrv->id_table)
return platform_match_id(pdrv->id_table, pdev) != NULL;
return (strcmp(pdev->name, drv->name) == 0);
}This mechanism ensures that the driver obtains the correct board information without being hard‑coded, achieving high cohesion (driver logic stays together) and low coupling (board specifics are isolated).
Evolution Toward Device Trees
While the bus‑device‑driver model decouples drivers from board files, maintaining a separate board‑xxx.c for each platform becomes cumbersome as the number of boards grows. Linux introduced the Device Tree (DTS) format to describe hardware resources declaratively, moving the board description out of C code and further reducing maintenance overhead.
In summary, the Linux device driver model uses a three‑layer architecture—board‑level resource definitions, a platform bus, and drivers—to achieve modular, reusable code. The model has matured from static C board files to flexible Device Tree descriptions, addressing scalability challenges in modern heterogeneous hardware environments.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Liangxu Linux
Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
