From 4670f800ec1ebc23aff98bc14dd42961fdafaff5 Mon Sep 17 00:00:00 2001 From: Bruce Evans Date: Sat, 30 Nov 1996 15:19:19 +0000 Subject: [PATCH] Fixed sloppy clearing of TS_BUSY. Don't clear it until the transmitter is completely empty. There is no interrupt for output completion, so poll for it every 10 ms after output is nearly complete. Now ttywait() works right. Reminded by: NIST-PCTS --- sys/dev/sio/sio.c | 36 +++++++++++++++++++++++++++++++++--- sys/i386/isa/sio.c | 36 +++++++++++++++++++++++++++++++++--- sys/isa/sio.c | 36 +++++++++++++++++++++++++++++++++--- 3 files changed, 99 insertions(+), 9 deletions(-) diff --git a/sys/dev/sio/sio.c b/sys/dev/sio/sio.c index 5cc1f6c1593e..d4125c31352a 100644 --- a/sys/dev/sio/sio.c +++ b/sys/dev/sio/sio.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * from: @(#)com.c 7.5 (Berkeley) 5/16/91 - * $Id: sio.c,v 1.150 1996/11/30 14:51:04 bde Exp $ + * $Id: sio.c,v 1.151 1996/11/30 15:03:05 bde Exp $ */ #include "opt_comconsole.h" @@ -285,6 +285,7 @@ static int espattach __P((struct isa_device *isdp, struct com_s *com, Port_t esp_port)); #endif static int sioattach __P((struct isa_device *dev)); +static timeout_t siobusycheck; static timeout_t siodtrwakeup; static void comhardclose __P((struct com_s *com)); static void siointr1 __P((struct com_s *com)); @@ -1273,6 +1274,35 @@ siowrite(dev, uio, flag) return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); } +static void +siobusycheck(chan) + void *chan; +{ + struct com_s *com; + int s; + + com = (struct com_s *)chan; + + /* + * Clear TS_BUSY if low-level output is complete. + * spl locking is sufficient because siointr1() does not set CS_BUSY. + * If siointr() clears CS_BUSY after we look at it, then we'll get + * called again. Reading the line status port outside of siointr1() + * is safe because CS_BUSY is clear so there are no output interrupts + * to lose. + */ + s = spltty(); + if (com->state & CS_BUSY) + ; /* False alarm. */ + else if ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY)) + == (LSR_TSRE | LSR_TXRDY)) { + com->tp->t_state &= ~TS_BUSY; + ttwwakeup(com->tp); + } else + timeout(siobusycheck, com, hz / 100); + splx(s); +} + static void siodtrwakeup(chan) void *chan; @@ -1753,9 +1783,9 @@ siopoll() disable_intr(); com_events -= LOTS_OF_EVENTS; com->state &= ~CS_ODONE; - if (!(com->state & CS_BUSY)) - com->tp->t_state &= ~TS_BUSY; enable_intr(); + if (!(com->state & CS_BUSY)) + timeout(siobusycheck, com, hz / 100); (*linesw[tp->t_line].l_start)(tp); } if (incc <= 0 || !(tp->t_state & TS_ISOPEN) || diff --git a/sys/i386/isa/sio.c b/sys/i386/isa/sio.c index 5cc1f6c1593e..d4125c31352a 100644 --- a/sys/i386/isa/sio.c +++ b/sys/i386/isa/sio.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * from: @(#)com.c 7.5 (Berkeley) 5/16/91 - * $Id: sio.c,v 1.150 1996/11/30 14:51:04 bde Exp $ + * $Id: sio.c,v 1.151 1996/11/30 15:03:05 bde Exp $ */ #include "opt_comconsole.h" @@ -285,6 +285,7 @@ static int espattach __P((struct isa_device *isdp, struct com_s *com, Port_t esp_port)); #endif static int sioattach __P((struct isa_device *dev)); +static timeout_t siobusycheck; static timeout_t siodtrwakeup; static void comhardclose __P((struct com_s *com)); static void siointr1 __P((struct com_s *com)); @@ -1273,6 +1274,35 @@ siowrite(dev, uio, flag) return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); } +static void +siobusycheck(chan) + void *chan; +{ + struct com_s *com; + int s; + + com = (struct com_s *)chan; + + /* + * Clear TS_BUSY if low-level output is complete. + * spl locking is sufficient because siointr1() does not set CS_BUSY. + * If siointr() clears CS_BUSY after we look at it, then we'll get + * called again. Reading the line status port outside of siointr1() + * is safe because CS_BUSY is clear so there are no output interrupts + * to lose. + */ + s = spltty(); + if (com->state & CS_BUSY) + ; /* False alarm. */ + else if ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY)) + == (LSR_TSRE | LSR_TXRDY)) { + com->tp->t_state &= ~TS_BUSY; + ttwwakeup(com->tp); + } else + timeout(siobusycheck, com, hz / 100); + splx(s); +} + static void siodtrwakeup(chan) void *chan; @@ -1753,9 +1783,9 @@ siopoll() disable_intr(); com_events -= LOTS_OF_EVENTS; com->state &= ~CS_ODONE; - if (!(com->state & CS_BUSY)) - com->tp->t_state &= ~TS_BUSY; enable_intr(); + if (!(com->state & CS_BUSY)) + timeout(siobusycheck, com, hz / 100); (*linesw[tp->t_line].l_start)(tp); } if (incc <= 0 || !(tp->t_state & TS_ISOPEN) || diff --git a/sys/isa/sio.c b/sys/isa/sio.c index 5cc1f6c1593e..d4125c31352a 100644 --- a/sys/isa/sio.c +++ b/sys/isa/sio.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * from: @(#)com.c 7.5 (Berkeley) 5/16/91 - * $Id: sio.c,v 1.150 1996/11/30 14:51:04 bde Exp $ + * $Id: sio.c,v 1.151 1996/11/30 15:03:05 bde Exp $ */ #include "opt_comconsole.h" @@ -285,6 +285,7 @@ static int espattach __P((struct isa_device *isdp, struct com_s *com, Port_t esp_port)); #endif static int sioattach __P((struct isa_device *dev)); +static timeout_t siobusycheck; static timeout_t siodtrwakeup; static void comhardclose __P((struct com_s *com)); static void siointr1 __P((struct com_s *com)); @@ -1273,6 +1274,35 @@ siowrite(dev, uio, flag) return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); } +static void +siobusycheck(chan) + void *chan; +{ + struct com_s *com; + int s; + + com = (struct com_s *)chan; + + /* + * Clear TS_BUSY if low-level output is complete. + * spl locking is sufficient because siointr1() does not set CS_BUSY. + * If siointr() clears CS_BUSY after we look at it, then we'll get + * called again. Reading the line status port outside of siointr1() + * is safe because CS_BUSY is clear so there are no output interrupts + * to lose. + */ + s = spltty(); + if (com->state & CS_BUSY) + ; /* False alarm. */ + else if ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY)) + == (LSR_TSRE | LSR_TXRDY)) { + com->tp->t_state &= ~TS_BUSY; + ttwwakeup(com->tp); + } else + timeout(siobusycheck, com, hz / 100); + splx(s); +} + static void siodtrwakeup(chan) void *chan; @@ -1753,9 +1783,9 @@ siopoll() disable_intr(); com_events -= LOTS_OF_EVENTS; com->state &= ~CS_ODONE; - if (!(com->state & CS_BUSY)) - com->tp->t_state &= ~TS_BUSY; enable_intr(); + if (!(com->state & CS_BUSY)) + timeout(siobusycheck, com, hz / 100); (*linesw[tp->t_line].l_start)(tp); } if (incc <= 0 || !(tp->t_state & TS_ISOPEN) ||