summaryrefslogtreecommitdiffstats
path: root/sys/isa/sio.c
diff options
context:
space:
mode:
authorache <ache@FreeBSD.org>1994-01-31 08:52:12 +0000
committerache <ache@FreeBSD.org>1994-01-31 08:52:12 +0000
commit805b2d4d90c77f94e31f786f0afbd08f5fd8e1cb (patch)
treea885583f08df48ec7ad5986b6226ee8c4f27b612 /sys/isa/sio.c
parent4cb172d2ef8af493bed31caf048f1db64a248c71 (diff)
downloadFreeBSD-src-805b2d4d90c77f94e31f786f0afbd08f5fd8e1cb.zip
FreeBSD-src-805b2d4d90c77f94e31f786f0afbd08f5fd8e1cb.tar.gz
1) Set ipending back to 4, because (16 + 4) bit not in
netmask or impmask. 2) Fixes from Bruce: o Changed name of schedsoftcom() to setsofttty() to match setsoftclock() o Bool_t isn't used. o tx_fifo_size is 1 for chips without fifos, 16 for 16550's, to help to output more efficiently for 16550's (LSR_TXRDY means that the fifo is empty, not that it has space for one char). o Changed name of softsio1() to siopoll() and merged compoll() into siopoll(). o The probe forgot to clear com_mcr after it failed. This is harmful for 4 single serial ports on 2 interrupts. It makes partial misconfigurations worse. o Don't bother initializing static variables that are 0 (bidir stuff). o Only initialize t_oflag to TTYDEF_OFLAG if unit == COMCONSOLE, not if COMCONSOLE is defined. o Don't call siointr() from comparam() if there is no output in progress. For the call from sioopen(), there's no output in progress, and siointr() often saw silo overflows for stale input because it was called before sioopen() discarded the input. o Let ttselect() do the work for select(), so that the fixes for ttselect() don't have to be duplicated in zillions of drivers.
Diffstat (limited to 'sys/isa/sio.c')
-rw-r--r--sys/isa/sio.c242
1 files changed, 91 insertions, 151 deletions
diff --git a/sys/isa/sio.c b/sys/isa/sio.c
index 21c9f90..30c9768 100644
--- a/sys/isa/sio.c
+++ b/sys/isa/sio.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)com.c 7.5 (Berkeley) 5/16/91
- * $Id: sio.c,v 1.22 1994/01/11 18:31:45 ache Exp $
+ * $Id: sio.c,v 1.23 1994/01/31 06:12:18 davidg Exp $
*/
#include "sio.h"
@@ -71,7 +71,7 @@
#define UNIT(x) (minor(x)) /* XXX */
#else /* COM_BIDIR */
#define COM_UNITMASK 0x7f
-#define COM_CALLOUTMASK 0x80
+#define COM_CALLOUTMASK 0x80 /* for both minor and dev */
#define UNIT(x) (minor(x) & COM_UNITMASK)
#define CALLOUT(x) (minor(x) & COM_CALLOUTMASK)
#endif /* COM_BIDIR */
@@ -98,7 +98,7 @@
#endif
#define com_scr 7 /* scratch register for 16450-16550 (R/W) */
-#define schedsoftcom() (ipending |= 1 << (16 + 4)) /* XXX */
+#define setsofttty() (ipending |= 1 << 4) /* XXX */
/*
* Input buffer watermarks.
@@ -148,7 +148,6 @@ static char *error_desc[] = {
/* types. XXX - should be elsewhere */
typedef u_int Port_t; /* hardware port */
-typedef int Bool_t; /* promoted boolean */
typedef u_char bool_t; /* boolean */
/* com device structure */
@@ -167,6 +166,7 @@ struct com_s {
bool_t multiport; /* is this unit part of a multiport device? */
#endif /* COM_MULTIPORT */
int dtr_wait; /* time to hold DTR down on close (* 1/HZ) */
+ u_int tx_fifo_size;
/*
* The high level of the driver never reads status registers directly
@@ -228,6 +228,7 @@ void siocnprobe __P((struct consdev *cp));
void siocnputc __P((Dev_t dev, int c));
int sioopen __P((Dev_t dev, int oflags, int devtype,
struct proc *p));
+void siopoll __P((void));
int sioread __P((Dev_t dev, struct uio *uio, int ioflag));
int sioselect __P((Dev_t dev, int rw, struct proc *p));
void siostop __P((struct tty *tp, int rw));
@@ -239,12 +240,11 @@ static void comflush __P((struct com_s *com));
static void comhardclose __P((struct com_s *com));
static void cominit __P((int unit, int rate));
#ifdef COM_MULTIPORT
-static bool_t comintr1 __P((struct com_s *com));
+static void comintr1 __P((struct com_s *com));
#endif /* COM_MULTIPORT */
static void commctl __P((struct com_s *com, int bits, int how));
static int comparam __P((struct tty *tp, struct termios *t));
static int sioprobe __P((struct isa_device *dev));
-static void compoll __P((void));
static void comstart __P((struct tty *tp));
static void comwakeup __P((caddr_t chan, int ticks));
static int tiocm_xxx2mcr __P((int tiocm_xxx));
@@ -386,12 +386,14 @@ sioprobe(dev)
|| isa_irq_pending(dev)
|| (inb(iobase + com_iir) & IIR_IMASK) != IIR_NOPEND)
result = 0;
+ if (result == 0)
+ outb(iobase + com_mcr, 0);
enable_intr();
return (result);
}
-static int /* XXX - should be void */
+static int
sioattach(isdp)
struct isa_device *isdp;
{
@@ -423,6 +425,7 @@ sioattach(isdp)
com->cfcr_image = CFCR_8BITS;
com->mcr_image = MCR_IENABLE;
com->dtr_wait = 200;
+ com->tx_fifo_size = 1;
com->iptr = com->ibuf = com->ibuf1;
com->ibufend = com->ibuf1 + RS_IBUFSIZE;
com->ihighwater = com->ibuf1 + RS_IHIGHWATER;
@@ -433,14 +436,6 @@ sioattach(isdp)
com->line_status_port = iobase + com_lsr;
com->modem_status_port = iobase + com_msr;
com->tp = &sio_tty[unit];
-#ifdef COM_BIDIR
- /*
- * if bidirectional ports possible, clear the bidir port info;
- */
- com->bidir = FALSE;
- com->active = FALSE;
- com->active_in = com->active_out = FALSE;
-#endif /* COM_BIDIR */
/* attempt to determine UART type */
printf("sio%d: type", unit);
@@ -481,6 +476,7 @@ sioattach(isdp)
printf(" fifo software disabled");
} else {
com->hasfifo = TRUE;
+ com->tx_fifo_size = 16;
}
break;
}
@@ -503,8 +499,7 @@ determined_type: ;
masterdev = find_isadev(isa_devtab_tty, &siodriver,
COM_MPMASTER(isdp));
outb(masterdev->id_iobase + com_scr, 0x80);
- }
- else
+ } else
com->multiport = FALSE;
#endif /* COM_MULTIPORT */
printf("\n");
@@ -522,8 +517,7 @@ determined_type: ;
*/
printf("sio%d: ", unit);
kgdb_connect(1);
- }
- else
+ } else
printf("sio%d: kgdb enabled\n", unit);
}
}
@@ -667,10 +661,10 @@ bidir_open_top:
* can be turned off.
*/
tp->t_iflag = 0;
+ tp->t_oflag = 0;
#ifdef COMCONSOLE
+ if (unit == comconsole)
tp->t_oflag = TTYDEF_OFLAG;
-#else
- tp->t_oflag = 0;
#endif
tp->t_cflag = CREAD | CS8 | HUPCL;
tp->t_lflag = 0;
@@ -695,22 +689,6 @@ bidir_open_top:
if (error != 0)
goto out;
ttsetwater(tp);
-
- /*
- * XXX temporary fix for deadlock in ttywait().
- *
- * If two processes wait for output to drain from the same
- * tty, and the amount of output to drain is > 0 and
- * <= tp->t_lowat, then the processes will take turns
- * uselessly waking each other up until the output drains,
- * with cpl higher than spltty() throughout.
- *
- * The sleep address and TS_ASLEEP flag ought to be different
- * for the different events (output done) and (output almost
- * done).
- */
- tp->t_lowat = 0;
-
iobase = com->iobase;
if (com->hasfifo) {
/* (re)enable and drain FIFO */
@@ -728,8 +706,7 @@ bidir_open_top:
enable_intr();
if (com->prev_modem_status & MSR_DCD || FAKE_DCD(unit))
tp->t_state |= TS_CARR_ON;
- }
- else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
+ } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
splx(s);
return (EBUSY);
}
@@ -799,18 +776,21 @@ comhardclose(com)
Port_t iobase;
int s;
struct tty *tp;
+ int unit;
s = spltty();
iobase = com->iobase;
outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
+ unit = com - &com_structs[0];
#ifdef KGDB
/* do not disable interrupts or hang up if debugging */
- if (kgdb_dev != makedev(commajor, com - &com_structs[0]))
+ if (kgdb_dev != makedev(commajor, unit))
#endif
{
outb(iobase + com_ier, 0);
tp = com->tp;
if (tp->t_cflag & HUPCL || tp->t_state & TS_WOPEN
+ || !(com->prev_modem_status & MSR_DCD) && !FAKE_DCD(unit)
|| !(tp->t_state & TS_ISOPEN)) {
commctl(com, MCR_RTS, DMSET);
if (com->dtr_wait != 0)
@@ -887,30 +867,28 @@ siointr(unit)
* If the IRQ signal is just an OR of the IRQ signals from several
* devices, then the edge from one may be lost because another is
* on.
- *
- * XXX getting the status from comintr1() is not best and may be
- * incorrect. It would be better to test the int_id's in a tight
- * loop. If each is off when it is tested, then they all must
- * have been off at the start.
*/
do {
possibly_more_intrs = FALSE;
for (unit = 0; unit < NSIO; ++unit) {
com = com_addr(unit);
- if (com != NULL) {
+ if (com != NULL
+ && (inb(com->int_id_port) & IIR_IMASK)
+ != IIR_NOPEND) {
/*
* XXX call comintr1() instead of here from
* comwakeup(). The interrupt edge problem
* only exists for real interrupts.
*/
- possibly_more_intrs |= comintr1(com);
+ comintr1(com);
+ possibly_more_intrs = TRUE;
}
}
} while (possibly_more_intrs);
return;
}
-static bool_t
+static void
comintr1(com)
struct com_s *com;
{
@@ -918,9 +896,6 @@ comintr1(com)
u_char modem_status;
u_char *ioptr;
u_char recv_data;
- bool_t donesomething;
-
- donesomething = FALSE;
#endif /* COM_MULTIPORT */
while (TRUE) {
@@ -929,9 +904,6 @@ comintr1(com)
/* input event? (check first to help avoid overruns) */
while (line_status & LSR_RCV_MASK) {
/* break/unnattached error bits or real input? */
-#ifdef COM_MULTIPORT
- donesomething = TRUE;
-#endif /* COM_MULTIPORT */
if (!(line_status & LSR_RXRDY))
recv_data = 0;
else
@@ -951,9 +923,9 @@ comintr1(com)
CE_RECORD(com, CE_INTERRUPT_BUF_OVERFLOW);
else {
++com_events;
-#if 0
+#if 0 /* for testing input latency vs efficiency */
if (com->iptr - com->ibuf == 8)
- schedsoftcom();
+ setsofttty();
#endif
ioptr[0] = recv_data;
ioptr[CE_INPUT_OFFSET] = line_status;
@@ -983,14 +955,11 @@ if (com->iptr - com->ibuf == 8)
* UARTs mess them up, and it's easy to remember the
* previous bits and calculate the delta.
*/
-#ifdef COM_MULTIPORT
- donesomething = TRUE;
-#endif /* COM_MULTIPORT */
com->last_modem_status = modem_status;
if (!(com->state & CS_CHECKMSR)) {
com_events += LOTS_OF_EVENTS;
com->state |= CS_CHECKMSR;
- schedsoftcom();
+ setsofttty();
}
/* handle CTS change immediately for crisp flow ctl */
@@ -1005,28 +974,35 @@ if (com->iptr - com->ibuf == 8)
/* output queued and everything ready? */
if (line_status & LSR_TXRDY
&& com->state >= (CS_ODEVREADY | CS_BUSY | CS_TTGO)) {
-#ifdef COM_MULTIPORT
- donesomething = TRUE;
-#endif /* COM_MULTIPORT */
ioptr = com->optr;
- outb(com->data_port, *ioptr);
+ if (com->tx_fifo_size > 1) {
+ u_int ocount;
+
+ ocount = com->obufend - ioptr;
+ if (ocount > com->tx_fifo_size)
+ ocount = com->tx_fifo_size;
+ com->bytes_out += ocount;
+ do
+ outb(com->data_port, *ioptr++);
+ while (--ocount != 0);
+ } else {
+ outb(com->data_port, *ioptr++);
++com->bytes_out;
- com->optr = ++ioptr;
+ }
+ com->optr = ioptr;
if (ioptr >= com->obufend) {
/* output just completed */
com_events += LOTS_OF_EVENTS;
com->state ^= (CS_ODONE | CS_BUSY);
- schedsoftcom(); /* handle at high level ASAP */
+ setsofttty(); /* handle at high level ASAP */
}
}
/* finished? */
+#ifndef COM_MULTIPORT
if ((inb(com->int_id_port) & IIR_IMASK) == IIR_NOPEND)
-#ifdef COM_MULTIPORT
- return (donesomething);
-#else
- return;
#endif /* COM_MULTIPORT */
+ return;
}
}
@@ -1063,21 +1039,19 @@ sioioctl(dev, cmd, data, flag, p)
com = com_addr(UNIT(dev));
tp = com->tp;
-
error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
if (error >= 0)
return (error);
error = ttioctl(tp, cmd, data, flag);
-#ifdef COM_BIDIR
- /* XXX: plug security hole while stucky bits not yet implemented */
+#ifdef COM_BIDIR
+ /* XXX: plug security hole while sticky bits not yet implemented */
if (com->bidir && com->active_in && p->p_ucred->cr_uid != 0)
tp->t_cflag &= ~CLOCAL;
#endif
- if (error >= 0) {
- tp->t_lowat = 0; /* XXX part of ttywait() deadlock fix */
+
+ if (error >= 0)
return (error);
- }
iobase = com->iobase;
s = spltty();
@@ -1204,11 +1178,10 @@ comflush(com)
com->tp->t_state &= ~TS_BUSY;
}
-static void
-compoll()
+void
+siopoll()
{
static bool_t awake = FALSE;
- struct com_s *com;
int s;
int unit;
@@ -1225,6 +1198,7 @@ compoll()
repeat:
for (unit = 0; unit < NSIO; ++unit) {
u_char *buf;
+ struct com_s *com;
u_char *ibuf;
int incc;
struct tty *tp;
@@ -1234,11 +1208,11 @@ repeat:
continue;
tp = com->tp;
- buf = NULL; /* avoid compiler warning */
/* switch the role of the low-level input buffers */
- if (com->iptr == (ibuf = com->ibuf))
+ if (com->iptr == (ibuf = com->ibuf)) {
+ buf = NULL; /* not used, but compiler can't tell */
incc = 0;
- else {
+ } else {
buf = ibuf;
disable_intr();
incc = com->iptr - buf;
@@ -1280,8 +1254,7 @@ repeat:
#ifdef COM_BIDIR
wakeup((caddr_t) &com->active_in);
#endif /* COM_BIDIR */
- }
- else
+ } else
(*linesw[tp->t_line].l_modem)(tp, 0);
}
}
@@ -1289,18 +1262,14 @@ repeat:
/* XXX */
if (TRUE) {
u_int delta;
- u_int delta_error_counts[CE_NTYPES];
int errnum;
u_long total;
+ for (errnum = 0; errnum < CE_NTYPES; ++errnum) {
disable_intr();
- bcopy(com->delta_error_counts, delta_error_counts,
- sizeof delta_error_counts);
- bzero(com->delta_error_counts,
- sizeof delta_error_counts);
+ delta = com->delta_error_counts[errnum];
+ com->delta_error_counts[errnum] = 0;
enable_intr();
- for (errnum = 0; errnum < CE_NTYPES; ++errnum) {
- delta = delta_error_counts[errnum];
if (delta != 0) {
total =
com->error_counts[errnum] += delta;
@@ -1359,8 +1328,7 @@ repeat:
tp->t_lflag &= ~FLUSHO;
ttstart(tp);
}
- }
- else {
+ } else {
do {
u_char line_status;
int recv_data;
@@ -1474,9 +1442,9 @@ retry:
/*
* XXX - clearing CS_TTGO is not sufficient to stop further output,
- * because compoll() calls comstart() which set it again because
- * TS_TTSTOP is set. Clearing TS_TTSTOP would not be sufficient,
- * for similar reasons.
+ * because siopoll() calls comstart() which usually sets it again
+ * because TS_TTSTOP is clear. Setting TS_TTSTOP would not be
+ * sufficient, for similar reasons.
*/
if ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
!= (LSR_TSRE | LSR_TXRDY))
@@ -1508,7 +1476,17 @@ retry:
com->state &= ~CS_ODEVREADY;
}
- siointr(unit); /* recover from fiddling with CS_TTGO */
+ /*
+ * Recover from fiddling with CS_TTGO. We used to call siointr()
+ * unconditionally, but that defeated the careful discarding of
+ * stale input in sioopen().
+ *
+ * XXX sioopen() is not careful waiting for carrier for the callout
+ * case.
+ */
+ if (com->state >= (CS_BUSY | CS_TTGO))
+ siointr(unit);
+
enable_intr();
splx(s);
return (0);
@@ -1533,8 +1511,7 @@ comstart(tp)
if (tp->t_state & TS_RTS_IFLOW) {
if (com->mcr_image & MCR_RTS && com->state & CS_RTS_IFLOW)
outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS);
- }
- else {
+ } else {
if (!(com->mcr_image & MCR_RTS) && com->iptr < com->ihighwater)
outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
}
@@ -1556,8 +1533,7 @@ comstart(tp)
disable_intr();
siointr(unit);
enable_intr();
- }
- else if (RB_LEN(&tp->t_out) != 0) {
+ } else if (RB_LEN(&tp->t_out) != 0) {
tp->t_state |= TS_BUSY;
com->ocount = RB_CONTIGGET(&tp->t_out);
disable_intr();
@@ -1593,6 +1569,15 @@ siostop(tp, rw)
enable_intr();
}
+int
+sioselect(dev, rw, p)
+ dev_t dev;
+ int rw;
+ struct proc *p;
+{
+ return ttselect(dev & ~COM_CALLOUTMASK, rw, p);
+}
+
static void
commctl(com, bits, how)
struct com_s *com;
@@ -1620,16 +1605,17 @@ comwakeup(chan, ticks)
caddr_t chan;
int ticks;
{
- struct com_s *com;
int unit;
timeout(comwakeup, (caddr_t) NULL, hz / 100);
if (com_events != 0)
- /* schedule compoll() to run when the cpl allows */
- schedsoftcom();
+ /* schedule siopoll() to run when the cpl allows */
+ setsofttty();
/* recover from lost output interrupts */
for (unit = 0; unit < NSIO; ++unit) {
+ struct com_s *com;
+
com = com_addr(unit);
if (com != NULL && com->state >= (CS_BUSY | CS_TTGO)) {
disable_intr();
@@ -1643,7 +1629,7 @@ comwakeup(chan, ticks)
void
softsio1()
{
- compoll();
+ siopoll();
}
/*
@@ -1674,7 +1660,6 @@ siocnprobe(cp)
/* initialize required fields */
cp->cn_dev = makedev(commajor, unit);
- cp->cn_tp = &sio_tty[unit];
#ifdef COMCONSOLE
cp->cn_pri = CN_REMOTE; /* Force a serial port console */
#else
@@ -1775,49 +1760,4 @@ siocnputc(dev, c)
splx(s);
}
-/*
- * XXX - sioselect() is almost a copy of ttselect(). It is required because
- * ttselect() can't determine the tty struct because stuff is encoded in the
- * high bit of the minor number.
- */
-int
-sioselect(dev, rw, p)
- dev_t dev;
- int rw;
- struct proc *p;
-{
- struct tty *tp = &sio_tty[UNIT(dev)];
- int nread;
- int s = spltty();
- struct proc *selp;
-
- switch (rw) {
-
- case FREAD:
- nread = ttnread(tp);
- if (nread > 0 ||
- ((tp->t_cflag&CLOCAL) == 0 && (tp->t_state&TS_CARR_ON) == 0))
- goto win;
- if (tp->t_rsel && (selp = pfind(tp->t_rsel)) && selp->p_wchan == (caddr_t)&selwait)
- tp->t_state |= TS_RCOLL;
- else
- tp->t_rsel = p->p_pid;
- break;
-
- case FWRITE:
- if (RB_LEN(&tp->t_out) <= tp->t_lowat)
- goto win;
- if (tp->t_wsel && (selp = pfind(tp->t_wsel)) && selp->p_wchan == (caddr_t)&selwait)
- tp->t_state |= TS_WCOLL;
- else
- tp->t_wsel = p->p_pid;
- break;
- }
- splx(s);
- return (0);
- win:
- splx(s);
- return (1);
-}
-
#endif /* NSIO > 0 */
OpenPOWER on IntegriCloud