diff options
author | bde <bde@FreeBSD.org> | 1996-11-30 15:19:19 +0000 |
---|---|---|
committer | bde <bde@FreeBSD.org> | 1996-11-30 15:19:19 +0000 |
commit | e7c48f38709dc93cc82ecf0c18723dff1081d3a2 (patch) | |
tree | 10c5d0f7e69c68a56584b6e87b216fefc6716719 /sys/dev | |
parent | b456a837431d11e8e18e95fac35dcdd5be585577 (diff) | |
download | FreeBSD-src-e7c48f38709dc93cc82ecf0c18723dff1081d3a2.zip FreeBSD-src-e7c48f38709dc93cc82ecf0c18723dff1081d3a2.tar.gz |
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
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/sio/sio.c | 36 |
1 files changed, 33 insertions, 3 deletions
diff --git a/sys/dev/sio/sio.c b/sys/dev/sio/sio.c index 5cc1f6c..d4125c3 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)); @@ -1274,6 +1275,35 @@ siowrite(dev, 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 @@ repeat: 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) || |