Like all devices in a Unix system, serial ports are accessed through
device special files, located in the /dev
directory. There are two varieties of device files related to serial
drivers, and there is one device file of each type for each port. The
device will behave slightly differently, depending on which of its
device files we open. We'll cover the differences because it will help you
understand some of the configurations and advice that you might see
relating to serial devices, but in practice you need to use only
one of these. At some point in the future, one of them may even
disappear completely.

The most important of the two classes of serial device has a major
number of 4, and its device special files are named
ttyS0, ttyS1, etc. The
second variety has a major number of 5, and was designed for use when
dialing out (calling out) through a port; its device special files are
called cua0, cua1, etc. In
the Unix world, counting generally starts at zero, while laypeople
tend to start at one. This creates a small amount of confusion for
people because COM1: is represented by
/dev/ttyS0, COM2: by
/dev/ttyS1, etc. Anyone familiar with IBM PC-style
hardware knows that COM3: and greater were never
really standardized anyway.

The cua, or “callout,” devices were
created to solve the problem of avoiding conflicts on serial devices
for modems that have to support both incoming and outgoing
connections. Unfortunately, they've created their own problems and
are now likely to be discontinued. Let's briefly look at the problem.

Linux, like Unix, allows a device, or any other file, to be opened by
more than one process simultaneously. Unfortunately, this is rarely
useful with tty devices, as the two processes will almost certainly
interfere with each other. Luckily, a mechanism was devised to allow a
process to check if a tty device had already been opened by another
device before opening it. The mechanism uses what are called
lock files. The idea was that when a process
wanted to open a tty device, it would check for the existence of a
file in a special location, named similarly to the device it intends
to open. If the file does not exist, the process creates it and opens
the tty device. If the file does exist, the process assumes another
process already has the tty device open and takes appropriate
action. One last clever trick to make the lock file management system
work was writing the process ID (pid) of the process that had created
the lock file into the lock file itself; we'll talk more about that in
a moment.

The lock file mechanism works perfectly well in circumstances in which
you have a defined location for the lock files and all programs know
where to find them. Alas, this wasn't always the case for Linux. It
wasn't until the Linux Filesystem Standard defined a standard location
for lock files when tty lock files began to work
correctly. At one time there were at least four, and possibly more
locations chosen by software developers to store lock files:
/usr/spool/locks/,
/var/spool/locks/,
/var/lock/, and
/usr/lock/. Confusion caused chaos. Programs were
opening lock files in different locations that were meant to control a
single tty device; it was as if lock files weren't being used at all.

The cua devices were created to provide a
solution to this problem. Rather than relying on the use of lock files
to prevent clashes between programs wanting to use the serial devices,
it was decided that the kernel could provide a simple means of
arbitrating who should be given access. If the
ttyS device were already opened, an attempt to
open the cua would result in an error that a
program could interpret to mean the device was already being used. If
the cua device were already open and an attempt
was made to open the ttyS, the request would
block; that is, it would be put on hold and wait until the
cua device was closed by the other process. This
worked quite well if you had a single modem that you had configured
for dial-in access and you occasionally wanted to dial out on the same
device. But it did not work very well in environments where you had
multiple programs wanting to call out on the same device. The only way
to solve the contention problem was to use lock files! Back to square
one.

Suffice it to say that the Linux Filesystem Standard came to the
rescue and now mandates that lock files be stored in the
/var/lock directory, and that by convention, the
lock file name for the ttyS1 device, for
instance, is LCK..ttyS1. The
cua lock files should also go in this directory,
but use of cua devices is now discouraged.

The cua devices will probably still be around for
some time to provide a period of backward compatibility, but in time
they will be retired. If you are wondering what to use, stick to the
ttyS device and make sure that your system is
Linux FSSTND compliant, or at the very least that all programs using
the serial devices agree on where the lock files are located. Most
software dealing with serial tty devices provides a compile-time
option to specify the location of the lock files. More often than not,
this will appear as a variable called something like
LOCKDIR in the Makefile or in
a configuration header file. If you're compiling the software
yourself, it is best to change this to agree with the FSSTND-specified
location. If you're using a precompiled binary and you're not sure
where the program will write its lock files, you can use the following
command to gain a hint:

stringsbinaryfile | grep lock

If the location found does not agree with the rest of your system, you
can try creating a symbolic link from the lock directory that the
foreign executable wants to use back to
/var/lock/. This is ugly, but it will work.

Minor numbers are identical for both types of serial devices. If you
have your modem on one of the ports COM1: through COM4:, its minor
number will be the COM port number plus 63. If you are using special
serial hardware, such as a high-performance multiple port serial
controller, you will probably need to create special device files for
it; it probably won't use the standard device driver. The Serial-HOWTO
should be able to assist you in finding the appropriate details.

Assume your modem is on COM2:. Its minor number will be 65, and its
major number will be 4 for normal use. There should be a device called
ttyS1 that has these numbers. List the serial
ttys in the /dev/ directory. The fifth and sixth
columns show the major and minor numbers, respectively:

If there is no device with major number 4 and minor number 65, you
will have to create one. Become the superuser and type:

# mknod -m 666 /dev/ttyS1 c 4 65
# chown uucp.dialout /dev/ttyS1

The various Linux distributions use slightly differing strategies for
who should own the serial devices. Sometimes they will be owned by
root, and other times they will be owned by
another user, such as uucp in our example.
Modern distributions have a group specifically for dial-out devices,
and any users who are allowed to use them are added to this group.

Some people suggest making /dev/modem a symbolic
link to your modem device so that casual users don't have to remember
the somewhat unintuitive ttyS1. However, you
cannot use modem in one program and the real
device file name in another. Their lock files would have different
names and the locking mechanism wouldn't work.