summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorscw <scw@NetBSD.org>1999-02-21 14:01:50 +0000
committerscw <scw@NetBSD.org>1999-02-21 14:01:50 +0000
commitfc658e2d3e491eb36a64b0bdbd705104f6324c3f (patch)
tree1b4f0e821a83c7bc91ec1e9e65b679548b146df7 /sys/dev
parent6312ec9ab7832ea7f2bf36e2726bc57be5d09363 (diff)
Don't update the CORx registers unless they really have changed.
Also make console Tx handling wait until the Tx FIFO has drained and the shift-register is empty before sending console characters.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/ic/clmpcc.c92
1 files changed, 73 insertions, 19 deletions
diff --git a/sys/dev/ic/clmpcc.c b/sys/dev/ic/clmpcc.c
index bf94bbd2997..9622b45dbae 100644
--- a/sys/dev/ic/clmpcc.c
+++ b/sys/dev/ic/clmpcc.c
@@ -1,4 +1,4 @@
-/* $NetBSD: clmpcc.c,v 1.3 1999/02/20 16:23:39 scw Exp $ */
+/* $NetBSD: clmpcc.c,v 1.4 1999/02/21 14:01:50 scw Exp $ */
/*-
* Copyright (c) 1999 The NetBSD Foundation, Inc.
@@ -938,30 +938,60 @@ clmpcc_set_params(ch)
struct clmpcc_chan *ch;
{
struct clmpcc_softc *sc = ch->ch_sc;
- u_char cor;
+ u_char r1;
+ u_char r2;
if ( ch->ch_tcor && ch->ch_tbpr ) {
- clmpcc_wrreg(sc, CLMPCC_REG_TCOR, ch->ch_tcor);
- clmpcc_wrreg(sc, CLMPCC_REG_TBPR, ch->ch_tbpr);
+ r1 = clmpcc_rdreg(sc, CLMPCC_REG_TCOR);
+ r2 = clmpcc_rdreg(sc, CLMPCC_REG_TBPR);
+ /* Only write Tx rate if it really has changed */
+ if ( ch->ch_tcor != r1 || ch->ch_tbpr != r2 ) {
+ clmpcc_wrreg(sc, CLMPCC_REG_TCOR, ch->ch_tcor);
+ clmpcc_wrreg(sc, CLMPCC_REG_TBPR, ch->ch_tbpr);
+ }
}
if ( ch->ch_rcor && ch->ch_rbpr ) {
- clmpcc_wrreg(sc, CLMPCC_REG_RCOR, ch->ch_rcor);
- clmpcc_wrreg(sc, CLMPCC_REG_RBPR, ch->ch_rbpr);
+ r1 = clmpcc_rdreg(sc, CLMPCC_REG_RCOR);
+ r2 = clmpcc_rdreg(sc, CLMPCC_REG_RBPR);
+ /* Only write Rx rate if it really has changed */
+ if ( ch->ch_rcor != r1 || ch->ch_rbpr != r2 ) {
+ clmpcc_wrreg(sc, CLMPCC_REG_RCOR, ch->ch_rcor);
+ clmpcc_wrreg(sc, CLMPCC_REG_RBPR, ch->ch_rbpr);
+ }
+ }
+
+ if ( clmpcc_rdreg(sc, CLMPCC_REG_COR1) != ch->ch_cor1 ) {
+ clmpcc_wrreg(sc, CLMPCC_REG_COR1, ch->ch_cor1);
+ /* Any change to COR1 requires an INIT command */
+ SET(ch->ch_flags, CLMPCC_FLG_NEED_INIT);
}
- clmpcc_wrreg(sc, CLMPCC_REG_COR1, ch->ch_cor1);
- clmpcc_wrreg(sc, CLMPCC_REG_COR2, ch->ch_cor2);
- clmpcc_wrreg(sc, CLMPCC_REG_COR3, ch->ch_cor3);
+ if ( clmpcc_rdreg(sc, CLMPCC_REG_COR2) != ch->ch_cor2 )
+ clmpcc_wrreg(sc, CLMPCC_REG_COR2, ch->ch_cor2);
- cor = clmpcc_rdreg(sc, CLMPCC_REG_COR4);
- clmpcc_wrreg(sc, CLMPCC_REG_COR4, cor & CLMPCC_COR4_FIFO_MASK);
- cor = clmpcc_rdreg(sc, CLMPCC_REG_IER);
- clmpcc_wrreg(sc, CLMPCC_REG_IER, cor & ~CLMPCC_IER_RET);
- SET(ch->ch_flags, CLMPCC_FLG_FIFO_CLEAR);
+ if ( clmpcc_rdreg(sc, CLMPCC_REG_COR3) != ch->ch_cor3 )
+ clmpcc_wrreg(sc, CLMPCC_REG_COR3, ch->ch_cor3);
+
+ r1 = clmpcc_rdreg(sc, CLMPCC_REG_COR4);
+ if ( ch->ch_cor4 != (r1 & CLMPCC_COR4_FIFO_MASK) ) {
+ /*
+ * Note: If the Rx FIFO has changed, we always set it to
+ * zero here and disable the Receive Timeout interrupt.
+ * It's up to the Rx Interrupt handler to pick the
+ * appropriate moment to write the Rx FIFO length.
+ */
+ clmpcc_wrreg(sc, CLMPCC_REG_COR4, r1 & ~CLMPCC_COR4_FIFO_MASK);
+ r1 = clmpcc_rdreg(sc, CLMPCC_REG_IER);
+ clmpcc_wrreg(sc, CLMPCC_REG_IER, r1 & ~CLMPCC_IER_RET);
+ SET(ch->ch_flags, CLMPCC_FLG_FIFO_CLEAR);
+ }
- cor = clmpcc_rdreg(sc, CLMPCC_REG_COR5) & ~CLMPCC_COR5_FLOW_MASK;
- clmpcc_wrreg(sc, CLMPCC_REG_COR5, cor | ch->ch_cor5);
+ r1 = clmpcc_rdreg(sc, CLMPCC_REG_COR5);
+ if ( ch->ch_cor5 != (r1 & CLMPCC_COR5_FLOW_MASK) ) {
+ r1 &= ~CLMPCC_COR5_FLOW_MASK;
+ clmpcc_wrreg(sc, CLMPCC_REG_COR5, r1 | ch->ch_cor5);
+ }
}
static void
@@ -1212,7 +1242,6 @@ clmpcc_txintr(arg)
if ( ISSET(ch->ch_flags, CLMPCC_FLG_UPDATE_PARMS) ) {
clmpcc_set_params(ch);
CLR(ch->ch_flags, CLMPCC_FLG_UPDATE_PARMS);
- SET(ch->ch_flags, CLMPCC_FLG_NEED_INIT);
SET(ch->ch_flags, CLMPCC_FLG_START);
goto tx_done;
}
@@ -1362,6 +1391,14 @@ clmpcc_softintr(arg)
CLR(ch->ch_flags, CLMPCC_FLG_NEED_INIT);
/*
+ * Allow time for the channel to initialise.
+ * (Empirically derived duration; the must be
+ * another way to determine the command
+ * has completed without busy-waiting...)
+ */
+ delay(800);
+
+ /*
* Update the tty layer's idea of the carrier bit,
* in case we changed CLOCAL or MDMBUF. We don't
* hang up here; we only do that by explicit request.
@@ -1412,6 +1449,7 @@ clmpcc_common_getc(sc, chan)
s = splhigh();
+ /* Save the currently active channel */
old_chan = clmpcc_select_channel(sc, chan);
/*
@@ -1461,6 +1499,7 @@ clmpcc_common_getc(sc, chan)
}
}
+ /* Restore the original IER and CAR register contents */
clmpcc_wrreg(sc, CLMPCC_REG_IER, old_ier);
clmpcc_select_channel(sc, old_chan);
@@ -1478,17 +1517,32 @@ clmpcc_common_putc(sc, chan, c)
u_char old_chan;
int s = splhigh();
+ /* Save the currently active channel */
old_chan = clmpcc_select_channel(sc, chan);
+ /*
+ * We wait here until the Tx FIFO is empty, and
+ * the chip signifies that the Tx output is idle.
+ */
+ while ((clmpcc_rdreg(sc,CLMPCC_REG_TISR) & CLMPCC_TISR_TX_EMPTY) ==0 &&
+ (clmpcc_rdreg(sc,CLMPCC_REG_TFTC) & CLMPCC_TFTC_MASK) != 0 )
+ ; /* Do nothing */
+
+ /*
+ * Since we can only access the Tx Data register from within
+ * the interrupt handler, the easiest way to get console data
+ * onto the wire is using one of the Special Transmit Character
+ * registers.
+ */
clmpcc_wrreg(sc, CLMPCC_REG_SCHR4, c);
clmpcc_wrreg(sc, CLMPCC_REG_STCR, CLMPCC_STCR_SSPC(4) |
CLMPCC_STCR_SND_SPC);
+ /* Wait until the "Send Special Character" command is accepted */
while ( clmpcc_rdreg(sc, CLMPCC_REG_STCR) != 0 )
;
- delay(5);
-
+ /* Restore the previous channel selected */
clmpcc_select_channel(sc, old_chan);
splx(s);