Index: bsp-howto/console.rst
===================================================================
--- bsp-howto/console.rst	(revision 3b42c96764c8aa49ce4e4ec381b1187d375d6e8f)
+++ bsp-howto/console.rst	(revision 5bb51a43d1c770dfaddd484f0e5f6d104b8df92e)
@@ -8,168 +8,158 @@
 **************
 
+.. warning::
+    The low-level driver API changed between RTEMS 4.10 and RTEMS 4.11.  The
+    legacy callback API is still supported, but its use is discouraged.  The
+    following functions are deprecated:
+
+    - :c:func:`rtems_termios_open()`
+
+    - :c:func:`rtems_termios_close()`
+
+    This manual describes the new API.
+
 Introduction
 ============
 
 This chapter describes the operation of a console driver using the RTEMS POSIX
-Termios support.  Traditionally RTEMS has referred to all serial device drivers
-as console device drivers.  A console driver can be used to do raw data
-processing in addition to the "normal" standard input and output device
-functions required of a console.
-
-The serial driver may be called as the consequence of a C Library call such as
-``printf`` or ``scanf`` or directly via the``read`` or ``write`` system calls.
-There are two main functioning modes:
-
-- console: formatted input/output, with special characters (end of line,
-  tabulations, etc.) recognition and processing,
-
-- raw: permits raw data processing.
-
-One may think that two serial drivers are needed to handle these two types of
-data, but Termios permits having only one driver.
-
-Termios
-=======
-
-Termios is a standard for terminal management, included in the POSIX 1003.1b
-standard.  As part of the POSIX and Open Group Single UNIX Specification, is
-commonly provided on UNIX implementations.  The Open Group has the termios
-portion of the POSIX standard online at
-http://opengroup.org/onlinepubs/007908775/xbd/termios.html.  The requirements
-for the ``<termios.h>`` file are also provided and are at
-http://opengroup.org/onlinepubs/007908775/xsh/termios.h.html.
-
-Having RTEMS support for Termios is beneficial because:
-
-- from the user's side because it provides standard primitive operations to
-  access the terminal and change configuration settings.  These operations are
-  the same under UNIX and RTEMS.
-
-- from the BSP developer's side because it frees the developer from dealing
-  with buffer states and mutual exclusions on them.  Early RTEMS console device
-  drivers also did their own special character processing.
-
-- it is part of an internationally recognized standard.
-
-- it makes porting code from other environments easier.
-
-Termios support includes:
-
-- raw and console handling,
-
-- blocking or non-blocking characters receive, with or without Timeout.
-
-At this time, RTEMS documentation does not include a thorough discussion of the
-Termios functionality.  For more information on Termios, type ``man termios``
-on a Unix box or point a web browser athttp://www.freebsd.org/cgi/man.cgi.
+Termios support.  Traditionally, RTEMS has referred to all serial device drivers
+as console drivers.
+`Termios <http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap11.html>`_
+is defined by IEEE Std 1003.1-2008 (POSIX.1-2008).  It supports various modes
+of operations at application level.  This chapter focuses on the low-level
+serial device driver.  Additional Termios information can be found in the
+`Linux TERMIOS(3) <http://man7.org/linux/man-pages/man3/termios.3.html>`_
+manpage or the
+`FreeBSD TERMIOS(4) <https://www.freebsd.org/cgi/man.cgi?query=termios&sektion=4>`_
+manpage.
+
+There are the following software layers.
+
++-------------------------+
+| Application             |
++-------------------------+
+| Termios                 |
++-------------------------+
+| Low-Level Device Driver |
++-------------------------+
+
+In the default application configuration RTEMS opens during system
+initialization a :file:`/dev/console` device file to create the file
+descriptors 0, 1 and 2 used for standard input, output and error, respectively.
+The corresponding device driver is usually a Termios serial device driver
+described here.  The standard file descriptors are used by standard C library
+calls such as :c:func:`printf` or :c:func:`scanf` or directly via the
+:c:func:`read` or :c:func:`write` system calls.
+
+Build System and Files
+======================
+
+A new serial device driver should consist of three parts.
+
+- A section in the BSPs Makefile.am:
+
+.. code-block:: makefile
+
+      [...]
+      libbsp_a_SOURCES += ../../shared/console-termios.c
+      libbsp_a_SOURCES += console/console.c
+      [...]
+
+- A general serial device specific low-level driver providing the handler table
+  and the device context specialization for the Termios
+  :c:func:`rtems_termios_device_install()` function.  This low-level driver
+  could be used for more than one BSP.
+
+- A BSP-specific initialization routine :c:func:`console_initialize()`, that calls
+  :c:func:`rtems_termios_device_install()` providing a low-level driver context for
+  each installed device.  This is usually defined in the file
+  :file:`console/console.c` relative to the BSP base directory.
+
+The low-level driver should provide a specialization of the Termios device
+context.  The initialization routine must provide a context for each installed
+device via :c:func:`rtems_termios_device_install()`.  Here is an example header
+file for a low-level serial device driver.
+
+.. code-block:: c
+
+    #ifndef MY_DRIVER_H
+    #define MY_DRIVER_H
+
+    #include <some-chip/serial.h>
+
+    #include <rtems/termiostypes.h>
+
+    /* My low-level driver specialization of Termios device context */
+    typedef struct {
+      rtems_termios_device_context base;
+      const char *device_name;
+      volatile some_chip_registers *regs;
+      /* More stuff */
+    } my_driver_context;
+
+    extern const rtems_termios_device_handler my_driver_handler_polled;
+
+    extern const rtems_termios_device_handler my_driver_handler_interrupt;
+
+    #endif /* MY_DRIVER_H */
 
 Driver Functioning Modes
 ========================
 
