diff options
| author | KATO Takenori <kato@FreeBSD.org> | 1999-02-05 11:37:40 +0000 |
|---|---|---|
| committer | KATO Takenori <kato@FreeBSD.org> | 1999-02-05 11:37:40 +0000 |
| commit | 533601dc35379a93943b9f516060f47a7e8438fa (patch) | |
| tree | 950d9e91823c465b8e4f4d16f3312049426d10a7 | |
| parent | 48caee2acde01f188590b7955963f294a746f2d6 (diff) | |
Notes
| -rw-r--r-- | sys/pc98/cbus/sio.c | 404 | ||||
| -rw-r--r-- | sys/pc98/pc98/sio.c | 404 |
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; |
