mirror of
https://github.com/sheumann/hush.git
synced 2024-08-16 09:29:16 +00:00
425 lines
14 KiB
Plaintext
425 lines
14 KiB
Plaintext
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.
|