Skip to content

Day71 - Linux Driver Model Fundamentals

Objective

Understand how the Linux Driver Core coordinates:

  • Bus
  • Device
  • Driver

and performs:

  • Device registration
  • Driver registration
  • Matching
  • Probe
  • Remove

without relying on Platform Bus or Device Tree.


Lab Environment

Kernel:

Linux 6.6.x

Platform:

Raspberry Pi 5

Module:

demo_driver_model.ko

Lab 1 - Minimal Driver Core

Goal

Create a minimal Linux Driver Model implementation using:

struct bus_type
struct device
struct device_driver

without using:

  • Platform Bus
  • Device Tree
  • Overlay

Demo Bus

static struct bus_type demo_bus_type = {
    .name = "demo_bus",
    .match = demo_match,
};

Demo Device

static struct device demo_device = {
    .init_name = DEMO_DEVICE_NAME,
    .bus = &demo_bus_type,
    .release = demo_device_release,
};

Demo Driver

static struct device_driver demo_driver = {
    .name = DEMO_DEVICE_NAME,
    .bus = &demo_bus_type,
    .probe = demo_drv_probe,
    .remove = demo_drv_remove,
};

Registration Flow

bus_register()
device_register()
driver_register()

Result

match dev=demo_device drv=demo_device

demo_drv_probe: probe

Verified:

driver_register()
match()
probe()

Lab 2 - Registration Order

Goal

Verify that registration order does not matter.


Driver First

bus_register()
driver_register()
device_register()

Result

driver registered

match dev=demo_device drv=demo_device

demo_drv_probe: probe

device registered

Observation

The Linux Driver Core performs matching whenever a new device or driver appears.

Therefore:

Device first

and

Driver first

both work correctly.


Lab 3 - Match Failure

Goal

Verify that matching controls probe execution.


Driver Name

.name = "wrong_driver";

Match Function

return strcmp(dev_name(dev), drv->name) == 0;

Result

match dev=demo_device drv=wrong_driver

No probe was executed.


Observation

Match Failed
No Probe

Lab 4 - Driver Wrapper

Goal

Implement a subsystem-style driver wrapper.


Wrapper Definition

struct demo_driver {
    struct device_driver driver;

    int (*probe)(struct device *dev);
    void (*remove)(struct device *dev);
};

Bus Probe

static int demo_bus_probe(struct device *dev)
{
    struct demo_driver *ddrv;

    ddrv = to_demo_driver(dev->driver);

    return ddrv->probe(dev);
}

Bus Remove

static void demo_bus_remove(struct device *dev)
{
    struct demo_driver *ddrv;

    ddrv = to_demo_driver(dev->driver);

    ddrv->remove(dev);
}

Result

match()

demo_bus_probe()

demo_drv_probe()

and

demo_bus_remove()

demo_drv_remove()

Observation

This architecture resembles:

platform_driver
i2c_driver
spi_driver

which all extend:

struct device_driver

with subsystem-specific callbacks.


Lab 5 - Probe Failure

Goal

Observe probe failure behavior.


Probe

static int demo_drv_probe(struct device *dev)
{
    return -EINVAL;
}

Result

match()

demo_bus_probe()

demo_drv_probe()

probe with driver demo_device failed with error -22

Observation

Verified:

Driver Register Success
Probe Failure
Binding Failure

Driver registration remains successful.

Remove callback is not executed because the device was never bound.


Lab 6 - sysfs Observation

Goal

Observe the generated sysfs hierarchy.


Commands

ls -R /sys/bus/demo_bus

readlink -f \
/sys/bus/demo_bus/devices/demo_device

find /sys/devices -name demo_device

Result

/sys/bus/demo_bus/devices/demo_device
/sys/devices/demo_device

Observation

Verified:

/sys/devices

contains the actual device object.

/sys/bus/demo_bus/devices

provides the bus view.

/sys/bus/demo_bus/drivers

provides the driver view.


Conclusion

This lab demonstrated the Linux Driver Core workflow:

Device Register
Driver Register
Match
Probe
Binding

and the corresponding removal flow:

Driver Unregister
Remove
Unbind

The implementation provides a minimal model of how Platform, I2C, SPI, USB, and PCI subsystems interact with the Linux Driver Core.