How to Use an ASCII Terminal as a Local Terminal and Console in Debian GNU/Linux

Contents

Disclaimer
Maintenance Log
The Hardware Connection
The Communications Parameters
Defining a Serial Terminal to Linux
     Defining a Serial Terminal Using sysvinit
     Defining a Serial Terminal Using systemd
     Tasks Common to Both Init Systems
Configuring the Kernel for Serial Console Support
Kernel Parameters for a Serial Console
Boot Loader Support for a Serial Console
Conclusion

Disclaimer

This is not an official Debian site.  This document details the author's experiences and recommendations with regard to using an ASCII terminal as a local serial terminal and console under Debian GNU/Linux on the i386 and amd64 architectures.  All opinions expressed are those of the author and do not necessarily represent the opinions or the official positions of the Debian project, Software in the Public Interest, the Linux kernel organization, or any other organization or individual.  This information is presented in the hope that it will be useful, but without any warranty or guarantee of any kind.  This information is presented free of charge, free of support, free of service, and free of liability.  Take this information with as many grains of salt as you think it's worth; and use it, if you choose to do so, entirely at your own risk.  The author hereby explicitly places this material in the public domain.  All trademarks, registered trademarks, service marks, etc. are the property of their respective owners.

Maintenance Log

The Hardware Connection

The traditional way for an ASCII terminal to be connected to a host computer is via two modems and a telephone network, such as this diagram shows:
 

     Host Computer ───── modem ───── modem ───── ASCII terminal
                     ▲           ▲           ▲
                     │           │           │
     serial cable ───┘           │           │
                                 │           │
     telephone network ──────────┘           │
                                             │
     serial cable ───────────────────────────┘

Note: the diagrams in this web page will not line up properly unless your browser is set up to use a true non-proportional font (monospaced font) to render "plain text".  I recommend DejaVu Sans Mono, which works perfectly.

There are two types of serial interface: DTE (Data Terminal Equipment) and DCE (Data Communications Equipment).  With rare exception, only modems use a DCE interface; everything else uses a DTE interface.  Thus, both of the serial cables shown in the above diagram connect a DTE device to a DCE device.  A standard serial cable, such as one which might be supplied in the box when you buy an external modem, is wired with the assumption that it will be used to connect a DTE device to a DCE device.  And as long as that's what you use it for, everything works fine.  The diagram below shows how a standard serial cable is wired:
 

      SG ──────────── SG

      RD ──────────── RD
      SD ──────────── SD

     RTS ──────────── RTS
     CTS ──────────── CTS

     DTR ──────────── DTR
     DSR ──────────── DSR

      CD ──────────── CD
      RI ──────────── RI

A standard serial cable is also sometimes called a "straight" serial cable, due to all the straight lines in the above diagram.

SG stands for Signal Ground.  It is, by definition, the reference voltage level against which the voltages of all the other lines are measured.

RD stands for Receive Data.  A DTE device receives data on the RD line.  A DCE device transmits data on the RD line.  SD stands for Send Data.  A DTE device transmits data on the SD line.  A DCE device receives data on the SD line.  (SD is sometimes called TD, for Transmit Data.)

RTS stands for Request To Send.  A DTE device asserts a signal on the RTS line when it is ready to receive data.  A DCE device monitors the RTS line to determine if the DTE device is ready to receive data.  CTS stands for Clear To Send.  A DTE device monitors the CTS line to determine if the DCE device is ready to receive data.  A DCE device asserts a signal on the CTS line when it is ready to receive data.

DTR stands for Data Terminal Ready.  A DTE device asserts a signal on the DTR line when it is active (i.e. powered on).  A DCE device monitors the DTR line to determine if the DTE device is active (i.e. powered on).  DSR stands for Data Set Ready.  A DTE device monitors the DSR line to determine if the DCE device is active (i.e. powered on).  A DCE device asserts a signal on the DSR line when it is active (i.e. powered on).

CD stands for Carrier Detect.  A DTE device monitors the CD line to determine if the DCE device (modem) has established a connection with a remote modem over the telephone network.  A DCE device (modem) asserts a signal on the CD line when it has established a connection with a remote modem over the telephone network.  RI stands for Ring Indicate.  A DTE device monitors the RI line to determine if the telephone line is ringing.  A DCE device asserts a signal on the RI line when it detects that the telephone line is ringing.

The following are the standard pinouts for these nine lines on both a DE-9 and a DB-25 D-shell connector:
 

     Signal    DE-9     DB-25
               pin      pin
     ──────    ─────    ─────
         SG      5        7
         RD      2        3
         SD      3        2
        RTS      7        4
        CTS      8        5
        DTR      4       20
        DSR      6        6
         CD      1        8
         RI      9       22

In a straight serial cable, if both ends use the same type of connector, then wires are connected to identical pin numbers on both sides.  For example, if both sides of the cable use DE-9 connectors, pin 1 on the left side is connected to pin 1 on the right side; pin 2 on the left side is connected to pin 2 on the right side; and so forth.

