Subject: Re: com driver problems
To: Mike Long <mike.long@analog.com>
From: None <Mark_Weaver@brown.edu>
List: port-i386
Date: 06/07/1995 15:47:22
Mike Long <mike.long@analog.com> writes:
> Something in the last com driver fix disagrees with my modem (DSI
> Connection 96+). Any process that tries to use it hangs; ps(1)
> reports that it is blocked in 'tty in' or 'tty out'.
>
> I would appreciate it if someone would send me either the complete
> version 1.56 of com.c, or a diff between 1.56 and 1.58.
diff -u /usr/src/sys/dev/isa/BACKUP/com.c /usr/src/sys/dev/isa/com.c
--- /usr/src/sys/dev/isa/BACKUP/com.c Fri Jun 2 06:06:36 1995
+++ /usr/src/sys/dev/isa/com.c Mon Jun 5 06:06:03 1995
@@ -1,7 +1,7 @@
-/* $NetBSD: com.c,v 1.56 1995/06/01 21:26:51 jtc Exp $ */
+/* $NetBSD: com.c,v 1.58 1995/06/04 20:50:14 mycroft Exp $ */
/*-
- * Copyright (c) 1993, 1994, 1995 Charles Hannum. All rights reserved.
+ * Copyright (c) 1993, 1994, 1995 Charles M. Hannum. All rights reserved.
* Copyright (c) 1991 The Regents of the University of California.
* All rights reserved.
*
@@ -62,12 +62,18 @@
#include <dev/isa/comreg.h>
#include <dev/ic/ns16550.h>
+#define COM_IBUFSIZE (2 * 256)
+#define COM_IHIGHWATER ((3 * COM_IBUFSIZE) / 4)
+
struct com_softc {
struct device sc_dev;
void *sc_ih;
struct tty *sc_tty;
int sc_overflows;
+ int sc_floods;
+ int sc_errors;
+
int sc_iobase;
u_char sc_hwflags;
#define COM_HW_NOIEN 0x01
@@ -79,6 +85,10 @@
#define COM_SW_CRTSCTS 0x04
#define COM_SW_MDMBUF 0x08
u_char sc_msr, sc_mcr;
+ u_char sc_dtr;
+
+ u_char *sc_ibuf, *sc_ibufp, *sc_ibufhigh, *sc_ibufend;
+ u_char sc_ibufs[2][COM_IBUFSIZE];
};
int comprobe __P((struct device *, void *, void *));
@@ -87,6 +97,7 @@
int comclose __P((dev_t, int, int, struct proc *));
void comdiag __P((void *));
int comintr __P((void *));
+void compoll __P((void *));
int comparam __P((struct tty *, struct termios *));
void comstart __P((struct tty *));
@@ -102,6 +113,8 @@
#endif
int comconsinit;
int commajor;
+int comsopen = 0;
+int comevents = 0;
#ifdef KGDB
#include <machine/remote-sl.h>
@@ -262,8 +275,6 @@
if (!sc)
return ENXIO;
- s = spltty();
-
if (!sc->sc_tty)
tp = sc->sc_tty = ttymalloc();
else
@@ -286,9 +297,19 @@
tp->t_cflag |= MDMBUF;
tp->t_lflag = TTYDEF_LFLAG;
tp->t_ispeed = tp->t_ospeed = comdefaultrate;
+
+ s = spltty();
+
comparam(tp, &tp->t_termios);
ttsetwater(tp);
+ if (comsopen++ == 0)
+ timeout(compoll, NULL, 1);
+
+ sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0];
+ sc->sc_ibufhigh = sc->sc_ibuf + COM_IHIGHWATER;
+ sc->sc_ibufend = sc->sc_ibuf + COM_IBUFSIZE;
+
iobase = sc->sc_iobase;
/* Set the FIFO threshold based on the receive speed. */
if (sc->sc_hwflags & COM_HW_FIFO)
@@ -296,8 +317,8 @@
FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST |
(tp->t_ispeed <= 1200 ? FIFO_TRIGGER_1 : FIFO_TRIGGER_8));
/* flush any pending I/O */
- (void) inb(iobase + com_lsr);
- (void) inb(iobase + com_data);
+ while (inb(iobase + com_lsr) & LSR_RXRDY)
+ (void) inb(iobase + com_data);
/* you turn me on, baby */
sc->sc_mcr = MCR_DTR | MCR_RTS;
if (!(sc->sc_hwflags & COM_HW_NOIEN))
@@ -313,9 +334,9 @@
else
tp->t_state &= ~TS_CARR_ON;
} else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0) {
- splx(s);
return EBUSY;
- }
+ } else
+ s = spltty();
/* wait for carrier if necessary */
if ((flag & O_NONBLOCK) == 0)
@@ -346,20 +367,25 @@
struct com_softc *sc = comcd.cd_devs[unit];
struct tty *tp = sc->sc_tty;
int iobase = sc->sc_iobase;
+ int s;
+
+ /* XXX This is for cons.c. */
+ if ((tp->t_state & TS_ISOPEN) == 0)
+ return 0;
(*linesw[tp->t_line].l_close)(tp, flag);
-#ifdef KGDB
- /* do not disable interrupts if debugging */
- if (kgdb_dev != makedev(commajor, unit))
-#endif
- {
- bic(iobase + com_cfcr, CFCR_SBREAK);
- outb(iobase + com_ier, 0);
- if (tp->t_cflag & HUPCL &&
- (sc->sc_swflags & COM_SW_SOFTCAR) == 0)
- /* XXX perhaps only clear DTR */
- outb(iobase + com_mcr, 0);
- }
+ s = spltty();
+ bic(iobase + com_cfcr, CFCR_SBREAK);
+ outb(iobase + com_ier, 0);
+ if (tp->t_cflag & HUPCL &&
+ (sc->sc_swflags & COM_SW_SOFTCAR) == 0) {
+ /* XXX perhaps only clear DTR */
+ outb(iobase + com_mcr, 0);
+ }
+ tp->t_state &= ~(TS_BUSY | TS_FLUSH);
+ if (--comsopen == 0)
+ untimeout(compoll, NULL);
+ splx(s);
ttyclose(tp);
#ifdef notyet /* XXXX */
if (unit != comconsole) {
@@ -446,10 +472,10 @@
bic(iobase + com_cfcr, CFCR_SBREAK);
break;
case TIOCSDTR:
- outb(iobase + com_mcr, sc->sc_mcr |= (MCR_DTR | MCR_RTS));
+ outb(iobase + com_mcr, sc->sc_mcr |= sc->sc_dtr);
break;
case TIOCCDTR:
- outb(iobase + com_mcr, sc->sc_mcr &= ~(MCR_DTR | MCR_RTS));
+ outb(iobase + com_mcr, sc->sc_mcr &= ~sc->sc_dtr);
break;
case TIOCMSET:
sc->sc_mcr &= ~(MCR_DTR | MCR_RTS);
@@ -536,6 +562,7 @@
int iobase = sc->sc_iobase;
int ospeed = comspeed(t->c_ospeed);
u_char cfcr;
+ tcflag_t oldcflag;
int s;
/* check requested parameters */
@@ -572,25 +599,22 @@
/*
* Set the FIFO threshold based on the receive speed, if we are
* changing it.
- *
- * XXX
- * It would be better if we waited for the FIFO to empty, so we don't
- * lose any in-transit characters.
*/
if (tp->t_ispeed != t->c_ispeed) {
if (sc->sc_hwflags & COM_HW_FIFO)
outb(iobase + com_fifo,
- FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST |
+ FIFO_ENABLE |
(t->c_ispeed <= 1200 ? FIFO_TRIGGER_1 : FIFO_TRIGGER_8));
}
- outb(iobase + com_cfcr, cfcr | CFCR_DLAB);
- outb(iobase + com_dlbl, ospeed);
- outb(iobase + com_dlbh, ospeed>>8);
- outb(iobase + com_cfcr, cfcr);
-
- if (ospeed != 0)
+ if (ospeed != 0) {
+ outb(iobase + com_cfcr, cfcr | CFCR_DLAB);
+ outb(iobase + com_dlbl, ospeed);
+ outb(iobase + com_dlbh, ospeed >> 8);
+ outb(iobase + com_cfcr, cfcr);
outb(iobase + com_mcr, sc->sc_mcr |= MCR_DTR);
+ } else
+ outb(iobase + com_cfcr, cfcr);
/* When not using CRTSCTS, RTS follows DTR. */
if ((t->c_cflag & CRTSCTS) == 0) {
@@ -601,40 +625,27 @@
if (sc->sc_mcr & MCR_RTS)
outb(iobase + com_mcr, sc->sc_mcr &= ~MCR_RTS);
}
- }
-
- /*
- * If CTS is off and CRTSCTS is changed, we must toggle TS_TTSTOP.
- * XXX should be done at tty layer.
- */
- if ((sc->sc_msr & MSR_CTS) == 0 &&
- (tp->t_cflag & CRTSCTS) != (t->c_cflag & CRTSCTS)) {
- if ((t->c_cflag & CRTSCTS) == 0) {
- tp->t_state &= ~TS_TTSTOP;
- (*linesw[tp->t_line].l_start)(tp);
- } else
- tp->t_state |= TS_TTSTOP;
- }
-
- /*
- * If DCD is off and MDMBUF is changed, we must toggle TS_TTSTOP.
- * XXX should be done at tty layer.
- */
- if ((sc->sc_swflags & COM_SW_SOFTCAR) == 0 &&
- (sc->sc_msr & MSR_DCD) == 0 &&
- (tp->t_cflag & MDMBUF) != (t->c_cflag & MDMBUF)) {
- if ((t->c_cflag & MDMBUF) == 0) {
- tp->t_state &= ~TS_TTSTOP;
- (*linesw[tp->t_line].l_start)(tp);
- } else
- tp->t_state |= TS_TTSTOP;
- }
+ sc->sc_dtr = MCR_DTR | MCR_RTS;
+ } else
+ sc->sc_dtr = MCR_DTR;
/* and copy to tty */
tp->t_ispeed = t->c_ispeed;
tp->t_ospeed = t->c_ospeed;
+ oldcflag = tp->t_cflag;
tp->t_cflag = t->c_cflag;
+ /*
+ * If DCD is off and MDMBUF is changed, ask the tty layer if we should
+ * stop the device.
+ */
+ if ((sc->sc_msr & MSR_DCD) == 0 &&
+ (sc->sc_swflags & COM_SW_SOFTCAR) == 0 &&
+ (oldcflag & MDMBUF) != (tp->t_cflag & MDMBUF) &&
+ (*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
+ outb(iobase + com_mcr, sc->sc_mcr &= ~sc->sc_dtr);
+ }
+
splx(s);
return 0;
}
@@ -650,10 +661,8 @@
s = spltty();
if (tp->t_state & (TS_TTSTOP | TS_BUSY))
goto out;
-#if 0 /* XXXX I think this is handled adequately by commint() and comparam(). */
if (tp->t_cflag & CRTSCTS && (sc->sc_mcr & MSR_CTS) == 0)
goto out;
-#endif
if (tp->t_outq.c_cc <= tp->t_lowat) {
if (tp->t_state & TS_ASLEEP) {
tp->t_state &= ~TS_ASLEEP;
@@ -692,59 +701,97 @@
splx(s);
}
-static inline void
-comeint(sc, stat)
- struct com_softc *sc;
- int stat;
-{
- struct tty *tp = sc->sc_tty;
- int iobase = sc->sc_iobase;
- int c;
-
- c = inb(iobase + com_data);
-#ifdef DDB
- if ((stat & LSR_BI) && (sc->sc_dev.dv_unit == comconsole)) {
- Debugger();
- return;
- }
-#endif
- if ((tp->t_state & TS_ISOPEN) == 0) {
-#ifdef KGDB
- /* we don't care about parity errors */
- if (((stat & (LSR_BI | LSR_FE | LSR_PE)) == LSR_PE) &&
- kgdb_dev == makedev(commajor, unit) && c == FRAME_END)
- kgdb_connect(0); /* trap into kgdb */
-#endif
- return;
- }
- if (stat & (LSR_BI | LSR_FE))
- c |= TTY_FE;
- else if (stat & LSR_PE)
- c |= TTY_PE;
- if (stat & LSR_OE) {
- if (sc->sc_overflows++ == 0)
- timeout(comdiag, sc, 60 * hz);
- }
- /* XXXX put in FIFO and process later */
- (*linesw[tp->t_line].l_rint)(c, tp);
-}
-
void
comdiag(arg)
void *arg;
{
struct com_softc *sc = arg;
- int overflows;
+ int overflows, floods;
int s;
s = spltty();
+ sc->sc_errors = 0;
overflows = sc->sc_overflows;
sc->sc_overflows = 0;
+ floods = sc->sc_floods;
+ sc->sc_floods = 0;
+ splx(s);
+
+ log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf overflow%s\n",
+ sc->sc_dev.dv_xname,
+ overflows, overflows == 1 ? "" : "s",
+ floods, floods == 1 ? "" : "s");
+}
+
+void
+compoll(arg)
+ void *arg;
+{
+ int unit;
+ struct com_softc *sc;
+ struct tty *tp;
+ register u_char *ibufp;
+ u_char *ibufend;
+ register int c;
+ int s;
+ static int lsrmap[8] = {
+ 0, TTY_PE,
+ TTY_FE, TTY_PE|TTY_FE,
+ TTY_FE, TTY_PE|TTY_FE,
+ TTY_FE, TTY_PE|TTY_FE
+ };
+
+ s = spltty();
+ if (comevents == 0) {
+ splx(s);
+ goto out;
+ }
+ comevents = 0;
splx(s);
- if (overflows)
- log(LOG_WARNING, "%s: %d silo overflow%s\n",
- sc->sc_dev.dv_xname, overflows, overflows == 1 ? "" : "s");
+ for (unit = 0; unit < comcd.cd_ndevs; unit++) {
+ sc = comcd.cd_devs[unit];
+ if (sc == 0 || sc->sc_ibufp == sc->sc_ibuf)
+ continue;
+
+ tp = sc->sc_tty;
+
+ s = spltty();
+
+ ibufp = sc->sc_ibuf;
+ ibufend = sc->sc_ibufp;
+
+ sc->sc_ibufp = sc->sc_ibuf = (ibufp == sc->sc_ibufs[0]) ?
+ sc->sc_ibufs[1] : sc->sc_ibufs[0];
+ sc->sc_ibufhigh = sc->sc_ibuf + COM_IHIGHWATER;
+ sc->sc_ibufend = sc->sc_ibuf + COM_IBUFSIZE;
+
+ if (tp == 0 || (tp->t_state & TS_ISOPEN) == 0) {
+ splx(s);
+ continue;
+ }
+
+ if ((tp->t_cflag & CRTSCTS) != 0 &&
+ (sc->sc_mcr & MCR_RTS) == 0)
+ outb(sc->sc_iobase + com_mcr, sc->sc_mcr |= MCR_RTS);
+
+ splx(s);
+
+ while (ibufp < ibufend) {
+ c = *ibufp++;
+ if (*ibufp & LSR_OE) {
+ sc->sc_overflows++;
+ if (sc->sc_errors++ == 0)
+ timeout(comdiag, sc, 60 * hz);
+ }
+ /* This is ugly, but fast. */
+ c |= lsrmap[(*ibufp++ & (LSR_BI|LSR_FE|LSR_PE)) >> 2];
+ (*linesw[tp->t_line].l_rint)(c, tp);
+ }
+ }
+
+out:
+ timeout(compoll, NULL, 1);
}
int
@@ -765,24 +812,37 @@
lsr = inb(iobase + com_lsr);
if (lsr & LSR_RCV_MASK) {
- /* XXXX put in FIFO and process later */
+ register u_char *p = sc->sc_ibufp;
+
+ comevents = 1;
do {
- if (lsr & (LSR_BI|LSR_FE|LSR_PE|LSR_OE))
- comeint(sc, lsr);
- else {
- data = inb(iobase + com_data);
- if (tp->t_state & TS_ISOPEN)
- (*linesw[tp->t_line].l_rint)(data, tp);
-#ifdef KGDB
- else {
- if (kgdb_dev == makedev(commajor, unit) &&
- data == FRAME_END)
- kgdb_connect(0);
- }
+ if ((lsr & LSR_BI) != 0) {
+#ifdef DDB
+ if (sc->sc_dev.dv_unit == comconsole) {
+ Debugger();
+ goto next;
+ } else
#endif
+ data = '\0';
+ } else
+ data = inb(iobase + com_data);
+ if (p >= sc->sc_ibufend) {
+ sc->sc_floods++;
+ if (sc->sc_errors++ == 0)
+ timeout(comdiag, sc, 60 * hz);
+ } else {
+ *p++ = data;
+ *p++ = lsr;
+ if (p == sc->sc_ibufhigh &&
+ (tp->t_cflag & CRTSCTS) != 0)
+ outb(iobase + com_mcr,
+ sc->sc_mcr &= ~MCR_RTS);
}
+ next:
lsr = inb(iobase + com_lsr);
} while (lsr & LSR_RCV_MASK);
+
+ sc->sc_ibufp = p;
}
if (lsr & LSR_TXRDY && (tp->t_state & TS_BUSY) != 0) {
@@ -801,20 +861,15 @@
if (msr != sc->sc_msr) {
delta = msr ^ sc->sc_msr;
sc->sc_msr = msr;
- if (delta & MSR_DCD && (sc->sc_swflags & COM_SW_SOFTCAR) == 0) {
- if (msr & MSR_DCD)
- (void)(*linesw[tp->t_line].l_modem)(tp, 1);
- else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0)
- outb(iobase + com_mcr,
- sc->sc_mcr &= ~(MCR_DTR | MCR_RTS));
+ if ((delta & MSR_DCD) != 0 &&
+ (sc->sc_swflags & COM_SW_SOFTCAR) == 0 &&
+ (*linesw[tp->t_line].l_modem)(tp, (msr & MSR_DCD) != 0) == 0) {
+ outb(iobase + com_mcr, sc->sc_mcr &= ~sc->sc_dtr);
}
- if (delta & MSR_CTS && (tp->t_cflag & CRTSCTS) != 0) {
+ if ((delta & msr & MSR_CTS) != 0 &&
+ (tp->t_cflag & CRTSCTS) != 0) {
/* the line is up and we want to do rts/cts flow control */
- if (msr & MSR_CTS) {
- tp->t_state &= ~TS_TTSTOP;
- (*linesw[tp->t_line].l_start)(tp);
- } else
- tp->t_state |= TS_TTSTOP;
+ (*linesw[tp->t_line].l_start)(tp);
}
}
Mark
--------------------------------------------------------------------
Email: Mark_Weaver@brown.edu | Brown University
PGP Key: finger mhw@cs.brown.edu | Dept of Computer Science