Subject: REAL Fix: more/vi on serial port
To: None <netbsd-bugs@sun-lamp.cs.berkeley.edu>
From: Mark Sienkiewicz <mark@roissy.umd.edu>
List: netbsd-bugs
Date: 04/12/1994 11:01:59
A while back I posted a hack that fixes the "more/vi screws up on serial 
port" bug.  It was a quick and dirty fix that I wrote while I went 
looking for the right fix.  It turns out that it wasn't that hard to find.

The problem is in sys/kern/tty_compat.c, where it is trying to take old
style ioctls() [ V6, V7, 4.1, 4.2 ] and make termios style parameters
out of them.  It would work if you enable parity checking, but if you
tried to use no parity, it would set your serial port to have only
* seven * bits in a byte.

This is a problem because a 7 bit data path is not really transmitting 
1 start bit, 7 data bits, and 1 stop bit.  It is transmitting 1 start,
8 data, and 1 stop, then ignoring the most significant bit because the
data path may have used it for parity.

I believe this is the correct fix for two reasons:

- it does what I expected it to do (unlike the unfixed version)

- it more correctly mimics the behaviour of the older systems, in that
  those older systems always used 8 bit bytes

- I would be pleased to know of *any* example of somebody trying to
  use a 1 start, 7 data, 1 stop bit configuration. :)

Some might argue that it should be fixed in the serial port device driver,
but I think that any such fix would break true-posix attempts to *really*
use 7 bit bytes.



*** tty_compat.c.old	Fri Feb 11 10:04:01 1994
--- tty_compat.c	Fri Feb 11 10:24:19 1994
***************
*** 333,348 ****
  		cflag |= CS8;
  		if (!(flags&(RAW|PASS8)) || (flags&(RAW|PASS8|ANYP)) == (PASS8|ANYP))
  			iflag |= ISTRIP;
  		else
  			iflag &= ~ISTRIP;
  	} else {
! 		cflag |= CS7;
! 		if ((flags&(EVENP|ODDP)) && (flags&ANYP) != ANYP)
! 			cflag |= PARENB;
! 		iflag |= ISTRIP;
  	}
  	if ((flags&(EVENP|ODDP)) == EVENP) {
  		iflag |= INPCK;
  		cflag &= ~PARODD;
  	} else if ((flags&(EVENP|ODDP)) == ODDP) {
  		iflag |= INPCK;
--- 333,358 ----
  		cflag |= CS8;
  		if (!(flags&(RAW|PASS8)) || (flags&(RAW|PASS8|ANYP)) == (PASS8|ANYP))
  			iflag |= ISTRIP;
  		else
  			iflag &= ~ISTRIP;
  	} else {
! 		/*
! 		* if we have parity, we want to set the port to 7 bits + parity
! 		* but if we have no parity, we do *not* want to set the
! 		* port to [ start bit, 7 data bits, stop bit ] because this 
! 		* breaks everything (and is not compatible with _anything_).
! 		* Since V6, Unix systems used 8 data bits, and optionally 
! 		* checked or not checked the parity.
! 		*/
! 		if ((flags&(EVENP|ODDP)) && (flags&ANYP) != ANYP) {
! 			cflag |= CS7 | PARENB;
! 			iflag |= ISTRIP;
! 		} else {
! 			cflag |= CS8;
! 		}
  	}
  	if ((flags&(EVENP|ODDP)) == EVENP) {
  		iflag |= INPCK;
  		cflag &= ~PARODD;
  	} else if ((flags&(EVENP|ODDP)) == ODDP) {
  		iflag |= INPCK;
***************
*** 403,418 ****
  			oflag |= OPOST;
  		if (!(flags&(RAW|PASS8)) || (flags&(RAW|PASS8|ANYP)) == (PASS8|ANYP))
    			iflag |= ISTRIP;
  		else
  			iflag &= ~ISTRIP;
  	} else if ((flags&RAW) == 0) {
! 		cflag |= CS7;
! 		if ((flags&(EVENP|ODDP)) && (flags&ANYP) != ANYP)
! 			cflag |= PARENB;
! 		oflag |= ISTRIP|OPOST;
  	}
  	t->c_iflag = iflag;
  	t->c_oflag = oflag;
  	t->c_lflag = lflag;
  	t->c_cflag = cflag;
  }
--- 413,434 ----
  			oflag |= OPOST;
  		if (!(flags&(RAW|PASS8)) || (flags&(RAW|PASS8|ANYP)) == (PASS8|ANYP))
    			iflag |= ISTRIP;
  		else
  			iflag &= ~ISTRIP;
  	} else if ((flags&RAW) == 0) {
! 		/*
! 		* see comment in ttcompatsetflags() near CS7
! 		*/
! 		if ((flags&(EVENP|ODDP)) && (flags&ANYP) != ANYP) {
! 			cflag |= CS7 | PARENB;
! 			iflag |= ISTRIP;
! 		} else {
! 			cflag |= CS8;
! 		}
! 		oflag |= OPOST;
  	}
  	t->c_iflag = iflag;
  	t->c_oflag = oflag;
  	t->c_lflag = lflag;
  	t->c_cflag = cflag;
  }




------------------------------------------------------------------------------