summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbde <bde@FreeBSD.org>1996-09-30 12:22:27 +0000
committerbde <bde@FreeBSD.org>1996-09-30 12:22:27 +0000
commitb5f59abb8bfc4b4af98ce5372b3db972b7068e0f (patch)
tree966eb8c651f465e2b740630df710a2a647c07019
parent834343f74ce229a4be1fd61ff3f3af741dfeb628 (diff)
downloadFreeBSD-src-b5f59abb8bfc4b4af98ce5372b3db972b7068e0f.zip
FreeBSD-src-b5f59abb8bfc4b4af98ce5372b3db972b7068e0f.tar.gz
Work around UMC8669F and Startech UART bugs by not writing to the
divisor latch registers if the registers wouldn't change. Use the default console cfcr setting while setting the divisor latch registers for console i/o. Input may be messed up by transiently changing the cfcr. Use a usual cfcr setting while setting the divisor latch registers in the probe. This shouldn't matter, but this is not the place to test the UART's handling of 5 bit words. Removed a stale devfs comment.
-rw-r--r--sys/dev/sio/sio.c47
-rw-r--r--sys/i386/isa/sio.c47
-rw-r--r--sys/isa/sio.c47
3 files changed, 108 insertions, 33 deletions
diff --git a/sys/dev/sio/sio.c b/sys/dev/sio/sio.c
index 8976cae..4b4f39d 100644
--- a/sys/dev/sio/sio.c
+++ b/sys/dev/sio/sio.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)com.c 7.5 (Berkeley) 5/16/91
- * $Id: sio.c,v 1.145 1996/09/06 23:08:05 phk Exp $
+ * $Id: sio.c,v 1.146 1996/09/14 04:27:42 bde Exp $
*/
#include "opt_comconsole.h"
@@ -569,7 +569,7 @@ sioprobe(dev)
* XXX what about the UART bug avoided by waiting in comparam()?
* We don't want to to wait long enough to drain at 2 bps.
*/
- outb(iobase + com_cfcr, CFCR_DLAB);
+ outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS);
outb(iobase + com_dlbl, COMBRD(9600) & 0xff);
outb(iobase + com_dlbh, (u_int) COMBRD(9600) >> 8);
outb(iobase + com_cfcr, CFCR_8BITS);
@@ -942,7 +942,6 @@ determined_type: ;
dev = makedev(CDEV_MAJOR, 0);
cdevsw_add(&dev, &sio_cdevsw, NULL);
#ifdef DEVFS
- /* devsw, minor, type, uid, gid, perm, fmt, ... */
com->devfs_token_ttyd = devfs_add_devswf(&sio_cdevsw,
unit, DV_CHR,
UID_ROOT, GID_WHEEL, 0600, "ttyd%n", unit);
@@ -1826,6 +1825,8 @@ comparam(tp, t)
int cflag;
struct com_s *com;
int divisor;
+ u_char dlbh;
+ u_char dlbl;
int error;
Port_t iobase;
int s;
@@ -1937,8 +1938,18 @@ retry:
if (divisor != 0) {
outb(iobase + com_cfcr, cfcr | CFCR_DLAB);
- outb(iobase + com_dlbl, divisor & 0xFF);
- outb(iobase + com_dlbh, (u_int) divisor >> 8);
+ /*
+ * 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 (inb(iobase + com_dlbl) != dlbl)
+ outb(iobase + com_dlbl, dlbl);
+ dlbh = (u_int) divisor >> 8;
+ if (inb(iobase + com_dlbh) != dlbh)
+ outb(iobase + com_dlbh, dlbh);
}
outb(iobase + com_cfcr, com->cfcr_image = cfcr);
if (!(tp->t_state & TS_TTSTOP))
@@ -2322,6 +2333,8 @@ siocnopen(sp)
struct siocnstate *sp;
{
int divisor;
+ u_char dlbh;
+ u_char dlbl;
Port_t iobase;
/*
@@ -2334,12 +2347,22 @@ siocnopen(sp)
outb(iobase + com_ier, 0); /* spltty() doesn't stop siointr() */
siocntxwait();
sp->cfcr = inb(iobase + com_cfcr);
- outb(iobase + com_cfcr, CFCR_DLAB);
+ outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS);
sp->dlbl = inb(iobase + com_dlbl);
sp->dlbh = inb(iobase + com_dlbh);
+ /*
+ * Only set the divisor registers if they would change, since on
+ * some 16550 incompatibles (Startech), setting them clears the
+ * data input register. This also reduces the effects of the
+ * UMC8669F bug.
+ */
divisor = ttspeedtab(comdefaultrate, comspeedtab);
- outb(iobase + com_dlbl, divisor & 0xFF);
- outb(iobase + com_dlbh, (u_int) divisor >> 8);
+ dlbl = divisor & 0xFF;
+ if (sp->dlbl != dlbl)
+ outb(iobase + com_dlbl, dlbl);
+ dlbh = (u_int) divisor >> 8;
+ if (sp->dlbh != dlbh)
+ outb(iobase + com_dlbh, dlbh);
outb(iobase + com_cfcr, CFCR_8BITS);
sp->mcr = inb(iobase + com_mcr);
/*
@@ -2361,9 +2384,11 @@ siocnclose(sp)
*/
siocntxwait();
iobase = siocniobase;
- outb(iobase + com_cfcr, CFCR_DLAB);
- outb(iobase + com_dlbl, sp->dlbl);
- outb(iobase + com_dlbh, sp->dlbh);
+ outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS);
+ if (sp->dlbl != inb(iobase + com_dlbl))
+ outb(iobase + com_dlbl, sp->dlbl);
+ if (sp->dlbh != inb(iobase + com_dlbh))
+ outb(iobase + com_dlbh, sp->dlbh);
outb(iobase + com_cfcr, sp->cfcr);
/*
* XXX damp oscillations of MCR_DTR and MCR_RTS by not restoring them.
diff --git a/sys/i386/isa/sio.c b/sys/i386/isa/sio.c
index 8976cae..4b4f39d 100644
--- a/sys/i386/isa/sio.c
+++ b/sys/i386/isa/sio.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)com.c 7.5 (Berkeley) 5/16/91
- * $Id: sio.c,v 1.145 1996/09/06 23:08:05 phk Exp $
+ * $Id: sio.c,v 1.146 1996/09/14 04:27:42 bde Exp $
*/
#include "opt_comconsole.h"
@@ -569,7 +569,7 @@ sioprobe(dev)
* XXX what about the UART bug avoided by waiting in comparam()?
* We don't want to to wait long enough to drain at 2 bps.
*/
- outb(iobase + com_cfcr, CFCR_DLAB);
+ outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS);
outb(iobase + com_dlbl, COMBRD(9600) & 0xff);
outb(iobase + com_dlbh, (u_int) COMBRD(9600) >> 8);
outb(iobase + com_cfcr, CFCR_8BITS);
@@ -942,7 +942,6 @@ determined_type: ;
dev = makedev(CDEV_MAJOR, 0);
cdevsw_add(&dev, &sio_cdevsw, NULL);
#ifdef DEVFS
- /* devsw, minor, type, uid, gid, perm, fmt, ... */
com->devfs_token_ttyd = devfs_add_devswf(&sio_cdevsw,
unit, DV_CHR,
UID_ROOT, GID_WHEEL, 0600, "ttyd%n", unit);
@@ -1826,6 +1825,8 @@ comparam(tp, t)
int cflag;
struct com_s *com;
int divisor;
+ u_char dlbh;
+ u_char dlbl;
int error;
Port_t iobase;
int s;
@@ -1937,8 +1938,18 @@ retry:
if (divisor != 0) {
outb(iobase + com_cfcr, cfcr | CFCR_DLAB);
- outb(iobase + com_dlbl, divisor & 0xFF);
- outb(iobase + com_dlbh, (u_int) divisor >> 8);
+ /*
+ * 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 (inb(iobase + com_dlbl) != dlbl)
+ outb(iobase + com_dlbl, dlbl);
+ dlbh = (u_int) divisor >> 8;
+ if (inb(iobase + com_dlbh) != dlbh)
+ outb(iobase + com_dlbh, dlbh);
}
outb(iobase + com_cfcr, com->cfcr_image = cfcr);
if (!(tp->t_state & TS_TTSTOP))
@@ -2322,6 +2333,8 @@ siocnopen(sp)
struct siocnstate *sp;
{
int divisor;
+ u_char dlbh;
+ u_char dlbl;
Port_t iobase;
/*
@@ -2334,12 +2347,22 @@ siocnopen(sp)
outb(iobase + com_ier, 0); /* spltty() doesn't stop siointr() */
siocntxwait();
sp->cfcr = inb(iobase + com_cfcr);
- outb(iobase + com_cfcr, CFCR_DLAB);
+ outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS);
sp->dlbl = inb(iobase + com_dlbl);
sp->dlbh = inb(iobase + com_dlbh);
+ /*
+ * Only set the divisor registers if they would change, since on
+ * some 16550 incompatibles (Startech), setting them clears the
+ * data input register. This also reduces the effects of the
+ * UMC8669F bug.
+ */
divisor = ttspeedtab(comdefaultrate, comspeedtab);
- outb(iobase + com_dlbl, divisor & 0xFF);
- outb(iobase + com_dlbh, (u_int) divisor >> 8);
+ dlbl = divisor & 0xFF;
+ if (sp->dlbl != dlbl)
+ outb(iobase + com_dlbl, dlbl);
+ dlbh = (u_int) divisor >> 8;
+ if (sp->dlbh != dlbh)
+ outb(iobase + com_dlbh, dlbh);
outb(iobase + com_cfcr, CFCR_8BITS);
sp->mcr = inb(iobase + com_mcr);
/*
@@ -2361,9 +2384,11 @@ siocnclose(sp)
*/
siocntxwait();
iobase = siocniobase;
- outb(iobase + com_cfcr, CFCR_DLAB);
- outb(iobase + com_dlbl, sp->dlbl);
- outb(iobase + com_dlbh, sp->dlbh);
+ outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS);
+ if (sp->dlbl != inb(iobase + com_dlbl))
+ outb(iobase + com_dlbl, sp->dlbl);
+ if (sp->dlbh != inb(iobase + com_dlbh))
+ outb(iobase + com_dlbh, sp->dlbh);
outb(iobase + com_cfcr, sp->cfcr);
/*
* XXX damp oscillations of MCR_DTR and MCR_RTS by not restoring them.
diff --git a/sys/isa/sio.c b/sys/isa/sio.c
index 8976cae..4b4f39d 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.145 1996/09/06 23:08:05 phk Exp $
+ * $Id: sio.c,v 1.146 1996/09/14 04:27:42 bde Exp $
*/
#include "opt_comconsole.h"
@@ -569,7 +569,7 @@ sioprobe(dev)
* XXX what about the UART bug avoided by waiting in comparam()?
* We don't want to to wait long enough to drain at 2 bps.
*/
- outb(iobase + com_cfcr, CFCR_DLAB);
+ outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS);
outb(iobase + com_dlbl, COMBRD(9600) & 0xff);
outb(iobase + com_dlbh, (u_int) COMBRD(9600) >> 8);
outb(iobase + com_cfcr, CFCR_8BITS);
@@ -942,7 +942,6 @@ determined_type: ;
dev = makedev(CDEV_MAJOR, 0);
cdevsw_add(&dev, &sio_cdevsw, NULL);
#ifdef DEVFS
- /* devsw, minor, type, uid, gid, perm, fmt, ... */
com->devfs_token_ttyd = devfs_add_devswf(&sio_cdevsw,
unit, DV_CHR,
UID_ROOT, GID_WHEEL, 0600, "ttyd%n", unit);
@@ -1826,6 +1825,8 @@ comparam(tp, t)
int cflag;
struct com_s *com;
int divisor;
+ u_char dlbh;
+ u_char dlbl;
int error;
Port_t iobase;
int s;
@@ -1937,8 +1938,18 @@ retry:
if (divisor != 0) {
outb(iobase + com_cfcr, cfcr | CFCR_DLAB);
- outb(iobase + com_dlbl, divisor & 0xFF);
- outb(iobase + com_dlbh, (u_int) divisor >> 8);
+ /*
+ * 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 (inb(iobase + com_dlbl) != dlbl)
+ outb(iobase + com_dlbl, dlbl);
+ dlbh = (u_int) divisor >> 8;
+ if (inb(iobase + com_dlbh) != dlbh)
+ outb(iobase + com_dlbh, dlbh);
}
outb(iobase + com_cfcr, com->cfcr_image = cfcr);
if (!(tp->t_state & TS_TTSTOP))
@@ -2322,6 +2333,8 @@ siocnopen(sp)
struct siocnstate *sp;
{
int divisor;
+ u_char dlbh;
+ u_char dlbl;
Port_t iobase;
/*
@@ -2334,12 +2347,22 @@ siocnopen(sp)
outb(iobase + com_ier, 0); /* spltty() doesn't stop siointr() */
siocntxwait();
sp->cfcr = inb(iobase + com_cfcr);
- outb(iobase + com_cfcr, CFCR_DLAB);
+ outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS);
sp->dlbl = inb(iobase + com_dlbl);
sp->dlbh = inb(iobase + com_dlbh);
+ /*
+ * Only set the divisor registers if they would change, since on
+ * some 16550 incompatibles (Startech), setting them clears the
+ * data input register. This also reduces the effects of the
+ * UMC8669F bug.
+ */
divisor = ttspeedtab(comdefaultrate, comspeedtab);
- outb(iobase + com_dlbl, divisor & 0xFF);
- outb(iobase + com_dlbh, (u_int) divisor >> 8);
+ dlbl = divisor & 0xFF;
+ if (sp->dlbl != dlbl)
+ outb(iobase + com_dlbl, dlbl);
+ dlbh = (u_int) divisor >> 8;
+ if (sp->dlbh != dlbh)
+ outb(iobase + com_dlbh, dlbh);
outb(iobase + com_cfcr, CFCR_8BITS);
sp->mcr = inb(iobase + com_mcr);
/*
@@ -2361,9 +2384,11 @@ siocnclose(sp)
*/
siocntxwait();
iobase = siocniobase;
- outb(iobase + com_cfcr, CFCR_DLAB);
- outb(iobase + com_dlbl, sp->dlbl);
- outb(iobase + com_dlbh, sp->dlbh);
+ outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS);
+ if (sp->dlbl != inb(iobase + com_dlbl))
+ outb(iobase + com_dlbl, sp->dlbl);
+ if (sp->dlbh != inb(iobase + com_dlbh))
+ outb(iobase + com_dlbh, sp->dlbh);
outb(iobase + com_cfcr, sp->cfcr);
/*
* XXX damp oscillations of MCR_DTR and MCR_RTS by not restoring them.
OpenPOWER on IntegriCloud