mirror of
https://github.com/sheumann/hush.git
synced 2025-01-03 00:31:16 +00:00
add serial HOWTO doc
This commit is contained in:
parent
4cb576ea98
commit
905ed8730f
424
loginutils/Serial-Programming-HOWTO.txt
Normal file
424
loginutils/Serial-Programming-HOWTO.txt
Normal file
@ -0,0 +1,424 @@
|
||||
Downloaded from http://www.lafn.org/~dave/linux/Serial-Programming-HOWTO.txt
|
||||
Seems to be somewhat old, but contains useful bits for getty.c hacking
|
||||
============================================================================
|
||||
|
||||
The Linux Serial Programming HOWTO, Part 1 of 2
|
||||
By Vernon C. Hoxie
|
||||
v2.0 10 September 1999
|
||||
|
||||
This document describes how to program communications with devices
|
||||
over a serial port on a Linux box.
|
||||
______________________________________________________________________
|
||||
|
||||
Table of Contents
|
||||
|
||||
1. Copyright
|
||||
|
||||
2. Introduction
|
||||
|
||||
3. Opening
|
||||
|
||||
4. Commands
|
||||
|
||||
5. Changing Baud Rates
|
||||
|
||||
6. Additional Control Calls
|
||||
|
||||
6.1 Sending a "break".
|
||||
6.2 Hardware flow control.
|
||||
6.3 Flushing I/O buffers.
|
||||
|
||||
7. Modem control
|
||||
|
||||
8. Process Groups
|
||||
|
||||
8.1 Sessions
|
||||
8.2 Process Groups
|
||||
8.3 Controlling Terminal
|
||||
8.3.1 Get the foreground group process id.
|
||||
8.3.2 Set the foreground process group id of a terminal.
|
||||
8.3.3 Get process group id.
|
||||
|
||||
9. Lockfiles
|
||||
|
||||
10. Additional Information
|
||||
|
||||
11. Feedback
|
||||
|
||||
______________________________________________________________________
|
||||
|
||||
1. Copyright
|
||||
|
||||
The Linux Serial-Programming-HOWTO is copyright (C) 1997 by Vernon
|
||||
Hoxie. Linux HOWTO documents may be reproduced and distributed in
|
||||
whole or in part, in any medium physical or electronic, as long as
|
||||
this copyright notice is retained on all copies. Commercial
|
||||
redistribution is allowed and encouraged; however, the author would
|
||||
like to be notified of any such distributions.
|
||||
|
||||
All translations, derivative works, or aggregate works incorporating
|
||||
this Linux HOWTO document must be covered under this copyright notice.
|
||||
That is, you may not produce a derivative work from this HOWTO and
|
||||
impose additional restrictions on its distribution.
|
||||
|
||||
This version is a complete rewrite of the previous Serial-Programming-
|
||||
HOWTO by Peter H. Baumann, <mailto:Peter.Baumann@dlr.de>
|
||||
|
||||
2. Introduction
|
||||
|
||||
This HOWTO will attempt to give hints about how to write a program
|
||||
which needs to access a serial port. Its principal focus will be on
|
||||
the Linux implementation and what the meaning of the various library
|
||||
functions available.
|
||||
|
||||
Someone asked about which of several sequences of operations was
|
||||
right. There is no absolute right way to accomplish an outcome. The
|
||||
options available are too numerous. If your sequences produces the
|
||||
desired results, then that is the right way for you. Another
|
||||
programmer may select another set of options and get the same results.
|
||||
His method is right for him.
|
||||
|
||||
Neither of these methods may operate properly with some other
|
||||
implementation of UNIX. It is strange that many of the concepts which
|
||||
were implemented in the SYSV version have been dumped. Because UNIX
|
||||
was developed by AT&T and much code has been generated on those
|
||||
concepts, the AT&T version should be the standard to which others
|
||||
should emulate.
|
||||
|
||||
Now the standard is POSIX.
|
||||
|
||||
It was once stated that the popularity of UNIX and C was that they
|
||||
were created by programmers for programmers. Not by scholars who
|
||||
insist on purity of style in deference to results and simplicity of
|
||||
use. Not by committees with people who have diverse personal or
|
||||
proprietary agenda. Now ANSI and POSIX have strayed from those
|
||||
original clear and simply concepts.
|
||||
|
||||
3. Opening
|
||||
|
||||
The various serial devices are opened just as any other file.
|
||||
Although, the fopen(3) command may be used, the plain open(2) is
|
||||
preferred. This call returns the file descriptor which is required
|
||||
for the various commands that configure the interface.
|
||||
|
||||
Open(2) has the format:
|
||||
|
||||
#include <fcntl.h>
|
||||
int open(char *path, int flags, [int mode]);
|
||||
|
||||
In addition to the obvious O_RDWR, O_WRONLY and O_RDONLY, two
|
||||
additional flags are available. These are O_NONBLOCK and O_NOCTTY.
|
||||
Other flags listed in the open(2) manual page are not applicable to
|
||||
serial devices.
|
||||
|
||||
Normally, a serial device opens in "blocking" mode. This means that
|
||||
the open() will not return until the Carrier Detect line from the port
|
||||
is active, e.g. modem, is active. When opened with the O_NONBLOCK
|
||||
flag set, the open() will return immediately regardless of the status
|
||||
of the DCD line. The "blocking" mode also affects the read() call.
|
||||
|
||||
The fcntl(2) command can be used to change the O_NONBLOCK flag anytime
|
||||
after the device has been opened.
|
||||
|
||||
The device driver and the data passing through it are controlled
|
||||
according to settings in the struct termios. This structure is
|
||||
defined in "/usr/include/termios.h". In the Linux tree, further
|
||||
reference is made to "/usr/include/asm/termbits.h".
|
||||
In blocking mode, a read(2) will block until data is available or a
|
||||
signal is received. It is still subject to state of the ICANON flag.
|
||||
|
||||
When the termios.c_lflag ICANON bit is set, input data is collected
|
||||
into strings until a NL, EOF or EOL character is received. You can
|
||||
define these in the termios.c_cc[] array. Also, ERASE and KILL
|
||||
characters will operate on the incoming data before it is delivered to
|
||||
the user.
|
||||
|
||||
In non-canonical mode, incoming data is quanitified by use of the
|
||||
c_cc[VMIN and c_cc[VTIME] values in termios.c_cc[].
|
||||
|
||||
Some programmers use the select() call to detect the completion of a
|
||||
read(). This is not the best way of checking for incoming data.
|
||||
Select() is part of the SOCKETS scheme and too complex for most
|
||||
applications.
|
||||
|
||||
A full explanation of the fields of the termios structure is contained
|
||||
in termios(7) of the Users Manual. A version is included in Part 2 of
|
||||
this HOWTO document.
|
||||
|
||||
4. Commands
|
||||
|
||||
Changes to the struct termios are made by retrieving the current
|
||||
settings, making the desired changes and transmitting the modified
|
||||
structure back to the kernel.
|
||||
|
||||
The historic means of communicating with the kernel was by use of the
|
||||
ioctl(fd, COMMAND, arg) system call. Then the purists in the
|
||||
computer industry decided that this was not genetically consistent.
|
||||
Their argument was that the argument changed its stripes. Sometimes
|
||||
it was an int, sometimes it was a pointer to int and other times it
|
||||
was a pointer to struct termios. Then there were those times it was
|
||||
empty or NULL. These variations are dependent upon the COMMAND.
|
||||
|
||||
As a alternative, the tc* series of functions were concocted.
|
||||
|
||||
These are:
|
||||
|
||||
int tcgetattr(int filedes, struct termios *termios_p);
|
||||
int tcsetattr(int filedes, int optional_actions,
|
||||
const struct termios *termios_p);
|
||||
|
||||
instead of:
|
||||
|
||||
int ioctl(int filedes, int command,
|
||||
struct termios *termios_p);
|
||||
|
||||
where command is TCGETS or one of TCSETS, TCSETSW or TCSETSF.
|
||||
|
||||
The TCSETS command is comparable to the TCSANOW optional_action for
|
||||
the tc* version. These direct the kernel to adopt the changes
|
||||
immediately. Other pairs are:
|
||||
|
||||
command optional_action Meaning
|
||||
TCSETSW TCSADRAIN Change after all output has drained.
|
||||
TCSETSF TCSAFLUSH Change after all output has drained
|
||||
then discard any input characters
|
||||
not read.
|
||||
|
||||
Since the return code from either the ioctl(2) or the tcsetattr(2)
|
||||
commands only indicate that the command was processed by the kernel.
|
||||
These do not indicate whether or not the changes were actually
|
||||
accomplished. Either of these commands should be followed by a call
|
||||
to:
|
||||
|
||||
ioctl(fd, TCGETS, &new_termios);
|
||||
|
||||
or:
|
||||
|
||||
tcgetattr(fd, &new_termios);
|
||||
|
||||
A user function which makes changes to the termios structure should
|
||||
define two struct termios variables. One of these variables should
|
||||
contain the desired configuration. The other should contain a copy of
|
||||
the kernels version. Then after the desired configuration has been
|
||||
sent to the kernel, another call should be made to retrieve the
|
||||
kernels version. Then the two compared.
|
||||
|
||||
Here is an example of how to add RTS/CTS flow control:
|
||||
|
||||
struct termios my_termios;
|
||||
struct termios new_termios;
|
||||
|
||||
tcgetattr(fd, &my_termios);
|
||||
my_termios.c_flag |= CRTSCTS;
|
||||
tcsetattr(fd, TCSANOW, &my_termios);
|
||||
tcgetattr(fd, &new_termios);
|
||||
if (memcmp(my_termios, new_termios,
|
||||
sizeof(my_termios)) != 0) {
|
||||
/* do some error handling */
|
||||
}
|
||||
|
||||
5. Changing Baud Rates
|
||||
|
||||
With Linux, the baud rate can be changed using a technique similar to
|
||||
add/delete RTS/CTS.
|
||||
|
||||
struct termios my_termios;
|
||||
struct termios new_termios;
|
||||
|
||||
tcgetattr(fd, &my_termios);
|
||||
my_termios.c_flag &= ~CBAUD;
|
||||
my_termios.c_flag |= B19200;
|
||||
tcsetattr(fd, TCSANOW, &my_termios);
|
||||
tcgetattr(fd, &new_termios);
|
||||
if (memcmp(my_termios, new_termios,
|
||||
sizeof(my_termios)) != 0) {
|
||||
/* do some error handling */
|
||||
}
|
||||
|
||||
POSIX adds another method. They define:
|
||||
|
||||
speed_t cfgetispeed(const struct termios *termios_p);
|
||||
speed_t cfgetospeed(const struct termios *termios_p);
|
||||
|
||||
library calls to extract the current input or output speed from the
|
||||
struct termios pointed to with *termio_p. This is a variable defined
|
||||
in the calling process. In practice, the data contained in this
|
||||
termios, should be obtained by the tcgetattr() call or an ioctl() call
|
||||
using the TCGETS command.
|
||||
|
||||
The companion library calls are:
|
||||
|
||||
int cfsetispeed(struct termios *termios_p, speed_t speed);
|
||||
int cfsetospeed(struct termios *termios_p, speed_t speed);
|
||||
|
||||
which are used to change the value of the baud rate in the locally
|
||||
defined *termios_p. Following either of these calls, either a call to
|
||||
tcsetattr() or ioctl() with one of TCSETS, TCSETSW or TCSETSF as the
|
||||
command to transmit the change to the kernel.
|
||||
|
||||
The cf* commands are preferred for portability. Some weird Unices use
|
||||
a considerably different format of termios.
|
||||
|
||||
Most implementations of Linux use only the input speed for both input
|
||||
and output. These functions are defined in the application program by
|
||||
reference to <termios.h>. In reality, they are in
|
||||
/usr/include/asm/termbits.h.
|
||||
|
||||
6. Additional Control Calls
|
||||
|
||||
6.1. Sending a "break".
|
||||
|
||||
int ioctl(fd, TCSBRK, int arg);
|
||||
int tcsendbreak(fd, int arg);
|
||||
|
||||
Send a break: Here the action differs between the conventional
|
||||
ioctl() call and the POSIX call. For the conventional call, an arg of
|
||||
'0' sets the break control line of the UART for 0.25 seconds. For the
|
||||
POSIX command, the break line is set for arg times 0.1 seconds.
|
||||
|
||||
6.2. Hardware flow control.
|
||||
|
||||
int ioctl(fd, TCXONC, int action);
|
||||
int tcflow(fd, int action);
|
||||
|
||||
The action flags are:
|
||||
|
||||
o TCOOFF 0 suspend output
|
||||
|
||||
o TCOON 1 restart output
|
||||
|
||||
o TCIOFF 2 transmit STOP character to suspend input
|
||||
|
||||
o TCION 3 transmit START character to restart input
|
||||
|
||||
6.3. Flushing I/O buffers.
|
||||
|
||||
int ioctl(fd, TCFLSH, queue_selector);
|
||||
int tcflush(fd, queue_selector);
|
||||
|
||||
The queue_selector flags are:
|
||||
|
||||
o TCIFLUSH 0 flush any data not yet read from the input buffer
|
||||
|
||||
o TCOFLUSH 1 flush any data written to the output buffer but not
|
||||
yet transmitted
|
||||
|
||||
o TCIOFLUSH 2 flush both buffers
|
||||
|
||||
7. Modem control
|
||||
|
||||
The hardware modem control lines can be monitored or modified by the
|
||||
ioctl(2) system call. A set of comparable tc* calls apparently do not
|
||||
exist. The form of this call is:
|
||||
|
||||
int ioctl(fd, COMMAND, (int *)flags);
|
||||
|
||||
The COMMANDS and their action are:
|
||||
|
||||
o TIOCMBIS turn on control lines depending upon which bits are set
|
||||
in flags.
|
||||
|
||||
o TIOCMBIC turn off control lines depending upon which bits are
|
||||
unset in flags.
|
||||
o TIOCMGET the appropriate bits are set in flags according to the
|
||||
current status
|
||||
|
||||
o TIOCMSET the state of the UART is changed according to which bits
|
||||
are set/unset in 'flags'
|
||||
|
||||
The bit pattern of flags refer to the following control lines:
|
||||
|
||||
o TIOCM_LE Line enable
|
||||
|
||||
o TIOCM_DTR Data Terminal Ready
|
||||
|
||||
o TIOCM_RTS Request to send
|
||||
|
||||
o TIOCM_ST Secondary transmit
|
||||
|
||||
o TIOCM_SR Secondary receive
|
||||
|
||||
o TIOCM_CTS Clear to send
|
||||
|
||||
o TIOCM_CAR Carrier detect
|
||||
|
||||
o TIOCM_RNG Ring
|
||||
|
||||
o TIOCM_DSR Data set ready
|
||||
|
||||
It should be noted that some of these bits are controlled by the modem
|
||||
and the UART cannot change them but their status can be sensed by
|
||||
TIOCMGET. Also, most Personal Computers do not provide hardware for
|
||||
secondary transmit and receive.
|
||||
|
||||
There are also a pair of ioctl() to monitor these lines. They are
|
||||
undocumented as far as I have learned. The commands are TIOCMIWAIT
|
||||
and TCIOGICOUNT. They also differ between versions of the Linux
|
||||
kernel.
|
||||
|
||||
See the lines.c file in my "serial_suite" for an example of how these
|
||||
can be used see <ftp://scicom.alphacd.com/pub/linux/serial_suite>
|
||||
|
||||
8. Process Groups
|
||||
|
||||
8.1. Sessions
|
||||
|
||||
8.2. Process Groups
|
||||
|
||||
Any newly created process inherits the Process Group of its creator.
|
||||
The Process Group leader has the same PID as PGID.
|
||||
|
||||
8.3. Controlling Terminal
|
||||
|
||||
There are a series of ioctl(2) and tc*(2) calls which can be used to
|
||||
monitor or to change the process group to which the device is
|
||||
attached.
|
||||
|
||||
8.3.1. Get the foreground group process id.
|
||||
|
||||
If there is no foreground group, a number not representing an existing
|
||||
process group is returned. On error, a -1 is returned and errno is
|
||||
set.
|
||||
|
||||
int ioctl(fd, TIOCGPGRP, (pid_t *)pid);
|
||||
int tcgetpgrp(fd, (pid_t *)pid);
|
||||
|
||||
8.3.2. Set the foreground process group id of a terminal.
|
||||
|
||||
The fd must be the controlling terminal and be associated with the
|
||||
session of the calling process.
|
||||
|
||||
int ioctl(fd, TIOCSPGRP, (pid_t *)pid);
|
||||
int tcsetpgrp(fd, (pid_t *)pid);
|
||||
|
||||
8.3.3. Get process group id.
|
||||
|
||||
int ioctl(fd, TIOCGPGRP, &(pid_t)pid);
|
||||
int tcgetpgrp(fd, &(pid_t)pid);
|
||||
|
||||
9. Lockfiles
|
||||
|
||||
Any process which accesses a serial device should first check for the
|
||||
existence of lock file for the desired device. If such a lock lock
|
||||
file exists, this means that the device may be in use by another
|
||||
process.
|
||||
|
||||
Check my "libdevlocks-x.x.tgz" at
|
||||
<ftp://scicom.alphacdc.com/pub/linux> for an example of how these lock
|
||||
files should be utilized.
|
||||
|
||||
10. Additional Information
|
||||
|
||||
Check out my "serial_suite.tgz" for more information about programming
|
||||
the serial ports at <mailto:vern@zebra.alphacdc.com>. There some
|
||||
examples and some blurbs about setting up modems and comments about
|
||||
some general considerations.
|
||||
|
||||
11. Feedback
|
||||
|
||||
Please send me any corrections, questions, comments, suggestions, or
|
||||
additional material. I would like to improve this HOWTO! Tell me
|
||||
exactly what you don't understand, or what could be clearer. You can
|
||||
reach me at <mailto:vern@zebra.alphacdc.com> via email. Please
|
||||
include the version number of the Serial-Programming-HOWTO when
|
||||
writing.
|
Loading…
Reference in New Issue
Block a user