Subject: bug in /sys/arch/i386/isa/com.c:1.31.2.4: discards output bytes

From: John Kohl <[email-masked]>

I sent this last week, but it never arrived back in my mailbox, and I
consider it important enough to spread the word.

>Number:         458
>Category:       port-i386
>Synopsis:       com.c will discard in-transit FIFO data if tcsetattr() invoked
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    gnats-admin (GNATS administrator)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Mon Sep  5 13:05:03 1994
>Originator:     John Kohl
>Organization:
"MIT SIPB"
>Release:        1.0_BETA
>Environment:
	NetBSD 1.0_BETA i386 (-current)
System: NetBSD kolvir 1.0_BETA NetBSD 1.0_BETA (KOLVIR) #42: Mon Sep 5 13:18:51 EDT 1994 jtk@kolvir:/local/usr/src/local/NetBSD/src/sys/arch/i386/compile/KOLVIR i386

>Description:
	The serial line COM code can destroy in-transit FIFO data if
comparam() is invoked to set some parameters.  This can cause UUCP to fail
in mysterious ways, and probably causes other programs some problems.

>How-To-Repeat:
	Open a com port with a FIFO, shove data down it, then do
something to affect the hardware (e.g. toggle CRTSCTS).  Note that the
receiver doesn't get all the in-transit bytes.

>Fix:
	The problem lies in the FIFO reset code inside comparam().
There's no need to adjust the FIFO trigger level unless the baud rate is
being changed.

The patch below includes a reinstatement of the FIFO trigger
initialization in comopen(); otherwise the trigger level would not be
set until the baud rate is changed from the default baud rate.  [This
code was removed when the trigger level stuff was moved to comparam()]

The patch is relative to:
!  *	$Id: com.c,v 1.31.2.4 1994/08/24 07:29:42 mycroft Exp $

*** 1.1	1994/09/05 15:15:28
--- com.c	1994/09/05 17:24:23
***************
*** 297,302 ****
--- 297,308 ----
  
  		iobase = sc->sc_iobase;
  		/* flush any pending I/O */
+ 		if (sc->sc_hwflags & COM_HW_FIFO)
+ 			outb(iobase + com_fifo,
+ 			    FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST |
+ 			    FIFO_TRIGGER_8);
+ 		/* The FIFO trigger level is adjusted when speed
+                    changes, see below */
  		(void) inb(iobase + com_lsr);
  		(void) inb(iobase + com_data);
  		/* you turn me on, baby */
***************
*** 555,562 ****
  
  	s = spltty();
  
! 	/* Set the FIFO threshold based on the receive speed. */
! 	if (sc->sc_hwflags & COM_HW_FIFO)
  		outb(iobase + com_fifo,
  		    FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST |
  		    (t->c_ispeed <= 1200 ? FIFO_TRIGGER_1 : FIFO_TRIGGER_8));
--- 561,570 ----
  
  	s = spltty();
  
! 	/* Set the FIFO threshold based on the receive speed, but only
! 	   if we're changing speed (otherwise we may destroy
! 	   in-transit characters). */
! 	if (tp->t_ospeed != t->c_ospeed && (sc->sc_hwflags & COM_HW_FIFO))
  		outb(iobase + com_fifo,
  		     FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST |
  		    (t->c_ispeed <= 1200 ? FIFO_TRIGGER_1 : FIFO_TRIGGER_8));