|
HomeCore 0.1.3 (07b5544)
Bare-metal personal computer firmware for Cortex-M
|
How device drivers are described, generated, initialized, and written.
HomeCore's hardware is described in YAML, not in code. A board names its SoC, enables the peripherals it uses, and adds board-level devices such as LEDs and ramdisks. At configure time a generator checks the description against each driver's binding and writes C code that instantiates and initializes exactly the enabled devices. Nothing is parsed at run time, and a driver is compiled only when some enabled device needs it.
| Page | Contents |
|---|---|
| Serial ports | UARTs: the console, /dev/uartN, interrupt-driven receive |
| GPIO ports | GPIO ports: pin modes, outputs, inputs |
| LEDs | LEDs: /dev/ledN, the led_*() API, BASIC, and emulator stand-ins |
| Block devices | Block devices: the ramdisk that filesystems mount |
| Device bindings | Generated reference of every compatible and its properties |
The layers merge in order (SoC, board, overlays), later ones winning per key. The Development guide's "Device description" section covers the keys each layer may set; this page covers what drivers see.
For each enabled device node <node> with a binding whose driver prefix is <driver>, the generator writes:
The configuration holds the description's values and lives in flash. The instance holds run-time state in RAM; its first member is always the config pointer, and the driver owns everything else in it.
A binding, src/drivers/<class>/<compatible>.yaml, declares the driver prefix, its sources, what it provides, and its properties:
| Property type | Description value | C field value |
|---|---|---|
int | An integer; minimum and maximum bound it | 123U, or hexadecimal for reg |
size | A byte count such as 64K; minimum and multiple bound it | Bytes; with buffer: <field>, also a generated .bss buffer |
bool | true or false | true or false |
string | A non-empty string | A string literal |
clock | A name from the board's clocks | The clock frequency in Hz |
devpath | A name of a-z, 0-9, and _; defaults to the node name | "/dev/<name>", unique across devices |
gpio | The node name of an enabled GPIO port | A gpio_port_t; the port is initialized first |
| Binding flag | The driver provides | Used by |
|---|---|---|
console: true | const console_ops_t <driver>_console_ops | chosen.console, Console |
isr: true | void <driver>_isr(<driver>_t *), with an irq property | dt_irq_dispatch() |
gpio: true | const gpio_ops_t <driver>_gpio_ops | gpio properties, GPIO |
led: true | const led_ops_t <driver>_led_ops | dt_led_table, LEDs |
block: true | const block_ops_t <driver>_block_ops | Board mounts, Block devices |
Every driver also provides void <driver>_init(<driver>_t *). The generated binding reference lists every compatible, its properties, and the boards that enable it.
dt_init() calls each enabled device's init function in description order, except that a device referenced by another (a GPIO port named by an LED's gpio property) is initialized first. Init functions run with the clocks and console pins already configured by board_init(), and:
k_init();A binding with isr: true and an irq property claims that interrupt; the generator rejects two devices claiming the same one. The driver enables it with arch_irq_enable() in its init function. Interrupt handlers must be short and bounded, must not allocate or print, and share data with thread code only through structures designed for it, such as the serial receive ring.
| Class | Compatible | Boards | Validation |
|---|---|---|---|
| Serial | st,stm32-usart | STM32F4DISCOVERY, STM32VLDISCOVERY | QEMU (STM32VLDISCOVERY), host contract test; hardware pending |
| Serial | ti,stellaris-uart | LM3S6965EVB | QEMU, host contract test |
| GPIO | st,stm32f4-gpio | STM32F4DISCOVERY | Host contract test; hardware pending |
| GPIO | st,stm32f1-gpio | STM32VLDISCOVERY | Host contract test; hardware pending (QEMU models no GPIO) |
| LED | homecore,gpio-led | STM32F4DISCOVERY, STM32VLDISCOVERY | Host test; hardware pending |
| LED | homecore,console-led | LM3S6965EVB, STM32VLDISCOVERY in QEMU | QEMU, host test |
| Block | homecore,ramdisk | LM3S6965EVB, STM32F4DISCOVERY | QEMU (littlefs on LM3S), host tests |
src/drivers/<class>/<compatible>.yaml with compatible, description, driver, sources, capability flags, and properties, each with a type and the C field it fills.<driver>.h next to it: <driver>_config_t (constants, one member per field), <driver>_t (state; first member const <driver>_config_t *config), void <driver>_init(<driver>_t *), and the operation tables its flags promise.soc_cmsis.h, at the address in config->base. Return 0 or a count, and -1 with errno set, from operations. Keep interrupt handlers bounded.soc.yaml with status: disabled; boards enable them. Board-level devices go straight into board.yaml.soc_cmsis.h in tests/fakes/, as tests/uart_contract_test.c and tests/gpio_contract_test.c do, and generator cases in tests/devicetree_generate_test.py for new property rules. Register host tests in scripts/check_quality.py.Public interfaces that other code uses (console, GPIO, LEDs, block devices) are in include/homecore/drivers; driver headers stay in src/drivers.