-There are generally three main functioning modes for an UART (Universal
-Asynchronous Receiver-Transmitter, i.e. the serial chip):
-
-- polled mode
-
-- interrupt driven mode
-
-- task driven mode
-
-In polled mode, the processor blocks on sending/receiving characters.  This
-mode is not the most efficient way to utilize the UART. But polled mode is
-usually necessary when one wants to print an error message in the event of a
-fatal error such as a fatal error in the BSP.  This is also the simplest mode
-to program.  Polled mode is generally preferred if the serial port is to be
-used primarily as a debug console.  In a simple polled driver, the software
-will continuously check the status of the UART when it is reading or writing to
-the UART.  Termios improves on this by delaying the caller for 1 clock tick
-between successive checks of the UART on a read operation.
-
-In interrupt driven mode, the processor does not block on sending/receiving
-characters.  Data is buffered between the interrupt service routine and
-application code.  Two buffers are used to insulate the application from the
-relative slowness of the serial device.  One of the buffers is used for
-incoming characters, while the other is used for outgoing characters.
-
-An interrupt is raised when a character is received by the UART.  The interrupt
-subroutine places the incoming character at the end of the input buffer.  When
-an application asks for input, the characters at the front of the buffer are
-returned.
-
-When the application prints to the serial device, the outgoing characters are
-placed at the end of the output buffer.  The driver will place one or more
-characters in the UART (the exact number depends on the UART) An interrupt will
-be raised when all the characters have been transmitted.  The interrupt service
-routine has to send the characters remaining in the output buffer the same way.
-When the transmitting side of the UART is idle, it is typically necessary to
-prime the transmitter before the first interrupt will occur.
-
-The task driven mode is similar to interrupt driven mode, but the actual data
-processing is done in dedicated tasks instead of interrupt routines.
-
-Serial Driver Functioning Overview
-==================================
-
-The following Figure shows how a Termios driven serial driver works: Figure not
-included in ASCII version
-
-The following list describes the basic flow.
-
-- the application programmer uses standard C library call (printf, scanf, read,
-  write, etc.),
-
-- C library (ctx.g. RedHat (formerly Cygnus) Newlib) calls the RTEMS system
-  call interface.  This code can be found in the:file:`cpukit/libcsupport/src`
-  directory.
-
-- Glue code calls the serial driver entry routines.
-
-Basics
-------
-
-The low-level driver API changed between RTEMS 4.10 and RTEMS 4.11.  The legacy
-callback API is still supported, but its use is discouraged.  The following
-functions are deprecated:
-
-- ``rtems_termios_open()`` - use ``rtems_termios_device_open()`` in combination
-  with ``rtems_termios_device_install()`` instead.
-
-- ``rtems_termios_close()`` - use ``rtems_termios_device_close()`` instead.
-
-This manual describes the new API.  A new console driver should consist of
-three parts.
-
-- The basic console driver functions using the Termios support.  Add this the
-  BSPs Makefile.am:
-
-.. code-block:: makefile
-
-      [...]
-      libbsp_a_SOURCES += ../../shared/console-termios.c
-      [...]
-
-- A general serial module specific low-level driver providing the handler table
-  for the Termios ``rtems_termios_device_install()`` function.  This low-level
-  driver could be used for more than one BSP.
-
-- A BSP specific initialization routine ``console_initialize()``, that calls
-  ``rtems_termios_device_install()`` providing a low-level driver context for
-  each installed device.
-
-You need to provide a device handler structure for the Termios device
-interface.  The functions are described later in this chapter.  The first open
-and set attributes handler return a boolean status to indicate success (true)
-or failure (false).  The polled read function returns an unsigned character in
-case one is available or minus one otherwise.
-
-If you want to use polled IO it should look like the following.  Termios must
-be told the addresses of the handler that are to be used for simple character
-IO, i.e. pointers to the ``my_driver_poll_read()`` and
-``my_driver_poll_write()`` functions described later in `Termios and Polled
-IO`_.
-
-.. code-block:: c
-
-    const rtems_termios_handler my_driver_handler_polled = {
+There are four main functioning modes for a Termios serial device driver.  The
+mode must be set during device creation and cannot be changed afterwards.
+
+Polled Mode (`TERMIOS_POLLED`)
+    In polled mode, the processor blocks on sending/receiving characters.  This
+    mode is not the most efficient way to utilize the serial device. But polled
+    mode is usually necessary when one wants to print an error message in the
+    event of a fatal error such as a fatal error in the BSP.  This is also the
+    simplest mode to program.  Polled mode is generally preferred if the serial
+    device is to be used primarily as a debug console.  In a simple polled
+    driver, the software will continuously check the status of the serial
+    device when it is reading or writing to the serial device.  Termios
+    improves on this by delaying the caller for one clock tick between
+    successive checks of the serial device on a read operation.
+
+Interrupt Driven Mode (`TERMIOS_IRQ_DRIVEN`)
+    In interrupt driven mode, the processor does not block on sending/receiving
+    characters.  Data is buffered between the interrupt service routine and
+    application code.  Two buffers are used to insulate the application from
+    the relative slowness of the serial device.  One of the buffers is used for
+    incoming characters, while the other is used for outgoing characters.
+
+    An interrupt is raised when a character is received by the serial device.
+    The interrupt routine places the incoming character at the end of the input
+    buffer.  When an application asks for input, the characters at the front of
+    the buffer are returned.
+
+    When the application prints to the serial device, the outgoing characters
+    are placed at the end of the output buffer.  The driver will place one or
+    more characters in the serial device (the exact number depends on the
+    serial device) An interrupt will be raised when all the characters have
+    been transmitted.  The interrupt service routine has to send the characters
+    remaining in the output buffer the same way.  When the transmitting side of
+    the serial device is idle, it is typically necessary to prime the
+    transmitter before the first interrupt will occur.
+
+Interrupt Server Driven Mode (`TERMIOS_IRQ_SERVER_DRIVEN`)
+    The interrupt server driven mode is identical to the interrupt driven mode,
+    except that a mutex is used to protect the low-level device state instead
+    of an interrupt lock (disabled interrupts).  Use this mode in case the
+    serial device is connected via I2C or SPI and the I2C or SPI framework is
+    used.
+
+Task Driven Mode (`TERMIOS_TASK_DRIVEN`)
+    The task driven mode is similar to interrupt driven mode, but the actual
+    data processing is done in dedicated tasks instead of interrupt routines.
+
+Polled Mode
+===========
+
+The handler table for the polled mode should look like the following.
+
+.. code-block:: c
+
+    const rtems_termios_device_handler my_driver_handler_polled = {
       .first_open = my_driver_first_open,
       .last_close = my_driver_last_close,
@@ -177,20 +167,58 @@
       .write = my_driver_poll_write,
       .set_attributes = my_driver_set_attributes,
-      .stop_remote_tx = NULL,
-      .start_remote_tx = NULL,
+      .ioctl = my_driver_ioctl, /* optional, may be NULL */
       .mode = TERMIOS_POLLED
     }
 
-For an interrupt driven implementation you need the following.  The driver
-functioning is quite different in this mode.  There is no device driver read
-handler to be passed to Termios.  Indeed a ``console_read()`` call returns the
-contents of Termios input buffer.  This buffer is filled in the driver
-interrupt subroutine, see also `Termios and Interrupt Driven IO`_.  The driver
-is responsible for providing a pointer to the``my_driver_interrupt_write()``
-function.
-
-.. code-block:: c
-
-    const rtems_termios_handler my_driver_handler_interrupt = {
+The :c:func:`my_driver_poll_write()` routine is responsible for writing ``n``
+characters from ``buf`` to the serial device specified by ``base``.
+
+.. code-block:: c
+
+    static void my_driver_poll_write(
+      rtems_termios_device_context *base,
+      const char                   *buf,
+      size_t                        n
+    )
+    {
+      my_driver_context *ctx;
+
+      ctx = (my_driver_context *) base;
+
+      for ( i = 0 ; i < n ; ++i ) {
+        my_driver_write_char( ctx, buf[ i ] );
+      }
+    }
+
+The :c:func:`my_driver_poll_read` routine is responsible for reading a single
+character from the serial device specified by ``base``.  If no character is
+available, then the routine should immediately return minus one.
+
+.. code-block:: c
+
+    static int my_driver_poll_read( rtems_termios_device_context *base )
+    {
+      my_driver_context *ctx;
+      size_t             i;
+
+      ctx = (my_driver_context *) base;
+
+      if ( my_driver_can_read_char( ctx ) ) {
+        /* Return the character (must be unsigned) */
+        return my_driver_read_char( ctx );
+      } else {
+        /* Return -1 to indicate that no character is available */
+        return -1;
+      }
+    }
+
+Interrupt Driven Mode
+=====================
+
+The handler table for the interrupt driven mode should look like the following.
+
+.. code-block:: c
+
+    const rtems_termios_device_handler my_driver_handler_interrupt = {
       .first_open = my_driver_first_open,
       .last_close = my_driver_last_close,
@@ -198,113 +226,38 @@
       .write = my_driver_interrupt_write,
       .set_attributes = my_driver_set_attributes,
-      .stopRemoteTx = NULL,
-      .stop_remote_tx = NULL,
-      .start_remote_tx = NULL,
+      .ioctl = my_driver_ioctl, /* optional, may be NULL */
       .mode = TERMIOS_IRQ_DRIVEN
     };
 
-You can also provide hander for remote transmission control.  This is not
-covered in this manual, so they are set to ``NULL`` in the above examples.
-
-The low-level driver should provide a data structure for its device context.
-The initialization routine must provide a context for each installed device via
-``rtems_termios_device_install()``.  For simplicity of the console
-initialization example the device name is also present.  Here is an example
-header file.
-
-.. code-block:: c
-
-    #ifndef MY_DRIVER_H
-    #define MY_DRIVER_H
-
-    #include <rtems/termiostypes.h>
-    #include <some-chip-header.h>
-
-    /* Low-level driver specific data structure */
-    typedef struct {
-      rtems_termios_device_context base;
-      const char *device_name;
-      volatile module_register_block *regs;
-      /* More stuff */
-    } my_driver_context;
-
-    extern const rtems_termios_handler my_driver_handler_polled;
-    extern const rtems_termios_handler my_driver_handler_interrupt;
-
-    #endif /* MY_DRIVER_H */
-
-Termios and Polled IO
----------------------
-
-The following handler are provided by the low-level driver and invoked by
-Termios for simple character IO.
-
-The ``my_driver_poll_write()`` routine is responsible for writing ``n``
-characters from ``buf`` to the serial device specified by ``tty``.
-
-.. code-block:: c
-
-    static void my_driver_poll_write(
-      rtems_termios_device_context *base,
-      const char                   *buf,
-      size_t                        n
-    )
-    {
-      my_driver_context *ctx = (my_driver_context *) base;
-      size_t i;
-      /* Write */
-      for (i = 0; i < n; ++i) {
-        my_driver_write_char(ctx, buf[i]);
-      }
-    }
-
-The ``my_driver_poll_read`` routine is responsible for reading a single
-character from the serial device specified by ``tty``.  If no character is
-available, then the routine should return minus one.
-
-.. code-block:: c
-
-    static int my_driver_poll_read(rtems_termios_device_context *base)
-    {
-      my_driver_context *ctx = (my_driver_context *) base;
-      /* Check if a character is available */
-      if (my_driver_can_read_char(ctx)) {
-        /* Return the character */
-        return my_driver_read_char(ctx);
-      } else {
-        /* Return an error status */
-        return -1;
-      }
-    }
-
-Termios and Interrupt Driven IO
--------------------------------
-
-The UART generally generates interrupts when it is ready to accept or to emit a
-number of characters.  In this mode, the interrupt subroutine is the core of
-the driver.
-
-The ``my_driver_interrupt_handler()`` is responsible for processing
-asynchronous interrupts from the UART.  There may be multiple interrupt
-handlers for a single UART.  Some UARTs can generate a unique interrupt vector
-for each interrupt source such as a character has been received or the
-transmitter is ready for another character.
-
-In the simplest case, the ``my_driver_interrupt_handler()`` will have to check
-the status of the UART and determine what caused the interrupt.  The following
-describes the operation of an ``my_driver_interrupt_handler`` which has to do
-this:
-
-.. code-block:: c
-
-    static void my_driver_interrupt_handler(
-      rtems_vector_number  vector,
-      void                *arg
-    )
-    {
-      rtems_termios_tty *tty = arg;
-      my_driver_context *ctx = rtems_termios_get_device_context(tty);
-      char buf[N];
-      size_t n;
+There is no device driver read handler to be passed to Termios.  Indeed a
+:c:func:`read()` call returns the contents of Termios input buffer.  This
+buffer is filled in the driver interrupt routine.
+
+A serial device generally generates interrupts when it is ready to accept or to
+emit a number of characters.  In this mode, the interrupt routine is the core
+of the driver.
+
+The :c:func:`my_driver_interrupt_handler` is responsible for processing
+asynchronous interrupts from the serial device.  There may be multiple
+interrupt handlers for a single serial device.  Some serial devices can
+generate a unique interrupt vector for each interrupt source such as a
+character has been received or the transmitter is ready for another character.
+
+In the simplest case, the :c:func:`my_driver_interrupt_handler` will have to
+check the status of the serial device and determine what caused the interrupt.
+The following describes the operation of an
+:c:func:`my_driver_interrupt_handler` which has to do this:
+
+.. code-block:: c
+
+    static void my_driver_interrupt_handler( void *arg )
+    {
+      rtems_termios_tty *tty;
+      my_driver_context *ctx;
+      char               buf[N];
+      size_t             n;
+
+      tty = arg;
+      ctx = rtems_termios_get_device_context( tty );
 
       /*
@@ -313,8 +266,8 @@
        * buffer.  It returns the number of read characters.
        */
-      n = my_driver_read_received_chars(ctx, buf, N);
-      if (n > 0) {
+      n = my_driver_read_received_chars( ctx, buf, N );
+      if ( n > 0 ) {
         /* Hand the data over to the Termios infrastructure */
-        rtems_termios_enqueue_raw_characters(tty, buf, n);
+        rtems_termios_enqueue_raw_characters( tty, buf, n );
       }
 
@@ -324,6 +277,6 @@
        * device.
        */
-      n = my_driver_transmitted_chars(ctx);
-      if (n > 0) {
+      n = my_driver_transmitted_chars( ctx );
+      if ( n > 0 ) {
         /*
          * Notify Termios that we have transmitted some characters.  It
@@ -331,10 +284,10 @@
          * are ready for transmission.
          */
-        rtems_termios_dequeue_characters(tty, n);
-      }
-    }
-
-The ``my_driver_interrupt_write()`` function is responsible for telling the
-device that the ``n`` characters at ``buf`` are to be transmitted.  It the
+        rtems_termios_dequeue_characters( tty, n );
+      }
+    }
+
+The :c:func:`my_driver_interrupt_write()` handler is responsible for telling
+the device that the ``n`` characters at ``buf`` are to be transmitted.  It the
 value ``n`` is zero to indicate that no more characters are to send.  The
 driver can disable the transmit interrupts now.  This routine is invoked either
@@ -355,37 +308,194 @@
     )
     {
-      my_driver_context *ctx = (my_driver_context *) base;
-
-      /*
-       * Tell the device to transmit some characters from buf (less than
-       * or equal to n).  When the device is finished it should raise an
-       * interrupt.  The interrupt handler will notify Termios that these
-       * characters have been transmitted and this may trigger this write
-       * function again.  You may have to store the number of outstanding
-       * characters in the device data structure.
-       */
-      /*
-       * Termios will set n to zero to indicate that the transmitter is
-       * now inactive.  The output buffer is empty in this case.  The
-       * driver may disable the transmit interrupts now.
-       */
-    }
-
-Initialization
---------------
-
-The BSP specific driver initialization is called once during the RTEMS
+      my_driver_context *ctx;
+
+      ctx = (my_driver_context *) base;
+
+      if ( n > 0 ) {
+        /*
+         * Tell the device to transmit some characters from buf (less than
+         * or equal to n).  When the device is finished it should raise an
+         * interrupt.  The interrupt handler will notify Termios that these
+         * characters have been transmitted and this may trigger this write
+         * function again.  You may have to store the number of outstanding
+         * characters in the device data structure.
+         */
+      } else {
+        /*
+         * Termios will set n to zero to indicate that the transmitter is
+         * now inactive.  The output buffer is empty in this case.  The
+         * driver may disable the transmit interrupts now.
+         */
+      }
+    }
+
+First Open
+==========
+
+Upon first open of the device, the :c:func:`my_driver_first_open` handler is
+called by Termios.  The device registered as :file:`/dev/console` (or
+``CONSOLE_DEVICE_NAME``) is opened automatically during RTEMS initialization.
+
+.. code-block:: c
+
+    static bool my_driver_first_open(
+      rtems_termios_tty             *tty,
+      rtems_termios_device_context  *base,
+      struct termios                *term,
+      rtems_libio_open_close_args_t *args
+    )
+    {
+      my_driver_context *ctx;
+      rtems_status_code  sc;
+      bool               ok;
+
+      ctx = (my_driver_context *) base;
+
+      /*
+       * You may add some initialization code here.
+       */
+
+      /*
+       * Sets the initial baud rate.  This should be set to the value of
+       * the boot loader.  This function accepts only exact Termios baud
+       * values.
+       */
+      sc = rtems_termios_set_initial_baud( tty, MY_DRIVER_BAUD_RATE );
+      if ( sc != RTEMS_SUCCESSFUL ) {
+        /* Not a valid Termios baud */
+      }
+
+      /*
+       * Alternatively you can set the best baud.
+       */
+      rtems_termios_set_best_baud( term, MY_DRIVER_BAUD_RATE );
+
+      /*
+       * To propagate the initial Termios attributes to the device use
+       * this.
+      */
+      ok = my_driver_set_attributes( base, term );
+      if ( !ok ) {
+        /* This is bad */
+      }
+
+      /*
+       * Return true to indicate a successful set attributes, and false
+       * otherwise.
+       */
+      return true;
+    }
+
+Last Close
+==========
+
+Termios will call the :c:func:`my_driver_last_close` handler if the last close
+happens on the device.
+
+.. code-block:: c
+
+    static void my_driver_last_close(
+      rtems_termios_tty             *tty,
+      rtems_termios_device_context  *base,
+      rtems_libio_open_close_args_t *args
+    )
+    {
+      my_driver_context *ctx;
+
+      ctx = (my_driver_context *) base;
+
+      /*
+       * The driver may do some cleanup here.
+       */
+    }
+
+Set Attributes
+==============
+
+Termios will call the :c:func:`my_driver_set_attributes` handler if a serial
+line configuration parameter changed, e.g. baud, character size, number of stop
+bits, parity, etc.
+
+.. code-block:: c
+
+    static bool my_driver_set_attributes(
+      rtems_termios_device_context *base,
+      const struct termios         *term
+    )
+    {
+      my_driver_context *ctx;
+
+      ctx = (my_driver_context *) base;
+
+      /*
+       * Inspect the termios data structure and configure the device
+       * appropriately.  The driver should only be concerned with the
+       * parts of the structure that specify hardware setting for the
+       * communications channel such as baud, character size, etc.
+       */
+
+      /*
+       * Return true to indicate a successful set attributes, and false
+       * otherwise.
+       */
+      return true;
+    }
+
+IO Control
+==========
+
+Optionally, the :c:func:`my_driver_ioctl()` routine may be provided for
+arbitrary device-specific functions.
+
+.. code-block:: c
+
+    static int my_driver_ioctl(
+      rtems_termios_device_context *base,
+      ioctl_command_t               request,
+      void                         *buffer
+    )
+    {
+      my_driver_context *ctx;
+
+      ctx = (my_driver_context *) base;
+
+      switch ( request ) {
+        case MY_DRIVER_DO_XYZ:
+          my_driver_do_xyz(ctx, buffer);
+          break;
+        default:
+          rtems_set_errno_and_return_minus_one( EINVAL );
+      }
+
+      return 0;
+    }
+
+Flow Control
+============
+
+You can also provide handler for remote transmission control.  This is not
+covered in this manual.
+
+General Initialization
+======================
+
+The BSP-specific driver initialization is called once during the RTEMS
 initialization process.
 
-The ``console_initialize()`` function may look like this:
+The :c:func:`console_initialize()` function may look like this:
 
 .. code-block:: c
 
     #include <my-driver.h>
+
     #include <rtems/console.h>
+
     #include <bsp.h>
     #include <bsp/fatal.h>
 
-    static my_driver_context driver_context_table[M] = { /* Some values */ };
+    static my_driver_context driver_context_table[] = {
+      { /* Some values for device 0 */ },
+      { /* Some values for device 1 */ }
+    };
 
     rtems_device_driver console_initialize(
@@ -395,9 +505,12 @@
     )
     {
-      rtems_status_code sc;
+      const rtems_termios_device_handler *handler;
+      rtems_status_code                   sc;
+      size_t                              i;
+
       #ifdef SOME_BSP_USE_INTERRUPTS
-        const rtems_termios_handler *handler = &my_driver_handler_interrupt;
+        handler = &my_driver_handler_interrupt;
       #else
-        const rtems_termios_handler *handler = &my_driver_handler_polled;
+        handler = &my_driver_handler_polled;
       #endif
 
@@ -410,10 +523,8 @@
 
       /* Initialize each device */
-      for (
-        minor = 0;
-        minor < RTEMS_ARRAY_SIZE(driver_context_table);
-        ++minor
-      ) {
-        my_driver_context *ctx = &driver_context_table[minor];
+      for ( i = 0; i < RTEMS_ARRAY_SIZE( driver_context_table ) ; ++i ) {
+        my_driver_context *ctx;
+
+        ctx = &driver_context_table[ i ];
 
         /*
@@ -423,14 +534,7 @@
          * "/dev/console" (CONSOLE_DEVICE_NAME).
          */
-        sc = rtems_termios_device_install(
-          ctx->device_name,
-          major,
-          minor,
-          handler,
-          NULL,
-          ctx
-        );
-        if (sc != RTEMS_SUCCESSFUL) {
-          bsp_fatal(SOME_BSP_FATAL_CONSOLE_DEVICE_INSTALL);
+        sc = rtems_termios_device_install( ctx->device_name, handler, NULL, ctx );
+        if ( sc != RTEMS_SUCCESSFUL ) {
+          bsp_fatal( SOME_BSP_FATAL_CONSOLE_DEVICE_INSTALL );
         }
       }
@@ -438,142 +542,2 @@
       return RTEMS_SUCCESSFUL;
     }
-
-Opening a serial device
------------------------
-
-The ``console_open()`` function provided by :file:`console-termios.c` is called
-whenever a serial device is opened.  The device registered as
-``"/dev/console"`` (``CONSOLE_DEVICE_NAME``) is opened automatically during
-RTEMS initialization.  For instance, if UART channel 2 is registered as
-``"/dev/tty1"``, the ``console_open()`` entry point will be called as the
-result of an ``fopen("/dev/tty1", mode)`` in the application.
-
-During the first open of the device Termios will call the
-``my_driver_first_open()`` handler.
-
-.. code-block:: c
-
-    static bool my_driver_first_open(
-      rtems_termios_tty             *tty,
-      rtems_termios_device_context  *base,
-      struct termios                *term,
-      rtems_libio_open_close_args_t *args
-    )
-    {
-      my_driver_context *ctx = (my_driver_context *) base;
-      rtems_status_code sc;
-      bool ok;
-
-      /*
-       * You may add some initialization code here.
-       */
-
-      /*
-       * Sets the initial baud rate.  This should be set to the value of
-       * the boot loader.  This function accepts only exact Termios baud
-       * values.
-       */
-      sc = rtems_termios_set_initial_baud(tty, MY_DRIVER_BAUD_RATE);
-      if (sc != RTEMS_SUCCESSFUL) {
-        /* Not a valid Termios baud */
-      }
-
-      /*
-       * Alternatively you can set the best baud.
-       */
-      rtems_termios_set_best_baud(term, MY_DRIVER_BAUD_RATE);
-
-      /*
-       * To propagate the initial Termios attributes to the device use
-       * this.
-      */
-      ok = my_driver_set_attributes(base, term);
-      if (!ok) {
-        /* This is bad */
-      }
-
-      /*
-       * Return true to indicate a successful set attributes, and false
-       * otherwise.
-       */
-      return true;
-    }
-
-Closing a Serial Device
------------------------
-
-The ``console_close()`` provided by :file:`console-termios.c` is invoked when
-the serial device is to be closed.  This entry point corresponds to the device
-driver close entry point.
-
-Termios will call the ``my_driver_last_close()`` handler if the last close
-happens on the device.
-
-.. code-block:: c
-
-    static void my_driver_last_close(
-      rtems_termios_tty             *tty,
-      rtems_termios_device_context  *base,
-      rtems_libio_open_close_args_t *args
-    )
-    {
-      my_driver_context *ctx = (my_driver_context *) base;
-
-      /*
-       * The driver may do some cleanup here.
-      */
-    }
-
-Reading Characters from a Serial Device
----------------------------------------
-
-The ``console_read()`` provided by :file:`console-termios.c` is invoked when
-the serial device is to be read from.  This entry point corresponds to the
-device driver read entry point.
-
-Writing Characters to a Serial Device
--------------------------------------
-
-The ``console_write()`` provided by :file:`console-termios.c` is invoked when
-the serial device is to be written to.  This entry point corresponds to the
-device driver write entry point.
-
-Changing Serial Line Parameters
--------------------------------
-
-The ``console_control()`` provided by :file:`console-termios.c` is invoked when
-the line parameters for a particular serial device are to be changed.  This
-entry point corresponds to the device driver IO control entry point.
-
-The application writer is able to control the serial line configuration with
-Termios calls (such as the ``ioctl()`` command, see the Termios documentation
-for more details).  If the driver is to support dynamic configuration, then it
-must have the ``console_control()`` piece of code.  Basically ``ioctl()``
-commands call ``console_control()`` with the serial line configuration in a
-Termios defined data structure.
-
-The driver is responsible for reinitializing the device with the correct
-settings.  For this purpose Termios calls the ``my_driver_set_attributes()``
-handler.
-
-.. code-block:: c
-
-    static bool my_driver_set_attributes(
-      rtems_termios_device_context *base,
-      const struct termios         *term
-    )
-    {
-      my_driver_context *ctx = (my_driver_context *) base;
-
-      /*
-       * Inspect the termios data structure and configure the device
-       * appropriately.  The driver should only be concerned with the
-       * parts of the structure that specify hardware setting for the
-       * communications channel such as baud, character size, etc.
-       */
-      /*
-       * Return true to indicate a successful set attributes, and false
-       * otherwise.
-       */
-      return true;
-    }
