forked from Imagelibrary/rtems
2008-12-11 Sebastian Huber <sebastian.huber@embedded-brains.de>
Joel Sherrrill <joel.sherrill@oarcorp.com> * bsp_howto/Makefile.am, bsp_howto/console.t: Sebastian improved documentation for termios device drivers. * bsp_howto/TERMIOSFlow.eps, bsp_howto/TERMIOSFlow.png: New files. Joel added Termios Flow figure from RTEMS Open Class material.
This commit is contained in:
@@ -19,7 +19,8 @@ GENERATED_FILES = intro.texi target.texi makefiles.texi linkcmds.texi \
|
||||
|
||||
COMMON_FILES += $(top_srcdir)/common/cpright.texi
|
||||
|
||||
PNG_FILES = Developer-User-Timeline.png BSPInitFlowchart-49.png
|
||||
PNG_FILES = Developer-User-Timeline.png BSPInitFlowchart-49.png \
|
||||
TERMIOSFlow.png
|
||||
|
||||
if USE_HTML
|
||||
html_project_DATA += $(PNG_FILES)
|
||||
|
||||
25574
doc/bsp_howto/TERMIOSFlow.eps
Normal file
25574
doc/bsp_howto/TERMIOSFlow.eps
Normal file
File diff suppressed because it is too large
Load Diff
BIN
doc/bsp_howto/TERMIOSFlow.png
Normal file
BIN
doc/bsp_howto/TERMIOSFlow.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
@@ -1,5 +1,5 @@
|
||||
@c
|
||||
@c COPYRIGHT (c) 1988-2002.
|
||||
@c COPYRIGHT (c) 1988-2008.
|
||||
@c On-Line Applications Research Corporation (OAR).
|
||||
@c All rights reserved.
|
||||
@c
|
||||
@@ -36,9 +36,17 @@ of data, but Termios permits having only one driver.
|
||||
|
||||
@section Termios
|
||||
|
||||
Termios is a standard for terminal management, included in the POSIX 1003.1b
|
||||
standard. It is commonly provided on UNIX implementations.
|
||||
Having RTEMS support for Termios is beneficial:
|
||||
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 @uref{http://opengroup.org/onlinepubs/007908775/xbd/termios.html
|
||||
,http://opengroup.org/onlinepubs/007908775/xbd/termios.html}.
|
||||
The requirements for the @code{<termios.h>} file are also provided
|
||||
and are at @uref{http://opengroup.org/onlinepubs/007908775/xsh/termios.h.html,
|
||||
http://opengroup.org/onlinepubs/007908775/xsh/termios.h.html}.
|
||||
|
||||
Having RTEMS support for Termios is beneficial because:
|
||||
|
||||
@itemize @bullet
|
||||
|
||||
@@ -51,6 +59,10 @@ developer from dealing with buffer states and mutual exclusions on them.
|
||||
Early RTEMS console device drivers also did their own special
|
||||
character processing.
|
||||
|
||||
@item it is part of an internationally recognized standard.
|
||||
|
||||
@item it makes porting code from other environments easier.
|
||||
|
||||
@end itemize
|
||||
|
||||
Termios support includes:
|
||||
@@ -118,9 +130,24 @@ before the first interrupt will occur.
|
||||
|
||||
The following Figure shows how a Termios driven serial driver works:
|
||||
|
||||
@example
|
||||
Figure not included in this draft
|
||||
@end example
|
||||
@ifset use-ascii
|
||||
@center Figure not included in ASCII version
|
||||
@end ifset
|
||||
|
||||
@ifset use-tex
|
||||
@sp1
|
||||
@center{@image{TERMIOSFlow,,6in}}
|
||||
@end ifset
|
||||
|
||||
@ifset use-html
|
||||
@html
|
||||
<P ALIGN="center"><IMG SRC="TERMIOSFlow.png"
|
||||
WIDTH=800 HEIGHT=610 ALT="Termios Flow"></P>
|
||||
@end html
|
||||
@end ifset
|
||||
|
||||
The most significant five bits are the object class. The next
|
||||
three bits indicate the API to which the object class belongs.
|
||||
|
||||
The following list describes the basic flow.
|
||||
|
||||
@@ -129,249 +156,522 @@ The following list describes the basic flow.
|
||||
@item the application programmer uses standard C library call (printf,
|
||||
scanf, read, write, etc.),
|
||||
|
||||
@item C library (in fact that's Cygnus Newlib) calls RTEMS
|
||||
system call interface. This code can be found in the
|
||||
@code{c/src/lib/libc} directory.
|
||||
@item C library (e.g. RedHat (formerly Cygnus) Newlib) calls
|
||||
the RTEMS system call interface. This code can be found in the
|
||||
@code{cpukit/libcsupport/src} directory.
|
||||
|
||||
@item Glue code calls the serial driver entry routines.
|
||||
|
||||
@end itemize
|
||||
|
||||
@subsection Termios and Polled I/O
|
||||
@subsection Basics
|
||||
|
||||
You need to include the following header files in your Termios device driver
|
||||
source file:
|
||||
@example
|
||||
@group
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
|
||||
#include <rtems.h>
|
||||
#include <rtems/libio.h>
|
||||
#include <rtems/console.h>
|
||||
@end group
|
||||
@end example
|
||||
|
||||
You need to provide a data structure for the Termios driver interface. The
|
||||
functions are described later in this chapter. The functions should return
|
||||
zero on succes and minus one in case of an error. Currently the return value
|
||||
will be not checked from the Termios infrastructure in most cases. One notable
|
||||
exception is the polled read function, here is the return value important.
|
||||
|
||||
If you want to use polled IO it should look like the following. You may also
|
||||
have a look at @code{c/src/lib/libbsp/shared/console-polled.c} for a shared
|
||||
implementation of the basic framework. Termios must be told the addresses of
|
||||
the functions that are to be used for simple character IO, i.e. pointers to the
|
||||
@code{my_driver_poll_read} and @code{my_driver_poll_write} functions described
|
||||
later in @ref{Console Driver Termios and Polled IO}.
|
||||
|
||||
@example
|
||||
@group
|
||||
static const rtems_termios_callbacks my_driver_callbacks_polled = @{
|
||||
.firstOpen = my_driver_first_open,
|
||||
.lastClose = my_driver_last_close,
|
||||
.pollRead = my_driver_poll_read,
|
||||
.write = my_driver_poll_write,
|
||||
.setAttributes = my_driver_set_attributes,
|
||||
.stopRemoteTx = NULL,
|
||||
.startRemoteTx = NULL,
|
||||
.outputUsesInterrupts = TERMIOS_POLLED
|
||||
@};
|
||||
@end group
|
||||
@end example
|
||||
|
||||
For an interrupt driven implementation you need the following. The driver
|
||||
functioning is quite different in this mode. There is no device driver read
|
||||
function to be passed to Termios. Indeed a @code{console_read} call returns
|
||||
the contents of Termios input buffer. This buffer is filled in the driver
|
||||
interrupt subroutine, see also
|
||||
@ref{Console Driver Termios and Interrupt Driven IO}.
|
||||
The driver is responsible for providing a pointer to the
|
||||
@code{my_driver_interrupt_write} function.
|
||||
|
||||
@example
|
||||
@group
|
||||
static const rtems_termios_callbacks my_driver_callbacks_interrupt = @{
|
||||
.firstOpen = my_driver_first_open,
|
||||
.lastClose = my_driver_last_close,
|
||||
.pollRead = NULL,
|
||||
.write = my_driver_interrupt_write,
|
||||
.setAttributes = my_driver_set_attributes,
|
||||
.stopRemoteTx = NULL,
|
||||
.startRemoteTx = NULL,
|
||||
.outputUsesInterrupts = TERMIOS_IRQ_DRIVEN
|
||||
@};
|
||||
@end group
|
||||
@end example
|
||||
|
||||
You can also provide callback functions for remote transmission control. This
|
||||
is not covered in this manual, so thay are set to @code{NULL} in the above
|
||||
examples.
|
||||
|
||||
Normally the device specific data structures are stored in a table which is
|
||||
indexed by the minor number. You may need an entry for the Termios handler
|
||||
pointer in your data structure. For simplicity of the console initialization
|
||||
example the device name is also present.
|
||||
|
||||
@example
|
||||
@group
|
||||
/* Driver specific data structure */
|
||||
typedef struct @{
|
||||
const char *device_name;
|
||||
struct rtems_termios_tty *tty;
|
||||
@} my_driver_entry;
|
||||
|
||||
/*
|
||||
* This table contains the driver specific data. It is later
|
||||
* indexed by the minor number.
|
||||
*/
|
||||
static my_driver_entry my_driver_table [MY_DRIVER_DEVICE_NUMBER];
|
||||
@end group
|
||||
@end example
|
||||
|
||||
@subsection Termios and Polled IO
|
||||
|
||||
The following functions are provided by the driver and invoked by
|
||||
Termios for simple character input/output. The specific names of
|
||||
these routines are not important as Termios invokes them indirectly
|
||||
via function pointers.
|
||||
Termios for simple character IO.
|
||||
|
||||
@subsubsection pollWrite
|
||||
|
||||
The @code{pollWrite} routine is responsible for writing @code{len} characters
|
||||
from @code{buf} to the serial device specified by @code{minor}.
|
||||
The @code{my_driver_poll_write} routine is responsible for writing @code{n}
|
||||
characters from @code{buf} to the serial device specified by @code{minor}.
|
||||
|
||||
@example
|
||||
@group
|
||||
int pollWrite (int minor, const char *buf, int len)
|
||||
static int my_driver_poll_write(int minor, const char *buf, int n)
|
||||
@{
|
||||
for (i=0; i<len; i++) @{
|
||||
put buf[i] into the UART channel minor
|
||||
wait for the character to be transmitted
|
||||
on the serial line
|
||||
@}
|
||||
return 0
|
||||
my_driver_entry *e = &my_driver_table [minor];
|
||||
int i = 0;
|
||||
|
||||
/*
|
||||
* There is no need to check the minor number since it is derived
|
||||
* from a file descriptor. The upper layer takes care that it is
|
||||
* in a valid range.
|
||||
*/
|
||||
|
||||
/* Write */
|
||||
for (i = 0; i < n; ++i) @{
|
||||
my_driver_write_char(e, buf [i]);
|
||||
@}
|
||||
|
||||
return 0;
|
||||
@}
|
||||
@end group
|
||||
@end example
|
||||
|
||||
@subsubsection pollRead
|
||||
|
||||
The @code{pollRead} routine is responsible for reading a single character
|
||||
from the serial device specified by @code{minor}. If no character is
|
||||
available, then the routine should return -1.
|
||||
The @code{my_driver_poll_read} routine is responsible for reading a single
|
||||
character from the serial device specified by @code{minor}. If no character is
|
||||
available, then the routine should return minus one.
|
||||
|
||||
@example
|
||||
@group
|
||||
int pollRead(int minor)
|
||||
static int my_driver_poll_read(int minor)
|
||||
@{
|
||||
read status of UART
|
||||
if status indicates a character is available
|
||||
return character
|
||||
return -1
|
||||
my_driver_entry *e = &my_driver_table [minor];
|
||||
|
||||
/*
|
||||
* There is no need to check the minor number since it is derived
|
||||
* from a file descriptor. The upper layer takes care that it is
|
||||
* in a valid range.
|
||||
*/
|
||||
|
||||
/* Check if a character is available */
|
||||
if (my_driver_can_read_char(e)) @{
|
||||
/* Return the character */
|
||||
return my_driver_read_char(e);
|
||||
@} else @{
|
||||
/* Return an error status */
|
||||
return -1;
|
||||
@}
|
||||
@}
|
||||
@end group
|
||||
@end example
|
||||
|
||||
@subsection Termios and Interrupt Driven I/O
|
||||
@subsection 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 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.
|
||||
|
||||
@subsubsection InterruptHandler
|
||||
|
||||
The @code{InterruptHandler} 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
|
||||
The @code{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 @code{InterruptHandler} will have to check
|
||||
the status of the UART and determine what caused the interrupt.
|
||||
The following describes the operation of an @code{InterruptHandler}
|
||||
which has to do this:
|
||||
In the simplest case, the @code{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 @code{my_driver_interrupt_handler} which has to
|
||||
do this:
|
||||
|
||||
@example
|
||||
@group
|
||||
rtems_isr InterruptHandler (rtems_vector_number v)
|
||||
static void my_driver_interrupt_handler(
|
||||
rtems_vector_number vector,
|
||||
void *arg
|
||||
)
|
||||
@{
|
||||
check whether there was an error
|
||||
my_driver_entry *e = (my_driver_entry *) arg;
|
||||
char buf [N];
|
||||
int n = 0;
|
||||
|
||||
if some characters were received:
|
||||
Ask Termios to put them on his input buffer
|
||||
/*
|
||||
* 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(e, buf, N);
|
||||
if (n > 0) @{
|
||||
/* Hand the data over to the Termios infrastructure */
|
||||
rtems_termios_enqueue_raw_characters(e->tty, buf, n);
|
||||
@}
|
||||
|
||||
if some characters have been transmitted
|
||||
(i.e. the UART output buffer is empty)
|
||||
Tell TERMIOS that the characters have been
|
||||
transmitted. The TERMIOS routine will call
|
||||
the InterruptWrite function with the number
|
||||
of characters not transmitted yet if it is
|
||||
not zero.
|
||||
/*
|
||||
* 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(e);
|
||||
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(e->tty, n);
|
||||
@}
|
||||
@}
|
||||
@end group
|
||||
@end example
|
||||
|
||||
@subsubsection InterruptWrite
|
||||
|
||||
The @code{InterruptWrite} is responsible for telling the UART
|
||||
that the @code{len} characters at @code{buf} are to be transmitted.
|
||||
The @code{my_driver_interrupt_write} function is responsible for telling the
|
||||
device that the @code{n} characters at @code{buf} are to be transmitted. The
|
||||
return value may be arbitrary since it is not checked from Termios.
|
||||
|
||||
@example
|
||||
static int InterruptWrite(int minor, const char *buf, int len)
|
||||
@group
|
||||
static int my_driver_interrupt_write(int minor, const char *buf, int n)
|
||||
@{
|
||||
tell the UART to transmit len characters from buf
|
||||
return 0
|
||||
my_driver_entry *e = &my_driver_table [minor];
|
||||
|
||||
/*
|
||||
* There is no need to check the minor number since it is derived
|
||||
* from a file descriptor. The upper layer takes care that it is
|
||||
* in a valid range.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Tell the device to transmit some characters from buf (less than
|
||||
* or equal to n). If 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.
|
||||
*/
|
||||
|
||||
return 0;
|
||||
@}
|
||||
@end group
|
||||
@end example
|
||||
|
||||
The driver has to put the @i{n} first buf characters in the UART channel minor
|
||||
buffer (@i{n} is the UART channel size, @i{n}=1 on the MC68640). Generally, an
|
||||
interrupt is raised after these @i{n} characters being transmitted. So
|
||||
UART interrupts may have to be enabled after putting the characters in the
|
||||
UART.
|
||||
|
||||
|
||||
@subsection Initialization
|
||||
|
||||
The driver initialization is called once during the RTEMS initialization
|
||||
process.
|
||||
|
||||
The @code{console_initialize} function has to:
|
||||
|
||||
@itemize @bullet
|
||||
|
||||
@item initialize Termios support: call @code{rtems_termios_initialize()}. If
|
||||
Termios has already been initialized by another device driver, then
|
||||
this call will have no effect.
|
||||
|
||||
@item Initialize the UART: This procedure should
|
||||
be described in the UART manual. This procedure @b{MUST} be
|
||||
followed precisely. This procedure varies but
|
||||
usually consists of:
|
||||
|
||||
@itemize @bullet
|
||||
@item reinitialize the UART channels
|
||||
|
||||
@item set the channels configuration to the Termios default:
|
||||
9600 bauds, no parity, 1 stop bit, and 8 bits per character
|
||||
@end itemize
|
||||
|
||||
@item If interrupt driven, register the console interrupt routine to RTEMS:
|
||||
The @code{console_initialize} function may look like this:
|
||||
|
||||
@example
|
||||
rtems_interrupt_catch(
|
||||
InterruptHandler, CONSOLE_VECTOR, &old_handler);
|
||||
@group
|
||||
rtems_device_driver console_initialize(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *arg
|
||||
)
|
||||
@{
|
||||
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
||||
rtems_device_minor_number i = 0;
|
||||
|
||||
/*
|
||||
* 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 (i = 0; i < MY_DRIVER_DEVICE_NUMBER; ++i) @{
|
||||
my_driver_entry *e = &my_driver_table [i];
|
||||
|
||||
/*
|
||||
* Register this device in the file system. In order to use the
|
||||
* console (i.e. being able to do printf, scanf etc. on stdin,
|
||||
* stdout and stderr), some device must be registered
|
||||
* as "/dev/console" (CONSOLE_DEVICE_NAME).
|
||||
*/
|
||||
sc = rtems_io_register_name (e->device_name, major, i);
|
||||
RTEMS_CHECK_SC(sc, "Register IO device");
|
||||
|
||||
/*
|
||||
* Initialize this device and install the interrupt handler if
|
||||
* necessary. You may also initialize the device in the first
|
||||
* open call.
|
||||
*/
|
||||
@}
|
||||
|
||||
return RTEMS_SUCCESSFUL;
|
||||
@}
|
||||
@end group
|
||||
@end example
|
||||
|
||||
@item enable the UART channels.
|
||||
|
||||
@item register the device name: in order to use the console (i.e. being
|
||||
able to do printf/scanf on stdin, stdout, and stderr), some device
|
||||
must be registered as "/dev/console":
|
||||
|
||||
@example
|
||||
rtems_io_register_name ("dev/console", major, i);
|
||||
@end example
|
||||
|
||||
@end itemize
|
||||
|
||||
@subsection Opening a serial device
|
||||
|
||||
The @code{console_open} function is called whenever a serial
|
||||
device is opened. The device registered as @code{"/dev/console"}
|
||||
is opened automatically during RTEMS initialization.
|
||||
For instance, if UART channel 2 is registered as "/dev/tty1",
|
||||
the @code{console_open} entry point will be called as
|
||||
the result of an @code{fopen("/dev/tty1", mode)} in the
|
||||
The @code{console_open} function is called whenever a serial device is opened.
|
||||
The device registered as @code{"/dev/console"} (@code{CONSOLE_DEVICE_NAME}) is
|
||||
opened automatically during RTEMS initialization. For instance, if UART
|
||||
channel 2 is registered as "/dev/tty1", the @code{console_open} entry point
|
||||
will be called as the result of an @code{fopen("/dev/tty1", mode)} in the
|
||||
application.
|
||||
|
||||
The @code{console_open} function has to inform Termios of the low-level
|
||||
functions for serial line support; the "callbacks".
|
||||
functions for serial line support.
|
||||
|
||||
The gen68340 BSP defines two sets of callback tables:
|
||||
@example
|
||||
@group
|
||||
rtems_device_driver console_open(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *arg
|
||||
)
|
||||
@{
|
||||
struct rtems_termios_callbacks *callbacks =
|
||||
&my_driver_callbacks_polled;
|
||||
|
||||
@itemize @bullet
|
||||
/*
|
||||
* Check the minor number. Termios does currently not check
|
||||
* the return value of the first open call so the minor
|
||||
* number must be checked here.
|
||||
*/
|
||||
if (MY_DRIVER_IS_MINOR_INVALID(minor)) @{
|
||||
return RTEMS_INVALID_NUMBER;
|
||||
@}
|
||||
|
||||
@item one with functions for polled input/output
|
||||
/*
|
||||
* Depending on the IO mode you need to pass a different set of
|
||||
* callback functions to Termios.
|
||||
*/
|
||||
if (MY_DRIVER_USES_INTERRUPTS(minor)) @{
|
||||
callbacks = &my_driver_callbacks_interrupt;
|
||||
@}
|
||||
|
||||
@item another with functions for interrupt driven input/output
|
||||
return rtems_termios_open(major, minor, arg, callbacks);
|
||||
@}
|
||||
@end group
|
||||
@end example
|
||||
|
||||
@end itemize
|
||||
During the first open of the device Termios will call @code{my_driver_first_open}.
|
||||
|
||||
This code can be found in the file @code{$BSPROOT/console/console.c}.
|
||||
@example
|
||||
@group
|
||||
static int my_driver_first_open(int major, int minor, void *arg)
|
||||
@{
|
||||
my_driver_entry *e = &my_driver_table [minor];
|
||||
struct rtems_termios_tty *tty =
|
||||
((rtems_libio_open_close_args_t *) arg)->iop->data1;
|
||||
|
||||
/* Check minor number */
|
||||
if (MY_DRIVER_IS_MINOR_INVALID(minor)) @{
|
||||
return -1;
|
||||
@}
|
||||
|
||||
@subsubsection Polled I/O
|
||||
/* Connect the TTY data structure */
|
||||
e->tty = tty;
|
||||
|
||||
Termios must be told the addresses of the functions that are to be
|
||||
used for simple character input/output, i.e. pointers to the
|
||||
@code{pollWrite} and @code{pollRead} functions
|
||||
defined earlier in @ref{Console Driver Termios and Polled I/O}.
|
||||
/*
|
||||
* You may add some initialization code here.
|
||||
*/
|
||||
|
||||
@subsubsection Interrupt Driven I/O
|
||||
|
||||
Driver functioning is quite different in this mode. There is no
|
||||
device driver read function to be passed to Termios. Indeed a
|
||||
@code{console_read} call returns the contents of Termios input buffer.
|
||||
This buffer is filled in the driver interrupt subroutine
|
||||
(see @ref{Console Driver Termios and Interrupt Driven I/O}).
|
||||
|
||||
The driver is responsible for providing a pointer to the
|
||||
@code{InterruptWrite} function.
|
||||
/*
|
||||
* Sets the inital baud rate. This should be set to the value of
|
||||
* the boot loader.
|
||||
*/
|
||||
return rtems_termios_set_initial_baud(e->tty, MY_DRIVER_BAUD_RATE);
|
||||
@}
|
||||
@end group
|
||||
@end example
|
||||
|
||||
@subsection Closing a Serial Device
|
||||
|
||||
The @code{console_close} is invoked when the serial device is to
|
||||
be closed. This entry point corresponds to the device driver
|
||||
close entry point.
|
||||
The @code{console_close} is invoked when the serial device is to be closed.
|
||||
This entry point corresponds to the device driver close entry point.
|
||||
|
||||
This routine is responsible for notifying Termios that the serial
|
||||
device was closed. This is done with a call to @code{rtems_termios_close}.
|
||||
This routine is responsible for notifying Termios that the serial device was
|
||||
closed. This is done with a call to @code{rtems_termios_close}.
|
||||
|
||||
@subsection Reading Characters From a Serial Device
|
||||
@example
|
||||
@group
|
||||
rtems_device_driver console_close(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *arg
|
||||
)
|
||||
@{
|
||||
return rtems_termios_close(arg);
|
||||
@}
|
||||
@end group
|
||||
@end example
|
||||
|
||||
The @code{console_read} is invoked when the serial device is to
|
||||
be read from. This entry point corresponds to the device driver
|
||||
read entry point.
|
||||
Termios will call the @code{my_driver_last_close} function if the last close
|
||||
happens on the device.
|
||||
@example
|
||||
@group
|
||||
static int my_driver_last_close(int major, int minor, void *arg)
|
||||
@{
|
||||
my_driver_entry *e = &my_driver_table [minor];
|
||||
|
||||
/*
|
||||
* There is no need to check the minor number since it is derived
|
||||
* from a file descriptor. The upper layer takes care that it is
|
||||
* in a valid range.
|
||||
*/
|
||||
|
||||
This routine is responsible for returning the content of the
|
||||
Termios input buffer. This is done by invoking the
|
||||
@code{rtems_termios_read} routine.
|
||||
/* Disconnect the TTY data structure */
|
||||
e->tty = NULL;
|
||||
|
||||
/*
|
||||
* The driver may do some cleanup here.
|
||||
*/
|
||||
|
||||
return 0;
|
||||
@}
|
||||
@end group
|
||||
@end example
|
||||
|
||||
@subsection Reading Characters from a Serial Device
|
||||
|
||||
The @code{console_read} is invoked when the serial device is to be read from.
|
||||
This entry point corresponds to the device driver read entry point.
|
||||
|
||||
This routine is responsible for returning the content of the Termios input
|
||||
buffer. This is done by invoking the @code{rtems_termios_read} routine.
|
||||
|
||||
@example
|
||||
@group
|
||||
rtems_device_driver console_read(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *arg
|
||||
)
|
||||
@{
|
||||
return rtems_termios_read(arg);
|
||||
@}
|
||||
@end group
|
||||
@end example
|
||||
|
||||
@subsection Writing Characters to a Serial Device
|
||||
|
||||
The @code{console_write} is invoked when the serial device is to
|
||||
be written to. This entry point corresponds to the device driver
|
||||
write entry point.
|
||||
The @code{console_write} is invoked when the serial device is to be written to.
|
||||
This entry point corresponds to the device driver write entry point.
|
||||
|
||||
This routine is responsible for adding the requested characters to
|
||||
the Termios output queue for this device. This is done by
|
||||
calling the routine @code{rtems_termios_write}
|
||||
to add the characters at the end of the Termios output
|
||||
buffer.
|
||||
This routine is responsible for adding the requested characters to the Termios
|
||||
output queue for this device. This is done by calling the routine
|
||||
@code{rtems_termios_write} to add the characters at the end of the Termios
|
||||
output buffer.
|
||||
|
||||
@example
|
||||
@group
|
||||
rtems_device_driver console_write(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *arg
|
||||
)
|
||||
@{
|
||||
return rtems_termios_write(arg);
|
||||
@}
|
||||
@end group
|
||||
@end example
|
||||
|
||||
@subsection Changing Serial Line Parameters
|
||||
|
||||
The @code{console_control} 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 @code{console_control} 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 write is able to control the serial line configuration
|
||||
with Termios calls (such as the @code{ioctl} command, see
|
||||
the Termios documentation for
|
||||
more details). If the driver is to support dynamic configuration, then
|
||||
is must have the @code{console_control} piece of code. Refer to the gen68340
|
||||
BSP for an example of how it is done. Basically @code{ioctl}
|
||||
commands call @code{console_control} with the serial line
|
||||
configuration in a Termios defined data structure. The driver
|
||||
is responsible for reinitializing the UART with the correct settings.
|
||||
The application writer is able to control the serial line configuration with
|
||||
Termios calls (such as the @code{ioctl} command, see the Termios documentation
|
||||
for more details). If the driver is to support dynamic configuration, then it
|
||||
must have the @code{console_control} piece of code. Basically @code{ioctl}
|
||||
commands call @code{console_control} with the serial line configuration in a
|
||||
Termios defined data structure.
|
||||
|
||||
@example
|
||||
@group
|
||||
rtems_device_driver console_control(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *arg
|
||||
)
|
||||
@{
|
||||
return rtems_termios_ioctl(arg);
|
||||
@}
|
||||
@end group
|
||||
@end example
|
||||
|
||||
The driver is responsible for reinitializing the device with the correct
|
||||
settings. For this purpuse Termios calls the @code{my_driver_set_attributes}
|
||||
function.
|
||||
|
||||
@example
|
||||
@group
|
||||
static int my_driver_set_attributes(
|
||||
int minor,
|
||||
const struct termios *t
|
||||
)
|
||||
@{
|
||||
my_driver_entry *e = &my_driver_table [minor];
|
||||
|
||||
/*
|
||||
* There is no need to check the minor number since it is derived
|
||||
* from a file descriptor. The upper layer takes care that it is
|
||||
* in a valid range.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 0;
|
||||
@}
|
||||
@end group
|
||||
@end example
|
||||
|
||||
Reference in New Issue
Block a user