But when you use an ASCII terminal as a local terminal or a system console, you want to eliminate the two modems and the telephone network and connect the ASCII terminal directly to the host computer, as this diagram shows:
 

     Host Computer ───── ASCII terminal
                     ▲
                     │
     serial cable ───┘

This means that you want to connect two devices together which both use a DTE interface.  A standard (or straight) serial cable cannot be used for this purpose.  In order to directly connect two DTE interfaces, you must use a special "crossover" serial cable, which is specifically wired for the purpose of directly connecting two DTE interfaces.  As an alternative to using a crossover serial cable, you can use a straight serial cable in conjunction with a null modem.  A null modem is a device which attaches to one end of a straight serial cable and contains the crossover wiring necessary to make a straight serial cable work like a crossover serial cable.  Failure to use a crossover serial cable or a standard serial cable in conjunction with a null modem is the most common mistake made when attempting to use an ASCII terminal as a serial terminal or console.  (The same situation exists when attaching any serial device other than a modem directly to a PC.  Both devices use a DTE interface.)  The following diagram shows how a typical crossover cable or null modem is wired:
 

      SG ──────────── SG

      RD ─────╲╱───── RD
      SD ─────╱╲───── SD

     RTS ─────╲╱───── RTS
     CTS ─────╱╲───── CTS

     DTR ─────╲╱───── DTR
     DSR ──┬──╱╲──┬── DSR
           │      │
      CD ──┘      └── CD

      RI ──x      x── RI

The two SG lines are connected to each other, of course.  But the RD and SD lines are "crossed over" each other; so that RD on the left end is connected to SD on the right end, and SD on the left end is connected to RD on the right end.  (There is no connection at the crossover point.)  This is what gives the "crossover" serial cable its name.  RTS and CTS are also crossed over each other.  DTR and DSR are also crossed over each other.  CD on the left end is tied to DSR on the left end, and CD on the right end is tied to DSR on the right end; so that when the other end asserts DTR, both DSR and CD on this end will show an assertion.  RI is left unconnected on both ends.  (Thus, neither side of the connection will ever "see" a ringing telephone line via the RI hardware signal.)

You can see now why the crossover connections are necessary.  Without them, it would be like one party on a telephone call talking into the earpiece and listening to the mouthpiece.  No communication would take place. 

As you can see, only seven wires are needed in a crossover cable, whereas nine are needed in a straight cable.  (That is due to the fact that RI is left unconnected, and CD is tied to DSR on the same side.)  However, there are many so-called crossover cables out there that only use three wires.  They have SG, of course; and they have RD and SD crossed over each other; and that's it.  If you're going to assume software flow control, as opposed to hardware flow control, you may be able to eliminate RTS and CTS.  That can get you down to five wires.  Even then you may have trouble, as some communications software will not work unless it sees an assertion on CTS, even if software flow control is used.  But eliminating DTR and DSR will be even more likely to cause trouble, as even more communications software will not work if it doesn't see an assertion on DSR or CD.

My advice, for what it's worth, is Don't skimp.  Use a full, seven-wire, properly-wired crossover serial cable or a full, nine-wire, properly-wired straight serial cable in conjunction with a full, seven-wire, properly-wired null modem; and you won't have any problems.

I use an IBM 3151 ASCII Display Station, model 41, for my example, since that is what I have.  (The model 31 uses a green screen; the model 41 uses an amber-gold screen.  In all other respects, the two models are identical.  So if you have a model 31, everything discussed here for a model 41 applies to you as well.)  On the back of the display unit for this terminal are two serial ports, both of which use a female DB-25 connector.  Unfortunately, neither one of them is labeled!  The main port, the one you want to connect to your PC, is the one on the far right (when viewing the display unit from the back).  It is a DTE interface, so you will need a crossover serial cable or a straight serial cable plus a null modem to make a direct connection between the terminal and your PC.

The other female DB-25 connector, more towards the middle, is the auxiliary port.  The auxiliary port is for attaching a serial printer to your terminal: it cannot be used to attach the terminal to a PC.  If you do decide to attach a serial printer to the terminal (not documented here), keep in mind that the auxiliary port is a DCE interface; so you must use a straight serial cable to connect this port to a serial printer, which has a DTE interface.  The auxiliary port is one of those "rare exceptions" to the general rule that only modems use a DCE interface.  Another "rare exception" is a serial mouse.

The Communications Parameters

