Module 11 ยท Lab 8
Drivers
You write a driver for a part twice over: first as a tested userspace library, then by comparing it with what a kernel driver gives, and, as a stretch, by building and loading a minimal kernel module.
Key ideas
- User space and kernel space: applications run at EL0 with no direct access to hardware; the kernel runs at EL1 and owns it.
- The driver model: buses, devices and drivers. The kernel matches a driver to a device (from the device tree in module 9) and calls its probe function.
- Interfaces such as
spidevandi2c-devlet a userspace program talk to a bus directly. That is quick to write and safe to crash, and is often right for one program and one part. - A kernel driver is better when several programs share a part, when it needs fast interrupt handling, or when it should appear through a standard interface. The kernel already has a driver for the MCP3008 ADC in its industrial I/O subsystem; part of the lab is explaining what it adds.
- A kernel module is code loaded into the running kernel: an init function, an exit function and whatever it registers in between.
On the bench
In short, what you do in lab 8, where the steps are given in full:
- Write a userspace library for the MCP3008 with a clean API, unit tests against a mocked SPI bus, and a small command-line tool.
- Bind the kernel's own MCP3008 driver with an overlay, read the same channel through
/sys, and compare. - Stretch: build and load a minimal module that registers a character device reporting a counter, and read its messages in
dmesg.
Resources
| Resource | Use in this module |
|---|---|
| Kernel driver API documentation | The driver model, SPI and I2C |
| Kernel industrial I/O documentation | The subsystem the kernel's ADC drivers use |
| libretech-wiring-tool | Overlays to bind a kernel driver to a part |