summaryrefslogtreecommitdiffstats
path: root/bsp_howto/console.rst
diff options
context:
space:
mode:
Diffstat (limited to 'bsp_howto/console.rst')
-rw-r--r--bsp_howto/console.rst579
1 files changed, 0 insertions, 579 deletions
diff --git a/bsp_howto/console.rst b/bsp_howto/console.rst
deleted file mode 100644
index bcca519..0000000
--- a/bsp_howto/console.rst
+++ /dev/null
@@ -1,579 +0,0 @@
-.. comment SPDX-License-Identifier: CC-BY-SA-4.0
-
-.. COMMENT: COPYRIGHT (c) 1988-2002.
-.. COMMENT: On-Line Applications Research Corporation (OAR).
-.. COMMENT: All rights reserved.
-
-Console Driver
-##############
-
-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.
-
-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 = {
- .first_open = my_driver_first_open,
- .last_close = my_driver_last_close,
- .poll_read = my_driver_poll_read,
- .write = my_driver_poll_write,
- .set_attributes = my_driver_set_attributes,
- .stop_remote_tx = NULL,
- .start_remote_tx = 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 = {
- .first_open = my_driver_first_open,
- .last_close = my_driver_last_close,
- .poll_read = NULL,
- .write = my_driver_interrupt_write,
- .set_attributes = my_driver_set_attributes,
- .stopRemoteTx = NULL,
- .stop_remote_tx = NULL,
- .start_remote_tx = 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;
-
- /*
- * Check if we have received something. The function reads the
- * received characters from the device and stores them in the
- * buffer. It returns the number of read characters.
- */
- 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);
- }
-
- /*
- * Check if we have something transmitted. The functions returns
- * the number of transmitted characters since the last write to the
- * device.
- */
- n = my_driver_transmitted_chars(ctx);
- if (n > 0) {
- /*
- * Notify Termios that we have transmitted some characters. It
- * will call now the interrupt write function if more characters
- * 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
-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
-from task context with disabled interrupts to start a new transmission process
-with exactly one character in case of an idle output state or from the
-interrupt handler to refill the transmitter. If the routine is invoked to
-start the transmit process the output state will become busy and Termios starts
-to fill the output buffer. If the transmit interrupt arises before Termios was
-able to fill the transmit buffer you will end up with one interrupt per
-character.
-
-.. code-block:: c
-
- static void my_driver_interrupt_write(
- rtems_termios_device_context *base,
- const char *buf,
- size_t n
- )
- {
- 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
-initialization process.
-
-The ``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 */ };
-
- rtems_device_driver console_initialize(
- rtems_device_major_number major,
- rtems_device_minor_number minor,
- void *arg
- )
- {
- rtems_status_code sc;
- #ifdef SOME_BSP_USE_INTERRUPTS
- const rtems_termios_handler *handler = &my_driver_handler_interrupt;
- #else
- const rtems_termios_handler *handler = &my_driver_handler_polled;
- #endif
-
- /*
- * Initialize the Termios infrastructure. If Termios has already
- * been initialized by another device driver, then this call will
- * have no effect.
- */
- rtems_termios_initialize();
-
- /* Initialize each device */
- for (
- minor = 0;
- minor < RTEMS_ARRAY_SIZE(driver_context_table);
- ++minor
- ) {
- my_driver_context *ctx = &driver_context_table[minor];
-
- /*
- * Install this device in the file system and Termios. In order
- * to use the console (i.e. being able to do printf, scanf etc.
- * on stdin, stdout and stderr), one device must be registered as
- * "/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);
- }
- }
-
- 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;
- }