summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornyan <nyan@FreeBSD.org>2003-10-05 11:55:14 +0000
committernyan <nyan@FreeBSD.org>2003-10-05 11:55:14 +0000
commit9f426ad28287f3868d5708ad65643187b1f23dfd (patch)
treeba4d81fda3cf70ecb6c18fb8405bac484df513df
parent40395a5b737d77f5ffd47c73ece1545c52992f3b (diff)
downloadFreeBSD-src-9f426ad28287f3868d5708ad65643187b1f23dfd.zip
FreeBSD-src-9f426ad28287f3868d5708ad65643187b1f23dfd.tar.gz
Merged from sys/dev/sio/sio.c revisions from 1.405 to 1.414.
-rw-r--r--sys/pc98/cbus/sio.c291
-rw-r--r--sys/pc98/pc98/sio.c291
2 files changed, 274 insertions, 308 deletions
diff --git a/sys/pc98/cbus/sio.c b/sys/pc98/cbus/sio.c
index 2ca08cb..3c4b165 100644
--- a/sys/pc98/cbus/sio.c
+++ b/sys/pc98/cbus/sio.c
@@ -182,20 +182,20 @@
#define COM_ISMULTIPORT(flags) (0)
#endif /* COM_MULTIPORT */
+#define COM_C_IIR_TXRDYBUG 0x80000
#define COM_CONSOLE(flags) ((flags) & 0x10)
+#define COM_DEBUGGER(flags) ((flags) & 0x80)
+#define COM_FIFOSIZE(flags) (((flags) & 0xff000000) >> 24)
#define COM_FORCECONSOLE(flags) ((flags) & 0x20)
+#define COM_IIR_TXRDYBUG(flags) ((flags) & COM_C_IIR_TXRDYBUG)
#define COM_LLCONSOLE(flags) ((flags) & 0x40)
-#define COM_DEBUGGER(flags) ((flags) & 0x80)
#define COM_LOSESOUTINTS(flags) ((flags) & 0x08)
-#define COM_NOFIFO(flags) ((flags) & 0x02)
+#define COM_NOFIFO(flags) ((flags) & 0x02)
+#define COM_NOPROBE(flags) ((flags) & 0x40000)
+#define COM_NOSCR(flags) ((flags) & 0x100000)
#define COM_PPSCTS(flags) ((flags) & 0x10000)
-#define COM_ST16650A(flags) ((flags) & 0x20000)
-#define COM_C_NOPROBE (0x40000)
-#define COM_NOPROBE(flags) ((flags) & COM_C_NOPROBE)
-#define COM_C_IIR_TXRDYBUG (0x80000)
-#define COM_IIR_TXRDYBUG(flags) ((flags) & COM_C_IIR_TXRDYBUG)
-#define COM_NOSCR(flags) ((flags) & 0x100000)
-#define COM_FIFOSIZE(flags) (((flags) & 0xff000000) >> 24)
+#define COM_ST16650A(flags) ((flags) & 0x20000)
+#define COM_TI16754(flags) ((flags) & 0x200000)
#define sio_getreg(com, off) \
(bus_space_read_1((com)->bst, (com)->bsh, (off)))
@@ -254,7 +254,6 @@ struct lbq {
/* com device structure */
struct com_s {
- u_int flags; /* Copy isa device flags */
u_char state; /* miscellaneous flag bits */
bool_t active_out; /* nonzero if the callout device is open */
u_char cfcr_image; /* copy of value written to CFCR */
@@ -264,7 +263,6 @@ struct com_s {
u_char extra_state; /* more flag bits, separate for order trick */
u_char fifo_image; /* copy of value written to FIFO */
bool_t hasfifo; /* nonzero for 16550 UARTs */
- bool_t st16650a; /* Is a Startech 16650A or RTS/CTS compat */
bool_t loses_outints; /* nonzero if device loses output interrupts */
u_char mcr_image; /* copy of value written to MCR */
#ifdef COM_MULTIPORT
@@ -274,8 +272,10 @@ struct com_s {
bool_t gone; /* hardware disappeared */
bool_t poll; /* nonzero if polling is required */
bool_t poll_output; /* nonzero if polling for output is required */
+ bool_t st16650a; /* nonzero if Startech 16650A compatible */
int unit; /* unit number */
int dtr_wait; /* time to hold DTR down on close (* 1/hz) */
+ u_int flags; /* copy of device flags */
u_int tx_fifo_size;
u_int wopeners; /* # processes waiting for DCD in open() */
@@ -325,11 +325,11 @@ struct com_s {
#ifdef COM_ESP
Port_t esp_port;
#endif
+ Port_t int_ctl_port;
Port_t int_id_port;
Port_t modem_ctl_port;
Port_t line_status_port;
Port_t modem_status_port;
- Port_t intr_ctl_port; /* Ports of IIR register */
struct tty *tp; /* cross reference */
@@ -784,7 +784,7 @@ siodetach(dev)
device_printf(dev, "NULL com in siounload\n");
return (0);
}
- com->gone = 1;
+ com->gone = TRUE;
for (i = 0 ; i < 6; i++)
destroy_dev(com->devs[i]);
if (com->irqres) {
@@ -1172,7 +1172,10 @@ sioprobe(dev, xrid, rclk, noprobe)
* it's unlikely to do more than allow the null byte out.
*/
sio_setreg(com, com_data, 0);
- DELAY((1 + 2) * 1000000 / (SIO_TEST_SPEED / 10));
+ if (iobase == siocniobase)
+ DELAY((1 + 2) * 1000000 / (comdefaultrate / 10));
+ else
+ DELAY((1 + 2) * 1000000 / (SIO_TEST_SPEED / 10));
/*
* Turn off loopback mode so that the interrupt gate works again
@@ -1192,30 +1195,37 @@ sioprobe(dev, xrid, rclk, noprobe)
sio_setreg(com, com_cfcr, CFCR_8BITS);
/*
- * Some pcmcia cards have the "TXRDY bug", so we check everyone
- * for IIR_TXRDY implementation ( Palido 321s, DC-1S... )
+ * Some PCMCIA cards (Palido 321s, DC-1S, ...) have the "TXRDY bug",
+ * so we probe for a buggy IIR_TXRDY implementation even in the
+ * noprobe case. We don't probe for it in the !noprobe case because
+ * noprobe is always set for PCMCIA cards and the problem is not
+ * known to affect any other cards.
*/
if (noprobe) {
- /* Reading IIR register twice */
+ /* Read IIR a few times. */
for (fn = 0; fn < 2; fn ++) {
DELAY(10000);
failures[6] = sio_getreg(com, com_iir);
}
- /* Check IIR_TXRDY clear ? */
+
+ /* IIR_TXRDY should be clear. Is it? */
result = 0;
if (failures[6] & IIR_TXRDY) {
- /* No, Double check with clearing IER */
+ /*
+ * No. We seem to have the bug. Does our fix for
+ * it work?
+ */
sio_setreg(com, com_ier, 0);
if (sio_getreg(com, com_iir) & IIR_NOPEND) {
- /* Ok. We discovered TXRDY bug! */
+ /* Yes. We discovered the TXRDY bug! */
SET_FLAG(dev, COM_C_IIR_TXRDYBUG);
} else {
- /* Unknown, Just omit this chip.. XXX */
+ /* No. Just fail. XXX */
result = ENXIO;
sio_setreg(com, com_mcr, 0);
}
} else {
- /* OK. this is well-known guys */
+ /* Yes. No bug. */
CLR_FLAG(dev, COM_C_IIR_TXRDYBUG);
}
sio_setreg(com, com_ier, 0);
@@ -1526,21 +1536,21 @@ sioattach(dev, xrid, rclk)
bus_addr_t *iat = if_16550a_type[if_type & 0x0f].iat;
com->data_port = iobase + iat[com_data];
+ com->int_ctl_port = iobase + iat[com_ier];
com->int_id_port = iobase + iat[com_iir];
com->modem_ctl_port = iobase + iat[com_mcr];
com->mcr_image = inb(com->modem_ctl_port);
com->line_status_port = iobase + iat[com_lsr];
com->modem_status_port = iobase + iat[com_msr];
- com->intr_ctl_port = iobase + iat[com_ier];
}
#else /* not PC98 */
com->data_port = iobase + com_data;
+ com->int_ctl_port = iobase + com_ier;
com->int_id_port = iobase + com_iir;
com->modem_ctl_port = iobase + com_mcr;
com->mcr_image = inb(com->modem_ctl_port);
com->line_status_port = iobase + com_lsr;
com->modem_status_port = iobase + com_msr;
- com->intr_ctl_port = iobase + com_ier;
#endif
#ifdef PC98
@@ -1635,7 +1645,6 @@ sioattach(dev, xrid, rclk)
#endif /* PC98 */
sio_setreg(com, com_fifo, FIFO_ENABLE | FIFO_RX_HIGH);
DELAY(100);
- com->st16650a = 0;
switch (inb(com->int_id_port) & IIR_FIFO_MASK) {
case FIFO_RX_LOW:
printf(" 16450");
@@ -1649,22 +1658,9 @@ sioattach(dev, xrid, rclk)
case FIFO_RX_HIGH:
if (COM_NOFIFO(flags)) {
printf(" 16550A fifo disabled");
- } else {
- com->hasfifo = TRUE;
-#ifdef PC98
- com->tx_fifo_size = 0; /* XXX flag conflicts. */
- printf(" 16550A");
-#else
- if (COM_ST16650A(flags)) {
- com->st16650a = 1;
- com->tx_fifo_size = 32;
- printf(" ST16650A");
- } else {
- com->tx_fifo_size = COM_FIFOSIZE(flags);
- printf(" 16550A");
- }
-#endif
+ break;
}
+ com->hasfifo = TRUE;
#ifdef PC98
if (com->pc98_if_type == COM_IF_RSA98III) {
com->tx_fifo_size = 2048;
@@ -1672,8 +1668,20 @@ sioattach(dev, xrid, rclk)
outb(com->rsabase + rsa_ier, 0x00);
outb(com->rsabase + rsa_frr, 0x00);
}
+#else
+ if (COM_ST16650A(flags)) {
+ printf(" ST16650A");
+ com->st16650a = TRUE;
+ com->tx_fifo_size = 32;
+ break;
+ }
+ if (COM_TI16754(flags)) {
+ printf(" TI16754");
+ com->tx_fifo_size = 64;
+ break;
+ }
#endif
-
+ printf(" 16550A");
#ifdef COM_ESP
#ifdef PC98
if (com->pc98_if_type == COM_IF_ESP98)
@@ -1683,15 +1691,19 @@ sioattach(dev, xrid, rclk)
com->tx_fifo_size = 1024;
break;
}
+ if (com->esp != NULL)
+ break;
+#endif
+#ifdef PC98
+ com->tx_fifo_size = 16;
+#else
+ com->tx_fifo_size = COM_FIFOSIZE(flags);
+ if (com->tx_fifo_size == 0)
+ com->tx_fifo_size = 16;
+ else
+ printf(" lookalike with %u bytes FIFO",
+ com->tx_fifo_size);
#endif
- if (!com->st16650a) {
- if (!com->tx_fifo_size)
- com->tx_fifo_size = 16;
- else
- printf(" lookalike with %d bytes FIFO",
- com->tx_fifo_size);
- }
-
break;
}
@@ -1707,7 +1719,7 @@ sioattach(dev, xrid, rclk)
#endif
#ifdef COM_ESP
- if (com->esp) {
+ if (com->esp != NULL) {
/*
* Set 16550 compatibility mode.
* We don't use the ESP_MODE_SCALE bit to increase the
@@ -1784,7 +1796,7 @@ determined_type: ;
if (unit == comconsole)
printf(", console");
if (COM_IIR_TXRDYBUG(flags))
- printf(" with a bogus IIR_TXRDY register");
+ printf(" with a buggy IIR_TXRDY implementation");
printf("\n");
if (sio_fast_ih == NULL) {
@@ -2019,17 +2031,13 @@ open_top:
(void) inb(com->data_port);
com->prev_modem_status = com->last_modem_status
= inb(com->modem_status_port);
- if (COM_IIR_TXRDYBUG(com->flags)) {
- outb(com->intr_ctl_port, IER_ERXRDY | IER_ERLS
- | IER_EMSC);
- } else {
- outb(com->intr_ctl_port, IER_ERXRDY | IER_ETXRDY
- | IER_ERLS | IER_EMSC);
- }
+ outb(com->int_ctl_port,
+ IER_ERXRDY | IER_ERLS | IER_EMSC
+ | (COM_IIR_TXRDYBUG(com->flags) ? 0 : IER_ETXRDY));
#ifdef PC98
if (com->pc98_if_type == COM_IF_RSA98III) {
outb(com->rsabase + rsa_ier, 0x1d);
- outb(com->intr_ctl_port, IER_ERLS | IER_EMSC);
+ outb(com->int_ctl_port, IER_ERLS | IER_EMSC);
}
#endif
#ifdef PC98
@@ -2327,8 +2335,12 @@ siodivisor(rclk, speed)
u_int divisor;
int error;
- if (speed == 0 || speed > (ULONG_MAX - 1) / 8)
+ if (speed == 0)
+ return (0);
+#if UINT_MAX > (ULONG_MAX - 1) / 8
+ if (speed > (ULONG_MAX - 1) / 8)
return (0);
+#endif
divisor = (rclk / (8UL * speed) + 1) / 2;
if (divisor == 0 || divisor >= 65536)
return (0);
@@ -2570,12 +2582,12 @@ static void
siointr1(com)
struct com_s *com;
{
+ u_char int_ctl;
+ u_char int_ctl_new;
u_char line_status;
u_char modem_status;
u_char *ioptr;
u_char recv_data;
- u_char int_ctl;
- u_char int_ctl_new;
#ifdef PC98
u_char tmp = 0;
@@ -2583,8 +2595,13 @@ siointr1(com)
int rsa_tx_fifo_size = 0;
#endif /* PC98 */
- int_ctl = inb(com->intr_ctl_port);
- int_ctl_new = int_ctl;
+ if (COM_IIR_TXRDYBUG(com->flags)) {
+ int_ctl = inb(com->int_ctl_port);
+ int_ctl_new = int_ctl;
+ } else {
+ int_ctl = 0;
+ int_ctl_new = 0;
+ }
while (!com->gone) {
#ifdef PC98
@@ -2854,9 +2871,8 @@ cont:
com_int_Tx_enable(com);
#endif
com->obufq.l_head = ioptr;
- if (COM_IIR_TXRDYBUG(com->flags)) {
+ if (COM_IIR_TXRDYBUG(com->flags))
int_ctl_new = int_ctl | IER_ETXRDY;
- }
if (ioptr >= com->obufq.l_tail) {
struct lbq *qp;
@@ -2869,9 +2885,9 @@ cont:
com->obufq.l_next = qp;
} else {
/* output just completed */
- if (COM_IIR_TXRDYBUG(com->flags)) {
- int_ctl_new = int_ctl & ~IER_ETXRDY;
- }
+ if (COM_IIR_TXRDYBUG(com->flags))
+ int_ctl_new = int_ctl
+ & ~IER_ETXRDY;
com->state &= ~CS_BUSY;
#if defined(PC98)
if (IS_8251(com->pc98_if_type) &&
@@ -2886,16 +2902,21 @@ cont:
swi_sched(sio_fast_ih, 0);
}
}
- if (COM_IIR_TXRDYBUG(com->flags) && (int_ctl != int_ctl_new)) {
#ifdef PC98
+ if (COM_IIR_TXRDYBUG(com->flags)
+ && int_ctl != int_ctl_new) {
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->int_ctl_port, int_ctl_new);
outb(com->rsabase + rsa_ier, 0x1d);
} else
-#endif
- outb(com->intr_ctl_port, int_ctl_new);
+ outb(com->int_ctl_port, int_ctl_new);
}
+#else
+ if (COM_IIR_TXRDYBUG(com->flags)
+ && int_ctl != int_ctl_new)
+ outb(com->int_ctl_port, int_ctl_new);
+#endif
}
#ifdef PC98
else if (line_status & LSR_TXRDY) {
@@ -3235,6 +3256,7 @@ comparam(tp, t)
u_int divisor;
u_char dlbh;
u_char dlbl;
+ u_char efr_flowbits;
int s;
int unit;
#ifdef PC98
@@ -3254,20 +3276,12 @@ comparam(tp, t)
return (EINVAL);
} else {
#endif
- /* do historical conversions */
- if (t->c_ispeed == 0)
- t->c_ispeed = t->c_ospeed;
-
/* check requested parameters */
- if (t->c_ospeed == 0)
- divisor = 0;
- else {
- if (t->c_ispeed != t->c_ospeed)
- return (EINVAL);
- divisor = siodivisor(com->rclk, t->c_ispeed);
- if (divisor == 0)
- return (EINVAL);
- }
+ if (t->c_ispeed != (t->c_ospeed != 0 ? t->c_ospeed : tp->t_ospeed))
+ return (EINVAL);
+ divisor = siodivisor(com->rclk, t->c_ispeed);
+ if (divisor == 0)
+ return (EINVAL);
#ifdef PC98
}
#endif
@@ -3276,13 +3290,13 @@ comparam(tp, t)
s = spltty();
#ifdef PC98
if (IS_8251(com->pc98_if_type)) {
- if (divisor == 0)
+ if (t->c_ospeed == 0)
com_tiocm_bic(com, TIOCM_DTR|TIOCM_RTS|TIOCM_LE);
else
com_tiocm_bis(com, TIOCM_DTR|TIOCM_RTS|TIOCM_LE);
} else
#endif
- if (divisor == 0)
+ if (t->c_ospeed == 0)
(void)commctl(com, TIOCM_DTR, DMBIC); /* hang up line */
else
(void)commctl(com, TIOCM_DTR, DMBIS);
@@ -3312,7 +3326,7 @@ comparam(tp, t)
if (cflag & CSTOPB)
cfcr |= CFCR_STOPB;
- if (com->hasfifo && divisor != 0) {
+ if (com->hasfifo) {
/*
* Use a fifo trigger level low enough so that the input
* latency from the fifo is less than about 16 msec and
@@ -3321,13 +3335,13 @@ comparam(tp, t)
* protocols shouldn't expect anything better since modem
* latencies are larger.
*
- * We have to set the FIFO trigger point such that we
- * don't overflow it accidently if a serial interrupt
- * is delayed. At high speeds, FIFO_RX_HIGH does not
- * leave enough slots free.
+ * The fifo trigger level cannot be set at RX_HIGH for high
+ * speed connections without further work on reducing
+ * interrupt disablement times in other parts of the system,
+ * without producing silo overflow errors.
*/
com->fifo_image = com->unit == siotsunit ? 0
- : t->c_ospeed <= 4800
+ : t->c_ispeed <= 4800
? FIFO_ENABLE : FIFO_ENABLE | FIFO_RX_MEDH;
#ifdef COM_ESP
/*
@@ -3356,39 +3370,27 @@ comparam(tp, t)
com_cflag_and_speed_set(com, cflag, t->c_ospeed);
else {
#endif
- if (divisor != 0) {
- sio_setreg(com, com_cfcr, cfcr | CFCR_DLAB);
- /*
- * Only set the divisor registers if they would change,
- * since on some 16550 incompatibles (UMC8669F), setting
- * them while input is arriving them loses sync until
- * data stops arriving.
- */
- dlbl = divisor & 0xFF;
- if (sio_getreg(com, com_dlbl) != dlbl)
- sio_setreg(com, com_dlbl, dlbl);
- dlbh = divisor >> 8;
- if (sio_getreg(com, com_dlbh) != dlbh)
- sio_setreg(com, com_dlbh, dlbh);
- }
-
- sio_setreg(com, com_cfcr, com->cfcr_image = cfcr);
+ sio_setreg(com, com_cfcr, cfcr | CFCR_DLAB);
+ /*
+ * Only set the divisor registers if they would change, since on
+ * some 16550 incompatibles (UMC8669F), setting them while input
+ * is arriving loses sync until data stops arriving.
+ */
+ dlbl = divisor & 0xFF;
+ if (sio_getreg(com, com_dlbl) != dlbl)
+ sio_setreg(com, com_dlbl, dlbl);
+ dlbh = divisor >> 8;
+ if (sio_getreg(com, com_dlbh) != dlbh)
+ sio_setreg(com, com_dlbh, dlbh);
#ifdef PC98
}
#endif
- if (!(tp->t_state & TS_TTSTOP))
- com->state |= CS_TTGO;
+ efr_flowbits = 0;
if (cflag & CRTS_IFLOW) {
-#ifndef PC98
- if (com->st16650a) {
- sio_setreg(com, com_cfcr, 0xbf);
- sio_setreg(com, com_fifo,
- sio_getreg(com, com_fifo) | 0x40);
- }
-#endif
com->state |= CS_RTS_IFLOW;
+ efr_flowbits |= EFR_AUTORTS;
/*
* If CS_RTS_IFLOW just changed from off to on, the change
* needs to be propagated to MCR_RTS. This isn't urgent,
@@ -3408,15 +3410,9 @@ comparam(tp, t)
outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
#else
outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
- if (com->st16650a) {
- sio_setreg(com, com_cfcr, 0xbf);
- sio_setreg(com, com_fifo,
- sio_getreg(com, com_fifo) & ~0x40);
- }
#endif
}
-
/*
* Set up state to handle output flow control.
* XXX - worth handling MDMBUF (DCD) flow control at the lowest level?
@@ -3432,49 +3428,35 @@ comparam(tp, t)
#endif
if (cflag & CCTS_OFLOW) {
com->state |= CS_CTS_OFLOW;
+ efr_flowbits |= EFR_AUTOCTS;
#ifdef PC98
if (IS_8251(com->pc98_if_type)) {
if (!(pc98_get_modem_status(com) & TIOCM_CTS))
com->state &= ~CS_ODEVREADY;
- } else {
- if (com->pc98_if_type == COM_IF_RSA98III) {
- /* Set automatic flow control mode */
- outb(com->rsabase + rsa_msr, param | 0x08);
- } else
+ } else if (com->pc98_if_type == COM_IF_RSA98III) {
+ /* Set automatic flow control mode */
+ outb(com->rsabase + rsa_msr, param | 0x08);
+ } else
#endif
if (!(com->last_modem_status & MSR_CTS))
com->state &= ~CS_ODEVREADY;
-#ifdef PC98
- }
-#else
- if (com->st16650a) {
- sio_setreg(com, com_cfcr, 0xbf);
- sio_setreg(com, com_fifo,
- sio_getreg(com, com_fifo) | 0x80);
- }
- } else {
- if (com->st16650a) {
- sio_setreg(com, com_cfcr, 0xbf);
- sio_setreg(com, com_fifo,
- sio_getreg(com, com_fifo) & ~0x80);
- }
-#endif
}
#ifdef PC98
if (!IS_8251(com->pc98_if_type))
+ sio_setreg(com, com_cfcr, com->cfcr_image = cfcr);
+#else
+ if (com->st16650a) {
+ sio_setreg(com, com_lcr, LCR_EFR_ENABLE);
+ sio_setreg(com, com_efr,
+ (sio_getreg(com, com_efr)
+ & ~(EFR_AUTOCTS | EFR_AUTORTS)) | efr_flowbits);
+ }
+ sio_setreg(com, com_cfcr, com->cfcr_image = cfcr);
#endif
- sio_setreg(com, com_cfcr, com->cfcr_image);
/* XXX shouldn't call functions while intrs are disabled. */
disc_optim(tp, t, com);
- /*
- * Recover from fiddling with CS_TTGO. We used to call siointr1()
- * unconditionally, but that defeated the careful discarding of
- * stale input in sioopen().
- */
- if (com->state >= (CS_BUSY | CS_TTGO))
- siointr1(com);
mtx_unlock_spin(&sio_lock);
splx(s);
@@ -4158,6 +4140,7 @@ siocnprobe(cp)
for (unit = 0; unit < 16; unit++) { /* XXX need to know how many */
int flags;
+
if (resource_disabled("sio", unit))
continue;
if (resource_int_value("sio", unit, "flags", &flags))
diff --git a/sys/pc98/pc98/sio.c b/sys/pc98/pc98/sio.c
index 2ca08cb..3c4b165 100644
--- a/sys/pc98/pc98/sio.c
+++ b/sys/pc98/pc98/sio.c
@@ -182,20 +182,20 @@
#define COM_ISMULTIPORT(flags) (0)
#endif /* COM_MULTIPORT */
+#define COM_C_IIR_TXRDYBUG 0x80000
#define COM_CONSOLE(flags) ((flags) & 0x10)
+#define COM_DEBUGGER(flags) ((flags) & 0x80)
+#define COM_FIFOSIZE(flags) (((flags) & 0xff000000) >> 24)
#define COM_FORCECONSOLE(flags) ((flags) & 0x20)
+#define COM_IIR_TXRDYBUG(flags) ((flags) & COM_C_IIR_TXRDYBUG)
#define COM_LLCONSOLE(flags) ((flags) & 0x40)
-#define COM_DEBUGGER(flags) ((flags) & 0x80)
#define COM_LOSESOUTINTS(flags) ((flags) & 0x08)
-#define COM_NOFIFO(flags) ((flags) & 0x02)
+#define COM_NOFIFO(flags) ((flags) & 0x02)
+#define COM_NOPROBE(flags) ((flags) & 0x40000)
+#define COM_NOSCR(flags) ((flags) & 0x100000)
#define COM_PPSCTS(flags) ((flags) & 0x10000)
-#define COM_ST16650A(flags) ((flags) & 0x20000)
-#define COM_C_NOPROBE (0x40000)
-#define COM_NOPROBE(flags) ((flags) & COM_C_NOPROBE)
-#define COM_C_IIR_TXRDYBUG (0x80000)
-#define COM_IIR_TXRDYBUG(flags) ((flags) & COM_C_IIR_TXRDYBUG)
-#define COM_NOSCR(flags) ((flags) & 0x100000)
-#define COM_FIFOSIZE(flags) (((flags) & 0xff000000) >> 24)
+#define COM_ST16650A(flags) ((flags) & 0x20000)
+#define COM_TI16754(flags) ((flags) & 0x200000)
#define sio_getreg(com, off) \
(bus_space_read_1((com)->bst, (com)->bsh, (off)))
@@ -254,7 +254,6 @@ struct lbq {
/* com device structure */
struct com_s {
- u_int flags; /* Copy isa device flags */
u_char state; /* miscellaneous flag bits */
bool_t active_out; /* nonzero if the callout device is open */
u_char cfcr_image; /* copy of value written to CFCR */
@@ -264,7 +263,6 @@ struct com_s {
u_char extra_state; /* more flag bits, separate for order trick */
u_char fifo_image; /* copy of value written to FIFO */
bool_t hasfifo; /* nonzero for 16550 UARTs */
- bool_t st16650a; /* Is a Startech 16650A or RTS/CTS compat */
bool_t loses_outints; /* nonzero if device loses output interrupts */
u_char mcr_image; /* copy of value written to MCR */
#ifdef COM_MULTIPORT
@@ -274,8 +272,10 @@ struct com_s {
bool_t gone; /* hardware disappeared */
bool_t poll; /* nonzero if polling is required */
bool_t poll_output; /* nonzero if polling for output is required */
+ bool_t st16650a; /* nonzero if Startech 16650A compatible */
int unit; /* unit number */
int dtr_wait; /* time to hold DTR down on close (* 1/hz) */
+ u_int flags; /* copy of device flags */
u_int tx_fifo_size;
u_int wopeners; /* # processes waiting for DCD in open() */
@@ -325,11 +325,11 @@ struct com_s {
#ifdef COM_ESP
Port_t esp_port;
#endif
+ Port_t int_ctl_port;
Port_t int_id_port;
Port_t modem_ctl_port;
Port_t line_status_port;
Port_t modem_status_port;
- Port_t intr_ctl_port; /* Ports of IIR register */
struct tty *tp; /* cross reference */
@@ -784,7 +784,7 @@ siodetach(dev)
device_printf(dev, "NULL com in siounload\n");
return (0);
}
- com->gone = 1;
+ com->gone = TRUE;
for (i = 0 ; i < 6; i++)
destroy_dev(com->devs[i]);
if (com->irqres) {
@@ -1172,7 +1172,10 @@ sioprobe(dev, xrid, rclk, noprobe)
* it's unlikely to do more than allow the null byte out.
*/
sio_setreg(com, com_data, 0);
- DELAY((1 + 2) * 1000000 / (SIO_TEST_SPEED / 10));
+ if (iobase == siocniobase)
+ DELAY((1 + 2) * 1000000 / (comdefaultrate / 10));
+ else
+ DELAY((1 + 2) * 1000000 / (SIO_TEST_SPEED / 10));
/*
* Turn off loopback mode so that the interrupt gate works again
@@ -1192,30 +1195,37 @@ sioprobe(dev, xrid, rclk, noprobe)
sio_setreg(com, com_cfcr, CFCR_8BITS);
/*
- * Some pcmcia cards have the "TXRDY bug", so we check everyone
- * for IIR_TXRDY implementation ( Palido 321s, DC-1S... )
+ * Some PCMCIA cards (Palido 321s, DC-1S, ...) have the "TXRDY bug",
+ * so we probe for a buggy IIR_TXRDY implementation even in the
+ * noprobe case. We don't probe for it in the !noprobe case because
+ * noprobe is always set for PCMCIA cards and the problem is not
+ * known to affect any other cards.
*/
if (noprobe) {
- /* Reading IIR register twice */
+ /* Read IIR a few times. */
for (fn = 0; fn < 2; fn ++) {
DELAY(10000);
failures[6] = sio_getreg(com, com_iir);
}
- /* Check IIR_TXRDY clear ? */
+
+ /* IIR_TXRDY should be clear. Is it? */
result = 0;
if (failures[6] & IIR_TXRDY) {
- /* No, Double check with clearing IER */
+ /*
+ * No. We seem to have the bug. Does our fix for
+ * it work?
+ */
sio_setreg(com, com_ier, 0);
if (sio_getreg(com, com_iir) & IIR_NOPEND) {
- /* Ok. We discovered TXRDY bug! */
+ /* Yes. We discovered the TXRDY bug! */
SET_FLAG(dev, COM_C_IIR_TXRDYBUG);
} else {
- /* Unknown, Just omit this chip.. XXX */
+ /* No. Just fail. XXX */
result = ENXIO;
sio_setreg(com, com_mcr, 0);
}
} else {
- /* OK. this is well-known guys */
+ /* Yes. No bug. */
CLR_FLAG(dev, COM_C_IIR_TXRDYBUG);
}
sio_setreg(com, com_ier, 0);
@@ -1526,21 +1536,21 @@ sioattach(dev, xrid, rclk)
bus_addr_t *iat = if_16550a_type[if_type & 0x0f].iat;
com->data_port = iobase + iat[com_data];
+ com->int_ctl_port = iobase + iat[com_ier];
com->int_id_port = iobase + iat[com_iir];
com->modem_ctl_port = iobase + iat[com_mcr];
com->mcr_image = inb(com->modem_ctl_port);
com->line_status_port = iobase + iat[com_lsr];
com->modem_status_port = iobase + iat[com_msr];
- com->intr_ctl_port = iobase + iat[com_ier];
}
#else /* not PC98 */
com->data_port = iobase + com_data;
+ com->int_ctl_port = iobase + com_ier;
com->int_id_port = iobase + com_iir;
com->modem_ctl_port = iobase + com_mcr;
com->mcr_image = inb(com->modem_ctl_port);
com->line_status_port = iobase + com_lsr;
com->modem_status_port = iobase + com_msr;
- com->intr_ctl_port = iobase + com_ier;
#endif
#ifdef PC98
@@ -1635,7 +1645,6 @@ sioattach(dev, xrid, rclk)
#endif /* PC98 */
sio_setreg(com, com_fifo, FIFO_ENABLE | FIFO_RX_HIGH);
DELAY(100);
- com->st16650a = 0;
switch (inb(com->int_id_port) & IIR_FIFO_MASK) {
case FIFO_RX_LOW:
printf(" 16450");
@@ -1649,22 +1658,9 @@ sioattach(dev, xrid, rclk)
case FIFO_RX_HIGH:
if (COM_NOFIFO(flags)) {
printf(" 16550A fifo disabled");
- } else {
- com->hasfifo = TRUE;
-#ifdef PC98
- com->tx_fifo_size = 0; /* XXX flag conflicts. */
- printf(" 16550A");
-#else
- if (COM_ST16650A(flags)) {
- com->st16650a = 1;
- com->tx_fifo_size = 32;
- printf(" ST16650A");
- } else {
- com->tx_fifo_size = COM_FIFOSIZE(flags);
- printf(" 16550A");
- }
-#endif
+ break;
}
+ com->hasfifo = TRUE;
#ifdef PC98
if (com->pc98_if_type == COM_IF_RSA98III) {
com->tx_fifo_size = 2048;
@@ -1672,8 +1668,20 @@ sioattach(dev, xrid, rclk)
outb(com->rsabase + rsa_ier, 0x00);
outb(com->rsabase + rsa_frr, 0x00);
}
+#else
+ if (COM_ST16650A(flags)) {
+ printf(" ST16650A");
+ com->st16650a = TRUE;
+ com->tx_fifo_size = 32;
+ break;
+ }
+ if (COM_TI16754(flags)) {
+ printf(" TI16754");
+ com->tx_fifo_size = 64;
+ break;
+ }
#endif
-
+ printf(" 16550A");
#ifdef COM_ESP
#ifdef PC98
if (com->pc98_if_type == COM_IF_ESP98)
@@ -1683,15 +1691,19 @@ sioattach(dev, xrid, rclk)
com->tx_fifo_size = 1024;
break;
}
+ if (com->esp != NULL)
+ break;
+#endif
+#ifdef PC98
+ com->tx_fifo_size = 16;
+#else
+ com->tx_fifo_size = COM_FIFOSIZE(flags);
+ if (com->tx_fifo_size == 0)
+ com->tx_fifo_size = 16;
+ else
+ printf(" lookalike with %u bytes FIFO",
+ com->tx_fifo_size);
#endif
- if (!com->st16650a) {
- if (!com->tx_fifo_size)
- com->tx_fifo_size = 16;
- else
- printf(" lookalike with %d bytes FIFO",
- com->tx_fifo_size);
- }
-
break;
}
@@ -1707,7 +1719,7 @@ sioattach(dev, xrid, rclk)
#endif
#ifdef COM_ESP
- if (com->esp) {
+ if (com->esp != NULL) {
/*
* Set 16550 compatibility mode.
* We don't use the ESP_MODE_SCALE bit to increase the
@@ -1784,7 +1796,7 @@ determined_type: ;
if (unit == comconsole)
printf(", console");
if (COM_IIR_TXRDYBUG(flags))
- printf(" with a bogus IIR_TXRDY register");
+ printf(" with a buggy IIR_TXRDY implementation");
printf("\n");
if (sio_fast_ih == NULL) {
@@ -2019,17 +2031,13 @@ open_top:
(void) inb(com->data_port);
com->prev_modem_status = com->last_modem_status
= inb(com->modem_status_port);
- if (COM_IIR_TXRDYBUG(com->flags)) {
- outb(com->intr_ctl_port, IER_ERXRDY | IER_ERLS
- | IER_EMSC);
- } else {
- outb(com->intr_ctl_port, IER_ERXRDY | IER_ETXRDY
- | IER_ERLS | IER_EMSC);
- }
+ outb(com->int_ctl_port,
+ IER_ERXRDY | IER_ERLS | IER_EMSC
+ | (COM_IIR_TXRDYBUG(com->flags) ? 0 : IER_ETXRDY));
#ifdef PC98
if (com->pc98_if_type == COM_IF_RSA98III) {
outb(com->rsabase + rsa_ier, 0x1d);
- outb(com->intr_ctl_port, IER_ERLS | IER_EMSC);
+ outb(com->int_ctl_port, IER_ERLS | IER_EMSC);
}
#endif
#ifdef PC98
@@ -2327,8 +2335,12 @@ siodivisor(rclk, speed)
u_int divisor;
int error;
- if (speed == 0 || speed > (ULONG_MAX - 1) / 8)
+ if (speed == 0)
+ return (0);
+#if UINT_MAX > (ULONG_MAX - 1) / 8
+ if (speed > (ULONG_MAX - 1) / 8)
return (0);
+#endif
divisor = (rclk / (8UL * speed) + 1) / 2;
if (divisor == 0 || divisor >= 65536)
return (0);
@@ -2570,12 +2582,12 @@ static void
siointr1(com)
struct com_s *com;
{
+ u_char int_ctl;
+ u_char int_ctl_new;
u_char line_status;
u_char modem_status;
u_char *ioptr;
u_char recv_data;
- u_char int_ctl;
- u_char int_ctl_new;
#ifdef PC98
u_char tmp = 0;
@@ -2583,8 +2595,13 @@ siointr1(com)
int rsa_tx_fifo_size = 0;
#endif /* PC98 */
- int_ctl = inb(com->intr_ctl_port);
- int_ctl_new = int_ctl;
+ if (COM_IIR_TXRDYBUG(com->flags)) {
+ int_ctl = inb(com->int_ctl_port);
+ int_ctl_new = int_ctl;
+ } else {
+ int_ctl = 0;
+ int_ctl_new = 0;
+ }
while (!com->gone) {
#ifdef PC98
@@ -2854,9 +2871,8 @@ cont:
com_int_Tx_enable(com);
#endif
com->obufq.l_head = ioptr;
- if (COM_IIR_TXRDYBUG(com->flags)) {
+ if (COM_IIR_TXRDYBUG(com->flags))
int_ctl_new = int_ctl | IER_ETXRDY;
- }
if (ioptr >= com->obufq.l_tail) {
struct lbq *qp;
@@ -2869,9 +2885,9 @@ cont:
com->obufq.l_next = qp;
} else {
/* output just completed */
- if (COM_IIR_TXRDYBUG(com->flags)) {
- int_ctl_new = int_ctl & ~IER_ETXRDY;
- }
+ if (COM_IIR_TXRDYBUG(com->flags))
+ int_ctl_new = int_ctl
+ & ~IER_ETXRDY;
com->state &= ~CS_BUSY;
#if defined(PC98)
if (IS_8251(com->pc98_if_type) &&
@@ -2886,16 +2902,21 @@ cont:
swi_sched(sio_fast_ih, 0);
}
}
- if (COM_IIR_TXRDYBUG(com->flags) && (int_ctl != int_ctl_new)) {
#ifdef PC98
+ if (COM_IIR_TXRDYBUG(com->flags)
+ && int_ctl != int_ctl_new) {
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->int_ctl_port, int_ctl_new);
outb(com->rsabase + rsa_ier, 0x1d);
} else
-#endif
- outb(com->intr_ctl_port, int_ctl_new);
+ outb(com->int_ctl_port, int_ctl_new);
}
+#else
+ if (COM_IIR_TXRDYBUG(com->flags)
+ && int_ctl != int_ctl_new)
+ outb(com->int_ctl_port, int_ctl_new);
+#endif
}
#ifdef PC98
else if (line_status & LSR_TXRDY) {
@@ -3235,6 +3256,7 @@ comparam(tp, t)
u_int divisor;
u_char dlbh;
u_char dlbl;
+ u_char efr_flowbits;
int s;
int unit;
#ifdef PC98
@@ -3254,20 +3276,12 @@ comparam(tp, t)
return (EINVAL);
} else {
#endif
- /* do historical conversions */
- if (t->c_ispeed == 0)
- t->c_ispeed = t->c_ospeed;
-
/* check requested parameters */
- if (t->c_ospeed == 0)
- divisor = 0;
- else {
- if (t->c_ispeed != t->c_ospeed)
- return (EINVAL);
- divisor = siodivisor(com->rclk, t->c_ispeed);
- if (divisor == 0)
- return (EINVAL);
- }
+ if (t->c_ispeed != (t->c_ospeed != 0 ? t->c_ospeed : tp->t_ospeed))
+ return (EINVAL);
+ divisor = siodivisor(com->rclk, t->c_ispeed);
+ if (divisor == 0)
+ return (EINVAL);
#ifdef PC98
}
#endif
@@ -3276,13 +3290,13 @@ comparam(tp, t)
s = spltty();
#ifdef PC98
if (IS_8251(com->pc98_if_type)) {
- if (divisor == 0)
+ if (t->c_ospeed == 0)
com_tiocm_bic(com, TIOCM_DTR|TIOCM_RTS|TIOCM_LE);
else
com_tiocm_bis(com, TIOCM_DTR|TIOCM_RTS|TIOCM_LE);
} else
#endif
- if (divisor == 0)
+ if (t->c_ospeed == 0)
(void)commctl(com, TIOCM_DTR, DMBIC); /* hang up line */
else
(void)commctl(com, TIOCM_DTR, DMBIS);
@@ -3312,7 +3326,7 @@ comparam(tp, t)
if (cflag & CSTOPB)
cfcr |= CFCR_STOPB;
- if (com->hasfifo && divisor != 0) {
+ if (com->hasfifo) {
/*
* Use a fifo trigger level low enough so that the input
* latency from the fifo is less than about 16 msec and
@@ -3321,13 +3335,13 @@ comparam(tp, t)
* protocols shouldn't expect anything better since modem
* latencies are larger.
*
- * We have to set the FIFO trigger point such that we
- * don't overflow it accidently if a serial interrupt
- * is delayed. At high speeds, FIFO_RX_HIGH does not
- * leave enough slots free.
+ * The fifo trigger level cannot be set at RX_HIGH for high
+ * speed connections without further work on reducing
+ * interrupt disablement times in other parts of the system,
+ * without producing silo overflow errors.
*/
com->fifo_image = com->unit == siotsunit ? 0
- : t->c_ospeed <= 4800
+ : t->c_ispeed <= 4800
? FIFO_ENABLE : FIFO_ENABLE | FIFO_RX_MEDH;
#ifdef COM_ESP
/*
@@ -3356,39 +3370,27 @@ comparam(tp, t)
com_cflag_and_speed_set(com, cflag, t->c_ospeed);
else {
#endif
- if (divisor != 0) {
- sio_setreg(com, com_cfcr, cfcr | CFCR_DLAB);
- /*
- * Only set the divisor registers if they would change,
- * since on some 16550 incompatibles (UMC8669F), setting
- * them while input is arriving them loses sync until
- * data stops arriving.
- */
- dlbl = divisor & 0xFF;
- if (sio_getreg(com, com_dlbl) != dlbl)
- sio_setreg(com, com_dlbl, dlbl);
- dlbh = divisor >> 8;
- if (sio_getreg(com, com_dlbh) != dlbh)
- sio_setreg(com, com_dlbh, dlbh);
- }
-
- sio_setreg(com, com_cfcr, com->cfcr_image = cfcr);
+ sio_setreg(com, com_cfcr, cfcr | CFCR_DLAB);
+ /*
+ * Only set the divisor registers if they would change, since on
+ * some 16550 incompatibles (UMC8669F), setting them while input
+ * is arriving loses sync until data stops arriving.
+ */
+ dlbl = divisor & 0xFF;
+ if (sio_getreg(com, com_dlbl) != dlbl)
+ sio_setreg(com, com_dlbl, dlbl);
+ dlbh = divisor >> 8;
+ if (sio_getreg(com, com_dlbh) != dlbh)
+ sio_setreg(com, com_dlbh, dlbh);
#ifdef PC98
}
#endif
- if (!(tp->t_state & TS_TTSTOP))
- com->state |= CS_TTGO;
+ efr_flowbits = 0;
if (cflag & CRTS_IFLOW) {
-#ifndef PC98
- if (com->st16650a) {
- sio_setreg(com, com_cfcr, 0xbf);
- sio_setreg(com, com_fifo,
- sio_getreg(com, com_fifo) | 0x40);
- }
-#endif
com->state |= CS_RTS_IFLOW;
+ efr_flowbits |= EFR_AUTORTS;
/*
* If CS_RTS_IFLOW just changed from off to on, the change
* needs to be propagated to MCR_RTS. This isn't urgent,
@@ -3408,15 +3410,9 @@ comparam(tp, t)
outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
#else
outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
- if (com->st16650a) {
- sio_setreg(com, com_cfcr, 0xbf);
- sio_setreg(com, com_fifo,
- sio_getreg(com, com_fifo) & ~0x40);
- }
#endif
}
-
/*
* Set up state to handle output flow control.
* XXX - worth handling MDMBUF (DCD) flow control at the lowest level?
@@ -3432,49 +3428,35 @@ comparam(tp, t)
#endif
if (cflag & CCTS_OFLOW) {
com->state |= CS_CTS_OFLOW;
+ efr_flowbits |= EFR_AUTOCTS;
#ifdef PC98
if (IS_8251(com->pc98_if_type)) {
if (!(pc98_get_modem_status(com) & TIOCM_CTS))
com->state &= ~CS_ODEVREADY;
- } else {
- if (com->pc98_if_type == COM_IF_RSA98III) {
- /* Set automatic flow control mode */
- outb(com->rsabase + rsa_msr, param | 0x08);
- } else
+ } else if (com->pc98_if_type == COM_IF_RSA98III) {
+ /* Set automatic flow control mode */
+ outb(com->rsabase + rsa_msr, param | 0x08);
+ } else
#endif
if (!(com->last_modem_status & MSR_CTS))
com->state &= ~CS_ODEVREADY;
-#ifdef PC98
- }
-#else
- if (com->st16650a) {
- sio_setreg(com, com_cfcr, 0xbf);
- sio_setreg(com, com_fifo,
- sio_getreg(com, com_fifo) | 0x80);
- }
- } else {
- if (com->st16650a) {
- sio_setreg(com, com_cfcr, 0xbf);
- sio_setreg(com, com_fifo,
- sio_getreg(com, com_fifo) & ~0x80);
- }
-#endif
}
#ifdef PC98
if (!IS_8251(com->pc98_if_type))
+ sio_setreg(com, com_cfcr, com->cfcr_image = cfcr);
+#else
+ if (com->st16650a) {
+ sio_setreg(com, com_lcr, LCR_EFR_ENABLE);
+ sio_setreg(com, com_efr,
+ (sio_getreg(com, com_efr)
+ & ~(EFR_AUTOCTS | EFR_AUTORTS)) | efr_flowbits);
+ }
+ sio_setreg(com, com_cfcr, com->cfcr_image = cfcr);
#endif
- sio_setreg(com, com_cfcr, com->cfcr_image);
/* XXX shouldn't call functions while intrs are disabled. */
disc_optim(tp, t, com);
- /*
- * Recover from fiddling with CS_TTGO. We used to call siointr1()
- * unconditionally, but that defeated the careful discarding of
- * stale input in sioopen().
- */
- if (com->state >= (CS_BUSY | CS_TTGO))
- siointr1(com);
mtx_unlock_spin(&sio_lock);
splx(s);
@@ -4158,6 +4140,7 @@ siocnprobe(cp)
for (unit = 0; unit < 16; unit++) { /* XXX need to know how many */
int flags;
+
if (resource_disabled("sio", unit))
continue;
if (resource_int_value("sio", unit, "flags", &flags))
OpenPOWER on IntegriCloud