mirror of
https://github.com/apache/nuttx.git
synced 2026-10-11 08:10:21 +00:00
The documentation grew one page at a time, so the tree follows the
history of who wrote what and not the shape of NuttX. Scheduling is
spread over three places, a driver page can sit above the subsystem
that owns it, and the front page lists everything at the same level.
That is a lot to face when all you want to know is where the scheduler
lives.
This change files every page under the code it describes. It is a move,
not a rewrite: outside the ten pages named below, every page keeps the
text that is already in master, and no page's text is deleted.
What it does:
* Groups the table of contents into nine chapters.
* Moves the OS subsystems under os/: scheduling, memory, drivers,
filesystem, networking, IPC, interrupts, libs, time.
* Renames the platform pages to the names the source tree uses, and
derives their tags from the tree instead of by hand.
* Splits guides/ by subject.
* Adds Documentation/redirects.py, with a rule for every page that left
its old path, so old URLs keep working. The redirect page also carries
a link's #anchor across to the new page.
Ten pages have text that is new or rewritten. Nine of them are the
landing page of a chapter, which has to exist for the new structure:
index the front page
os/index OS Design
os/scheduling/index Scheduling
os/interrupts/index Interrupts
os/ipc/index IPC
os/time/index Time and timers
about/index About
developing/index Developing NuttX
ReleaseNotes/index Release notes
The tenth is os/libs/libbuiltin, the only page here with technical
content: libs/libbuiltin/ had no page at all. Five SVG diagrams come
with these pages, hand-written XML with no editor metadata.
Nothing outside Documentation/ is touched.
How it was checked:
* Sphinx builds with -W: no warnings, and no document left outside a
toctree.
* A script, offered in the PR, proves the narrow claim this rests on.
For every page outside the ten named above it erases what a move
touches -- link target, path, tag line, toctree block, table border --
from the whole old text and the whole new text, and requires the two
to be byte for byte identical. It also requires every sentence of a
deleted page to turn up somewhere, and every page that left its old
path to have a redirect, from a URL that existed, to where its content
went. It exits non-zero and names the page if any of that is not true,
and it tests added pages too, so forgetting to declare one cannot make
it pass.
* An independent audit checked 133 factual claims on these ten pages
against the tree, one shell command per claim: 130 confirmed, 1
refuted and fixed here, 2 not checkable.
* tools/checkpatch.sh is clean over the range.
The diff is large because moving a page changes every link that points
to it. Most of it is pure renames, and board pages that gained one tag
line.
Assisted-by: Claude:claude-opus-5
132 lines
6.3 KiB
ReStructuredText
132 lines
6.3 KiB
ReStructuredText
=================
|
|
OS Drivers Design
|
|
=================
|
|
|
|
There are three kinds of drivers that are recognized by the OS and are visible to
|
|
applications. Two are POSIX standard device driver types, one is non-standard.
|
|
There are also internal OS components that may also be considered to be drivers
|
|
or, more correctly, lower-half drivers. Details about these are given below.
|
|
|
|
Character and Block Drivers
|
|
===========================
|
|
|
|
The standard driver types include:
|
|
|
|
* **Character Drivers**. First there are the character drivers These are drivers
|
|
that support user accessibility via ``read()``, ``write()`` etc. The others do
|
|
not naturally. Character drivers implement a stream of incoming or outgoing bytes.
|
|
|
|
* **Block Drivers**. These are used to support files systems that supported
|
|
block-oriented I/O, not a character stream. The user cannot *directly* access
|
|
block drivers.
|
|
|
|
The user can, however, access block drivers indirectly through a character driver proxy.
|
|
Both character and block drivers are represented by device nodes, usually in ``/dev``.
|
|
But if you try to open the block driver, something very strange happens: A temporary,
|
|
nameless proxy character driver is automatically instantiated that maps a character
|
|
driver's byte stream into blocks and mediates the driver access to the block driver.
|
|
This is the logic in ``drivers/bch``. BCH stands for block to character. So from the
|
|
application point of view, the both seem to be character drivers and applications
|
|
can interact with both in the same way.
|
|
|
|
This capability is exploited, for example, by the NuttX file system formatting
|
|
applications like mkfatfs to format a FAT system on a block driver.
|
|
|
|
There is also the complement, the loop device that converts a character driver into
|
|
a block driver. Loop devices are commonly used to format a file system image in RAM.
|
|
|
|
MTD Drivers
|
|
===========
|
|
|
|
And the non-standard driver is:
|
|
|
|
* The **Memory Technology Driver (MTD)**. This naming was borrowed from ``infradead.org``,
|
|
but does not derive from any of their MTD logic. The MTD driver manages memory-based
|
|
devices like FLASH or EEPROM. And MTD FLASH memory driver is very similar to a block
|
|
driver but FLASH has some different properties, most notably that you have to erase
|
|
FLASH before you write to it.
|
|
|
|
MTD has the same conveniences as block drivers: Then can appear as device nodes
|
|
under ``/dev`` and can be proxied to behave like character drivers if the opened
|
|
as character drivers. Plus they have some additional twists: MTD drivers can be
|
|
stacked one on top of another to extend the capabilities of the lower level MTD
|
|
driver. For example, ``drivers/mtd/sector512.c`` is an MTD driver that when layered
|
|
on top of another MTD driver, it changes the apparent page size of the FLASH to
|
|
512 bytes.
|
|
|
|
``drivers/mtd/mtd_partitions.c`` can be used to break up a large FLASH into
|
|
separate, independent partitions, each of which looks like another MTD driver.
|
|
|
|
``drivers/mtd/ftl.c`` is also interesting. FTL stands for FLASH Translation Layer.
|
|
The FTL driver is an MTD driver that when layered on top of another MTD driver,
|
|
converts the MTD driver to a block driver. The permutations are endless.
|
|
|
|
Monolithic Drivers
|
|
==================
|
|
|
|
When one thinks about device drivers in an OS, one thinks of a single thing,
|
|
a single block in a block diagram with these two primary interfaces:
|
|
|
|
* The device monolithic driver exposes a single, standard device driver interface.
|
|
With the **Virtual File System (VFS)**, this provides the application user interface
|
|
to the driver functionality. And
|
|
|
|
* A low-level interface to the hardware that is managed by the device driver.
|
|
|
|
Upper Half and Lower Half Drivers
|
|
=================================
|
|
|
|
NuttX supports many, many different MCU platforms, each with many similar but
|
|
distinct built-in peripherals.
|
|
Certainly we could imagine a realization where each such peripheral is supported
|
|
by monolithic driver as described in the preceding paragraph.
|
|
That would involve a lot code duplication, however.
|
|
The MCU peripherals may be unique at a low, register-level interface.
|
|
However, the peripherals are really very similar at a higher level of abstraction.
|
|
|
|
NuttX reduces the duplication, both in the code and in driver development,
|
|
using the notion of *Upper Half* and *Lower Half* drivers.
|
|
Such an implementation results in two things; two blocks in the system block
|
|
diagram: The upper half driver in a group of common, shared drivers, and
|
|
the MCU-specific lower half driver.
|
|
|
|
As before, each of these two driver components has two functional interfaces.
|
|
For the upper half driver:
|
|
|
|
* The upper half device driver exposes a single, standard driver interface.
|
|
With the **Virtual File System (VFS)**, this, again, provides the application
|
|
user interface to the driver functionality. And
|
|
|
|
* The upper-half side of the lower-half interface to the MCU-specific hardware
|
|
that is managed by the lower-half device driver.
|
|
|
|
And for the lower half driver:
|
|
|
|
* The lower-half side of the interface to the upper-half driver, and
|
|
|
|
* The low-level interface to the hardware that is managed by the lower half
|
|
device driver.
|
|
|
|
One to Many: Encapsulation and Polymorphism
|
|
-------------------------------------------
|
|
|
|
These modular upper- and lower-half drivers have certain properties that you
|
|
would associate with an object oriented design: Encapsulation, data abstraction,
|
|
and polymorphism certainly.
|
|
Because of this encapsulation, the upper-half driver is completely unaware of any
|
|
implementation details within the lower-half driver.
|
|
Everything needed for the upper- and lower-half drivers to integrate is provided
|
|
by the defined interface between between those two things.
|
|
In fact, a single upper-half driver may service many lower-half driver instances
|
|
in a one-to-many relationship.
|
|
|
|
As an example, some MCUs support UARTs, USARTs functioning as UARTs,
|
|
Low-Power UARTs (LPUARTs), and other Flexible devices that may function as UARTs.
|
|
Each of these is managed by a separate lower-half driver that can be found in the
|
|
appropriate ``src/`` directory under ``arch/``.
|
|
In addition a board could have off-chip, external 16550 UART hardware (which has
|
|
a common lower-half driver).
|
|
Yet all of them would be supported by the single, common, serial upper half
|
|
driver that can be found at ``drivers/serial/serial.c``.
|
|
This is only possible due to the object-like properties of the lower-half driver
|
|
implementations.
|