Linux

Drivers

How the kernel represents hardware, and the paths by which that hardware becomes reachable from userspace — the piece that connects the protocol pages in this notebook to actual running code.

Quick reference
What it is
How the kernel matches devices to drivers, and the paths (spidev, i2c-dev, tty, gpiochip) by which userspace reaches them.
Mental model
A device tree entry is a job posting; a driver's compatible string is the résumé — the bus matches them and calls probe().
Key numbers
4 generic userspace paths cover most protocols this notebook covers: spidev, i2c-dev, tty, gpiochip.
Reach for it when
Debugging why a peripheral isn't showing up, or deciding between a quick userspace hack and a real kernel driver.

The device model, in one paragraph

A bus (platform, SPI, I2C, USB, ...) knows how to enumerate or is told about the devices attached to it. A driver registers with a bus, declaring which devices it knows how to handle (by compatible string, ID table, etc.). The bus matches devices to drivers and calls the driver's probe() function for each match. On most embedded ARM/RISC-V boards, the devices themselves — and which bus/pins/IRQ they're wired to — are described in the device tree, not hardcoded in the kernel.

How this notebook's protocols reach userspace

ProtocolKernel-side conceptUserspace path
SPISPI master/controller driver + device tree node/dev/spidevB.C via the spidev driver
I2CI2C adapter driver + device tree node/dev/i2c-N via i2c-dev
UARTSerial (tty) driver/dev/ttySN, /dev/ttyUSBN, etc., configured with termios
GPIOGPIO controller driver/dev/gpiochipN via libgpiod

Note the pattern: each subsystem exposes a generic userspace interface (spidev, i2c-dev, tty, gpiochip) that doesn't know anything about the specific chip on the other end — that chip-specific knowledge (register maps, command framing) lives in application code or, for devices with a real in-kernel driver, in a dedicated kernel module that exposes a higher-level interface instead (e.g. an IIO device for a sensor, rather than raw register access).

Character devices vs. a real kernel driver

Using spidev/i2c-dev directly from userspace is the fast path for prototyping or one-off tools, but it pushes all protocol logic into userspace and gives up kernel-level integration (power management, standard subsystem interfaces like IIO or input, interrupt-driven operation without a userspace polling loop). Writing a dedicated kernel driver is more work but is the right call for a peripheral that needs to behave like a first-class kernel device.

Finding what's bound to what

# what's on this I2C bus, and did anything claim address 0x68?
i2cdetect -l
i2cdetect -y 1

# device tree nodes actually seen by the running kernel
ls /sys/firmware/devicetree/base/

# which driver is bound to a given platform device
ls /sys/bus/platform/devices/<device>/driver

Real-world applications

What I learned

"The device tree looks right but the device isn't showing up" is usually one of: the driver for that compatible string isn't built/loaded, the node is disabled (status = "disabled"), or an overlay didn't actually get applied — check dmesg for probe failures before assuming the wiring or device tree syntax is wrong.