In addition to proper wiring, both sides of the interface (the PC's serial port and the ASCII terminal) must agree on the communications parameters in order for communication to be successful.  The communications parameters are the data transfer rate, the number of start bits, the number of data bits, the number of parity bits, the type of parity, the number of stop bits, and the type of flow control used.  (The order of the bits matters too.  The start bit(s) come first (duh), followed by the data bits, in increasing order of significance (from the least significant bit to the most significant bit), followed by the parity bit (if used), followed by the stop bit(s).  The bit order is a universal standard and is assumed by all asynchronous serial communications devices.  It is not configurable.)  Your ASCII terminal typically has a setup mode in which you can set these parameters.  See the manual for your ASCII terminal for details on how to set these parameters on the terminal side.  For the IBM 3151 terminal, there is a "Setup" key.  Setting these parameters on the PC side will be covered later.

You should set the data transfer rate to the highest value supported by both the terminal and the PC's serial port.  This will maximize the speed at which data can be transferred between the two devices.  For an IBM 3151 model 41 terminal, the maximum data transfer rate is 38400 bits per second.  The PC's serial port is capable of this rate also, so I set the data transfer rate of the terminal to 38400 bits per second.  The number of start bits is not configurable.  One start bit seems to be an almost universal standard.  Both the terminal and the PC's serial port are "hard wired" to use one start bit.  (Start bits are always 0.)  The number of data bits is either seven or eight.  The IBM 3151 is an eight-bit-capable terminal.  That is, it can handle byte codes in the range 0x80-0xff.  In particular, the "box-drawing characters" in the alternate character set use codes in the range 0x80-0xff; so I set the number of data bits to 8 to allow the box-drawing characters to work.

With seven data bits, one can use mark parity (parity bit always 1), space parity (parity bit always 0), odd parity (parity bit either 1 or 0 to make the total number of 1 bits in the byte odd), even parity (parity bit either 1 or 0 to make the total number of 1 bits in the byte even), or no parity (parity bit not present).  Some parts of Linux do not support mark parity or space parity, so I don't want to choose one of those.  But with eight data bits, there are no bits left over for parity; so no parity bit can be used.  The number of stop bits is either one or two, but one stop bit is nearly universal these days.  (Stop bits are always 1.)

The IBM 3151 terminal in native mode uses XON/XOFF software flow control.  This is not configurable, nor can it be disabled.  Flow control is also called pacing.  If the terminal is receiving data from the PC faster than it can be displayed, and the terminal's data buffer is almost full, the terminal will send the XOFF (transmit off) character to the PC.  This is also known as DC3, ^S, 0x13 (hexadecimal), \023 (octal) or 19 (decimal).  The PC will then stop transmitting data to the terminal.  Once the terminal's data buffer has been sufficiently emptied, the terminal will send the XON (transmit on) character to the PC to get the data flowing again.  This is also known as DC1, ^Q, 0x11 (hexadecimal), \021 (octal), or 17 (decimal).  The line discipline recognizes the XOFF and XON characters received from the terminal and uses them for flow control, but it does not queue them for retransmission back to the terminal (echo mode), nor does it pass them on to the application.

XON/XOFF flow control can also take place in the reverse direction.  If the PC's input buffer is getting full, the PC will also send XOFF to the terminal until it is once again ready to receive data, at which point it will send XON to the terminal to get the data flowing again.  With a real terminal, this is not likely to happen.  After all, how fast can you type?  But with terminal emulation programs doing file transfers, such as uploading a file to the host, this can happen.

It is important, when using XON/XOFF software flow control, that the data itself not contain either of these two characters, for obvious reasons.  The terminal user must never type ^S or ^Q at the keyboard.  (If you accidentally type ^S, you will lock your terminal.  To recover, type ^Q.)  Only the Linux line discipline and the internal logic circuitry of the terminal should ever send ^S or ^Q to its communications partner.  And when using a terminal emulation program to transfer data files between the "terminal" and the host, the data transmitted must never contain either of these two characters.  The ZMODEM protocol takes care that any such data bytes in the file being transferred are encoded in such a way that the ^S or ^Q characters are never transmitted "as is".  Then they are decoded on the receiving end back to their original form.  XMODEM and YMODEM, however, do not do this.  Therefore, it is not safe to transmit a file which might contain ^S or ^Q characters using either of these two protocols when XON/XOFF software flow control is being used.

There are other ways to do flow control (pacing), such as RTS/CTS hardware flow control; but XON/XOFF software flow control seems to be an almost universal standard for asynchronous serial ASCII terminals.  There are a few very old real ASCII terminals that do not support any form of flow control.  But they generally operate at such a slow maximum data transfer rate that the terminal can easily keep up with data arriving from the host.  And with a real terminal, again, how fast can you type?  If you type 100 words per minute, that works out to about 83 bits per second.  I think the PC will be able to keep up with you!

In summary, I use a data transfer rate of 38400 bits per second, 1 start bit, 8 data bits, 0 parity bits, 1 stop bit, and XON/XOFF software flow control.  The PC side of the interface will have to be configured identically in order for communication to be successful.  The start bits, data bits, parity bits, and stop bits together make what is called a frame.  There are 10 bits per frame in this case, so the number of bytes per second is the number of bits per second divided by 10.  At a data transfer rate of 38400 bits per second, that is equivalent to 3840 bytes per second, or about 46,080 words per minute.

In addition to the communications parameters listed above, the IBM 3151 terminal has a number of other settings.  Here are IBM's recommendations for how the terminal should be set up for use with AIX®, which I assume are optimal for Linux as well:
 

     General Setup Menu

     Machine Mode     IBM 3151
     Screen           NORMAL
     Row and Column   24x80
     Scroll           JUMP
     Auto LF          OFF
     CRT Saver        ON
     Line Wrap        ON
     Forcing Insert   LINE
     Tab              FIELD


     Communication Setup Menu

     Operating Mode         ECHO
     Line Speed (bps)       9600*
     Word Length (bits)     8
     Parity                 NO
     Stop Bit               1
     Turnaround Character   CR
     Line Control           IPRTS
     Break Signal (ms)      500
     Send Null Suppress     ON


     Keyboard/Printer Menu

     Keyboard:

     Enter                RETURN
     Return               NEW LINE
     New Line             CR
     Send                 PAGE
     Insert Character     SPACE

     Printer:

     Line Speed (bps)     9600*
     Word Length (bits)   8
     Parity               NO
     Stop Bit             1
     Characters           NATIONAL

     *9600 is a typical default value, but use the fastest speed supported
     by your setup.  The terminal's maximum speed is 38400.  The maximum
     speed for an attached printer, if there is one, is 19200.

Note: although IBM recommends setting Line Control to IPRTS, I prefer setting it to PRTS.  That way, I can tell from the terminal's operator information area whether the host has the serial port open or not.  If the serial port is not open, I see
 

     COMM NOT READY 2

in the operator information area.  Once the host system has opened the serial port and put assertions on DTR and RTS (seen by the terminal as assertions on DSR, CD, and CTS), the above status message disappears.

Defining a Serial Terminal to Linux

The next step in the process is defining a serial terminal to Linux.  This does not define the terminal as a system console, but it will allow the terminal to be used for login sessions.  How you do this depends on which init system you are using.

Defining a Serial Terminal Using sysvinit

If your init system is sysvinit, become root; then edit the file /etc/inittab.  Place an entry in it something like this:
 

     T0:23:respawn:/sbin/agetty -8 --noclear -I \033H\033J 38400 ttyS0 ibm3151

The "-8" option means eight data bits and zero parity bits.  One start bit and one stop bit are assumed by default.  XON/XOFF flow control is not a default setting, and agetty does not have an option to enable it.  Enabling this setting must wait until the user logs on.  agetty is supposed to send a control code sequence to clear the screen when it initializes, unless the "--noclear" option is used.  Either agetty is not sending the clear sequence, or it is sending the wrong clear sequence.  Either way, the screen doesn't clear.  To get around this, I specify the "--noclear" option (to disable the wrong code, if any), then add the "-I \033H\033J" option to send the correct clear sequence for this terminal type.  The "-I" option was originally intended to be used to send a modem initialization string, but it certainly comes in handy in this situation as well.

38400 is the data transfer rate in bits per second, of course; ttyS0 specifies the Linux character device special file name under /dev to which the terminal is connected; and ibm3151 is the terminal type definition in ncurses that will be used for this terminal.  Make adjustments depending on your terminal and parameters, then save the file and exit the editor. If the file /etc/ioctl.save exists, erase it.  Make sure the terminal is connected and powered on.  Then activate the terminal by issuing
 

     telinit q

If you made no mistakes in editing your /etc/inittab file, you should see a login prompt on your ASCII terminal.

Whenever you make a change to /etc/inittab, it is a good idea to activate it prior to a reboot via
 

     telinit q

then examine /var/log/syslog for any error messages.  (Go to the bottom of the file and see if you can find any error messages from init related to the change you made to /etc/inittab.)  If there are mistakes, correct the problem and try again until you get no error messages.  /etc/inittab is a critical file; and if there are mistakes in it, your system might not boot the next time!  Switching to the backup kernel won't help, since both kernels use the same /etc/inittab file.

From now on, you will get a login prompt on your serial terminal automatically on every boot, provided it is powered on at boot time.  If it is powered off at boot time, you will get a login prompt whenever you turn it on.

Defining a Serial Terminal Using systemd

If your init system is systemd, become root; then issue the following commands: 
 

     cd /etc/systemd/system
     mkdir serial-getty@ttyS0.service.d
     cd serial-getty@ttyS0.service.d

Now create a file in the current directory called "override.conf".  It should look like this:
 

     [Service]
     ExecStart=
     ExecStart=-/sbin/agetty -8 --noclear -I \033H\033J 38400 %I ibm3151

Save the file and exit the editor.  "%I" will be substituted with the name of the serial port at execution time (ttyS0).  The definitions of the other parameters are given in the sysvinit section above.  Make sure that the terminal is connected and powered on.  Tell systemd to reload the configuration by issuing
 

     systemctl daemon-reload

Check that your changes have been recognized by systemd by issuing
 

     systemctl cat serial-getty@ttyS0.service|tail -n 5

You should see output something like this:
 


     # /etc/systemd/system/serial-getty@ttyS0.service.d/override.conf
     [Service]
     ExecStart=
     ExecStart=-/sbin/agetty -8 --noclear -I \033H\033J 38400 %I ibm3151

(The first line of output should be blank.)  Start the service by issuing
 

     systemctl start serial-getty@ttyS0.service

You should now see a login prompt on your serial terminal.  Finally, make the service permanent, so that it will start automatically at the next reboot, by issuing
 

     systemctl enable serial-getty@ttyS0.service

Tasks Common to Both Init Systems

You will probably want to make some tweaks to accommodate the capabilities (or lack thereof) of your terminal.  Under ncurses versions prior to 5.9+20150502, there are some important omissions in the terminal definitions in ncurses for the ibm3161 terminal and terminals derived from it.  These include i3164, ibm3151, ibm3161, ibm3161-C, ibm3162, ibm3163, ibm3164, wy60-316X, and wyse60-316X.  The insert character (ich1) and insert line (il1) functions are not defined for many of them, and XON/XOFF flow control (xon) is not defined for any of them.  The absence of the il1 function in particular makes "less" think that the terminal is "dumb".  That is, you will get warnings from "less" like this if you use, say, the ibm3161 terminal definition without the patch applied:
 

     WARNING: terminal is not fully functional

Here is a link to a patch to the terminal definition file in ncurses which fixes this problem.  Apply this patch to the source package ncurses, then rebuild the package.  Rebuilding the source package will produce many binary packages.  Only the ncurses-term binary package needs to be reinstalled.

I also added something like the following to my ~/.bashrc file:
 

     case "$TERM" in
     ibm3151|ibm3161)
             LANG=en_US
             MANOPT="-7"
             MANPAGER="less -r"
             export MANOPT MANPAGER
             stty ixon ixoff -iutf8 tab3 -clocal
             ;;
     esac

