diff --git a/Documentation/implementation/drivers_design.rst b/Documentation/implementation/drivers_design.rst new file mode 100644 index 00000000000..4127bee6cb8 --- /dev/null +++ b/Documentation/implementation/drivers_design.rst @@ -0,0 +1,132 @@ +================= +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 the upper0half 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 complete 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. diff --git a/Documentation/implementation/index.rst b/Documentation/implementation/index.rst index 28e7f4ebf34..07891136920 100644 --- a/Documentation/implementation/index.rst +++ b/Documentation/implementation/index.rst @@ -6,6 +6,7 @@ Implementation Details :maxdepth: 2 :caption: Contents: + drivers_design.rst processes_vs_tasks.rst critical_sections.rst interrupt_controls.rst