[net.unix] ioctl question - IMPORTANT - READ THIS

guy@sun.uucp (Guy Harris) (08/10/85)

Everybody should read this; it contains a brief summary of the two main
terminal drivers out there - V7 (of which 4.xBSD is a derivative) and S3/S5.
With any luck this will answer all questions on this topic that would
otherwise have been posted to the net - at least for the next few months.

> Everything seems to work except for a few ioctl system calls in the
> main routine.

(Which, BTW, is nice to hear after all the flaming about incompatibilities
between V7/4.xBSD and S3/S5 systems; see, it doesn't *have* to be that
bad...)

> I changed tchars to termio structs.  Also, I had to change TIOCGETs to
> TCGETs, TIOCSETs to TCSETs. The problem I'm having is with the TIOCSETN
> call - this call returns -1 and I can't seem to track the problem down.

TIOCSETP waits till any queued-up output drains, flushes any queued-up
input, and sets the modes.  TIOCSETN doesn't wait for the output to drain or
flush the input.  You have to convert TIOCSETN to TCSETA, just as you
convert TIOCSETP to TCSETAF (not TCSETA - TCSETA neither waits nor flushes,
TCSETAW waits but doesn't flush, and TCSETAF waits and flushes - no, you
didn't stumble into net.plumbing by mistake :-)).  I presume you were
issuing TIOCSETN calls under RTU (which is S3/S5 based); they aren't
implementeded in S3/S5 systems.  TIOCGETP and TIOCSETP are implemented, but
are not compatible with V7 and should not be used.  Any TIOCGETP or TIOCSETP
calls (or any "gtty" or "stty" calls) should be converted.

The rules for "straightforward" calls:

V7/4.xBSD: TIOCGETP and TIOCGETC get the modes and some special characters,
and the rest of the special characters, respectively.  Similarly, TIOCSETP
and TIOCSETC set what the matching TIOCGETs get.  TIOC[GS]ETP uses a "struct
sgttyb", included by "sgtty.h" or "sys/ioctl.h", and TIOC[GS]ETC uses a
"struct tchars", included by one or the other of those include files.

S3/S5: TCGETA and TCSETA get and set all the modes and special characters,
respectively.  They use a "struct termio" included by "termio.h".

The items you can set and get are:

1) Baud rates.  The names for the baud rates are the same (B1200, B2400,
B9600, etc.).  In the "sgttyb" structure, there are two speeds - one for
input and one for output.  They are in "sg_ispeed" and "sg_ospeed".  In the
"termio" structure, they are part of the "c_cflag" word.  The bit mask for
the baud rate portion is CBAUD, so the baud rate is "c_cflag&CBAUD".  You
set the baud rate by doing "c_cflag &= ~CBAUD" and then ORing in the baud
rate.

2) Special characters.  The erase and kill characters are in the "sgttyb"
structure in "sg_erase" and "sg_kill".  The other characters are in the
"tchars" structure: interrupt in "t_intrc", the quit character in "t_quitc",
the end-of-file character in "t_eofc", and the "secondary EOL character" in
"t_brkc".  There is an array "c_cc" in the "termio" structure which holds
all the special characters.  The #defines for the indices into this array
are:

	VERASE		erase character
	VKILL		kill character
	VINTR		interrupt character
	VQUIT		quit character
	VEOF		end-of-file character
	VEOL		"secondary EOL character"

3) Modes.  This is the tricky part.  Instead of describing all the bits,
I'll just list common modes and how they're set in both drivers.

No-echo mode - i.e., what the user types isn't echoed by the operating
system, but is either echoed by the application (like a screen editor) or
not at all (like when typing in a password).  To go into no-echo mode in the
V7 driver, clear the ECHO bit in the "sg_flags" word.  To go into no-echo
mode in the S3/S5 driver, clear the ECHO bit in the "c_lflag" word.

Carriage-return/new-line mapping.  To turn on mapping of CR to NL on input,
and NL to CR/LF on output, turn on the CRMOD bit in the "sg_flags" word in
V7, and turn on:

	the ICRNL bit in the "c_iflag" word
	the OPOST and ONLCR bits in the "c_oflag" word

in the S3/S5 driver.  To turn this mapping off, turn off the CRMOD bit in
the V7 driver, and turn off ICRNL and ONLCR, but *not* necessarily OPOST, in
S3/S5.

Case-mapping (for those of you with 19th century upper-case-only terminals).
To turn case-mappng on, turn on the LCASE bit in the "sg_flags" word in V7,
and turn on:

	the IUCLC bit in the "c_iflag" word
	the OPOST and OLCUC bit in the "c_oflag" word
	the XCASE bit in the "c_lflag" word

in S3/S5.  To turn it off, turn LCASE off in V7, and turn IUCLC, OLCUC, and
XCASE, but again *not* necessarily OPOST, in S3/S5.

Tab-expansion.  To turn off tab expansion, select any "tab delay" value
(which is stored in part of the "sg_flags" word in V7 and part of the
"c_oflag" word in S3/S5) other than XTABS in V7 and other than TAB3 in
S3/S5.   To turn tab expansion on, select XTABS in V7 and select TAB3 and
turn on OPOST in S3/S5.

Turning off *all* output processing - used, for example, when you're running
a full-screen application and want every character you output to go to the
terminal as is.  You have to turn LCASE, CRMOD, and tab-expansion and
(possibly) delays off individually in V7.  You can just turn off OPOST in
the "c_oflag" word in S3/S5 - in fact, this is the way it should be done,
because it's faster than turning off the individual mappings and delays.

Turning off the interrupt characters.  Set them to '\377' in V7; you can
also do this in S3/S5, but a better way to do it is to turn off the ISIG bit
in the "c_lflag" word.

Turning off erase/kill handling and getting each character as type - the
mode that most full-screen programs, like "vi", run in.  To do this, just
turn on the CBREAK bit in the "sg_flags" word in V7.  Turn *off* the ICANON
bit in the "c_lflag" word in S3/S5.  You should also save the values of the
VEOF and VEOL characters (but then you're probably saving the whole mode
structure anyway), because they change their meanings if ICANON is turned
off, and their old values cause problems.  Set "c_cc[VMIN]" to 1 and
"c_cc[VTIME]" to 0.  (Other values may be more efficient, but this is just
as good as V7's and is nice and simple.)

Getting 8-bit raw data, such as when talking to another computer.  To do
this just turn on the RAW bit in the "sg_flags" word in V7.  It's more
complicated in S3/S5.  First, save the "termio" structure if you plan to
restore the modes; it's simpler that way.  Then:

	clear the ISTRIP, INLCR, IGNCR, ICRNL, IUCLC, and IXON bits
	in the "c_iflag" word.  (If you don't want "break"s to interrupt
	you, turn off BRKINT as well.)

	clear the OPOST bit in the "c_oflag" word.

	clear the "character size" portion of the "c_cflag" word, as
	well as the PARENB and PARODD bits (i.e., do an & ~flags with
	"flags" equal to CSIZE|PARENB|PARODD) and OR in CS8 (to request
	8 bits per character and no parity bit).

	clear the ISIG, ICANON, and XCASE bits in the "c_lflag" word.
	Also set VMIN to 1 and VTIME to 0.

	Guy Harris