The system locale is en_US.UTF-8, but this terminal is not capable of UTF-8 encoding, so I use LANG=en_US when using this terminal.  The "-7" option in MANOPT tells "man" that only the standard 7-bit ASCII codes can be used for ordinary characters.  The terminal does support certain codes above 0x7f, but they do not conform to the ISO-8859 standard (Latin 1), so man pages generally look better if the data is restricted to standard 7-bit ASCII.  MANPAGER is set to "less -r" in order to get rid of trailing lower-case "m"s at the end of each line.  (It appears that grotty generates some control code sequences which this terminal does not support.  Using the "-r" option of "less" suppresses those annoying trailing "m"s.)

The "export" command lists the names of variables to be included in the environment.  Note that LANG is not listed, even though it is altered, since LANG is already marked as an environment variable.

The stty command makes some changes to the line discipline.  ixon and ixoff enable XON/XOFF software flow control.  ixon allows the terminal to throttle the host with XOFF and XON characters.  ixoff allows the host to throttle the terminal by sending it XOFF and XON characters.  Enabling both options allows XON/XOFF software flow control to be bidirectional.  -iutf8 tells the line discipline that characters coming in from the terminal are not encoded using UTF-8.  (In other words, it's one byte per character, even for character codes between 0x7f and 0xff.) 

tab3 tells the line discipline to expand horizontal tab characters (^I, 0x09) to blanks on output (assuming tab stops every 8 columns).  If you don't have this set, tabs sent to the IBM 3151 terminal will not work as expected and will likely result in garbled output.  The "ls" command often includes tab characters in its output, particularly when output is in multi-column mode.  -clocal tells the line discipline to expect an assertion on the CD (Carrier Detect) line.  If you're using a properly-wired crossover serial cable or null modem, this signal will be present.  Note that "#!/bin/sh" is not necessary at the beginning of this file, nor does it need to be marked executable, because it is "sourced" by bash.

The above tweaks attempt to address the most common problems, but there will probably be other situations where poorly-written applications will produce less-than-desirable output.  These applications fail to interrogate the terminfo database to determine if the terminal supports a given feature, and if it does, how that feature is supported.  These applications may make assumptions that are not true on your terminal.  For example, when you issue the command
 

     systemctl status serial-getty@ttyS0.service

on a system which uses systemd as its init system, the output contains some garbage characters.  It is trying to set some colors using ANSI-standard control sequences, and these are not supported by an IBM 3151 terminal.  (Sorry, you can't get color output on a monochrome terminal!)  The application doesn't check, it just assumes.  Redirecting standard output to something other than the terminal removes the offending codes, but you might want to report a bug against the offending software for making unwarranted assumptions!  You can work around the above problem with something like this:
 

     systemctl status serial-getty@ttyS0.service|cat

Despite the fact that XON/XOFF software flow control is an industry standard, there are some application programs which use ^Q or ^S as command keys or disable XON/XOFF software flow control, or both.  In my opinion, no application program should ever use ^Q or ^S for application functions by default, and no application program should ever disable any type of flow control, be it hardware or software.  But, sadly, there are some that do; so we need to make some adjustments.

The two best-known offenders in this regard are info and Emacs.  I don't use Emacs on my system, but I do use info.  info uses ^S as the "isearch-forward" key in info windows.  This key allows you to search interactively for a string as you type it.  It uses ^Q as the "echo-area-quoted-insert" key in the echo area.  This key allows you to insert the next character verbatim.  Obviously, neither key will work on an ASCII terminal which uses XON/XOFF software flow control.  The line discipline will "eat" both codes without passing them on to the application.  Furthermore, ^S will lock your terminal.

The good news is that info gives you a way to remap its default keys.  For example, create a file called ~/.infokey which looks like this:
 

     #info
     ^_  isearch-forward
     ^S  invalid
     #echo-area
     ^^  echo-area-quoted-insert
     ^Q  invalid

Now enter the command "infokey" with no operands.  This will create a binary file called ~/.info, which will be read by info at execution time to remap the keys.

The bad news is that this won't work in this case!  The info application actually disables XON/XOFF software flow control while it is running in order to allow its default ^Q and ^S keys to work.  And as far as I can tell, info does not give you a way to alter this behavior.  You can remap the keys, but the application will still disable XON/XOFF software flow control while it is running, even if neither ^Q nor ^S is assigned to a function.  And that is unacceptable.  This terminal must use XON/XOFF software flow control, especially at higher speeds.

The only way that I know to fix it is to make a source code change.  Here is a link to a patch which fixes this problem.  (Aren't you glad you use open-source software?  If you were using proprietary, closed-source software, you wouldn't have access to the source code; and you wouldn't be able to fix problems like this!)  The above patch applies to the texinfo source package.  Only the info binary package needs to be installed.

Since I had to make a source code change to prevent info from disabling XON/XOFF software flow control, while I was in there I changed the default keys too.  Here is a patch to change the info manuals to document the changes to the key bindings.  A version of this patch which I published earlier attempted to directly change the info files.  However, this messed up the info manual's tag entries.  This version of the patch changes the source code for the info manuals.  You will need to download the source code for package texinfo-doc-nonfree, apply the patch, then re-build and re-install the package.  Only one binary package is built from this source.  It is also called texinfo-doc-nonfree.

Note: For version 6.0.0 of texinfo-doc-nonfree and later, the last hunk of the patch will fail to apply.  That's OK.  The portion of the document it is trying to update does not exist in this version of the manual.  Just ignore the failed hunk and erase the .rej and .orig files.

The above key-binding changes are necessary for any terminal which uses XON/XOFF software flow control.  But for my IBM 3151 terminal, I find it useful to make the following additional key binding in ~/.infokey:
 

     #info
     \e2  move-to-prev-xref

On this particular terminal, this binds the "Backtab" key to the "move-to-prev-xref" function.  On this particular terminal, Shift+Tab sends the same codes as Backtab; so this also binds Shift+Tab to this function.  (Don't forget to compile the ~/.infokey file with the infokey command to produce the binary ~/.info file, which is what the info command actually looks at during execution.) 

Note: under version 6 of info, which comes with Debian stretch (9.x), there are two differences to note.  First, it is no longer necessary to "compile" the ~/.infokey file into the ~/.info file with the infokey command.  Version 6 of info reads the ~/.infokey file directly: it no longer uses the ~/.info file, and the infokey command no longer exists.  Second, for the IBM 3151 terminal, it is no longer necessary to define \e2 in the ~/.infokey file as the move-to-prev-xref function in order to get the Backtab key to work.  The Backtab key works automatically in version 6.

You can make Emacs treat ^S and ^Q as flow control characters by evaluating the following form to unconditionally enable flow control:
 

     (enable-flow-control)

To enable flow control selectively, do something like this:
 

     (enable-flow-control-on "ibm3151" "ibm3161")

As written above, ^S will be replaced by ^\ and ^Q will be replaced by ^^.  However, ^\ is a poor choice, since ^\ is the "quit" key recognized by the line discipline.  You can use variables to change the default swap keys (flow-control-c-s-replacement and flow-control-c-q-replacement).  Put the form in your .emacs file.  If I were doing it, I would set flow-control-c-s-replacement to ^_ (\C-_) to be consistent with what I did for info.  But maybe Emacs already has a definition for ^_.  I don't know enough about Emacs to know the answer to that question.  The point is, you have to enable flow control and you have to remap the ^S and ^Q keys to something else that isn't already in use.

By default, readline also has key bindings to ^S and ^Q.  ^S is bound to "forward-search-history", and ^Q is bound to "quoted-insert".  In the case of "quoted-insert", this function is also bound to ^V; and I always use ^V anyway, since I'm used to that being the key binding for this function in "vi".  Therefore, I don't bother binding "quoted-insert" to another key to replace ^Q.  But "forward-search-history" is only bound to ^S, so it will need to be bound to another key or I will lose access to that function.  I bind it to ^_ for consistency with what I did in "info".  By default, ^_ is bound to "undo".  But "undo" is also bound to ^X^U, so I won't lose access to "undo" by rebinding ^_ to "forward-search-history".  Here is my ~/.inputrc file:
 

     \C-q:
     \C-s:
     \C-_: forward-search-history

It doesn't need to be "compiled".  Results will take effect at the next login.

If you use nano, you will need to make some changes to it also.  nano also disables XON/XOFF software flow control while it is running, though I don't understand why.  (nano doesn't seem to have any key bindings to ^S or ^Q, so I can see no reason for doing this.)  You can prevent nano from disabling XON/XOFF software flow control by creating a file called ~/.nanorc and putting the following line in it:
 

     set preserve

There seems to be a bug in nvi in its resume processing when XON/XOFF software flow control is used.  (The process is suspended with ^Z and then resumed with the "fg" command at the shell prompt.)  The symptom is that the error message
 

     ^S is not a vi command

is received upon resumption.  Also, the screen is usually only partially repainted.  The error can be recovered from easily by typing ^L to refresh the screen, but it's annoying.  As a result, I've switched from nvi to vim-tiny.  The vim-tiny implementation of vi can be suspended and resumed without incident, even when XON/XOFF software flow control is used.  I have reported the nvi bug to Debian; but at the time of this writing, no fix is available.  (See Debian bug report 785771 for details.)

Since this terminal does not support color, I find myself using the -F option of the "ls" command quite a bit.  I find that I've become quite dependent on the color cues to identify the type of file; and with that gone, the -F option really comes in handy.  Of course, it is generally not needed when I use the -l option, since the extra information provided by the -l option eliminates the need for the visual cues provided by the -F option or color.

If you use the lynx web browser on your ASCII terminal, you may find the --display_charset=us-ascii option useful.  This comes in handy, for example, if your terminal cannot display some characters that the browser wants to use, such as the registered trademark symbol.  In this case, the browser substitutes the three-character sequence "(R)" for the registered trademark symbol.  I couldn't find a way to pass command options to lynx via an environment variable, the way I can with less; so I resorted to the old wrapper script technique.  Create a script file called ~/bin/lynx, which looks like this:
 

     #!/bin/sh
     case "$TERM" in
     ibm3151|ibm3161)
             exec /usr/bin/lynx --display_charset=us-ascii "$@"
             ;;
     *)
             exec /usr/bin/lynx "$@"
             ;;
     esac

Mark it executable with "chmod +x".  You can then use the "hash -d lynx" command to discard the shell's previously-remembered path for the lynx command.  Now, since ~/bin comes before /usr/bin in the PATH environment variable, the above wrapper script will be invoked instead of the system-level lynx command.  As you can see, the purpose of the wrapper script is to supply the "--display_charset=us-ascii" option to lynx whenever the terminal type is ibm3151 or ibm3161.

ssh and lsh are two more programs that disable XON/XOFF software flow control.  Here is a patch for ssh.  The Debian source package is openssh.  When you rebuild the source package, it will produce several binary packages.  Only the openssh-client package needs to be installed.

I have tested the ssh patch and confirmed that it works.  (Rebuilding the lsh-utils source package would have required me to remove the openssh-server binary package, which I was unwilling to do.)  Of course, you will need to make all the modifications to the target host system of ssh or lsh that you made to your local host system if you want to use your ASCII terminal with the remote host system.

c3270 is a popular 3270 emulation program for the Linux console.  Here is how I invoke it when using my 3151 terminal:
 

     c3270 -cbreak -xrm "c3270.metaEscape: False" -model 3278-2 -charset us-intl -keymap ~/my3270keys ...

-cbreak prevents c3270 from disabling XON/XOFF software flow control.  -xrm "c3270.metaEscape: False" prevents c3270 from combining the Escape character with the next character received.  c3270 normally combines the Escape character with the next character received by setting the high-order bit of the next character received, as a true Meta key would do.  Thus, "ESC x" (two consecutive characters) is treated as "Meta-x" (a single character), which is the numeric code for x plus 0x80.  The above option prevents this behavior.  Note that the option value must be quoted, since it contains a blank.  -model 3278-2 tells c3270 to emulate a 24-line by 80-column monochrome terminal.  (Unfortunately, there is no 25th line available for use as the 3270 operator information area; so indications such as X-SYSTEM, X-CLOCK, and other information normally displayed in the c3270 operator information area are suppressed.)  -charset us-intl tells c3270 to use EBCDIC code page 037, and -keymap ~/my3270keys specifies the name of a key map file to be used.  I find the following c3270 key maps to be useful on this terminal:
 

     <Key>EOL: EraseEOF
     <Key>BTAB: BackTab
     <Key>CLEAR: Clear
     Ctrl<Key>[ <Key>! <Key>m Ctrl<Key>m: PA(1)
     Ctrl<Key>[ <Key>! <Key>n Ctrl<Key>m: PA(2)
     Ctrl<Key>[ <Key>! <Key>o Ctrl<Key>m: PA(3)
     Ctrl<Key>[ <Key>K: EraseInput

These key maps allow the keys on the keyboard which are labeled Erase EOF, <-Tab, Clear, PA1, PA2, PA3, and ErInp to be used for the corresponding 3270 functions in c3270.  Note that the key definitions for PA1, PA2, PA3, and ErInp won't work without the -xrm "c3270.metaEscape: False" option, as discussed above.

Configuring the Kernel for Serial Console Support

If you want your ASCII terminal to be used as a serial console (i.e. one on which kernel boot messages are displayed) you must first make sure that such support is included in your kernel.  Examine your kernel config file.  Kernel config files are stored in files with the name pattern "/boot/config-*".  In order to use your ASCII terminal as a Linux serial console, two kernel configuration options must be set.  These are
 

     ...
     CONFIG_SERIAL_8250=y
     ...
     CONFIG_SERIAL_8250_CONSOLE=y
     ...

Make sure that both of these configuration options are present.  (Modularized support will not do: they must be compiled into the kernel.)  If both of these options are present, your kernel is good to go.  If not, then you must install a kernel which has these options.  See my kernel-building web page for information about how to build a custom kernel.

If you are building a custom kernel, here's how to enable these options.  In the "make menuconfig" main menu, select the sub-menu "Device Drivers".  Below that, select the sub-menu "Character devices".  Below that, select the sub-menu "Serial drivers".  On this menu, look for a line labeled "8250/16550 and compatible serial support".  This is the CONFIG_SERIAL_8250 option.  Set it to Y.  (M will not do: it must be Y.)  Once the above option is set to Y, you will see a line below it labeled "Console on 8250/16550 and compatible serial port".  This is the CONFIG_SERIAL_8250_CONSOLE option.  Set it to Y also.  (M will not do: it must be Y.)  Now save your kernel configuration file and continue the kernel build process.  Once you have installed this kernel and rebooted, you will have serial console support in your kernel.

Kernel Parameters for a Serial Console

Although your kernel may have support in it for a serial console, it will not use the serial terminal as a console by default.  In order to get the Linux kernel to use your serial terminal as a console, you will need to pass some parameters to it on the kernel command line.  The method for doing this depends on what boot loader you use.  The example I use here is for the LILO boot loader.  If you use a different boot loader, consult the documentation for your boot loader to determine how to pass parameters to the kernel.  For LILO, edit /etc/lilo.conf.  Add or change the append option to look something like this:
 

     append="console=ttyS0,38400N8 console=tty0"

It should be obvious what the parameters are.  ttyS0 is the name of the device file in /dev to which the terminal is attached.  38400 is the data transfer rate.  1 start bit is assumed.  The N means no parity bit is present, the 8 means 8 data bits.  1 stop bit is also assumed by default.

Unfortunately, XON/XOFF software flow control is not enabled by default, and I know of no way to enable it until a user logs in.  (If someone out there knows of a way, please tell me!)  The only way that I know to circumvent this problem is to slow down the terminal (by specifying a lower data transfer rate) to the point where the terminal can always keep up with the host without needing to send it any flow control characters.  If you want to do this, you will probably need to go down to 9600 bps, maybe even lower, to keep the host from overrunning the buffers.  (Of course, you must change the speed everywhere to be consistent.)  I am not willing to do this: I want maximum speed for use during a login session.  Therefore, I put up with lost output during boot.  Similarly, tab characters produce funky output during boot, since tab3 is not set either.

The console parameter is specified twice.  The first specification is for the serial console.  The second is for the currently existing console, tty0 (the VGA console).  This leaves you with a functioning console in case your serial terminal is powered off at boot time.  The Linux kernel will write to both consoles if the serial terminal is powered on at boot time.

If you want the serial console output to start even earlier in the boot process, use the "uart" form of the console parameter.  For example,
 

     append="console=uart8250,io,0x3f8,38400N8 console=tty0"

Here, 0x3f8 is the I/O address of the serial port.  The early console will switch automatically to the ttyS0 device as soon as enough kernel initialization has taken place for it to work.  If you use the above form for a serial console, even the very first kernel boot messages will be displayed on the console.

If your init system is systemd, be advised that systemd, for the most part, will only write its boot messages to the VGA console.  On my system, "loop: module loaded" is the last kernel boot message displayed on the serial console.  After that, it is nothing but systemd messages on the VGA console until agetty gets launched to display a login prompt.

Boot Loader Support for a Serial Console

Some boot loaders also have support for a serial console.  The example given here is for the LILO boot loader.  If you use a different boot loader, consult your boot loader documentation to determine if and how it supports a serial console.  The LILO boot loader will normally use only the VGA console unless some configuration changes are made.  To tell the LILO boot loader to use the ASCII terminal as a console, in addition to the VGA console, add the following option to the global section of the /etc/lilo.conf file:
 

     serial="0,38400N8"

The same options are specified here as on the non-early serial console kernel boot parameter, except that the leading "ttyS" is omitted.  Only the traditional text-mode interface (install=text) is supported when LILO initializes on a serial console.  When LILO initializes on a serial console, pressing the Shift key on the serial console does not interrupt the delay timer and cause a "boot:" prompt to be displayed, as it does on the VGA console.  When LILO initializes on a serial console, press the Break key on the serial console to interrupt the delay timer and cause a "boot:" prompt to be displayed.  (On an IBM 3151 terminal, Break is Ctrl+Hold.)  Other than that, interacting with LILO on a serial console is identical to interacting with LILO using the traditional text-mode interface on a VGA console.

When using LILO on a serial console, I like to increase the delay timer a little bit, to account for the slower response to the serial console.  I normally set delay to 60 (six seconds), instead of 40 (four seconds), when using a serial console.  Save the changes and exit the editor.

As usual, when making changes to the /etc/lilo.conf file, you must re-run lilo (with no operands) after saving the file.  The changes will then take effect on the next boot.  For more information about LILO, see my LILO web page.

Conclusion

May you receive much enjoyment using your ASCII terminal as a local terminal and/or console with Debian GNU/Linux!  If anyone has any comments, suggestions, complaints, corrections, or any other form of feedback, please drop me a line at zlinuxman (at) fastmail (dot) com.

Return to my home page