summaryrefslogtreecommitdiffstats
path: root/sys/dev/cy
diff options
context:
space:
mode:
authorbde <bde@FreeBSD.org>1998-11-28 15:48:09 +0000
committerbde <bde@FreeBSD.org>1998-11-28 15:48:09 +0000
commit9eb948517872cbf893bb6f18d88ff5016b9fd899 (patch)
tree16181d084c0ce8b208d77eb276724f01c1c1062a /sys/dev/cy
parent8f11507158b1ddd01885cc36b8da7e9f3e076721 (diff)
downloadFreeBSD-src-9eb948517872cbf893bb6f18d88ff5016b9fd899.zip
FreeBSD-src-9eb948517872cbf893bb6f18d88ff5016b9fd899.tar.gz
Fixed sloppy clearing of TS_BUSY. Don't clear it until the transmitter
is completely empty. There is an interrupt for output completion. It is painful to use, but polling method used in the corresponding fix in sio.c (rev.1.152) can't be used because there is no status bit for transmitter-empty. Now ttywait() works right. Reminded by: NIST-PCTS
Diffstat (limited to 'sys/dev/cy')
-rw-r--r--sys/dev/cy/cy.c83
-rw-r--r--sys/dev/cy/cy_isa.c83
2 files changed, 142 insertions, 24 deletions
diff --git a/sys/dev/cy/cy.c b/sys/dev/cy/cy.c
index 6e810c0..d85b90c 100644
--- a/sys/dev/cy/cy.c
+++ b/sys/dev/cy/cy.c
@@ -27,7 +27,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: cy.c,v 1.74 1998/11/23 13:58:55 bde Exp $
+ * $Id: cy.c,v 1.75 1998/11/28 13:18:16 bde Exp $
*/
#include "opt_compat.h"
@@ -200,6 +200,7 @@
#define CS_DTR_OFF 0x10 /* DTR held off */
#define CS_ODONE 4 /* output completed */
#define CS_RTS_IFLOW 8 /* use RTS input flow control */
+#define CSE_ODONE 1 /* output transmitted */
static char const * const error_desc[] = {
#define CE_OVERRUN 0
@@ -231,6 +232,9 @@ struct com_s {
bool_t active_out; /* nonzero if the callout device is open */
#if 0
u_char cfcr_image; /* copy of value written to CFCR */
+#endif
+ u_char extra_state; /* more flag bits, separate for order trick */
+#if 0
u_char fifo_image; /* copy of value written to FIFO */
#endif
u_char gfrcr_image; /* copy of value read from GFRCR */
@@ -1280,7 +1284,9 @@ cont:
cd_outb(iobase, CD1400_SRER,
cy_align,
com->intr_enable
- |= CD1400_SRER_TXRDY);
+ = com->intr_enable
+ & ~CD1400_SRER_TXMPTY
+ | CD1400_SRER_TXRDY);
} else {
com->state &= ~CS_ODEVREADY;
if (com->intr_enable
@@ -1288,7 +1294,9 @@ cont:
cd_outb(iobase, CD1400_SRER,
cy_align,
com->intr_enable
- &= ~CD1400_SRER_TXRDY);
+ = com->intr_enable
+ & ~CD1400_SRER_TXRDY
+ | CD1400_SRER_TXMPTY);
}
}
#endif
@@ -1331,6 +1339,17 @@ cont:
& CD1400_xIVR_CHAN));
#endif
+ if (com->intr_enable & CD1400_SRER_TXMPTY) {
+ if (!(com->extra_state & CSE_ODONE)) {
+ com_events += LOTS_OF_EVENTS;
+ com->extra_state |= CSE_ODONE;
+ setsofttty();
+ }
+ cd_outb(iobase, CD1400_SRER, cy_align,
+ com->intr_enable
+ &= ~CD1400_SRER_TXMPTY);
+ goto terminate_tx_service;
+ }
if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) {
u_char *ioptr;
u_int ocount;
@@ -1358,9 +1377,24 @@ cont:
} else {
/* output just completed */
com->state &= ~CS_BUSY;
+
+ /*
+ * The setting of CSE_ODONE may be
+ * stale here. We currently only
+ * use it when CS_BUSY is set, and
+ * fixing it when we clear CS_BUSY
+ * is easiest.
+ */
+ if (com->extra_state & CSE_ODONE) {
+ com_events -= LOTS_OF_EVENTS;
+ com->extra_state &= ~CSE_ODONE;
+ }
+
cd_outb(iobase, CD1400_SRER, cy_align,
com->intr_enable
- &= ~CD1400_SRER_TXRDY);
+ = com->intr_enable
+ & ~CD1400_SRER_TXRDY
+ | CD1400_SRER_TXMPTY);
}
if (!(com->state & CS_ODONE)) {
com_events += LOTS_OF_EVENTS;
@@ -1373,6 +1407,7 @@ cont:
}
/* terminate service context */
+terminate_tx_service:
#ifdef PollMode
cd_outb(iobase, CD1400_TIR, cy_align,
save_tir
@@ -1651,11 +1686,19 @@ 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();
(*linesw[tp->t_line].l_start)(tp);
}
+ if (com->extra_state & CSE_ODONE) {
+ disable_intr();
+ com_events -= LOTS_OF_EVENTS;
+ com->extra_state &= ~CSE_ODONE;
+ enable_intr();
+ if (!(com->state & CS_BUSY)) {
+ tp->t_state &= ~TS_BUSY;
+ ttwwakeup(com->tp);
+ }
+ }
if (incc <= 0 || !(tp->t_state & TS_ISOPEN))
continue;
/*
@@ -2049,11 +2092,15 @@ comparam(tp, t)
if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) {
if (!(com->intr_enable & CD1400_SRER_TXRDY))
cd_setreg(com, CD1400_SRER,
- com->intr_enable |= CD1400_SRER_TXRDY);
+ com->intr_enable
+ = com->intr_enable & ~CD1400_SRER_TXMPTY
+ | CD1400_SRER_TXRDY);
} else {
if (com->intr_enable & CD1400_SRER_TXRDY)
cd_setreg(com, CD1400_SRER,
- com->intr_enable &= ~CD1400_SRER_TXRDY);
+ com->intr_enable
+ = com->intr_enable & ~CD1400_SRER_TXRDY
+ | CD1400_SRER_TXMPTY);
}
enable_intr();
@@ -2087,13 +2134,17 @@ comstart(tp)
com->state &= ~CS_TTGO;
if (com->intr_enable & CD1400_SRER_TXRDY)
cd_setreg(com, CD1400_SRER,
- com->intr_enable &= ~CD1400_SRER_TXRDY);
+ com->intr_enable
+ = com->intr_enable & ~CD1400_SRER_TXRDY
+ | CD1400_SRER_TXMPTY);
} else {
com->state |= CS_TTGO;
if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)
&& !(com->intr_enable & CD1400_SRER_TXRDY))
cd_setreg(com, CD1400_SRER,
- com->intr_enable |= CD1400_SRER_TXRDY);
+ com->intr_enable
+ = com->intr_enable & ~CD1400_SRER_TXMPTY
+ | CD1400_SRER_TXRDY);
}
if (tp->t_state & TS_TBLOCK) {
if (com->mcr_image & com->mcr_rts && com->state & CS_RTS_IFLOW)
@@ -2148,7 +2199,9 @@ comstart(tp)
| CS_ODEVREADY))
cd_setreg(com, CD1400_SRER,
com->intr_enable
- |= CD1400_SRER_TXRDY);
+ = com->intr_enable
+ & ~CD1400_SRER_TXMPTY
+ | CD1400_SRER_TXRDY);
}
enable_intr();
}
@@ -2176,7 +2229,9 @@ comstart(tp)
| CS_ODEVREADY))
cd_setreg(com, CD1400_SRER,
com->intr_enable
- |= CD1400_SRER_TXRDY);
+ = com->intr_enable
+ & ~CD1400_SRER_TXMPTY
+ | CD1400_SRER_TXRDY);
}
enable_intr();
}
@@ -2211,6 +2266,10 @@ siostop(tp, rw)
if (com->state & CS_ODONE)
com_events -= LOTS_OF_EVENTS;
com->state &= ~(CS_ODONE | CS_BUSY);
+ if (com->extra_state & CSE_ODONE) {
+ com_events -= LOTS_OF_EVENTS;
+ com->extra_state &= ~CSE_ODONE;
+ }
com->tp->t_state &= ~TS_BUSY;
}
if (rw & FREAD) {
diff --git a/sys/dev/cy/cy_isa.c b/sys/dev/cy/cy_isa.c
index 6e810c0..d85b90c 100644
--- a/sys/dev/cy/cy_isa.c
+++ b/sys/dev/cy/cy_isa.c
@@ -27,7 +27,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: cy.c,v 1.74 1998/11/23 13:58:55 bde Exp $
+ * $Id: cy.c,v 1.75 1998/11/28 13:18:16 bde Exp $
*/
#include "opt_compat.h"
@@ -200,6 +200,7 @@
#define CS_DTR_OFF 0x10 /* DTR held off */
#define CS_ODONE 4 /* output completed */
#define CS_RTS_IFLOW 8 /* use RTS input flow control */
+#define CSE_ODONE 1 /* output transmitted */
static char const * const error_desc[] = {
#define CE_OVERRUN 0
@@ -231,6 +232,9 @@ struct com_s {
bool_t active_out; /* nonzero if the callout device is open */
#if 0
u_char cfcr_image; /* copy of value written to CFCR */
+#endif
+ u_char extra_state; /* more flag bits, separate for order trick */
+#if 0
u_char fifo_image; /* copy of value written to FIFO */
#endif
u_char gfrcr_image; /* copy of value read from GFRCR */
@@ -1280,7 +1284,9 @@ cont:
cd_outb(iobase, CD1400_SRER,
cy_align,
com->intr_enable
- |= CD1400_SRER_TXRDY);
+ = com->intr_enable
+ & ~CD1400_SRER_TXMPTY
+ | CD1400_SRER_TXRDY);
} else {
com->state &= ~CS_ODEVREADY;
if (com->intr_enable
@@ -1288,7 +1294,9 @@ cont:
cd_outb(iobase, CD1400_SRER,
cy_align,
com->intr_enable
- &= ~CD1400_SRER_TXRDY);
+ = com->intr_enable
+ & ~CD1400_SRER_TXRDY
+ | CD1400_SRER_TXMPTY);
}
}
#endif
@@ -1331,6 +1339,17 @@ cont:
& CD1400_xIVR_CHAN));
#endif
+ if (com->intr_enable & CD1400_SRER_TXMPTY) {
+ if (!(com->extra_state & CSE_ODONE)) {
+ com_events += LOTS_OF_EVENTS;
+ com->extra_state |= CSE_ODONE;
+ setsofttty();
+ }
+ cd_outb(iobase, CD1400_SRER, cy_align,
+ com->intr_enable
+ &= ~CD1400_SRER_TXMPTY);
+ goto terminate_tx_service;
+ }
if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) {
u_char *ioptr;
u_int ocount;
@@ -1358,9 +1377,24 @@ cont:
} else {
/* output just completed */
com->state &= ~CS_BUSY;
+
+ /*
+ * The setting of CSE_ODONE may be
+ * stale here. We currently only
+ * use it when CS_BUSY is set, and
+ * fixing it when we clear CS_BUSY
+ * is easiest.
+ */
+ if (com->extra_state & CSE_ODONE) {
+ com_events -= LOTS_OF_EVENTS;
+ com->extra_state &= ~CSE_ODONE;
+ }
+
cd_outb(iobase, CD1400_SRER, cy_align,
com->intr_enable
- &= ~CD1400_SRER_TXRDY);
+ = com->intr_enable
+ & ~CD1400_SRER_TXRDY
+ | CD1400_SRER_TXMPTY);
}
if (!(com->state & CS_ODONE)) {
com_events += LOTS_OF_EVENTS;
@@ -1373,6 +1407,7 @@ cont:
}
/* terminate service context */
+terminate_tx_service:
#ifdef PollMode
cd_outb(iobase, CD1400_TIR, cy_align,
save_tir
@@ -1651,11 +1686,19 @@ 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();
(*linesw[tp->t_line].l_start)(tp);
}
+ if (com->extra_state & CSE_ODONE) {
+ disable_intr();
+ com_events -= LOTS_OF_EVENTS;
+ com->extra_state &= ~CSE_ODONE;
+ enable_intr();
+ if (!(com->state & CS_BUSY)) {
+ tp->t_state &= ~TS_BUSY;
+ ttwwakeup(com->tp);
+ }
+ }
if (incc <= 0 || !(tp->t_state & TS_ISOPEN))
continue;
/*
@@ -2049,11 +2092,15 @@ comparam(tp, t)
if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) {
if (!(com->intr_enable & CD1400_SRER_TXRDY))
cd_setreg(com, CD1400_SRER,
- com->intr_enable |= CD1400_SRER_TXRDY);
+ com->intr_enable
+ = com->intr_enable & ~CD1400_SRER_TXMPTY
+ | CD1400_SRER_TXRDY);
} else {
if (com->intr_enable & CD1400_SRER_TXRDY)
cd_setreg(com, CD1400_SRER,
- com->intr_enable &= ~CD1400_SRER_TXRDY);
+ com->intr_enable
+ = com->intr_enable & ~CD1400_SRER_TXRDY
+ | CD1400_SRER_TXMPTY);
}
enable_intr();
@@ -2087,13 +2134,17 @@ comstart(tp)
com->state &= ~CS_TTGO;
if (com->intr_enable & CD1400_SRER_TXRDY)
cd_setreg(com, CD1400_SRER,
- com->intr_enable &= ~CD1400_SRER_TXRDY);
+ com->intr_enable
+ = com->intr_enable & ~CD1400_SRER_TXRDY
+ | CD1400_SRER_TXMPTY);
} else {
com->state |= CS_TTGO;
if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)
&& !(com->intr_enable & CD1400_SRER_TXRDY))
cd_setreg(com, CD1400_SRER,
- com->intr_enable |= CD1400_SRER_TXRDY);
+ com->intr_enable
+ = com->intr_enable & ~CD1400_SRER_TXMPTY
+ | CD1400_SRER_TXRDY);
}
if (tp->t_state & TS_TBLOCK) {
if (com->mcr_image & com->mcr_rts && com->state & CS_RTS_IFLOW)
@@ -2148,7 +2199,9 @@ comstart(tp)
| CS_ODEVREADY))
cd_setreg(com, CD1400_SRER,
com->intr_enable
- |= CD1400_SRER_TXRDY);
+ = com->intr_enable
+ & ~CD1400_SRER_TXMPTY
+ | CD1400_SRER_TXRDY);
}
enable_intr();
}
@@ -2176,7 +2229,9 @@ comstart(tp)
| CS_ODEVREADY))
cd_setreg(com, CD1400_SRER,
com->intr_enable
- |= CD1400_SRER_TXRDY);
+ = com->intr_enable
+ & ~CD1400_SRER_TXMPTY
+ | CD1400_SRER_TXRDY);
}
enable_intr();
}
@@ -2211,6 +2266,10 @@ siostop(tp, rw)
if (com->state & CS_ODONE)
com_events -= LOTS_OF_EVENTS;
com->state &= ~(CS_ODONE | CS_BUSY);
+ if (com->extra_state & CSE_ODONE) {
+ com_events -= LOTS_OF_EVENTS;
+ com->extra_state &= ~CSE_ODONE;
+ }
com->tp->t_state &= ~TS_BUSY;
}
if (rw & FREAD) {
OpenPOWER on IntegriCloud