blob: a5e1d28910347a3597de65266f34e030953b179b [file] [log] [blame]
<!--
Documentation/_templates/layout.html
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership. The
ASF licenses this file to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
-->
<!DOCTYPE html>
<html class="writer-html5" lang="en">
<head>
<meta charset="utf-8" /><meta name="generator" content="Docutils 0.19: https://docutils.sourceforge.io/" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>OS Drivers Design &mdash; NuttX latest documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/css/theme.css" />
<link rel="stylesheet" type="text/css" href="../_static/copybutton.css" />
<link rel="stylesheet" type="text/css" href="../_static/custom.css" />
<link rel="shortcut icon" href="../_static/favicon.ico"/>
<script src="../_static/jquery.js"></script>
<script src="../_static/_sphinx_javascript_frameworks_compat.js"></script>
<script data-url_root="../" id="documentation_options" src="../_static/documentation_options.js"></script>
<script src="../_static/doctools.js"></script>
<script src="../_static/sphinx_highlight.js"></script>
<script src="../_static/clipboard.min.js"></script>
<script src="../_static/copybutton.js"></script>
<script src="../_static/js/theme.js"></script>
<link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Search" href="../search.html" />
<link rel="next" title="Device Drivers" href="device_drivers.html" />
<link rel="prev" title="Implementation Details" href="index.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="../index.html" class="icon icon-home"> NuttX
</a>
<!-- this version selector is quite ugly, should be probably replaced by something
more modern -->
<div class="version-selector">
<select onchange="javascript:location.href = this.value;">
<option value="../../latest" selected="selected">latest</option>
<option value="../../10.0.0" >10.0.0</option>
<option value="../../10.0.1" >10.0.1</option>
<option value="../../10.1.0" >10.1.0</option>
<option value="../../10.2.0" >10.2.0</option>
<option value="../../10.3.0" >10.3.0</option>
<option value="../../11.0.0" >11.0.0</option>
<option value="../../12.0.0" >12.0.0</option>
<option value="../../12.1.0" >12.1.0</option>
<option value="../../12.2.0" >12.2.0</option>
<option value="../../12.2.1" >12.2.1</option>
<option value="../../12.3.0" >12.3.0</option>
<option value="../../12.4.0" >12.4.0</option>
<option value="../../12.5.0" >12.5.0</option>
<option value="../../12.5.1" >12.5.1</option>
<option value="../../12.6.0" >12.6.0</option>
<option value="../../12.7.0" >12.7.0</option>
<option value="../../12.8.0" >12.8.0</option>
<option value="../../12.9.0" >12.9.0</option>
<option value="../../12.10.0" >12.10.0</option>
<option value="../../12.11.0" >12.11.0</option>
</select>
</div>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Table of Contents</span></p>
<ul class="current">
<li class="toctree-l1"><a class="reference internal" href="../index.html">Home</a></li>
<li class="toctree-l1"><a class="reference internal" href="../introduction/index.html">Introduction</a></li>
<li class="toctree-l1"><a class="reference internal" href="../quickstart/index.html">Getting Started</a></li>
<li class="toctree-l1"><a class="reference internal" href="../contributing/index.html">Contributing</a></li>
<li class="toctree-l1"><a class="reference internal" href="../introduction/inviolables.html">The Inviolable Principles of NuttX</a></li>
<li class="toctree-l1"><a class="reference internal" href="../platforms/index.html">Supported Platforms</a></li>
<li class="toctree-l1"><a class="reference internal" href="../components/index.html">OS Components</a></li>
<li class="toctree-l1"><a class="reference internal" href="../applications/index.html">Applications</a></li>
<li class="toctree-l1 current"><a class="reference internal" href="index.html">Implementation Details</a><ul class="current">
<li class="toctree-l2 current"><a class="current reference internal" href="#">OS Drivers Design</a><ul>
<li class="toctree-l3"><a class="reference internal" href="#character-and-block-drivers">Character and Block Drivers</a></li>
<li class="toctree-l3"><a class="reference internal" href="#mtd-drivers">MTD Drivers</a></li>
<li class="toctree-l3"><a class="reference internal" href="#monolithic-drivers">Monolithic Drivers</a></li>
<li class="toctree-l3"><a class="reference internal" href="#upper-half-and-lower-half-drivers">Upper Half and Lower Half Drivers</a><ul>
<li class="toctree-l4"><a class="reference internal" href="#one-to-many-encapsulation-and-polymorphism">One to Many: Encapsulation and Polymorphism</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="device_drivers.html">Device Drivers</a></li>
<li class="toctree-l2"><a class="reference internal" href="processes_vs_tasks.html">Linux Processes vs NuttX Tasks</a></li>
<li class="toctree-l2"><a class="reference internal" href="critical_sections.html">Critical Sections</a></li>
<li class="toctree-l2"><a class="reference internal" href="interrupt_controls.html">Per-Thread Interrupt Controls</a></li>
<li class="toctree-l2"><a class="reference internal" href="preemption_latency.html">Effects of Disabling Interrupts or Pre-Emption on Response Latency</a></li>
<li class="toctree-l2"><a class="reference internal" href="bottomhalf_interrupt.html">Bottom-Half Interrupt Handlers</a></li>
<li class="toctree-l2"><a class="reference internal" href="simulation.html">The NuttX Simulation</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../reference/index.html">API Reference</a></li>
<li class="toctree-l1"><a class="reference internal" href="../faq/index.html">FAQ</a></li>
<li class="toctree-l1"><a class="reference internal" href="../guides/index.html">Guides</a></li>
<li class="toctree-l1"><a class="reference internal" href="../glossary.html">Glossary</a></li>
<li class="toctree-l1"><a class="reference internal" href="../logos/index.html">NuttX Logos</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="../index.html">NuttX</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li>
<li class="breadcrumb-item"><a href="index.html">Implementation Details</a></li>
<li class="breadcrumb-item active">OS Drivers Design</li>
<li class="wy-breadcrumbs-aside">
<a href="../_sources/implementation/drivers_design.rst.txt" rel="nofollow"> View page source</a>
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<section id="os-drivers-design">
<h1>OS Drivers Design<a class="headerlink" href="#os-drivers-design" title="Permalink to this heading"></a></h1>
<p>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.</p>
<section id="character-and-block-drivers">
<h2>Character and Block Drivers<a class="headerlink" href="#character-and-block-drivers" title="Permalink to this heading"></a></h2>
<p>The standard driver types include:</p>
<ul class="simple">
<li><p><strong>Character Drivers</strong>. First there are the character drivers These are drivers
that support user accessibility via <code class="docutils literal notranslate"><span class="pre">read()</span></code>, <code class="docutils literal notranslate"><span class="pre">write()</span></code> etc. The others do
not naturally. Character drivers implement a stream of incoming or outgoing bytes.</p></li>
<li><p><strong>Block Drivers</strong>. These are used to support files systems that supported
block-oriented I/O, not a character stream. The user cannot <em>directly</em> access
block drivers.</p></li>
</ul>
<p>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 <code class="docutils literal notranslate"><span class="pre">/dev</span></code>.
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 <code class="docutils literal notranslate"><span class="pre">drivers/bch</span></code>. 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.</p>
<p>This capability is exploited, for example, by the NuttX file system formatting
applications like mkfatfs to format a FAT system on a block driver.</p>
<p>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.</p>
</section>
<section id="mtd-drivers">
<h2>MTD Drivers<a class="headerlink" href="#mtd-drivers" title="Permalink to this heading"></a></h2>
<p>And the non-standard driver is:</p>
<ul class="simple">
<li><p>The <strong>Memory Technology Driver (MTD)</strong>. This naming was borrowed from <code class="docutils literal notranslate"><span class="pre">infradead.org</span></code>,
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.</p></li>
</ul>
<p>MTD has the same conveniences as block drivers: Then can appear as device nodes
under <code class="docutils literal notranslate"><span class="pre">/dev</span></code> 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, <code class="docutils literal notranslate"><span class="pre">drivers/mtd/sector512.c</span></code> 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.</p>
<p><code class="docutils literal notranslate"><span class="pre">drivers/mtd/mtd_partitions.c</span></code> can be used to break up a large FLASH into
separate, independent partitions, each of which looks like another MTD driver.</p>
<p><code class="docutils literal notranslate"><span class="pre">drivers/mtd/ftl.c</span></code> 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.</p>
</section>
<section id="monolithic-drivers">
<h2>Monolithic Drivers<a class="headerlink" href="#monolithic-drivers" title="Permalink to this heading"></a></h2>
<p>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:</p>
<ul class="simple">
<li><p>The device monolithic driver exposes a single, standard device driver interface.
With the <strong>Virtual File System (VFS)</strong>, this provides the application user interface
to the driver functionality. And</p></li>
<li><p>A low-level interface to the hardware that is managed by the device driver.</p></li>
</ul>
</section>
<section id="upper-half-and-lower-half-drivers">
<h2>Upper Half and Lower Half Drivers<a class="headerlink" href="#upper-half-and-lower-half-drivers" title="Permalink to this heading"></a></h2>
<p>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.</p>
<p>NuttX reduces the duplication, both in the code and in driver development,
using the notion of <em>Upper Half</em> and <em>Lower Half</em> 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.</p>
<p>As before, each of these two driver components has two functional interfaces.
For the upper half driver:</p>
<ul class="simple">
<li><p>The upper half device driver exposes a single, standard driver interface.
With the <strong>Virtual File System (VFS)</strong>, this, again, provides the application
user interface to the driver functionality. And</p></li>
<li><p>The upper-half side of the lower-half interface to the MCU-specific hardware
that is managed by the lower-half device driver.</p></li>
</ul>
<p>And for the lower half driver:</p>
<ul class="simple">
<li><p>The lower-half side of the interface to the the upper0half driver, and</p></li>
<li><p>The low-level interface to the hardware that is managed by the lower half
device driver.</p></li>
</ul>
<section id="one-to-many-encapsulation-and-polymorphism">
<h3>One to Many: Encapsulation and Polymorphism<a class="headerlink" href="#one-to-many-encapsulation-and-polymorphism" title="Permalink to this heading"></a></h3>
<p>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.</p>
<p>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 <code class="docutils literal notranslate"><span class="pre">src/</span></code> directory under <code class="docutils literal notranslate"><span class="pre">arch/</span></code>.
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 <code class="docutils literal notranslate"><span class="pre">drivers/serial/serial.c</span></code>.
This is only possible due to the object-like properties of the lower-half driver
implementations.</p>
</section>
</section>
</section>
</div>
</div>
<footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer">
<a href="index.html" class="btn btn-neutral float-left" title="Implementation Details" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a>
<a href="device_drivers.html" class="btn btn-neutral float-right" title="Device Drivers" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a>
</div>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2023, The Apache Software Foundation.</p>
</div>
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>