summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKATO Takenori <kato@FreeBSD.org>1999-02-05 11:37:40 +0000
committerKATO Takenori <kato@FreeBSD.org>1999-02-05 11:37:40 +0000
commit533601dc35379a93943b9f516060f47a7e8438fa (patch)
tree950d9e91823c465b8e4f4d16f3312049426d10a7
parent48caee2acde01f188590b7955963f294a746f2d6 (diff)
Notes
-rw-r--r--sys/pc98/cbus/sio.c404
-rw-r--r--sys/pc98/pc98/sio.c404
2 files changed, 442 insertions, 366 deletions
diff --git a/sys/pc98/cbus/sio.c b/sys/pc98/cbus/sio.c
index 27ab00e427d4..9492ea301f86 100644
--- a/sys/pc98/cbus/sio.c
+++ b/sys/pc98/cbus/sio.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)com.c 7.5 (Berkeley) 5/16/91
- * $Id: sio.c,v 1.79 1999/01/30 12:17:37 phk Exp $
+ * $Id: sio.c,v 1.80 1999/02/02 17:26:03 kato Exp $
*/
#include "opt_comconsole.h"
@@ -205,7 +205,6 @@
#define NSIOTOT (NSIO + EXTRA_SIO)
#define LOTS_OF_EVENTS 64 /* helps separate urgent events from input */
-#define RS_IBUFSIZE 256
#define CALLOUT_MASK 0x80
#define CONTROL_MASK 0x60
@@ -243,18 +242,6 @@
#endif
/*
- * Input buffer watermarks.
- * The external device is asked to stop sending when the buffer exactly reaches
- * high water, or when the high level requests it.
- * The high level is notified immediately (rather than at a later clock tick)
- * when this watermark is reached.
- * The buffer size is chosen so the watermark should almost never be reached.
- * The low watermark is invisibly 0 since the buffer is always emptied all at
- * once.
- */
-#define RS_IHIGHWATER (3 * RS_IBUFSIZE / 4)
-
-/*
* com state bits.
* (CS_BUSY | CS_TTGO) and (CS_BUSY | CS_TTGO | CS_ODEVREADY) must be higher
* than the other bits so that they can be tested as a group without masking
@@ -343,8 +330,11 @@ struct com_s {
u_char hotchar; /* ldisc-specific char to be handled ASAP */
u_char *ibuf; /* start of input buffer */
u_char *ibufend; /* end of input buffer */
+ u_char *ibufold; /* old input buffer, to be freed */
u_char *ihighwater; /* threshold in input buffer */
u_char *iptr; /* next free spot in input buffer */
+ int ibufsize; /* size of ibuf (not include error bytes) */
+ int ierroff; /* offset of error bytes in ibuf */
struct lbq obufq; /* head of queue of output buffers */
struct lbq obufs[2]; /* output buffers */
@@ -398,29 +388,14 @@ struct com_s {
u_long error_counts[CE_NTYPES];
/*
- * Ping-pong input buffers. The extra factor of 2 in the sizes is
- * to allow for an error byte for each input byte.
- */
-#ifdef PC98
- u_long CE_INPUT_OFFSET;
- u_char *ibuf1;
- u_char *ibuf2;
-
- /*
* Data area for output buffers. Someday we should build the output
* buffer queue without copying data.
*/
+#ifdef PC98
+ int obufsize;
u_char *obuf1;
u_char *obuf2;
#else
-#define CE_INPUT_OFFSET RS_IBUFSIZE
- u_char ibuf1[2 * RS_IBUFSIZE];
- u_char ibuf2[2 * RS_IBUFSIZE];
-
- /*
- * Data area for output buffers. Someday we should build the output
- * buffer queue without copying data.
- */
u_char obuf1[256];
u_char obuf2[256];
#endif
@@ -442,6 +417,7 @@ 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 sioinput __P((struct com_s *com));
static ointhand2_t siointr;
static void siointr1 __P((struct com_s *com));
static int commctl __P((struct com_s *com, int bits, int how));
@@ -449,6 +425,7 @@ static int comparam __P((struct tty *tp, struct termios *t));
static swihand_t siopoll;
static int sioprobe __P((struct isa_device *dev));
static void siosettimeout __P((void));
+static int siosetwater __P((struct com_s *com, speed_t speed));
static void comstart __P((struct tty *tp));
static timeout_t comwakeup;
static void disc_optim __P((struct tty *tp, struct termios *t,
@@ -932,11 +909,9 @@ siounload(struct pccard_devinfo *devi)
ttwwakeup(com->tp);
} else {
com_addr(com->unit) = NULL;
-#ifdef PC98
- bzero(com->ibuf1, com->CE_INPUT_OFFSET * 6);
-#endif
- bzero(com, sizeof *com);
- free(com,M_TTYS);
+ if (com->ibuf != NULL)
+ free(com->ibuf, M_DEVBUF);
+ free(com, M_DEVBUF);
printf("sio%d: unload,gone\n", devi->isahd.id_unit);
}
}
@@ -1503,7 +1478,7 @@ sioattach(isdp)
int unit;
#ifdef PC98
int port_shift = 0;
- u_long ibufsize;
+ u_long obufsize;
#endif
isdp->id_ointr = siointr;
@@ -1516,12 +1491,12 @@ sioattach(isdp)
iobase = isdp->id_iobase;
unit = isdp->id_unit;
#ifndef PC98
- com = malloc(sizeof *com, M_TTYS, M_NOWAIT);
+ com = malloc(sizeof *com, M_DEVBUF, M_NOWAIT);
#else
- ibufsize = RS_IBUFSIZE;
+ obufsize = 256;
if (((isdp->id_flags >> 24) & 0xff) == COM_IF_RSA98III)
- ibufsize = 2048;
- com = malloc((sizeof *com) + ibufsize * 6, M_TTYS, M_NOWAIT);
+ obufsize = 2048;
+ com = malloc((sizeof *com) + obufsize * 2, M_DEVBUF, M_NOWAIT);
#endif
if (com == NULL)
return (0);
@@ -1540,12 +1515,10 @@ sioattach(isdp)
*/
bzero(com, sizeof *com);
#ifdef PC98
- com->CE_INPUT_OFFSET = ibufsize;
- com->ibuf1 = (u_char *)com + (sizeof *com);
- com->ibuf2 = com->ibuf1 + (ibufsize * 2);
- com->obuf1 = com->ibuf2 + (ibufsize * 2);
- com->obuf2 = com->obuf1 + ibufsize;
- bzero(com->ibuf1, ibufsize * 6);
+ com->obufsize = obufsize;
+ com->obuf1 = (u_char *)com + (sizeof *com);
+ com->obuf2 = com->obuf1 + obufsize;
+ bzero(com->obuf1, obufsize * 2);
#endif
com->unit = unit;
com->cfcr_image = CFCR_8BITS;
@@ -1553,14 +1526,6 @@ sioattach(isdp)
com->loses_outints = COM_LOSESOUTINTS(isdp) != 0;
com->no_irq = isdp->id_irq == 0;
com->tx_fifo_size = 1;
- com->iptr = com->ibuf = com->ibuf1;
-#ifndef PC98
- com->ibufend = com->ibuf1 + RS_IBUFSIZE;
- com->ihighwater = com->ibuf1 + RS_IHIGHWATER;
-#else
- com->ibufend = com->ibuf1 + com->CE_INPUT_OFFSET;
- com->ihighwater = com->ibuf1 + (3 * com->CE_INPUT_OFFSET / 4);
-#endif
com->obufs[0].l_head = com->obuf1;
com->obufs[1].l_head = com->obuf2;
@@ -1612,6 +1577,12 @@ sioattach(isdp)
com->it_in.c_ispeed = com->it_in.c_ospeed = comdefaultrate;
} else
com->it_in.c_ispeed = com->it_in.c_ospeed = TTYDEF_SPEED;
+ if (siosetwater(com, com->it_in.c_ispeed) != 0) {
+ enable_intr();
+ free(com, M_DEVBUF);
+ return (0);
+ }
+ enable_intr();
termioschars(&com->it_in);
com->it_out = com->it_in;
@@ -1793,7 +1764,7 @@ determined_type: ;
printf(")");
com->no_irq = find_isadev(isa_devtab_tty, &siodriver,
COM_MPMASTER(isdp))->id_irq == 0;
- }
+ }
#endif /* COM_MULTIPORT */
#ifdef PC98
}
@@ -1929,13 +1900,6 @@ open_top:
tp->t_dev = dev;
tp->t_termios = mynor & CALLOUT_MASK
? com->it_out : com->it_in;
-#ifndef PC98
- tp->t_ififosize = 2 * RS_IBUFSIZE;
-#else
- tp->t_ififosize = 2 * com->CE_INPUT_OFFSET;
-#endif
- tp->t_ispeedwat = (speed_t)-1;
- tp->t_ospeedwat = (speed_t)-1;
#ifdef PC98
if (!IS_8251(com->pc98_if_type))
#endif
@@ -2121,10 +2085,11 @@ sioclose(dev, flag, mode, p)
if (com->gone) {
printf("sio%d: gone\n", com->unit);
s = spltty();
- com_addr(com->unit) = 0;
- bzero(tp,sizeof *tp);
- bzero(com,sizeof *com);
- free(com,M_TTYS);
+ com_addr(com->unit) = NULL;
+ if (com->ibuf != NULL)
+ free(com->ibuf, M_DEVBUF);
+ bzero(tp, sizeof *tp);
+ free(com, M_DEVBUF);
splx(s);
}
return (0);
@@ -2331,6 +2296,104 @@ siodtrwakeup(chan)
}
static void
+sioinput(com)
+ struct com_s *com;
+{
+ u_char *buf;
+ int incc;
+ u_char line_status;
+ int recv_data;
+ struct tty *tp;
+#ifdef PC98
+ u_char tmp;
+#endif
+
+ buf = com->ibuf;
+ tp = com->tp;
+ if (!(tp->t_state & TS_ISOPEN) || !(tp->t_cflag & CREAD)) {
+ com_events -= (com->iptr - com->ibuf);
+ com->iptr = com->ibuf;
+ return;
+ }
+ if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
+ /*
+ * Avoid the grotesquely inefficient lineswitch routine
+ * (ttyinput) in "raw" mode. It usually takes about 450
+ * instructions (that's without canonical processing or echo!).
+ * slinput is reasonably fast (usually 40 instructions plus
+ * call overhead).
+ */
+ do {
+ enable_intr();
+ incc = com->iptr - buf;
+ if (tp->t_rawq.c_cc + incc > tp->t_ihiwat
+ && (com->state & CS_RTS_IFLOW
+ || tp->t_iflag & IXOFF)
+ && !(tp->t_state & TS_TBLOCK))
+ ttyblock(tp);
+ com->delta_error_counts[CE_TTY_BUF_OVERFLOW]
+ += b_to_q((char *)buf, incc, &tp->t_rawq);
+ buf += incc;
+ tk_nin += incc;
+ tk_rawcc += incc;
+ tp->t_rawcc += incc;
+ ttwakeup(tp);
+ if (tp->t_state & TS_TTSTOP
+ && (tp->t_iflag & IXANY
+ || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
+ tp->t_state &= ~TS_TTSTOP;
+ tp->t_lflag &= ~FLUSHO;
+ comstart(tp);
+ }
+ disable_intr();
+ } while (buf < com->iptr);
+ } else {
+ do {
+ enable_intr();
+ line_status = buf[com->ierroff];
+ recv_data = *buf++;
+ if (line_status
+ & (LSR_BI | LSR_FE | LSR_OE | LSR_PE)) {
+ if (line_status & LSR_BI)
+ recv_data |= TTY_BI;
+ if (line_status & LSR_FE)
+ recv_data |= TTY_FE;
+ if (line_status & LSR_OE)
+ recv_data |= TTY_OE;
+ if (line_status & LSR_PE)
+ recv_data |= TTY_PE;
+ }
+ (*linesw[tp->t_line].l_rint)(recv_data, tp);
+ disable_intr();
+ } while (buf < com->iptr);
+ }
+ com_events -= (com->iptr - com->ibuf);
+ com->iptr = com->ibuf;
+
+ /*
+ * There is now room for another low-level buffer full of input,
+ * so enable RTS if it is now disabled and there is room in the
+ * high-level buffer.
+ */
+#ifdef PC98
+ if (IS_8251(com->pc98_if_type))
+ tmp = com_tiocm_get(com) & TIOCM_RTS;
+ else
+ tmp = com->mcr_image & MCR_RTS;
+ if ((com->state & CS_RTS_IFLOW) && !(tmp) &&
+ !(tp->t_state & TS_TBLOCK))
+ if (IS_8251(com->pc98_if_type))
+ com_tiocm_bis(com, TIOCM_RTS);
+ else
+ outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
+#else
+ if ((com->state & CS_RTS_IFLOW) && !(com->mcr_image & MCR_RTS) &&
+ !(tp->t_state & TS_TBLOCK))
+ outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
+#endif
+}
+
+static void
siointr(unit)
int unit;
{
@@ -2522,11 +2585,7 @@ if (com->iptr - com->ibuf == 8)
setsofttty();
#endif
ioptr[0] = recv_data;
-#ifdef PC98
- ioptr[com->CE_INPUT_OFFSET] = line_status;
-#else
- ioptr[CE_INPUT_OFFSET] = line_status;
-#endif
+ ioptr[com->ierroff] = line_status;
com->iptr = ++ioptr;
if (ioptr == com->ihighwater
&& com->state & CS_RTS_IFLOW)
@@ -2666,11 +2725,13 @@ cont:
}
}
if ( COM_IIR_TXRDYBUG(com) && (int_ctl != int_ctl_new)) {
+#ifdef PC98
if (com->pc98_if_type == COM_IF_RSA98III) {
int_ctl_new &= ~(IER_ETXRDY | IER_ERXRDY);
outb(com->intr_ctl_port, int_ctl_new);
outb(com->rsabase + rsa_ier, 0x1d);
} else
+#endif
outb(com->intr_ctl_port, int_ctl_new);
}
}
@@ -2934,14 +2995,9 @@ siopoll()
return;
repeat:
for (unit = 0; unit < NSIOTOT; ++unit) {
- u_char *buf;
struct com_s *com;
- u_char *ibuf;
int incc;
struct tty *tp;
-#ifdef PC98
- int tmp;
-#endif
com = com_addr(unit);
if (com == NULL)
@@ -2963,58 +3019,11 @@ repeat:
enable_intr();
continue;
}
-
- /* switch the role of the low-level input buffers */
- if (com->iptr == (ibuf = com->ibuf)) {
- buf = NULL; /* not used, but compiler can't tell */
- incc = 0;
- } else {
- buf = ibuf;
+ if (com->iptr != com->ibuf) {
disable_intr();
- incc = com->iptr - buf;
- com_events -= incc;
- if (ibuf == com->ibuf1)
- ibuf = com->ibuf2;
- else
- ibuf = com->ibuf1;
-#ifndef PC98
- com->ibufend = ibuf + RS_IBUFSIZE;
- com->ihighwater = ibuf + RS_IHIGHWATER;
-#else
- com->ibufend = ibuf + com->CE_INPUT_OFFSET;
- com->ihighwater = ibuf + (3 * com->CE_INPUT_OFFSET / 4);
-#endif
- com->iptr = ibuf;
-
- /*
- * There is now room for another low-level buffer full
- * of input, so enable RTS if it is now disabled and
- * there is room in the high-level buffer.
- */
-#ifdef PC98
- if (IS_8251(com->pc98_if_type))
- tmp = com_tiocm_get(com) & TIOCM_RTS;
- else
- tmp = com->mcr_image & MCR_RTS;
-#endif
- if ((com->state & CS_RTS_IFLOW)
-#ifdef PC98
- && !(tmp)
-#else
- && !(com->mcr_image & MCR_RTS)
-#endif
- && !(tp->t_state & TS_TBLOCK))
-#ifdef PC98
- if (IS_8251(com->pc98_if_type))
- com_tiocm_bis(com, TIOCM_RTS);
- else
-#endif
- outb(com->modem_ctl_port,
- com->mcr_image |= MCR_RTS);
+ sioinput(com);
enable_intr();
- com->ibuf = ibuf;
}
-
if (com->state & CS_CHECKMSR) {
u_char delta_modem_status;
@@ -3047,60 +3056,6 @@ repeat:
}
(*linesw[tp->t_line].l_start)(tp);
}
- if (incc <= 0 || !(tp->t_state & TS_ISOPEN) ||
- !(tp->t_cflag & CREAD))
- continue;
- /*
- * Avoid the grotesquely inefficient lineswitch routine
- * (ttyinput) in "raw" mode. It usually takes about 450
- * instructions (that's without canonical processing or echo!).
- * slinput is reasonably fast (usually 40 instructions plus
- * call overhead).
- */
- if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
- if (tp->t_rawq.c_cc + incc > tp->t_ihiwat
- && (com->state & CS_RTS_IFLOW
- || tp->t_iflag & IXOFF)
- && !(tp->t_state & TS_TBLOCK))
- ttyblock(tp);
- tk_nin += incc;
- tk_rawcc += incc;
- tp->t_rawcc += incc;
- com->delta_error_counts[CE_TTY_BUF_OVERFLOW]
- += b_to_q((char *)buf, incc, &tp->t_rawq);
- ttwakeup(tp);
- if (tp->t_state & TS_TTSTOP
- && (tp->t_iflag & IXANY
- || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
- tp->t_state &= ~TS_TTSTOP;
- tp->t_lflag &= ~FLUSHO;
- comstart(tp);
- }
- } else {
- do {
- u_char line_status;
- int recv_data;
-
-#ifndef PC98
- line_status = (u_char) buf[CE_INPUT_OFFSET];
-#else
- line_status = (u_char) buf[com->CE_INPUT_OFFSET];
-#endif
- recv_data = (u_char) *buf++;
- if (line_status
- & (LSR_BI | LSR_FE | LSR_OE | LSR_PE)) {
- if (line_status & LSR_BI)
- recv_data |= TTY_BI;
- if (line_status & LSR_FE)
- recv_data |= TTY_FE;
- if (line_status & LSR_OE)
- recv_data |= TTY_OE;
- if (line_status & LSR_PE)
- recv_data |= TTY_PE;
- }
- (*linesw[tp->t_line].l_rint)(recv_data, tp);
- } while (--incc > 0);
- }
if (com_events == 0)
break;
}
@@ -3234,7 +3189,12 @@ comparam(tp, t)
}
#endif
- disable_intr(); /* very important while com_data is hidden */
+ /*
+ * This returns with interrupts disabled so that we can complete
+ * the speed change atomically. Keeping interrupts disabled is
+ * especially important while com_data is hidden.
+ */
+ (void) siosetwater(com, t->c_ispeed);
#ifdef PC98
if (IS_8251(com->pc98_if_type))
@@ -3375,6 +3335,84 @@ comparam(tp, t)
enable_intr();
splx(s);
comstart(tp);
+ if (com->ibufold != NULL) {
+ free(com->ibufold, M_DEVBUF);
+ com->ibufold = NULL;
+ }
+ return (0);
+}
+
+static int
+siosetwater(com, speed)
+ struct com_s *com;
+ speed_t speed;
+{
+ int cp4ticks;
+ u_char *ibuf;
+ int ibufsize;
+ struct tty *tp;
+
+ /*
+ * Make the buffer size large enough to handle a softtty interrupt
+ * latency of about 2 ticks without loss of throughput or data
+ * (about 3 ticks if input flow control is not used or not honoured,
+ * but a bit less for CS5-CS7 modes).
+ */
+ cp4ticks = speed / 10 / hz * 4;
+ for (ibufsize = 128; ibufsize < cp4ticks;)
+ ibufsize <<= 1;
+#ifdef PC98
+ if (com->pc98_if_type == COM_IF_RSA98III)
+ ibufsize = 2048;
+#endif
+ if (ibufsize == com->ibufsize) {
+ disable_intr();
+ return (0);
+ }
+
+ /*
+ * Allocate input buffer. The extra factor of 2 in the size is
+ * to allow for an error byte for each input byte.
+ */
+ ibuf = malloc(2 * ibufsize, M_DEVBUF, M_NOWAIT);
+ if (ibuf == NULL) {
+ disable_intr();
+ return (ENOMEM);
+ }
+
+ /* Initialize non-critical variables. */
+ com->ibufold = com->ibuf;
+ com->ibufsize = ibufsize;
+ tp = com->tp;
+ if (tp != NULL) {
+ tp->t_ififosize = 2 * ibufsize;
+ tp->t_ispeedwat = (speed_t)-1;
+ tp->t_ospeedwat = (speed_t)-1;
+ }
+
+ /*
+ * Read current input buffer, if any. Continue with interrupts
+ * disabled.
+ */
+ disable_intr();
+ if (com->iptr != com->ibuf)
+ sioinput(com);
+
+ /*-
+ * Initialize critical variables, including input buffer watermarks.
+ * The external device is asked to stop sending when the buffer
+ * exactly reaches high water, or when the high level requests it.
+ * The high level is notified immediately (rather than at a later
+ * clock tick) when this watermark is reached.
+ * The buffer size is chosen so the watermark should almost never
+ * be reached.
+ * The low watermark is invisibly 0 since the buffer is always
+ * emptied all at once.
+ */
+ com->iptr = com->ibuf = ibuf;
+ com->ibufend = ibuf + ibufsize;
+ com->ierroff = ibufsize;
+ com->ihighwater = ibuf + 3 * ibufsize / 4;
return (0);
}
@@ -3452,7 +3490,7 @@ comstart(tp)
#ifndef PC98
sizeof com->obuf1);
#else
- com->CE_INPUT_OFFSET);
+ com->obufsize);
#endif
com->obufs[0].l_next = NULL;
com->obufs[0].l_queued = TRUE;
@@ -3476,7 +3514,7 @@ comstart(tp)
#ifndef PC98
sizeof com->obuf2);
#else
- com->CE_INPUT_OFFSET);
+ com->obufsize);
#endif
com->obufs[1].l_next = NULL;
com->obufs[1].l_queued = TRUE;
diff --git a/sys/pc98/pc98/sio.c b/sys/pc98/pc98/sio.c
index 27ab00e427d4..9492ea301f86 100644
--- a/sys/pc98/pc98/sio.c
+++ b/sys/pc98/pc98/sio.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)com.c 7.5 (Berkeley) 5/16/91
- * $Id: sio.c,v 1.79 1999/01/30 12:17:37 phk Exp $
+ * $Id: sio.c,v 1.80 1999/02/02 17:26:03 kato Exp $
*/
#include "opt_comconsole.h"
@@ -205,7 +205,6 @@
#define NSIOTOT (NSIO + EXTRA_SIO)
#define LOTS_OF_EVENTS 64 /* helps separate urgent events from input */
-#define RS_IBUFSIZE 256
#define CALLOUT_MASK 0x80
#define CONTROL_MASK 0x60
@@ -243,18 +242,6 @@
#endif
/*
- * Input buffer watermarks.
- * The external device is asked to stop sending when the buffer exactly reaches
- * high water, or when the high level requests it.
- * The high level is notified immediately (rather than at a later clock tick)
- * when this watermark is reached.
- * The buffer size is chosen so the watermark should almost never be reached.
- * The low watermark is invisibly 0 since the buffer is always emptied all at
- * once.
- */
-#define RS_IHIGHWATER (3 * RS_IBUFSIZE / 4)
-
-/*
* com state bits.
* (CS_BUSY | CS_TTGO) and (CS_BUSY | CS_TTGO | CS_ODEVREADY) must be higher
* than the other bits so that they can be tested as a group without masking
@@ -343,8 +330,11 @@ struct com_s {
u_char hotchar; /* ldisc-specific char to be handled ASAP */
u_char *ibuf; /* start of input buffer */
u_char *ibufend; /* end of input buffer */
+ u_char *ibufold; /* old input buffer, to be freed */
u_char *ihighwater; /* threshold in input buffer */
u_char *iptr; /* next free spot in input buffer */
+ int ibufsize; /* size of ibuf (not include error bytes) */
+ int ierroff; /* offset of error bytes in ibuf */
struct lbq obufq; /* head of queue of output buffers */
struct lbq obufs[2]; /* output buffers */
@@ -398,29 +388,14 @@ struct com_s {
u_long error_counts[CE_NTYPES];
/*
- * Ping-pong input buffers. The extra factor of 2 in the sizes is
- * to allow for an error byte for each input byte.
- */
-#ifdef PC98
- u_long CE_INPUT_OFFSET;
- u_char *ibuf1;
- u_char *ibuf2;
-
- /*
* Data area for output buffers. Someday we should build the output
* buffer queue without copying data.
*/
+#ifdef PC98
+ int obufsize;
u_char *obuf1;
u_char *obuf2;
#else
-#define CE_INPUT_OFFSET RS_IBUFSIZE
- u_char ibuf1[2 * RS_IBUFSIZE];
- u_char ibuf2[2 * RS_IBUFSIZE];
-
- /*
- * Data area for output buffers. Someday we should build the output
- * buffer queue without copying data.
- */
u_char obuf1[256];
u_char obuf2[256];
#endif
@@ -442,6 +417,7 @@ 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 sioinput __P((struct com_s *com));
static ointhand2_t siointr;
static void siointr1 __P((struct com_s *com));
static int commctl __P((struct com_s *com, int bits, int how));
@@ -449,6 +425,7 @@ static int comparam __P((struct tty *tp, struct termios *t));
static swihand_t siopoll;
static int sioprobe __P((struct isa_device *dev));
static void siosettimeout __P((void));
+static int siosetwater __P((struct com_s *com, speed_t speed));
static void comstart __P((struct tty *tp));
static timeout_t comwakeup;
static void disc_optim __P((struct tty *tp, struct termios *t,
@@ -932,11 +909,9 @@ siounload(struct pccard_devinfo *devi)
ttwwakeup(com->tp);
} else {
com_addr(com->unit) = NULL;
-#ifdef PC98
- bzero(com->ibuf1, com->CE_INPUT_OFFSET * 6);
-#endif
- bzero(com, sizeof *com);
- free(com,M_TTYS);
+ if (com->ibuf != NULL)
+ free(com->ibuf, M_DEVBUF);
+ free(com, M_DEVBUF);
printf("sio%d: unload,gone\n", devi->isahd.id_unit);
}
}
@@ -1503,7 +1478,7 @@ sioattach(isdp)
int unit;
#ifdef PC98
int port_shift = 0;
- u_long ibufsize;
+ u_long obufsize;
#endif
isdp->id_ointr = siointr;
@@ -1516,12 +1491,12 @@ sioattach(isdp)
iobase = isdp->id_iobase;
unit = isdp->id_unit;
#ifndef PC98
- com = malloc(sizeof *com, M_TTYS, M_NOWAIT);
+ com = malloc(sizeof *com, M_DEVBUF, M_NOWAIT);
#else
- ibufsize = RS_IBUFSIZE;
+ obufsize = 256;
if (((isdp->id_flags >> 24) & 0xff) == COM_IF_RSA98III)
- ibufsize = 2048;
- com = malloc((sizeof *com) + ibufsize * 6, M_TTYS, M_NOWAIT);
+ obufsize = 2048;
+ com = malloc((sizeof *com) + obufsize * 2, M_DEVBUF, M_NOWAIT);
#endif
if (com == NULL)
return (0);
@@ -1540,12 +1515,10 @@ sioattach(isdp)
*/
bzero(com, sizeof *com);
#ifdef PC98
- com->CE_INPUT_OFFSET = ibufsize;
- com->ibuf1 = (u_char *)com + (sizeof *com);
- com->ibuf2 = com->ibuf1 + (ibufsize * 2);
- com->obuf1 = com->ibuf2 + (ibufsize * 2);
- com->obuf2 = com->obuf1 + ibufsize;
- bzero(com->ibuf1, ibufsize * 6);
+ com->obufsize = obufsize;
+ com->obuf1 = (u_char *)com + (sizeof *com);
+ com->obuf2 = com->obuf1 + obufsize;
+ bzero(com->obuf1, obufsize * 2);
#endif
com->unit = unit;
com->cfcr_image = CFCR_8BITS;
@@ -1553,14 +1526,6 @@ sioattach(isdp)
com->loses_outints = COM_LOSESOUTINTS(isdp) != 0;
com->no_irq = isdp->id_irq == 0;
com->tx_fifo_size = 1;
- com->iptr = com->ibuf = com->ibuf1;
-#ifndef PC98
- com->ibufend = com->ibuf1 + RS_IBUFSIZE;
- com->ihighwater = com->ibuf1 + RS_IHIGHWATER;
-#else
- com->ibufend = com->ibuf1 + com->CE_INPUT_OFFSET;
- com->ihighwater = com->ibuf1 + (3 * com->CE_INPUT_OFFSET / 4);
-#endif
com->obufs[0].l_head = com->obuf1;
com->obufs[1].l_head = com->obuf2;
@@ -1612,6 +1577,12 @@ sioattach(isdp)
com->it_in.c_ispeed = com->it_in.c_ospeed = comdefaultrate;
} else
com->it_in.c_ispeed = com->it_in.c_ospeed = TTYDEF_SPEED;
+ if (siosetwater(com, com->it_in.c_ispeed) != 0) {
+ enable_intr();
+ free(com, M_DEVBUF);
+ return (0);
+ }
+ enable_intr();
termioschars(&com->it_in);
com->it_out = com->it_in;
@@ -1793,7 +1764,7 @@ determined_type: ;
printf(")");
com->no_irq = find_isadev(isa_devtab_tty, &siodriver,
COM_MPMASTER(isdp))->id_irq == 0;
- }
+ }
#endif /* COM_MULTIPORT */
#ifdef PC98
}
@@ -1929,13 +1900,6 @@ open_top:
tp->t_dev = dev;
tp->t_termios = mynor & CALLOUT_MASK
? com->it_out : com->it_in;
-#ifndef PC98
- tp->t_ififosize = 2 * RS_IBUFSIZE;
-#else
- tp->t_ififosize = 2 * com->CE_INPUT_OFFSET;
-#endif
- tp->t_ispeedwat = (speed_t)-1;
- tp->t_ospeedwat = (speed_t)-1;
#ifdef PC98
if (!IS_8251(com->pc98_if_type))
#endif
@@ -2121,10 +2085,11 @@ sioclose(dev, flag, mode, p)
if (com->gone) {
printf("sio%d: gone\n", com->unit);
s = spltty();
- com_addr(com->unit) = 0;
- bzero(tp,sizeof *tp);
- bzero(com,sizeof *com);
- free(com,M_TTYS);
+ com_addr(com->unit) = NULL;
+ if (com->ibuf != NULL)
+ free(com->ibuf, M_DEVBUF);
+ bzero(tp, sizeof *tp);
+ free(com, M_DEVBUF);
splx(s);
}
return (0);
@@ -2331,6 +2296,104 @@ siodtrwakeup(chan)
}
static void
+sioinput(com)
+ struct com_s *com;
+{
+ u_char *buf;
+ int incc;
+ u_char line_status;
+ int recv_data;
+ struct tty *tp;
+#ifdef PC98
+ u_char tmp;
+#endif
+
+ buf = com->ibuf;
+ tp = com->tp;
+ if (!(tp->t_state & TS_ISOPEN) || !(tp->t_cflag & CREAD)) {
+ com_events -= (com->iptr - com->ibuf);
+ com->iptr = com->ibuf;
+ return;
+ }
+ if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
+ /*
+ * Avoid the grotesquely inefficient lineswitch routine
+ * (ttyinput) in "raw" mode. It usually takes about 450
+ * instructions (that's without canonical processing or echo!).
+ * slinput is reasonably fast (usually 40 instructions plus
+ * call overhead).
+ */
+ do {
+ enable_intr();
+ incc = com->iptr - buf;
+ if (tp->t_rawq.c_cc + incc > tp->t_ihiwat
+ && (com->state & CS_RTS_IFLOW
+ || tp->t_iflag & IXOFF)
+ && !(tp->t_state & TS_TBLOCK))
+ ttyblock(tp);
+ com->delta_error_counts[CE_TTY_BUF_OVERFLOW]
+ += b_to_q((char *)buf, incc, &tp->t_rawq);
+ buf += incc;
+ tk_nin += incc;
+ tk_rawcc += incc;
+ tp->t_rawcc += incc;
+ ttwakeup(tp);
+ if (tp->t_state & TS_TTSTOP
+ && (tp->t_iflag & IXANY
+ || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
+ tp->t_state &= ~TS_TTSTOP;
+ tp->t_lflag &= ~FLUSHO;
+ comstart(tp);
+ }
+ disable_intr();
+ } while (buf < com->iptr);
+ } else {
+ do {
+ enable_intr();
+ line_status = buf[com->ierroff];
+ recv_data = *buf++;
+ if (line_status
+ & (LSR_BI | LSR_FE | LSR_OE | LSR_PE)) {
+ if (line_status & LSR_BI)
+ recv_data |= TTY_BI;
+ if (line_status & LSR_FE)
+ recv_data |= TTY_FE;
+ if (line_status & LSR_OE)
+ recv_data |= TTY_OE;
+ if (line_status & LSR_PE)
+ recv_data |= TTY_PE;
+ }
+ (*linesw[tp->t_line].l_rint)(recv_data, tp);
+ disable_intr();
+ } while (buf < com->iptr);
+ }
+ com_events -= (com->iptr - com->ibuf);
+ com->iptr = com->ibuf;
+
+ /*
+ * There is now room for another low-level buffer full of input,
+ * so enable RTS if it is now disabled and there is room in the
+ * high-level buffer.
+ */
+#ifdef PC98
+ if (IS_8251(com->pc98_if_type))
+ tmp = com_tiocm_get(com) & TIOCM_RTS;
+ else
+ tmp = com->mcr_image & MCR_RTS;
+ if ((com->state & CS_RTS_IFLOW) && !(tmp) &&
+ !(tp->t_state & TS_TBLOCK))
+ if (IS_8251(com->pc98_if_type))
+ com_tiocm_bis(com, TIOCM_RTS);
+ else
+ outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
+#else
+ if ((com->state & CS_RTS_IFLOW) && !(com->mcr_image & MCR_RTS) &&
+ !(tp->t_state & TS_TBLOCK))
+ outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
+#endif
+}
+
+static void
siointr(unit)
int unit;
{
@@ -2522,11 +2585,7 @@ if (com->iptr - com->ibuf == 8)
setsofttty();
#endif
ioptr[0] = recv_data;
-#ifdef PC98
- ioptr[com->CE_INPUT_OFFSET] = line_status;
-#else
- ioptr[CE_INPUT_OFFSET] = line_status;
-#endif
+ ioptr[com->ierroff] = line_status;
com->iptr = ++ioptr;
if (ioptr == com->ihighwater
&& com->state & CS_RTS_IFLOW)
@@ -2666,11 +2725,13 @@ cont:
}
}
if ( COM_IIR_TXRDYBUG(com) && (int_ctl != int_ctl_new)) {
+#ifdef PC98
if (com->pc98_if_type == COM_IF_RSA98III) {
int_ctl_new &= ~(IER_ETXRDY | IER_ERXRDY);
outb(com->intr_ctl_port, int_ctl_new);
outb(com->rsabase + rsa_ier, 0x1d);
} else
+#endif
outb(com->intr_ctl_port, int_ctl_new);
}
}
@@ -2934,14 +2995,9 @@ siopoll()
return;
repeat:
for (unit = 0; unit < NSIOTOT; ++unit) {
- u_char *buf;
struct com_s *com;
- u_char *ibuf;
int incc;
struct tty *tp;
-#ifdef PC98
- int tmp;
-#endif
com = com_addr(unit);
if (com == NULL)
@@ -2963,58 +3019,11 @@ repeat:
enable_intr();
continue;
}
-
- /* switch the role of the low-level input buffers */
- if (com->iptr == (ibuf = com->ibuf)) {
- buf = NULL; /* not used, but compiler can't tell */
- incc = 0;
- } else {
- buf = ibuf;
+ if (com->iptr != com->ibuf) {
disable_intr();
- incc = com->iptr - buf;
- com_events -= incc;
- if (ibuf == com->ibuf1)
- ibuf = com->ibuf2;
- else
- ibuf = com->ibuf1;
-#ifndef PC98
- com->ibufend = ibuf + RS_IBUFSIZE;
- com->ihighwater = ibuf + RS_IHIGHWATER;
-#else
- com->ibufend = ibuf + com->CE_INPUT_OFFSET;
- com->ihighwater = ibuf + (3 * com->CE_INPUT_OFFSET / 4);
-#endif
- com->iptr = ibuf;
-
- /*
- * There is now room for another low-level buffer full
- * of input, so enable RTS if it is now disabled and
- * there is room in the high-level buffer.
- */
-#ifdef PC98
- if (IS_8251(com->pc98_if_type))
- tmp = com_tiocm_get(com) & TIOCM_RTS;
- else
- tmp = com->mcr_image & MCR_RTS;
-#endif
- if ((com->state & CS_RTS_IFLOW)
-#ifdef PC98
- && !(tmp)
-#else
- && !(com->mcr_image & MCR_RTS)
-#endif
- && !(tp->t_state & TS_TBLOCK))
-#ifdef PC98
- if (IS_8251(com->pc98_if_type))
- com_tiocm_bis(com, TIOCM_RTS);
- else
-#endif
- outb(com->modem_ctl_port,
- com->mcr_image |= MCR_RTS);
+ sioinput(com);
enable_intr();
- com->ibuf = ibuf;
}
-
if (com->state & CS_CHECKMSR) {
u_char delta_modem_status;
@@ -3047,60 +3056,6 @@ repeat:
}
(*linesw[tp->t_line].l_start)(tp);
}
- if (incc <= 0 || !(tp->t_state & TS_ISOPEN) ||
- !(tp->t_cflag & CREAD))
- continue;
- /*
- * Avoid the grotesquely inefficient lineswitch routine
- * (ttyinput) in "raw" mode. It usually takes about 450
- * instructions (that's without canonical processing or echo!).
- * slinput is reasonably fast (usually 40 instructions plus
- * call overhead).
- */
- if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
- if (tp->t_rawq.c_cc + incc > tp->t_ihiwat
- && (com->state & CS_RTS_IFLOW
- || tp->t_iflag & IXOFF)
- && !(tp->t_state & TS_TBLOCK))
- ttyblock(tp);
- tk_nin += incc;
- tk_rawcc += incc;
- tp->t_rawcc += incc;
- com->delta_error_counts[CE_TTY_BUF_OVERFLOW]
- += b_to_q((char *)buf, incc, &tp->t_rawq);
- ttwakeup(tp);
- if (tp->t_state & TS_TTSTOP
- && (tp->t_iflag & IXANY
- || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
- tp->t_state &= ~TS_TTSTOP;
- tp->t_lflag &= ~FLUSHO;
- comstart(tp);
- }
- } else {
- do {
- u_char line_status;
- int recv_data;
-
-#ifndef PC98
- line_status = (u_char) buf[CE_INPUT_OFFSET];
-#else
- line_status = (u_char) buf[com->CE_INPUT_OFFSET];
-#endif
- recv_data = (u_char) *buf++;
- if (line_status
- & (LSR_BI | LSR_FE | LSR_OE | LSR_PE)) {
- if (line_status & LSR_BI)
- recv_data |= TTY_BI;
- if (line_status & LSR_FE)
- recv_data |= TTY_FE;
- if (line_status & LSR_OE)
- recv_data |= TTY_OE;
- if (line_status & LSR_PE)
- recv_data |= TTY_PE;
- }
- (*linesw[tp->t_line].l_rint)(recv_data, tp);
- } while (--incc > 0);
- }
if (com_events == 0)
break;
}
@@ -3234,7 +3189,12 @@ comparam(tp, t)
}
#endif
- disable_intr(); /* very important while com_data is hidden */
+ /*
+ * This returns with interrupts disabled so that we can complete
+ * the speed change atomically. Keeping interrupts disabled is
+ * especially important while com_data is hidden.
+ */
+ (void) siosetwater(com, t->c_ispeed);
#ifdef PC98
if (IS_8251(com->pc98_if_type))
@@ -3375,6 +3335,84 @@ comparam(tp, t)
enable_intr();
splx(s);
comstart(tp);
+ if (com->ibufold != NULL) {
+ free(com->ibufold, M_DEVBUF);
+ com->ibufold = NULL;
+ }
+ return (0);
+}
+
+static int
+siosetwater(com, speed)
+ struct com_s *com;
+ speed_t speed;
+{
+ int cp4ticks;
+ u_char *ibuf;
+ int ibufsize;
+ struct tty *tp;
+
+ /*
+ * Make the buffer size large enough to handle a softtty interrupt
+ * latency of about 2 ticks without loss of throughput or data
+ * (about 3 ticks if input flow control is not used or not honoured,
+ * but a bit less for CS5-CS7 modes).
+ */
+ cp4ticks = speed / 10 / hz * 4;
+ for (ibufsize = 128; ibufsize < cp4ticks;)
+ ibufsize <<= 1;
+#ifdef PC98
+ if (com->pc98_if_type == COM_IF_RSA98III)
+ ibufsize = 2048;
+#endif
+ if (ibufsize == com->ibufsize) {
+ disable_intr();
+ return (0);
+ }
+
+ /*
+ * Allocate input buffer. The extra factor of 2 in the size is
+ * to allow for an error byte for each input byte.
+ */
+ ibuf = malloc(2 * ibufsize, M_DEVBUF, M_NOWAIT);
+ if (ibuf == NULL) {
+ disable_intr();
+ return (ENOMEM);
+ }
+
+ /* Initialize non-critical variables. */
+ com->ibufold = com->ibuf;
+ com->ibufsize = ibufsize;
+ tp = com->tp;
+ if (tp != NULL) {
+ tp->t_ififosize = 2 * ibufsize;
+ tp->t_ispeedwat = (speed_t)-1;
+ tp->t_ospeedwat = (speed_t)-1;
+ }
+
+ /*
+ * Read current input buffer, if any. Continue with interrupts
+ * disabled.
+ */
+ disable_intr();
+ if (com->iptr != com->ibuf)
+ sioinput(com);
+
+ /*-
+ * Initialize critical variables, including input buffer watermarks.
+ * The external device is asked to stop sending when the buffer
+ * exactly reaches high water, or when the high level requests it.
+ * The high level is notified immediately (rather than at a later
+ * clock tick) when this watermark is reached.
+ * The buffer size is chosen so the watermark should almost never
+ * be reached.
+ * The low watermark is invisibly 0 since the buffer is always
+ * emptied all at once.
+ */
+ com->iptr = com->ibuf = ibuf;
+ com->ibufend = ibuf + ibufsize;
+ com->ierroff = ibufsize;
+ com->ihighwater = ibuf + 3 * ibufsize / 4;
return (0);
}
@@ -3452,7 +3490,7 @@ comstart(tp)
#ifndef PC98
sizeof com->obuf1);
#else
- com->CE_INPUT_OFFSET);
+ com->obufsize);
#endif
com->obufs[0].l_next = NULL;
com->obufs[0].l_queued = TRUE;
@@ -3476,7 +3514,7 @@ comstart(tp)
#ifndef PC98
sizeof com->obuf2);
#else
- com->CE_INPUT_OFFSET);
+ com->obufsize);
#endif
com->obufs[1].l_next = NULL;
com->obufs[1].l_queued = TRUE;