Changeset 5bb51a4 in rtems-docs


Ignore:
Timestamp:
Dec 23, 2016, 1:38:35 PM (3 years ago)
Author:
Sebastian Huber <sebastian.huber@…>
Branches:
master
Children:
5ef17b7
Parents:
3b42c96
Message:

Update Console Driver chapter

Close #2785.
Close #2838.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • bsp-howto/console.rst

    r3b42c96 r5bb51a4  
    88**************
    99
     10.. warning::
     11    The low-level driver API changed between RTEMS 4.10 and RTEMS 4.11.  The
     12    legacy callback API is still supported, but its use is discouraged.  The
     13    following functions are deprecated:
     14
     15    - :c:func:`rtems_termios_open()`
     16
     17    - :c:func:`rtems_termios_close()`
     18
     19    This manual describes the new API.
     20
    1021Introduction
    1122============
    1223
    1324This chapter describes the operation of a console driver using the RTEMS POSIX
    14 Termios support.  Traditionally RTEMS has referred to all serial device drivers
    15 as console device drivers.  A console driver can be used to do raw data
    16 processing in addition to the "normal" standard input and output device
    17 functions required of a console.
    18 
    19 The serial driver may be called as the consequence of a C Library call such as
    20 ``printf`` or ``scanf`` or directly via the``read`` or ``write`` system calls.
    21 There are two main functioning modes:
    22 
    23 - console: formatted input/output, with special characters (end of line,
    24   tabulations, etc.) recognition and processing,
    25 
    26 - raw: permits raw data processing.
    27 
    28 One may think that two serial drivers are needed to handle these two types of
    29 data, but Termios permits having only one driver.
    30 
    31 Termios
    32 =======
    33 
    34 Termios is a standard for terminal management, included in the POSIX 1003.1b
    35 standard.  As part of the POSIX and Open Group Single UNIX Specification, is
    36 commonly provided on UNIX implementations.  The Open Group has the termios
    37 portion of the POSIX standard online at
    38 http://opengroup.org/onlinepubs/007908775/xbd/termios.html.  The requirements
    39 for the ``<termios.h>`` file are also provided and are at
    40 http://opengroup.org/onlinepubs/007908775/xsh/termios.h.html.
    41 
    42 Having RTEMS support for Termios is beneficial because:
    43 
    44 - from the user's side because it provides standard primitive operations to
    45   access the terminal and change configuration settings.  These operations are
    46   the same under UNIX and RTEMS.
    47 
    48 - from the BSP developer's side because it frees the developer from dealing
    49   with buffer states and mutual exclusions on them.  Early RTEMS console device
    50   drivers also did their own special character processing.
    51 
    52 - it is part of an internationally recognized standard.
    53 
    54 - it makes porting code from other environments easier.
    55 
    56 Termios support includes:
    57 
    58 - raw and console handling,
    59 
    60 - blocking or non-blocking characters receive, with or without Timeout.
    61 
    62 At this time, RTEMS documentation does not include a thorough discussion of the
    63 Termios functionality.  For more information on Termios, type ``man termios``
    64 on a Unix box or point a web browser athttp://www.freebsd.org/cgi/man.cgi.
     25Termios support.  Traditionally, RTEMS has referred to all serial device drivers
     26as console drivers.
     27`Termios <http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap11.html>`_
     28is defined by IEEE Std 1003.1-2008 (POSIX.1-2008).  It supports various modes
     29of operations at application level.  This chapter focuses on the low-level
     30serial device driver.  Additional Termios information can be found in the
     31`Linux TERMIOS(3) <http://man7.org/linux/man-pages/man3/termios.3.html>`_
     32manpage or the
     33`FreeBSD TERMIOS(4) <https://www.freebsd.org/cgi/man.cgi?query=termios&sektion=4>`_
     34manpage.
     35
     36There are the following software layers.
     37
     38+-------------------------+
     39| Application             |
     40+-------------------------+
     41| Termios                 |
     42+-------------------------+
     43| Low-Level Device Driver |
     44+-------------------------+
     45
     46In the default application configuration RTEMS opens during system
     47initialization a :file:`/dev/console` device file to create the file
     48descriptors 0, 1 and 2 used for standard input, output and error, respectively.
     49The corresponding device driver is usually a Termios serial device driver
     50described here.  The standard file descriptors are used by standard C library
     51calls such as :c:func:`printf` or :c:func:`scanf` or directly via the
     52:c:func:`read` or :c:func:`write` system calls.
     53
     54Build System and Files
     55======================
     56
     57A new serial device driver should consist of three parts.
     58
     59- A section in the BSPs Makefile.am:
     60
     61.. code-block:: makefile
     62
     63      [...]
     64      libbsp_a_SOURCES += ../../shared/console-termios.c
     65      libbsp_a_SOURCES += console/console.c
     66      [...]
     67
     68- A general serial device specific low-level driver providing the handler table
     69  and the device context specialization for the Termios
     70  :c:func:`rtems_termios_device_install()` function.  This low-level driver
     71  could be used for more than one BSP.
     72
     73- A BSP-specific initialization routine :c:func:`console_initialize()`, that calls
     74  :c:func:`rtems_termios_device_install()` providing a low-level driver context for
     75  each installed device.  This is usually defined in the file
     76  :file:`console/console.c` relative to the BSP base directory.
     77
     78The low-level driver should provide a specialization of the Termios device
     79context.  The initialization routine must provide a context for each installed
     80device via :c:func:`rtems_termios_device_install()`.  Here is an example header
     81file for a low-level serial device driver.
     82
     83.. code-block:: c
     84
     85    #ifndef MY_DRIVER_H
     86    #define MY_DRIVER_H
     87
     88    #include <some-chip/serial.h>
     89
     90    #include <rtems/termiostypes.h>
     91
     92    /* My low-level driver specialization of Termios device context */
     93    typedef struct {
     94      rtems_termios_device_context base;
     95      const char *device_name;
     96      volatile some_chip_registers *regs;
     97      /* More stuff */
     98    } my_driver_context;
     99
     100    extern const rtems_termios_device_handler my_driver_handler_polled;
     101
     102    extern const rtems_termios_device_handler my_driver_handler_interrupt;
     103
     104    #endif /* MY_DRIVER_H */
    65105
    66106Driver Functioning Modes
    67107========================
    68108
    69 There are generally three main functioning modes for an UART (Universal
    70 Asynchronous Receiver-Transmitter, i.e. the serial chip):
    71 
    72 - polled mode
    73 
    74 - interrupt driven mode
    75 
    76 - task driven mode
    77 
    78 In polled mode, the processor blocks on sending/receiving characters.  This
    79 mode is not the most efficient way to utilize the UART. But polled mode is
    80 usually necessary when one wants to print an error message in the event of a
    81 fatal error such as a fatal error in the BSP.  This is also the simplest mode
    82 to program.  Polled mode is generally preferred if the serial port is to be
    83 used primarily as a debug console.  In a simple polled driver, the software
    84 will continuously check the status of the UART when it is reading or writing to
    85 the UART.  Termios improves on this by delaying the caller for 1 clock tick
    86 between successive checks of the UART on a read operation.
    87 
    88 In interrupt driven mode, the processor does not block on sending/receiving
    89 characters.  Data is buffered between the interrupt service routine and
    90 application code.  Two buffers are used to insulate the application from the
    91 relative slowness of the serial device.  One of the buffers is used for
    92 incoming characters, while the other is used for outgoing characters.
    93 
    94 An interrupt is raised when a character is received by the UART.  The interrupt
    95 subroutine places the incoming character at the end of the input buffer.  When
    96 an application asks for input, the characters at the front of the buffer are
    97 returned.
    98 
    99 When the application prints to the serial device, the outgoing characters are
    100 placed at the end of the output buffer.  The driver will place one or more
    101 characters in the UART (the exact number depends on the UART) An interrupt will
    102 be raised when all the characters have been transmitted.  The interrupt service
    103 routine has to send the characters remaining in the output buffer the same way.
    104 When the transmitting side of the UART is idle, it is typically necessary to
    105 prime the transmitter before the first interrupt will occur.
    106 
    107 The task driven mode is similar to interrupt driven mode, but the actual data
    108 processing is done in dedicated tasks instead of interrupt routines.
    109 
    110 Serial Driver Functioning Overview
    111 ==================================
    112 
    113 The following Figure shows how a Termios driven serial driver works: Figure not
    114 included in ASCII version
    115 
    116 The following list describes the basic flow.
    117 
    118 - the application programmer uses standard C library call (printf, scanf, read,
    119   write, etc.),
    120 
    121 - C library (ctx.g. RedHat (formerly Cygnus) Newlib) calls the RTEMS system
    122   call interface.  This code can be found in the:file:`cpukit/libcsupport/src`
    123   directory.
    124 
    125 - Glue code calls the serial driver entry routines.
    126 
    127 Basics
    128 ------
    129 
    130 The low-level driver API changed between RTEMS 4.10 and RTEMS 4.11.  The legacy
    131 callback API is still supported, but its use is discouraged.  The following
    132 functions are deprecated:
    133 
    134 - ``rtems_termios_open()`` - use ``rtems_termios_device_open()`` in combination
    135   with ``rtems_termios_device_install()`` instead.
    136 
    137 - ``rtems_termios_close()`` - use ``rtems_termios_device_close()`` instead.
    138 
    139 This manual describes the new API.  A new console driver should consist of
    140 three parts.
    141 
    142 - The basic console driver functions using the Termios support.  Add this the
    143   BSPs Makefile.am:
    144 
    145 .. code-block:: makefile
    146 
    147       [...]
    148       libbsp_a_SOURCES += ../../shared/console-termios.c
    149       [...]
    150 
    151 - A general serial module specific low-level driver providing the handler table
    152   for the Termios ``rtems_termios_device_install()`` function.  This low-level
    153   driver could be used for more than one BSP.
    154 
    155 - A BSP specific initialization routine ``console_initialize()``, that calls
    156   ``rtems_termios_device_install()`` providing a low-level driver context for
    157   each installed device.
    158 
    159 You need to provide a device handler structure for the Termios device
    160 interface.  The functions are described later in this chapter.  The first open
    161 and set attributes handler return a boolean status to indicate success (true)
    162 or failure (false).  The polled read function returns an unsigned character in
    163 case one is available or minus one otherwise.
    164 
    165 If you want to use polled IO it should look like the following.  Termios must
    166 be told the addresses of the handler that are to be used for simple character
    167 IO, i.e. pointers to the ``my_driver_poll_read()`` and
    168 ``my_driver_poll_write()`` functions described later in `Termios and Polled
    169 IO`_.
    170 
    171 .. code-block:: c
    172 
    173     const rtems_termios_handler my_driver_handler_polled = {
     109There are four main functioning modes for a Termios serial device driver.  The
     110mode must be set during device creation and cannot be changed afterwards.
     111
     112Polled Mode (`TERMIOS_POLLED`)
     113    In polled mode, the processor blocks on sending/receiving characters.  This
     114    mode is not the most efficient way to utilize the serial device. But polled
     115    mode is usually necessary when one wants to print an error message in the
     116    event of a fatal error such as a fatal error in the BSP.  This is also the
     117    simplest mode to program.  Polled mode is generally preferred if the serial
     118    device is to be used primarily as a debug console.  In a simple polled
     119    driver, the software will continuously check the status of the serial
     120    device when it is reading or writing to the serial device.  Termios
     121    improves on this by delaying the caller for one clock tick between
     122    successive checks of the serial device on a read operation.
     123
     124Interrupt Driven Mode (`TERMIOS_IRQ_DRIVEN`)
     125    In interrupt driven mode, the processor does not block on sending/receiving
     126    characters.  Data is buffered between the interrupt service routine and
     127    application code.  Two buffers are used to insulate the application from
     128    the relative slowness of the serial device.  One of the buffers is used for
     129    incoming characters, while the other is used for outgoing characters.
     130
     131    An interrupt is raised when a character is received by the serial device.
     132    The interrupt routine places the incoming character at the end of the input
     133    buffer.  When an application asks for input, the characters at the front of
     134    the buffer are returned.
     135
     136    When the application prints to the serial device, the outgoing characters
     137    are placed at the end of the output buffer.  The driver will place one or
     138    more characters in the serial device (the exact number depends on the
     139    serial device) An interrupt will be raised when all the characters have
     140    been transmitted.  The interrupt service routine has to send the characters
     141    remaining in the output buffer the same way.  When the transmitting side of
     142    the serial device is idle, it is typically necessary to prime the
     143    transmitter before the first interrupt will occur.
     144
     145Interrupt Server Driven Mode (`TERMIOS_IRQ_SERVER_DRIVEN`)
     146    The interrupt server driven mode is identical to the interrupt driven mode,
     147    except that a mutex is used to protect the low-level device state instead
     148    of an interrupt lock (disabled interrupts).  Use this mode in case the
     149    serial device is connected via I2C or SPI and the I2C or SPI framework is
     150    used.
     151
     152Task Driven Mode (`TERMIOS_TASK_DRIVEN`)
     153    The task driven mode is similar to interrupt driven mode, but the actual
     154    data processing is done in dedicated tasks instead of interrupt routines.
     155
     156Polled Mode
     157===========
     158
     159The handler table for the polled mode should look like the following.
     160
     161.. code-block:: c
     162
     163    const rtems_termios_device_handler my_driver_handler_polled = {
    174164      .first_open = my_driver_first_open,
    175165      .last_close = my_driver_last_close,
     
    177167      .write = my_driver_poll_write,
    178168      .set_attributes = my_driver_set_attributes,
    179       .stop_remote_tx = NULL,
    180       .start_remote_tx = NULL,
     169      .ioctl = my_driver_ioctl, /* optional, may be NULL */
    181170      .mode = TERMIOS_POLLED
    182171    }
    183172
    184 For an interrupt driven implementation you need the following.  The driver
    185 functioning is quite different in this mode.  There is no device driver read
    186 handler to be passed to Termios.  Indeed a ``console_read()`` call returns the
    187 contents of Termios input buffer.  This buffer is filled in the driver
    188 interrupt subroutine, see also `Termios and Interrupt Driven IO`_.  The driver
    189 is responsible for providing a pointer to the``my_driver_interrupt_write()``
    190 function.
    191 
    192 .. code-block:: c
    193 
    194     const rtems_termios_handler my_driver_handler_interrupt = {
     173The :c:func:`my_driver_poll_write()` routine is responsible for writing ``n``
     174characters from ``buf`` to the serial device specified by ``base``.
     175
     176.. code-block:: c
     177
     178    static void my_driver_poll_write(
     179      rtems_termios_device_context *base,
     180      const char                   *buf,
     181      size_t                        n
     182    )
     183    {
     184      my_driver_context *ctx;
     185
     186      ctx = (my_driver_context *) base;
     187
     188      for ( i = 0 ; i < n ; ++i ) {
     189        my_driver_write_char( ctx, buf[ i ] );
     190      }
     191    }
     192
     193The :c:func:`my_driver_poll_read` routine is responsible for reading a single
     194character from the serial device specified by ``base``.  If no character is
     195available, then the routine should immediately return minus one.
     196
     197.. code-block:: c
     198
     199    static int my_driver_poll_read( rtems_termios_device_context *base )
     200    {
     201      my_driver_context *ctx;
     202      size_t             i;
     203
     204      ctx = (my_driver_context *) base;
     205
     206      if ( my_driver_can_read_char( ctx ) ) {
     207        /* Return the character (must be unsigned) */
     208        return my_driver_read_char( ctx );
     209      } else {
     210        /* Return -1 to indicate that no character is available */
     211        return -1;
     212      }
     213    }
     214
     215Interrupt Driven Mode
     216=====================
     217
     218The handler table for the interrupt driven mode should look like the following.
     219
     220.. code-block:: c
     221
     222    const rtems_termios_device_handler my_driver_handler_interrupt = {
    195223      .first_open = my_driver_first_open,
    196224      .last_close = my_driver_last_close,
     
    198226      .write = my_driver_interrupt_write,
    199227      .set_attributes = my_driver_set_attributes,
    200       .stopRemoteTx = NULL,
    201       .stop_remote_tx = NULL,
    202       .start_remote_tx = NULL,
     228      .ioctl = my_driver_ioctl, /* optional, may be NULL */
    203229      .mode = TERMIOS_IRQ_DRIVEN
    204230    };
    205231
    206 You can also provide hander for remote transmission control.  This is not
    207 covered in this manual, so they are set to ``NULL`` in the above examples.
    208 
    209 The low-level driver should provide a data structure for its device context.
    210 The initialization routine must provide a context for each installed device via
    211 ``rtems_termios_device_install()``.  For simplicity of the console
    212 initialization example the device name is also present.  Here is an example
    213 header file.
    214 
    215 .. code-block:: c
    216 
    217     #ifndef MY_DRIVER_H
    218     #define MY_DRIVER_H
    219 
    220     #include <rtems/termiostypes.h>
    221     #include <some-chip-header.h>
    222 
    223     /* Low-level driver specific data structure */
    224     typedef struct {
    225       rtems_termios_device_context base;
    226       const char *device_name;
    227       volatile module_register_block *regs;
    228       /* More stuff */
    229     } my_driver_context;
    230 
    231     extern const rtems_termios_handler my_driver_handler_polled;
    232     extern const rtems_termios_handler my_driver_handler_interrupt;
    233 
    234     #endif /* MY_DRIVER_H */
    235 
    236 Termios and Polled IO
    237 ---------------------
    238 
    239 The following handler are provided by the low-level driver and invoked by
    240 Termios for simple character IO.
    241 
    242 The ``my_driver_poll_write()`` routine is responsible for writing ``n``
    243 characters from ``buf`` to the serial device specified by ``tty``.
    244 
    245 .. code-block:: c
    246 
    247     static void my_driver_poll_write(
    248       rtems_termios_device_context *base,
    249       const char                   *buf,
    250       size_t                        n
    251     )
    252     {
    253       my_driver_context *ctx = (my_driver_context *) base;
    254       size_t i;
    255       /* Write */
    256       for (i = 0; i < n; ++i) {
    257         my_driver_write_char(ctx, buf[i]);
    258       }
    259     }
    260 
    261 The ``my_driver_poll_read`` routine is responsible for reading a single
    262 character from the serial device specified by ``tty``.  If no character is
    263 available, then the routine should return minus one.
    264 
    265 .. code-block:: c
    266 
    267     static int my_driver_poll_read(rtems_termios_device_context *base)
    268     {
    269       my_driver_context *ctx = (my_driver_context *) base;
    270       /* Check if a character is available */
    271       if (my_driver_can_read_char(ctx)) {
    272         /* Return the character */
    273         return my_driver_read_char(ctx);
    274       } else {
    275         /* Return an error status */
    276         return -1;
    277       }
    278     }
    279 
    280 Termios and Interrupt Driven IO
    281 -------------------------------
    282 
    283 The UART generally generates interrupts when it is ready to accept or to emit a
    284 number of characters.  In this mode, the interrupt subroutine is the core of
    285 the driver.
    286 
    287 The ``my_driver_interrupt_handler()`` is responsible for processing
    288 asynchronous interrupts from the UART.  There may be multiple interrupt
    289 handlers for a single UART.  Some UARTs can generate a unique interrupt vector
    290 for each interrupt source such as a character has been received or the
    291 transmitter is ready for another character.
    292 
    293 In the simplest case, the ``my_driver_interrupt_handler()`` will have to check
    294 the status of the UART and determine what caused the interrupt.  The following
    295 describes the operation of an ``my_driver_interrupt_handler`` which has to do
    296 this:
    297 
    298 .. code-block:: c
    299 
    300     static void my_driver_interrupt_handler(
    301       rtems_vector_number  vector,
    302       void                *arg
    303     )
    304     {
    305       rtems_termios_tty *tty = arg;
    306       my_driver_context *ctx = rtems_termios_get_device_context(tty);
    307       char buf[N];
    308       size_t n;
     232There is no device driver read handler to be passed to Termios.  Indeed a
     233:c:func:`read()` call returns the contents of Termios input buffer.  This
     234buffer is filled in the driver interrupt routine.
     235
     236A serial device generally generates interrupts when it is ready to accept or to
     237emit a number of characters.  In this mode, the interrupt routine is the core
     238of the driver.
     239
     240The :c:func:`my_driver_interrupt_handler` is responsible for processing
     241asynchronous interrupts from the serial device.  There may be multiple
     242interrupt handlers for a single serial device.  Some serial devices can
     243generate a unique interrupt vector for each interrupt source such as a
     244character has been received or the transmitter is ready for another character.
     245
     246In the simplest case, the :c:func:`my_driver_interrupt_handler` will have to
     247check the status of the serial device and determine what caused the interrupt.
     248The following describes the operation of an
     249:c:func:`my_driver_interrupt_handler` which has to do this:
     250
     251.. code-block:: c
     252
     253    static void my_driver_interrupt_handler( void *arg )
     254    {
     255      rtems_termios_tty *tty;
     256      my_driver_context *ctx;
     257      char               buf[N];
     258      size_t             n;
     259
     260      tty = arg;
     261      ctx = rtems_termios_get_device_context( tty );
    309262
    310263      /*
     
    313266       * buffer.  It returns the number of read characters.
    314267       */
    315       n = my_driver_read_received_chars(ctx, buf, N);
    316       if (n > 0) {
     268      n = my_driver_read_received_chars( ctx, buf, N );
     269      if ( n > 0 ) {
    317270        /* Hand the data over to the Termios infrastructure */
    318         rtems_termios_enqueue_raw_characters(tty, buf, n);
     271        rtems_termios_enqueue_raw_characters( tty, buf, n );
    319272      }
    320273
     
    324277       * device.
    325278       */
    326       n = my_driver_transmitted_chars(ctx);
    327       if (n > 0) {
     279      n = my_driver_transmitted_chars( ctx );
     280      if ( n > 0 ) {
    328281        /*
    329282         * Notify Termios that we have transmitted some characters.  It
     
    331284         * are ready for transmission.
    332285         */
    333         rtems_termios_dequeue_characters(tty, n);
    334       }
    335     }
    336 
    337 The ``my_driver_interrupt_write()`` function is responsible for telling the
    338 device that the ``n`` characters at ``buf`` are to be transmitted.  It the
     286        rtems_termios_dequeue_characters( tty, n );
     287      }
     288    }
     289
     290The :c:func:`my_driver_interrupt_write()` handler is responsible for telling
     291the device that the ``n`` characters at ``buf`` are to be transmitted.  It the
    339292value ``n`` is zero to indicate that no more characters are to send.  The
    340293driver can disable the transmit interrupts now.  This routine is invoked either
     
    355308    )
    356309    {
    357       my_driver_context *ctx = (my_driver_context *) base;
    358 
    359       /*
    360        * Tell the device to transmit some characters from buf (less than
    361        * or equal to n).  When the device is finished it should raise an
    362        * interrupt.  The interrupt handler will notify Termios that these
    363        * characters have been transmitted and this may trigger this write
    364        * function again.  You may have to store the number of outstanding
    365        * characters in the device data structure.
    366        */
    367       /*
    368        * Termios will set n to zero to indicate that the transmitter is
    369        * now inactive.  The output buffer is empty in this case.  The
    370        * driver may disable the transmit interrupts now.
    371        */
    372     }
    373 
    374 Initialization
    375 --------------
    376 
    377 The BSP specific driver initialization is called once during the RTEMS
     310      my_driver_context *ctx;
     311
     312      ctx = (my_driver_context *) base;
     313
     314      if ( n > 0 ) {
     315        /*
     316         * Tell the device to transmit some characters from buf (less than
     317         * or equal to n).  When the device is finished it should raise an
     318         * interrupt.  The interrupt handler will notify Termios that these
     319         * characters have been transmitted and this may trigger this write
     320         * function again.  You may have to store the number of outstanding
     321         * characters in the device data structure.
     322         */
     323      } else {
     324        /*
     325         * Termios will set n to zero to indicate that the transmitter is
     326         * now inactive.  The output buffer is empty in this case.  The
     327         * driver may disable the transmit interrupts now.
     328         */
     329      }
     330    }
     331
     332First Open
     333==========
     334
     335Upon first open of the device, the :c:func:`my_driver_first_open` handler is
     336called by Termios.  The device registered as :file:`/dev/console` (or
     337``CONSOLE_DEVICE_NAME``) is opened automatically during RTEMS initialization.
     338
     339.. code-block:: c
     340
     341    static bool my_driver_first_open(
     342      rtems_termios_tty             *tty,
     343      rtems_termios_device_context  *base,
     344      struct termios                *term,
     345      rtems_libio_open_close_args_t *args
     346    )
     347    {
     348      my_driver_context *ctx;
     349      rtems_status_code  sc;
     350      bool               ok;
     351
     352      ctx = (my_driver_context *) base;
     353
     354      /*
     355       * You may add some initialization code here.
     356       */
     357
     358      /*
     359       * Sets the initial baud rate.  This should be set to the value of
     360       * the boot loader.  This function accepts only exact Termios baud
     361       * values.
     362       */
     363      sc = rtems_termios_set_initial_baud( tty, MY_DRIVER_BAUD_RATE );
     364      if ( sc != RTEMS_SUCCESSFUL ) {
     365        /* Not a valid Termios baud */
     366      }
     367
     368      /*
     369       * Alternatively you can set the best baud.
     370       */
     371      rtems_termios_set_best_baud( term, MY_DRIVER_BAUD_RATE );
     372
     373      /*
     374       * To propagate the initial Termios attributes to the device use
     375       * this.
     376      */
     377      ok = my_driver_set_attributes( base, term );
     378      if ( !ok ) {
     379        /* This is bad */
     380      }
     381
     382      /*
     383       * Return true to indicate a successful set attributes, and false
     384       * otherwise.
     385       */
     386      return true;
     387    }
     388
     389Last Close
     390==========
     391
     392Termios will call the :c:func:`my_driver_last_close` handler if the last close
     393happens on the device.
     394
     395.. code-block:: c
     396
     397    static void my_driver_last_close(
     398      rtems_termios_tty             *tty,
     399      rtems_termios_device_context  *base,
     400      rtems_libio_open_close_args_t *args
     401    )
     402    {
     403      my_driver_context *ctx;
     404
     405      ctx = (my_driver_context *) base;
     406
     407      /*
     408       * The driver may do some cleanup here.
     409       */
     410    }
     411
     412Set Attributes
     413==============
     414
     415Termios will call the :c:func:`my_driver_set_attributes` handler if a serial
     416line configuration parameter changed, e.g. baud, character size, number of stop
     417bits, parity, etc.
     418
     419.. code-block:: c
     420
     421    static bool my_driver_set_attributes(
     422      rtems_termios_device_context *base,
     423      const struct termios         *term
     424    )
     425    {
     426      my_driver_context *ctx;
     427
     428      ctx = (my_driver_context *) base;
     429
     430      /*
     431       * Inspect the termios data structure and configure the device
     432       * appropriately.  The driver should only be concerned with the
     433       * parts of the structure that specify hardware setting for the
     434       * communications channel such as baud, character size, etc.
     435       */
     436
     437      /*
     438       * Return true to indicate a successful set attributes, and false
     439       * otherwise.
     440       */
     441      return true;
     442    }
     443
     444IO Control
     445==========
     446
     447Optionally, the :c:func:`my_driver_ioctl()` routine may be provided for
     448arbitrary device-specific functions.
     449
     450.. code-block:: c
     451
     452    static int my_driver_ioctl(
     453      rtems_termios_device_context *base,
     454      ioctl_command_t               request,
     455      void                         *buffer
     456    )
     457    {
     458      my_driver_context *ctx;
     459
     460      ctx = (my_driver_context *) base;
     461
     462      switch ( request ) {
     463        case MY_DRIVER_DO_XYZ:
     464          my_driver_do_xyz(ctx, buffer);
     465          break;
     466        default:
     467          rtems_set_errno_and_return_minus_one( EINVAL );
     468      }
     469
     470      return 0;
     471    }
     472
     473Flow Control
     474============
     475
     476You can also provide handler for remote transmission control.  This is not
     477covered in this manual.
     478
     479General Initialization
     480======================
     481
     482The BSP-specific driver initialization is called once during the RTEMS
    378483initialization process.
    379484
    380 The ``console_initialize()`` function may look like this:
     485The :c:func:`console_initialize()` function may look like this:
    381486
    382487.. code-block:: c
    383488
    384489    #include <my-driver.h>
     490
    385491    #include <rtems/console.h>
     492
    386493    #include <bsp.h>
    387494    #include <bsp/fatal.h>
    388495
    389     static my_driver_context driver_context_table[M] = { /* Some values */ };
     496    static my_driver_context driver_context_table[] = {
     497      { /* Some values for device 0 */ },
     498      { /* Some values for device 1 */ }
     499    };
    390500
    391501    rtems_device_driver console_initialize(
     
    395505    )
    396506    {
    397       rtems_status_code sc;
     507      const rtems_termios_device_handler *handler;
     508      rtems_status_code                   sc;
     509      size_t                              i;
     510
    398511      #ifdef SOME_BSP_USE_INTERRUPTS
    399         const rtems_termios_handler *handler = &my_driver_handler_interrupt;
     512        handler = &my_driver_handler_interrupt;
    400513      #else
    401         const rtems_termios_handler *handler = &my_driver_handler_polled;
     514        handler = &my_driver_handler_polled;
    402515      #endif
    403516
     
    410523
    411524      /* Initialize each device */
    412       for (
    413         minor = 0;
    414         minor < RTEMS_ARRAY_SIZE(driver_context_table);
    415         ++minor
    416       ) {
    417         my_driver_context *ctx = &driver_context_table[minor];
     525      for ( i = 0; i < RTEMS_ARRAY_SIZE( driver_context_table ) ; ++i ) {
     526        my_driver_context *ctx;
     527
     528        ctx = &driver_context_table[ i ];
    418529
    419530        /*
     
    423534         * "/dev/console" (CONSOLE_DEVICE_NAME).
    424535         */
    425         sc = rtems_termios_device_install(
    426           ctx->device_name,
    427           major,
    428           minor,
    429           handler,
    430           NULL,
    431           ctx
    432         );
    433         if (sc != RTEMS_SUCCESSFUL) {
    434           bsp_fatal(SOME_BSP_FATAL_CONSOLE_DEVICE_INSTALL);
     536        sc = rtems_termios_device_install( ctx->device_name, handler, NULL, ctx );
     537        if ( sc != RTEMS_SUCCESSFUL ) {
     538          bsp_fatal( SOME_BSP_FATAL_CONSOLE_DEVICE_INSTALL );
    435539        }
    436540      }
     
    438542      return RTEMS_SUCCESSFUL;
    439543    }
    440 
    441 Opening a serial device
    442 -----------------------
    443 
    444 The ``console_open()`` function provided by :file:`console-termios.c` is called
    445 whenever a serial device is opened.  The device registered as
    446 ``"/dev/console"`` (``CONSOLE_DEVICE_NAME``) is opened automatically during
    447 RTEMS initialization.  For instance, if UART channel 2 is registered as
    448 ``"/dev/tty1"``, the ``console_open()`` entry point will be called as the
    449 result of an ``fopen("/dev/tty1", mode)`` in the application.
    450 
    451 During the first open of the device Termios will call the
    452 ``my_driver_first_open()`` handler.
    453 
    454 .. code-block:: c
    455 
    456     static bool my_driver_first_open(
    457       rtems_termios_tty             *tty,
    458       rtems_termios_device_context  *base,
    459       struct termios                *term,
    460       rtems_libio_open_close_args_t *args
    461     )
    462     {
    463       my_driver_context *ctx = (my_driver_context *) base;
    464       rtems_status_code sc;
    465       bool ok;
    466 
    467       /*
    468        * You may add some initialization code here.
    469        */
    470 
    471       /*
    472        * Sets the initial baud rate.  This should be set to the value of
    473        * the boot loader.  This function accepts only exact Termios baud
    474        * values.
    475        */
    476       sc = rtems_termios_set_initial_baud(tty, MY_DRIVER_BAUD_RATE);
    477       if (sc != RTEMS_SUCCESSFUL) {
    478         /* Not a valid Termios baud */
    479       }
    480 
    481       /*
    482        * Alternatively you can set the best baud.
    483        */
    484       rtems_termios_set_best_baud(term, MY_DRIVER_BAUD_RATE);
    485 
    486       /*
    487        * To propagate the initial Termios attributes to the device use
    488        * this.
    489       */
    490       ok = my_driver_set_attributes(base, term);
    491       if (!ok) {
    492         /* This is bad */
    493       }
    494 
    495       /*
    496        * Return true to indicate a successful set attributes, and false
    497        * otherwise.
    498        */
    499       return true;
    500     }
    501 
    502 Closing a Serial Device
    503 -----------------------
    504 
    505 The ``console_close()`` provided by :file:`console-termios.c` is invoked when
    506 the serial device is to be closed.  This entry point corresponds to the device
    507 driver close entry point.
    508 
    509 Termios will call the ``my_driver_last_close()`` handler if the last close
    510 happens on the device.
    511 
    512 .. code-block:: c
    513 
    514     static void my_driver_last_close(
    515       rtems_termios_tty             *tty,
    516       rtems_termios_device_context  *base,
    517       rtems_libio_open_close_args_t *args
    518     )
    519     {
    520       my_driver_context *ctx = (my_driver_context *) base;
    521 
    522       /*
    523        * The driver may do some cleanup here.
    524       */
    525     }
    526 
    527 Reading Characters from a Serial Device
    528 ---------------------------------------
    529 
    530 The ``console_read()`` provided by :file:`console-termios.c` is invoked when
    531 the serial device is to be read from.  This entry point corresponds to the
    532 device driver read entry point.
    533 
    534 Writing Characters to a Serial Device
    535 -------------------------------------
    536 
    537 The ``console_write()`` provided by :file:`console-termios.c` is invoked when
    538 the serial device is to be written to.  This entry point corresponds to the
    539 device driver write entry point.
    540 
    541 Changing Serial Line Parameters
    542 -------------------------------
    543 
    544 The ``console_control()`` provided by :file:`console-termios.c` is invoked when
    545 the line parameters for a particular serial device are to be changed.  This
    546 entry point corresponds to the device driver IO control entry point.
    547 
    548 The application writer is able to control the serial line configuration with
    549 Termios calls (such as the ``ioctl()`` command, see the Termios documentation
    550 for more details).  If the driver is to support dynamic configuration, then it
    551 must have the ``console_control()`` piece of code.  Basically ``ioctl()``
    552 commands call ``console_control()`` with the serial line configuration in a
    553 Termios defined data structure.
    554 
    555 The driver is responsible for reinitializing the device with the correct
    556 settings.  For this purpose Termios calls the ``my_driver_set_attributes()``
    557 handler.
    558 
    559 .. code-block:: c
    560 
    561     static bool my_driver_set_attributes(
    562       rtems_termios_device_context *base,
    563       const struct termios         *term
    564     )
    565     {
    566       my_driver_context *ctx = (my_driver_context *) base;
    567 
    568       /*
    569        * Inspect the termios data structure and configure the device
    570        * appropriately.  The driver should only be concerned with the
    571        * parts of the structure that specify hardware setting for the
    572        * communications channel such as baud, character size, etc.
    573        */
    574       /*
    575        * Return true to indicate a successful set attributes, and false
    576        * otherwise.
    577        */
    578       return true;
    579     }
Note: See TracChangeset for help on using the changeset viewer.