Setting up a High-Speed Modem
The prices on 14400 modems are coming down. Those modems
supported more and more widely by various services.
I've been using
one for months, but not on a UNIX system. The time came
one on a client's central site and on the client's beta
running SCO UNIX. Once that setup was proven, it would
standard setup for my client's turnkey product.
My first concern was the delay in making the connection
modems at each end negotiate with each other. That negotiation
the speed each modem is capable of, whether error correction
used, and whether data compression can be used. A few
years ago, when
MNP-5 modems were popular and inexpensive, I experimented
one to a Sun UNIX system. I ran into some problems with
delay. UUCP timed out before the negotiation could finish.
the priority for getting this MNP-5 modem to work was
very low. I
was moved to another project before I could find a way
problem and still get the MNP-5 advantages: data compression
up to 4800 BPS on a 2400 modem. This time, with making
it work a high
priority, I knew there had to be a way.
The 14400 modems can adjust their speed to that of the
modem at the
other end, which means that modem doesn't need to be
After adjusting, they can notify the computer of the
speed. On the
one hand, 14400 is not a standard BPS rate, since BPS
rates, as a
general rule, double from each increment starting with
300. In fact,
I know of no communication software that actually supports
rate. On the other hand, the modems are capable of communicating
the computer at speeds up to 57600 BPS. The modem does
this by taking
advantage of the difference between the data communications
(DCE) connection from modem to modem and the data terminal
(DTE) connection from modem to computer.
By not requiring each of the connections to run at the
one modem can negotiate with the other modem over the
establish the appropriate DCE speed according to what
the modems can
handle, and translate to a different DTE speed for transmission
and from the computer. To achieve a DTE speed higher
than the DCE
speed, each local modem buffers the data. If the DTE
speed is higher
than the DCE speed, the effect is an average faster
would be expected were the two speeds identical.
Because of the modem's local buffering, the computer
can be told to
connect to the modem (DTE) at a single BPS rate, ideally
the modem is capable of: 57600. However, the ideal and
the real are
often different. For instance, during Zmodem transfers
on some computers,
I've found that the time it takes for the system to
write a disk block
is long enough to miss the next modem data. The data
is just coming
in too fast for the disk handling. Slow the DTE speed
down and the
system can keep up. The DCE speed is still 14400, though,
so the transfers
are measurably fast.
SCO UNIX doesn't strictly support any modem speed faster
However, they do indicate that some Hayes compatible
modems have been
tested and work at the faster rates. I hooked up a Practical
14400 FXSA in early tests, and in the final installation
Practical Peripherals 14400 FXMTs. Those modems worked
I have no reason to believe other brands wouldn't work
as well; I
can't vouch for them because I haven't tried them.
To set up the 14400 modem on UNIX, some files need to
be changed for
the hardware interface and some for the UUCP interface.
be sure the getty on the modem port is disabled. On
the port I used for the modem is tty1A, so the command
This command changes the /etc/inittab file and
the /etc/conf/cf.d/init.base file. The SPBinittab(F)SPE
file contains the device names and characteristics used
starts. The init.base file supposedly feeds default
to inittab when the kernel is rebuilt, but I have no
this actually happens on SCO UNIX. Whenever the kernel
inittab settings come from a file named /etc/conf/init.d/sio.
(On SVR4, the equivalent to sio is named asy.) Unfortunately,
when the kernel is rebuilt the sio file's settings are
to the end of the inittab without checking to see if
creates duplicate settings. Since it does create duplicates,
spawning too rapidly" errors appear after subsequent
init is trying to spawn two or more gettys on the same
tty. To solve this problem, I commented out any lines
sio file that are also in the inittab file. I keep the
inittab and init.base files identical, just in case
SCO does draw from the init.base file.
Once the getty is disabled, two files need to be changed:
and /etc/gettydefs. The inittab file contains the init
reference for the tty. That reference points to the
entry. The gettydefs file contains the port settings
the getty before and after making a tty connection.
These settings are similar to stty(C) except that they
all capital letters. (See gettydefs(F) and termio(M)
for more information about those settings.)
I created the following single-line entry in /etc/gettydefs:
ppi14 # B38400 CS8 SANE HUPCL TAB3 ECHOE CRTSFL -IXANY
-IXON -IXOFF -CLOCAL -CTSFLOW -RTSFLOW # B38400 CS8
SANE HUPCL TAB3 ECHOE CRTSFL -IXANY -IXON -IXOFF
-CLOCAL -CTSFLOW -RTSFLOW #\r\n@!login: # ppi14
A gettydefs entry has five fields, each separated
by a pound sign (#). The first field contains the name
of the gettydefs
entry. Inittab refers to this name. The second field
the initial termio settings used when init runs getty.
The third field contains the final termio settings used
getty runs login(M). The fourth field contains the login
prompt string. The "@" symbol in the login
the system name, which is taken from /etc/systemid.
field refers to the next gettydefs entry to be used
if a BREAK
code is sent down the line. This BREAK is commonly used
to cycle through
multiple BPS rates controlled by software. For instance,
modem setups often allow users to dial in at 1200 and
300, while 9600
BPS setups typically allow 4800 and 2400. In the first
case, the 2400
entry refers to the 1200 entry, and the 1200 entry refers
to the 300
entry, and the 300 entry refers back to the 2400 entry,
cycle. The ppi14 entry refers to itself. There is no
need for software
cycling through different BPS rates because the modem
the rate. Thus, the DTE rate is fixed at 38400. Other
a lower speed if needed.
(I didn't honestly expect 57600 to work well under multitasking
I had hopes for 38400 and expected no trouble with 19200.)
This entry contains identical initial and final termio
The 14400 modem is best run with RTS/CTS turned on and
XON/XOFF is a software protocol. When an internal software
gets to a certain percentage of full, say 75 percent,
sends an XOFF data byte to the other system. The other
sending. The remaining 25 percent of the buffer catches
the data sent
down the line before the XOFF was received by the remote
the data flow stopped, the local system can empty the
worrying about a buffer overflow. When the buffer is
a certain smaller
percentage full, say 25 percent, the modem sends an
XON data byte.
The other system will start sending again. The remaining
of the buffer still containing data keeps the local
system busy while
the remote system is receiving the XON.
RTS/CTS (Ready-To-Send/Clear-To-Send) is a hardware
of the local modem telling the remote computer's software
sending, using the RTS/CTS protocol the local modem
tells the local
computer to stop sending. When data is available to
send, the RTS
line is raised. When the data can be received, the CTS
line is raised.
By toggling those lines, the local computer and modem
overflows and the data from modem to modem goes as fast
can. Yet, no extraneous data transmits between the two
the higher speed modems, RTS/CTS is required due to
the modem's internal
buffering, used to make the different DTE/DCE speeds
I was using SCO UNIX System V Release 3.2 Version 4.0.
I found out
that v4.0 didn't properly handle the RTS/CTS protocol.
This bug was
resolved in the interim release v4.1. Without RTS/CTS,
the best I
could do was 9600 BPS using XON/XOFF protocol. (The
setting for XON/XOFF in gettydefs would be the same
except you would substitute IXANY for all the settings
ECHOE and the #. Other AT-style initialization codes
are needed for
the modem itself. More about those later.) Once I installed
upgrade I got the RTS/CTS protocol working. The CRTSFL
was created by SCO for v4.0. In a single setting, it
is supposed to
replace the CTSFLOW and RTSFLOW flags. When CRTSFL
is used, the other flags must be turned off: -CTSFLOW
The CLOCAL flag must be turned off whenever RTS/CTS
is used. (SCO v4.2 is available now. I haven't installed
it as of
the time of this writing. I have seen a note from SCO
that the gettydefs
settings are slightly different, requiring the elimination
CRTSFL and use of CTSFLOW and RTSFLOW.)
With gettydefs set, I edited /etc/inittab to make tty1A
(labeled in the inittab file as "t1A") point
new gettydefs entry. If I change the last field in the
file to ppi14, the new gettydefs entry will be used
when I enable tty1A. It's also necessary to change the
The next steps configure cu(C) and uucp(C) to work.
After cding to /usr/lib/uucp, I edit /usr/lib/uucp/Devices.
The Devices(F) file identifies the speed and dialing
of the modem's tty port. If there is more than one entry
the same device in the Devices file, the first one becomes
the default entry. Otherwise, the speed identifies the
entry to use.
When cu or uucp names a system, the Systems(F)
file contains that system's speed and device information.
If you use
cu to dial any other phone number or to make a direct
to the modem, you must name the tty line with the "-l"
option. Then, you must either identify the speed to
use on the tty
line with the "-s" option or cu will use the
speed configured in the first entry in the Devices file.
I ended up using three Devices lines:
ACU tty1A - 19200-38400 /usr/lib/uucp/atdialPPI14
ACU tty1A - 300-9600 /usr/lib/uucp/atdialPPI9
Direct tty1a - 300-38400 direct
The first two lines specify two different dialers to
use for the ACU: the first one for the higher rates
using the 14400
DCE, and the second one for the lower rates using a
DCE of anything
else. The third line, labeled "Direct," lets
me make a direct
connection to the modem at any speed without modem control,
tty1a (notice the lowercase "a") has no modem
in the device driver.
The last field of each ACU line refers to the SCO "atdialer"
program as the dialer. I first tried to use entries
in the Dialers(F)
file, which is also found in /usr/lib/uucp. Here are
entries that I tried in the Dialers file:
ppi14400 =,-, "" ATZ\r\c OK\r
AT&FE1L2M1Q0X4&C1&D2&K3&Q5S0=0S2=43S95=46&W\r\c OK\r \
&ppi14400 =,-, "" +++\dATH OK\r ATS0=1S2=128\r
ppi9600 =,-, ATZ\r\c OK\r
AT&FE1L2M1Q0X4&C1&D2&K3&Q6S0=0S2=43S95=46&W\r\c OK\r \
&ppi9600 =,-, "" +++\dATH OK\r ATS0=1S2=128\r
There are really only three fields: the dialer name,
the pause translation table, and the chat script.
The lines named ppi14400 and ppi9600 are the dialer
to by the Devices file entries. These lines' chat scripts
sent as initialization codes just prior to dialing with
or uucp command. The lines having the same names but
by an ampersand (&) are used to hang up and reset
after the session
The pause translation table contains translation characters
kinds of delays. The first one is a wait-for-dialtone
pause, the second,
a simple pause. Some modems use different characters
for those different
pauses. In a phone number used on cu's command line
or in uucp's
Systems file, the equals sign represents the wait-for-dialtone
code, and the minus sign represents the pause code.
For example, if
you needed to dial 9, wait for a dialtone, then dial
the number, you
might use the phone number 9=5551212. The dialer script
the equals sign with the modem's character for that
kind of delay.
For Hayes-compatible modems, there is no distinction
between the two
pauses: the equals sign and minus sign is replaced by
a comma for
both of them.
The chat script is just like the one used in the Systems
a set of expect/send strings. The first string defines
response from the modem and the second is a string to
send. The rest
of the chat script is more expect/send sequences. When
an empty string
("") is used for the expect string, that means
The 14400 and 9600 chat scripts are identical except
for the &Q entry.
Briefly, the initialization string breaks down like
AT -- Get the modem's attention.
&F -- Load the default factory profile for
the switches and S-registers and completely reset the
is a more complete reset than that used by the old ATZ.
E1 -- Turn on command echo. Use this to
see what you're typing when you're not connected to
L2 -- Set speaker volume to medium. This
is a default setting. I have it here so I can explicitly
turn it low
(L0) for a customer site's modem.
M1 -- Keep speaker on until carrier detect.
This is also a default setting. Again, I have it here
so I can explicitly
turn it off (M0) so customers don't have to listen to
Q0 -- Enable result codes.
X4 -- Set extended result codes to show
connect speed. Also waits for a dialtone before dialing.
&C1 -- Set Data Carrier Detect (DCD) according
to the remote modem.
&D2 -- Use Data Terminal Ready (DTR). Dropped
DTR hangs up and goes to command mode.
&K3 -- Set local flow control to RTS/CTS.
Use &K4 if you must use 9600 with XON/XOFF instead.
&Q5 -- Set v.42 error control. The v.42bis
(data compression with theoretical 4:1 compression for
be automatically negotiated if the remote modem supports
it. If you
must use 9600 or less, use &Q6 instead. Data compression
will be disabled
but you should get a good connection. However, if you
must run XON/XOFF
(using &K4) this must be set to &Q0. That turns
off negotiation and
error correction, giving you a straightforward connection
the BPS rate specified. The BPS rate must be 9600 or
less to use XON/XOFF.
S0=0 -- Turn off the autoanswer.
S2=43 -- Enable the plus symbol as the escape
code. Normally, this is best turned off when connected
modem. But, while debugging the communication, it is
very handy to
be able to go into command mode and run ATI6 and AT&V.
the active BPS rates, &K and &Q settings, and
whether error correction
and data compression protocols were activated. AT&V
shows the current
DTE and DCE settings, all of the options, and all of
settings. After looking at them, I can go back online
by typing ATO.
If you're configuring both sides of a modem connection,
sure that the remote modem has the escape code turned
off, using S2=128.
Otherwise, when you escape your local modem, you might
remote modem too. If a timeout isn't active to kill
after carrier is dropped, that modem will hang on the
line even after
S95=46 -- Set the modem to tell the maximum
information about the connection. This is useful primarily
the communication. There are five bits available:
||Show Connect DCE speed instead of DTE.
||Show /ARQ if error correction active.
||Show Carrier DCE speed.
||Show Protocol NONE, LAP-M, or MNP.
||Show Compression NONE, 4.2BIS, or MNP5.
Just add the bits together to get the value to set
in the register. I don't use the 1 value because the
message shows the DTE speed while the Carrier message
shows the DCE
speed. This S-register can remain set this way because
and other chat scripts will either ignore or absorb
the other messages
this setting generates.
&W -- Write the current switch and register
settings to nonvolatile profile 0. Strictly speaking,
isn't needed with every dialer initialization. I could
have sent everything
other than the &Q (and maybe the &K) to the
modem manually, stored
it once with the &W, and then reduced the chat script's
string to AT&F to reset to factory conditions, followed
by ATZ to
set the profile 0 configurations. I didn't do it this
if I or anyone else in the future needed to experiment
settings, including changes to the modem's profile,
I wanted cu
and uucp to be able to reset the modem completely.
When the communication is finished, the appropriate
is activated. The three pluses get the modem's attention,
hangs up the line, the autoanswer will pick up the phone
on the first
ring (S0=1), and the modem escape is disabled (S2=128),
so that the
next remote call that comes in can't escape the local
modem to command
(The "\T" in the dialer entries marks the
location where the
phone number will be placed when the dialer is used.
The keyword "Speed"
in the expect field tells the dialing program to match
speed for a variable speed modem.)
These were good-looking Dialers entries. I got the 9600
to work in the XON/XOFF mode (using &K4&Q0)
while I waited for SCO's
v4.1 upgrade to arrive. When v4.1 arrived, I expected
the dialer entries
would continue to work with &K3&Q5 at 19200
and above. No such luck.
The problem was that despite my gettydefs entries, the
flow control simply wouldn't set properly. Using stty
the test connections were active, I could debug the
from another virtual terminal (SCO calls them multiscreens). The
program always works with the standard input (stdin),
it looks weird to do so. To find out what the line is
doing, I executed
the following command:
stty -a </dev/tty1A
That shows all the settings currently active on tty1A.
can't look at tty1A while the Terminal Ready (TR) light
off. The stty program simply hangs until an interrupt
to the stty process. When stty is interrupted, you'll
see a message such as "Can't open device."
If you must look
at the serial line when TR is off, use tty1a (notice
instead. The settings will be the same when there is
When the port has been disabled, the TR light turns
off. When it is
enabled, TR is on. The cu and uucp programs turn TR
on as needed.) I needed the following settings: -clocal,
-ctsflow, -rtsflow, -ixon, -ixany, and
-ixoff. I wasn't getting them with v4.1. Despite the
settings, RTS/CTS was off and XON/XOFF was on! Because
of that, the
modem connection would lose lots of characters and every
there would be ^S and ^Q characters in my keyboard commands.
To force the settings the way I wanted, I used the following
stty crtsfl -ctsflow -rtsflow -ixon -ixany -ixoff </dev/tty1A
That looks strange because the command seems to need
input from tty1A, yet the intent is to output to tty1A.
But, that's the way stty works. It reads input from
is on stdin, and it writes output to whatever is on
stdin. When I
had a 19200 BPS connection with lost data, it worked
I forced those settings. I needed something to force
settings. I have no idea why gettydefs isn't sufficient
Fortunately, SCO saved me some programming by providing
named atdialer. The C source code is included, but I
to use the supplied program without modification instead
of the Dialers
file entries. atdialer looks for a textfile in the /etc/defaults
directory containing a description of various modem
commands and responses.
You can use a shell script named make.dialer, supplied
the atdialer program, to create that file if you like,
a text editor. The textfile must be given a unique name.
Usually, the textfile name is "atdial" followed
by an all-capitals
abbreviation for the modem being configured. atdialer
which textfile to use by looking at its program name.
The name of
the atdialer program will be the same as the textfile
This is similar to the trick used for ls(1). On some
ls has alias names, such as ll and lc. They are
really hard links to the primary program. The program
looks at which
name was used to invoke it and modifies its operation
When make.dialer is run, it asks what name I want to
selected "atdialPPI14" for the 14400 mode
of operation. The
make.dialer script asked me a bunch of questions about
modem's commands and responses. The answers are put
into a textfile
named /etc/default/atdialPPI14, and a hard link to /usr/lib/uucp/atdialer,
named /usr/lib/uucp/atdialPPI14, is generated. In other
the program's basename is identical to the configuration
basename. Internally, the program only needs to change
the path to
get to the textfile.
Unfortunately, the make.dialer script doesn't request
settings, even though the atdialer.c source shows that
program can use them. To solve the problem, edit the
file and manually
enter the stty settings. Following is the resulting
the 14400 operations:
* Setup for Practical Peripherals 14400 FXMT
STTY=-IXON -IXOFF -RTSFLOW -CTSFLOW CRTSFL
(The atdialer program searches through the file
for an exact match of each variable name, so anything
in the file
not using one of those names is ignored. Since SCO used
(*) as if it were a comment introducer, I did the same.)
The only change for 9600 or less operations is to change
to &Q6, make one file for the 14400, (which I named
and another file for the 9600 (named atdialPPI9). Those
must be worldwide readable and are placed in /etc/default.
The next step is to make hard links to /usr/lib/uucp/atdialer
using those same names. After creating the files, the
sequence should be:
chmod a+r atdial*
ln atdialer atdialPPI14
ln atdialer atdialPPI9
After setting up the atdialer, I changed the Devices
file to refer to the atdialPPI14 and atdialPPI9 dialer
programs, as shown earlier.
Finally, so cu and uucp can use the system names, I
changed the /usr/lib/uucp/Systems file to make each
entry refer to the correct speed: 19200. I tried 38400
and got connections,
but cu lost characters when UNIX did other things. This
annoying with interactive connections; it would be devastating
uucp transfers. So, for now, set the top rate as 19200.
is probably that the sio driver can't keep up with that
in its current condition and SCO hasn't chosen to bring
up to date with modern higher-speed modems yet. There
might be a way
to fix that without rewriting the device driver. Writing
a new device
driver is the last resort.
The /usr/spool/uucp/.Admin/xferstats file keeps track
uucp transfer speeds. Sample entries, each a single
rezbook!mmdf S (6/24-11:57:01) (C,1997,1) [tty1A] -> 528 /
1.230 secs, 429 bytes/sec
rezbook!mmdf S (6/24-11:57:05) (C,1997,2) [tty1A] -> 146 /
0.090 secs, 1622 bytes/sec
chevrn1!mgr M (6/24-16:18:43) (C,3106,64) [tty1A] <- 308655 /
360.420 secs, 856 bytes/sec
chevrn1!mgr M (6/24-16:25:16) (C,3106,78) [tty1A] <- 309225 /
370.850 secs, 833 bytes/sec
(The rezbook system had a 2400 BPS connection. The chevrn1
system had the 14400 FXMT.) These samples show the system!user
sent the file, the date and time of the transfer, a
within the connection, the port, whether it is coming
from the other
system (an arrow formed from a less-than and a hyphen
<-) or going
to the other system (an arrow formed from a hyphen and
->), how many bytes are in the transfer, how many
seconds it took
to transfer, and the bytes-per-second throughput.
The number of seconds is total time, not just the time
of the actual
transferring. It reflects not only the time it took
to transfer the
bytes, but the time UNIX used to do other things, so
is a real throughput time. In the traditional estimation
time, you divide the BPS rate by 10 (eight data bits,
one start bit,
and one stop bit) to get the theoretical maximum bytes-per-second
rate. That means a 9600 transfer can reach a top rate
of 960 bytes
per second, and a 14400 transfer goes to 1440. Since
the DTE speed
is higher than 14400, the actual maximum speed could
be higher than
1440 (although not quite as high as 1920 or 3840). But,
UNIX has other
things to do. Time taken away from the transfer reduces
Still, the sample numbers show that the transfers are
in the 800 bytes-per-second
range. This time represents a four to five times speedup
Since 14400:2400 is a 6:1 ratio, we seem to be getting
most of the
speed out of the modem. Because the modem is able to
BPS, we might be able to get more out of the modem with
a better sio
About the Author
Larry Reznick has been programming professionally since
1978. He is currently
working on systems programming in UNIX and DOS. He teaches
C language courses
at American River College in Sacramento. He can be reached
via email at: