Subject: Re: kern/1042: Some serial cards hang on first open if data is in FIFO
To: None <gnats-admin@sun-lamp.cs.berkeley.edu, netbsd-bugs@NetBSD.ORG>
From: Scott Reynolds <scottr@Plexus.COM>
List: netbsd-bugs
Date: 07/06/1995 15:16:57
Here's an updated version of my patch to deal with some SMC brain 
damage.  The SMC 37C665 is included on at least a few Micronics boards.  
This patch doesn't break on a real 16550, and leaves the default behavior 
for UARTs that don't have multiple-byte FIFOs.

--scott

*** com.c	1995/07/06 16:23:49	1.4
--- com.c	1995/07/06 20:13:41
***************
*** 310,324 ****
  		sc->sc_ibufhigh = sc->sc_ibuf + COM_IHIGHWATER;
  		sc->sc_ibufend = sc->sc_ibuf + COM_IBUFSIZE;
  
- 		iobase = sc->sc_iobase;
- 		/* 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 |
- 			    (tp->t_ispeed <= 1200 ? FIFO_TRIGGER_1 : FIFO_TRIGGER_8));
  		/* flush any pending I/O */
! 		while (inb(iobase + com_lsr) & LSR_RXRDY)
! 			(void) inb(iobase + com_data);
  		/* you turn me on, baby */
  		sc->sc_mcr = MCR_DTR | MCR_RTS;
  		if ((sc->sc_hwflags & COM_HW_NOIEN) == 0)
--- 310,338 ----
  		sc->sc_ibufhigh = sc->sc_ibuf + COM_IHIGHWATER;
  		sc->sc_ibufend = sc->sc_ibuf + COM_IBUFSIZE;
  
  		/* flush any pending I/O */
! 		iobase = sc->sc_iobase;
! 		if (sc->sc_hwflags & COM_HW_FIFO) {
! 			/*
! 			 * Drain FIFOs this way to deal with certain SMC
! 			 * chips, otherwise we'll hang hard on the splx()
! 			 * just before returning.  Works with real 16550s
! 			 * as well.
! 			 */
! 			for (;;) {
! 				outb(iobase + com_fifo,
! 				    FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST |
! 				    (tp->t_ispeed <= 1200 ? FIFO_TRIGGER_1 : FIFO_TRIGGER_8));
! 				delay(100);
! 				if ((inb(iobase + com_lsr) & LSR_RXRDY) == 0)
! 					break;
! 				outb(iobase + com_fifo, 0);
! 				delay(100);
! 				(void) inb(iobase + com_data);
! 			}
! 		} else
! 			while (inb(iobase + com_lsr) & LSR_RXRDY)
! 				(void) inb(iobase + com_data);
  		/* you turn me on, baby */
  		sc->sc_mcr = MCR_DTR | MCR_RTS;
  		if ((sc->sc_hwflags & COM_HW_NOIEN) == 0)