summaryrefslogtreecommitdiffstats
path: root/sys/pc98/cbus/sio.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/pc98/cbus/sio.c')
-rw-r--r--sys/pc98/cbus/sio.c277
1 files changed, 123 insertions, 154 deletions
diff --git a/sys/pc98/cbus/sio.c b/sys/pc98/cbus/sio.c
index 8a88bc9..9d05403 100644
--- a/sys/pc98/cbus/sio.c
+++ b/sys/pc98/cbus/sio.c
@@ -347,6 +347,8 @@ struct com_s {
u_int delta_error_counts[CE_NTYPES];
u_long error_counts[CE_NTYPES];
+ u_long rclk;
+
struct resource *irqres;
struct resource *ioportres;
void *cookie;
@@ -371,6 +373,7 @@ static int espattach __P((struct com_s *com, Port_t esp_port));
#endif
static timeout_t siobusycheck;
+static u_int siodivisor __P((u_long rclk, speed_t speed));
static timeout_t siodtrwakeup;
static void comhardclose __P((struct com_s *com));
static void sioinput __P((struct com_s *com));
@@ -422,6 +425,8 @@ static struct cdevsw sio_cdevsw = {
int comconsole = -1;
static volatile speed_t comdefaultrate = CONSPEED;
+static u_long comdefaultrclk = DEFAULT_RCLK;
+SYSCTL_ULONG(_machdep, OID_AUTO, conrclk, CTLFLAG_RW, &comdefaultrclk, 0, "");
#ifdef __alpha__
static volatile speed_t gdbdefaultrate = CONSPEED;
#endif
@@ -527,11 +532,11 @@ static struct speedtab pc98speedtab[] = { /* internal RS232C interface */
{ -1, -1 }
};
static struct speedtab pc98fast_speedtab[] = {
- { 9600, 0x80 | COMBRD(9600), },
- { 19200, 0x80 | COMBRD(19200), },
- { 38400, 0x80 | COMBRD(38400), },
- { 57600, 0x80 | COMBRD(57600), },
- { 115200, 0x80 | COMBRD(115200), },
+ { 9600, 0x80 | (DEFAULT_RCLK / (16 * (9600))), },
+ { 19200, 0x80 | (DEFAULT_RCLK / (16 * (19200))), },
+ { 38400, 0x80 | (DEFAULT_RCLK / (16 * (38400))), },
+ { 57600, 0x80 | (DEFAULT_RCLK / (16 * (57600))), },
+ { 115200, 0x80 | (DEFAULT_RCLK / (16 * (115200))), },
{ -1, -1 }
};
static struct speedtab comspeedtab_pio9032b[] = {
@@ -560,7 +565,7 @@ static struct speedtab comspeedtab_b98_01[] = {
{ 153600, 0, },
{ -1, -1 }
};
-static struct speedtab comspeedtab_mc16550[] = {
+static struct speedtab comspeedtab_ind[] = {
{ 300, 1536, },
{ 600, 768, },
{ 1200, 384, },
@@ -576,77 +581,7 @@ static struct speedtab comspeedtab_mc16550[] = {
{ 460800, 1, },
{ -1, -1 }
};
-static struct speedtab comspeedtab_rsb384[] = {
- { 300, 3840, },
- { 600, 1920, },
- { 1200, 960, },
- { 2400, 480, },
- { 4800, 240, },
- { 9600, 120, },
- { 19200, 60, },
- { 38400, 30, },
- { 57600, 20, },
- { 115200, 10, },
- { 128000, 9, },
- { 144000, 8, },
- { 192000, 6, },
- { 230400, 5, },
- { 288000, 4, },
- { 384000, 3, },
- { 576000, 2, },
- { 1152000, 1, },
- { -1, -1 }
-};
-static struct speedtab comspeedtab_rsa[] = {
- { 0, 0 },
- { 50, COMBRD_RSA(50) },
- { 75, COMBRD_RSA(75) },
- { 110, COMBRD_RSA(110) },
- { 134, COMBRD_RSA(134) },
- { 150, COMBRD_RSA(150) },
- { 200, COMBRD_RSA(200) },
- { 300, COMBRD_RSA(300) },
- { 600, COMBRD_RSA(600) },
- { 1200, COMBRD_RSA(1200) },
- { 1800, COMBRD_RSA(1800) },
- { 2400, COMBRD_RSA(2400) },
- { 4800, COMBRD_RSA(4800) },
- { 9600, COMBRD_RSA(9600) },
- { 19200, COMBRD_RSA(19200) },
- { 38400, COMBRD_RSA(38400) },
- { 57600, COMBRD_RSA(57600) },
- { 115200, COMBRD_RSA(115200) },
- { 230400, COMBRD_RSA(230400) },
- { 460800, COMBRD_RSA(460800) },
- { 921600, COMBRD_RSA(921600) },
- { -1, -1 }
-};
-#endif /* PC98 */
-
-static struct speedtab comspeedtab[] = {
- { 0, 0 },
- { 50, COMBRD(50) },
- { 75, COMBRD(75) },
- { 110, COMBRD(110) },
- { 134, COMBRD(134) },
- { 150, COMBRD(150) },
- { 200, COMBRD(200) },
- { 300, COMBRD(300) },
- { 600, COMBRD(600) },
- { 1200, COMBRD(1200) },
- { 1800, COMBRD(1800) },
- { 2400, COMBRD(2400) },
- { 4800, COMBRD(4800) },
- { 9600, COMBRD(9600) },
- { 19200, COMBRD(19200) },
- { 28800, COMBRD(28800) },
- { 38400, COMBRD(38400) },
- { 57600, COMBRD(57600) },
- { 115200, COMBRD(115200) },
- { -1, -1 }
-};
-#ifdef PC98
struct {
char *name;
short port_table[7];
@@ -665,10 +600,10 @@ struct {
3, NULL, 1 },
/* COM_IF_IND_SS_1 */
{ " (IND-SS)", {0xb1, 0xb3, 0xb3, 0xb0, 0xb0, 0xb3, -1},
- 3, comspeedtab_mc16550, 1 },
+ 3, comspeedtab_ind, 1 },
/* COM_IF_IND_SS_2 */
{ " (IND-SS)", {0xb9, 0xbb, 0xbb, 0xb2, 0xb2, 0xbb, -1},
- 3, comspeedtab_mc16550, 1 },
+ 3, comspeedtab_ind, 1 },
/* COM_IF_PIO9032B_1 */
{ " (PIO9032B)", {0xb1, 0xb3, 0xb3, 0xb0, 0xb0, 0xb8, -1},
7, comspeedtab_pio9032b, 1 },
@@ -715,31 +650,29 @@ struct {
short irr_write;
bus_addr_t *iat;
bus_size_t iatsz;
- struct speedtab *speedtab;
+ u_long rclk;
} if_16550a_type[] = {
/* COM_IF_RSA98 */
- {" (RSA-98)", -1, -1, port_table_0, IO_COMSIZE, comspeedtab},
+ {" (RSA-98)", -1, -1, port_table_0, IO_COMSIZE, DEFAULT_RCLK},
/* COM_IF_NS16550 */
- {"", -1, -1, port_table_0, IO_COMSIZE, comspeedtab},
+ {"", -1, -1, port_table_0, IO_COMSIZE, DEFAULT_RCLK},
/* COM_IF_SECOND_CCU */
- {"", -1, -1, port_table_0, IO_COMSIZE, comspeedtab},
+ {"", -1, -1, port_table_0, IO_COMSIZE, DEFAULT_RCLK},
/* COM_IF_MC16550II */
{" (MC16550II)", -1, 0x1000, port_table_8, IO_COMSIZE,
- comspeedtab_mc16550},
+ DEFAULT_RCLK * 4},
/* COM_IF_MCRS98 */
- {" (MC-RS98)", -1, 0x1000, port_table_8, IO_COMSIZE,
- comspeedtab_mc16550},
+ {" (MC-RS98)", -1, 0x1000, port_table_8, IO_COMSIZE, DEFAULT_RCLK * 4},
/* COM_IF_RSB3000 */
- {" (RSB-3000)", 0xbf, -1, port_table_1, IO_COMSIZE,
- comspeedtab_rsb384},
+ {" (RSB-3000)", 0xbf, -1, port_table_1, IO_COMSIZE, DEFAULT_RCLK * 10},
/* COM_IF_RSB384 */
- {" (RSB-384)", 0xbf, -1, port_table_1, IO_COMSIZE, comspeedtab_rsb384},
+ {" (RSB-384)", 0xbf, -1, port_table_1, IO_COMSIZE, DEFAULT_RCLK * 10},
/* COM_IF_MODEM_CARD */
- {"", -1, -1, port_table_0, IO_COMSIZE, comspeedtab},
+ {"", -1, -1, port_table_0, IO_COMSIZE, DEFAULT_RCLK},
/* COM_IF_RSA98III */
- {" (RSA-98III)", -1, -1, port_table_rsa, 16, comspeedtab_rsa},
+ {" (RSA-98III)", -1, -1, port_table_rsa, 16, DEFAULT_RCLK * 8},
/* COM_IF_ESP98 */
- {" (ESP98)", -1, -1, port_table_1, IO_COMSIZE, comspeedtab_mc16550},
+ {" (ESP98)", -1, -1, port_table_1, IO_COMSIZE, DEFAULT_RCLK * 4},
};
#endif /* PC98 */
@@ -873,9 +806,10 @@ siodetach(dev)
}
int
-sioprobe(dev, xrid, noprobe)
+sioprobe(dev, xrid, rclk, noprobe)
device_t dev;
int xrid;
+ u_long rclk;
int noprobe;
{
#if 0
@@ -883,6 +817,7 @@ sioprobe(dev, xrid, noprobe)
device_t xdev;
#endif
struct com_s *com;
+ u_int divisor;
bool_t failures[10];
int fn;
device_t idev;
@@ -945,6 +880,14 @@ sioprobe(dev, xrid, noprobe)
device_set_softc(dev, com);
com->bst = rman_get_bustag(port);
com->bsh = rman_get_bushandle(port);
+#ifdef PC98
+ if (!IS_8251(iod.if_type) && rclk == 0)
+ rclk = if_16550a_type[iod.if_type & 0x0f].rclk;
+#else
+ if (rclk == 0)
+ rclk = DEFAULT_RCLK;
+#endif
+ com->rclk = rclk;
while (sio_inited != 2)
if (atomic_cmpset_int(&sio_inited, 0, 1)) {
@@ -1172,19 +1115,11 @@ sioprobe(dev, xrid, noprobe)
if (iobase == siocniobase)
DELAY((16 + 1) * 1000000 / (comdefaultrate / 10));
else {
-#ifdef PC98
- tmp = ttspeedtab(SIO_TEST_SPEED,
- if_16550a_type[iod.if_type & 0x0f].speedtab);
sio_setreg(com, com_cfcr, CFCR_DLAB | CFCR_8BITS);
- sio_setreg(com, com_dlbl, tmp & 0xff);
- sio_setreg(com, com_dlbh, (tmp >> 8) & 0xff);
+ divisor = siodivisor(rclk, SIO_TEST_SPEED);
+ sio_setreg(com, com_dlbl, divisor & 0xff);
+ sio_setreg(com, com_dlbh, divisor >> 8);
sio_setreg(com, com_cfcr, CFCR_8BITS);
-#else
- sio_setreg(com, com_cfcr, CFCR_DLAB | CFCR_8BITS);
- sio_setreg(com, com_dlbl, COMBRD(SIO_TEST_SPEED) & 0xff);
- sio_setreg(com, com_dlbh, (u_int) COMBRD(SIO_TEST_SPEED) >> 8);
- sio_setreg(com, com_cfcr, CFCR_8BITS);
-#endif
DELAY((16 + 1) * 1000000 / (SIO_TEST_SPEED / 10));
}
@@ -1456,9 +1391,10 @@ espattach(com, esp_port)
#endif /* COM_ESP */
int
-sioattach(dev, xrid)
+sioattach(dev, xrid, rclk)
device_t dev;
int xrid;
+ u_long rclk;
{
struct com_s *com;
#ifdef COM_ESP
@@ -1588,6 +1524,15 @@ sioattach(dev, xrid)
com->intr_ctl_port = iobase + com_ier;
#endif
+#ifdef PC98
+ if (!IS_8251(if_type) && rclk == 0)
+ rclk = if_16550a_type[if_type & 0x0f].rclk;
+#else
+ if (rclk == 0)
+ rclk = DEFAULT_RCLK;
+#endif
+ com->rclk = rclk;
+
/*
* We don't use all the flags from <sys/ttydefaults.h> since they
* are only relevant for logins. It's important to have echo off
@@ -2347,6 +2292,32 @@ siobusycheck(chan)
splx(s);
}
+static u_int
+siodivisor(rclk, speed)
+ u_long rclk;
+ speed_t speed;
+{
+ long actual_speed;
+ u_int divisor;
+ int error;
+
+ if (speed == 0 || speed > (ULONG_MAX - 1) / 8)
+ return (0);
+ divisor = (rclk / (8UL * speed) + 1) / 2;
+ if (divisor == 0 || divisor >= 65536)
+ return (0);
+ actual_speed = rclk / (16UL * divisor);
+
+ /* 10 times error in percent: */
+ error = ((actual_speed - (long)speed) * 2000 / (long)speed + 1) / 2;
+
+ /* 3.0% maximum error tolerance: */
+ if (error < -30 || error > 30)
+ return (0);
+
+ return (divisor);
+}
+
static void
siodtrwakeup(chan)
void *chan;
@@ -3221,7 +3192,7 @@ comparam(tp, t)
u_int cfcr;
int cflag;
struct com_s *com;
- int divisor;
+ u_int divisor;
u_char dlbh;
u_char dlbl;
int s;
@@ -3230,41 +3201,39 @@ comparam(tp, t)
u_char param = 0;
#endif
-#ifdef PC98
unit = DEV_TO_UNIT(tp->t_dev);
com = com_addr(unit);
+ if (com == NULL)
+ return (ENODEV);
+#ifdef PC98
cfcr = 0;
+
if (IS_8251(com->pc98_if_type)) {
- divisor = pc98_ttspeedtab(com, t->c_ospeed);
+ divisor = (int) pc98_ttspeedtab(com, t->c_ospeed);
+ if ((int)divisor < 0)
+ return (EINVAL);
} else {
- /* do historical conversions */
- if (t->c_ispeed == 0)
- t->c_ispeed = t->c_ospeed;
-
- /* check requested parameters */
- divisor = ttspeedtab(t->c_ospeed,
- if_16550a_type[com->pc98_if_type & 0x0f].speedtab);
- }
-#else
+#endif
/* do historical conversions */
if (t->c_ispeed == 0)
t->c_ispeed = t->c_ospeed;
/* check requested parameters */
- divisor = ttspeedtab(t->c_ospeed, comspeedtab);
+ 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);
+ }
+#ifdef PC98
+ }
#endif
- if (divisor < 0 || (divisor > 0 && t->c_ispeed != t->c_ospeed))
- return (EINVAL);
-
-#ifndef PC98
/* parameters are OK, convert them to the com struct and the device */
- unit = DEV_TO_UNIT(tp->t_dev);
- com = com_addr(unit);
- if (com == NULL)
- return (ENODEV);
-#endif
s = spltty();
#ifdef PC98
if (IS_8251(com->pc98_if_type)) {
@@ -3358,7 +3327,7 @@ comparam(tp, t)
dlbl = divisor & 0xFF;
if (sio_getreg(com, com_dlbl) != dlbl)
sio_setreg(com, com_dlbl, dlbl);
- dlbh = (u_int) divisor >> 8;
+ dlbh = divisor >> 8;
if (sio_getreg(com, com_dlbh) != dlbh)
sio_setreg(com, com_dlbh, dlbh);
}
@@ -3957,7 +3926,7 @@ struct siocnstate {
};
#ifndef __alpha__
-static speed_t siocngetspeed __P((Port_t, struct speedtab *));
+static speed_t siocngetspeed __P((Port_t, u_long rclk));
#endif
static void siocnclose __P((struct siocnstate *sp, Port_t iobase));
static void siocnopen __P((struct siocnstate *sp, Port_t iobase, int speed));
@@ -4016,11 +3985,11 @@ siocntxwait(iobase)
*/
static speed_t
-siocngetspeed(iobase, table)
- Port_t iobase;
- struct speedtab *table;
+siocngetspeed(iobase, rclk)
+ Port_t iobase;
+ u_long rclk;
{
- int code;
+ u_int divisor;
u_char dlbh;
u_char dlbl;
u_char cfcr;
@@ -4033,13 +4002,12 @@ siocngetspeed(iobase, table)
outb(iobase + com_cfcr, cfcr);
- code = dlbh << 8 | dlbl;
-
- for (; table->sp_speed != -1; table++)
- if (table->sp_code == code)
- return (table->sp_speed);
+ divisor = dlbh << 8 | dlbl;
- return (0); /* didn't match anything sane */
+ /* XXX there should be more sanity checking. */
+ if (divisor == 0)
+ return (CONSPEED);
+ return (rclk / (16UL * divisor));
}
#endif
@@ -4050,7 +4018,7 @@ siocnopen(sp, iobase, speed)
Port_t iobase;
int speed;
{
- int divisor;
+ u_int divisor;
u_char dlbh;
u_char dlbl;
@@ -4072,11 +4040,11 @@ siocnopen(sp, iobase, speed)
* data input register. This also reduces the effects of the
* UMC8669F bug.
*/
- divisor = ttspeedtab(speed, comspeedtab);
+ divisor = siodivisor(comdefaultrclk, speed);
dlbl = divisor & 0xFF;
if (sp->dlbl != dlbl)
outb(iobase + com_dlbl, dlbl);
- dlbh = (u_int) divisor >> 8;
+ dlbh = divisor >> 8;
if (sp->dlbh != dlbh)
outb(iobase + com_dlbh, dlbh);
outb(iobase + com_cfcr, CFCR_8BITS);
@@ -4119,6 +4087,7 @@ siocnprobe(cp)
{
speed_t boot_speed;
u_char cfcr;
+ u_int divisor;
int s, unit;
struct siocnstate sp;
@@ -4156,7 +4125,8 @@ siocnprobe(cp)
iobase = port;
s = spltty();
if (boothowto & RB_SERIAL) {
- boot_speed = siocngetspeed(iobase, comspeedtab);
+ boot_speed =
+ siocngetspeed(iobase, comdefaultrclk);
if (boot_speed)
comdefaultrate = boot_speed;
}
@@ -4172,10 +4142,9 @@ siocnprobe(cp)
*/
cfcr = inb(iobase + com_cfcr);
outb(iobase + com_cfcr, CFCR_DLAB | cfcr);
- outb(iobase + com_dlbl,
- COMBRD(comdefaultrate) & 0xff);
- outb(iobase + com_dlbh,
- (u_int) COMBRD(comdefaultrate) >> 8);
+ divisor = siodivisor(comdefaultrclk, comdefaultrate);
+ outb(iobase + com_dlbl, divisor & 0xff);
+ outb(iobase + com_dlbh, divisor >> 8);
outb(iobase + com_cfcr, cfcr);
siocnopen(&sp, iobase, comdefaultrate);
@@ -4250,6 +4219,7 @@ siocnattach(port, speed)
{
int s;
u_char cfcr;
+ u_int divisor;
struct siocnstate sp;
siocniobase = port;
@@ -4270,10 +4240,9 @@ siocnattach(port, speed)
*/
cfcr = inb(siocniobase + com_cfcr);
outb(siocniobase + com_cfcr, CFCR_DLAB | cfcr);
- outb(siocniobase + com_dlbl,
- COMBRD(comdefaultrate) & 0xff);
- outb(siocniobase + com_dlbh,
- (u_int) COMBRD(comdefaultrate) >> 8);
+ divisor = siodivisor(comdefaultrclk, comdefaultrate);
+ outb(siocniobase + com_dlbl, divisor & 0xff);
+ outb(siocniobase + com_dlbh, divisor >> 8);
outb(siocniobase + com_cfcr, cfcr);
siocnopen(&sp, siocniobase, comdefaultrate);
@@ -4290,6 +4259,7 @@ siogdbattach(port, speed)
{
int s;
u_char cfcr;
+ u_int divisor;
struct siocnstate sp;
int unit = 1; /* XXX !!! */
@@ -4317,10 +4287,9 @@ siogdbattach(port, speed)
*/
cfcr = inb(siogdbiobase + com_cfcr);
outb(siogdbiobase + com_cfcr, CFCR_DLAB | cfcr);
- outb(siogdbiobase + com_dlbl,
- COMBRD(gdbdefaultrate) & 0xff);
- outb(siogdbiobase + com_dlbh,
- (u_int) COMBRD(gdbdefaultrate) >> 8);
+ divisor = siodivisor(comdefaultrclk, gdbdefaultrate);
+ outb(siogdbiobase + com_dlbl, divisor & 0xff);
+ outb(siogdbiobase + com_dlbh, divisor >> 8);
outb(siogdbiobase + com_cfcr, cfcr);
siocnopen(&sp, siogdbiobase, gdbdefaultrate);
OpenPOWER on IntegriCloud