1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-12 09:58:36 +00:00

Merged from sys/dev/sio/sio.c revisions from 1.405 to 1.414.

This commit is contained in:
Yoshihiro Takahashi 2003-10-05 11:55:14 +00:00
parent fdd1597b47
commit 6d8fc6bf6f
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=120809
2 changed files with 278 additions and 312 deletions

View File

@ -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_FORCECONSOLE(flags) ((flags) & 0x20)
#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_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_FORCECONSOLE(flags) ((flags) & 0x20)
#define COM_IIR_TXRDYBUG(flags) ((flags) & COM_C_IIR_TXRDYBUG)
#define COM_LLCONSOLE(flags) ((flags) & 0x40)
#define COM_LOSESOUTINTS(flags) ((flags) & 0x08)
#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_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 @@ sioopen(dev, flag, mode, td)
(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 @@ if (com->iptr - com->ibuf == 8)
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 @@ if (com->iptr - com->ibuf == 8)
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 @@ if (com->iptr - com->ibuf == 8)
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))

View File

@ -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_FORCECONSOLE(flags) ((flags) & 0x20)
#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_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_FORCECONSOLE(flags) ((flags) & 0x20)
#define COM_IIR_TXRDYBUG(flags) ((flags) & COM_C_IIR_TXRDYBUG)
#define COM_LLCONSOLE(flags) ((flags) & 0x40)
#define COM_LOSESOUTINTS(flags) ((flags) & 0x08)
#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_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 @@ sioopen(dev, flag, mode, td)
(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 @@ if (com->iptr - com->ibuf == 8)
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 @@ if (com->iptr - com->ibuf == 8)
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 @@ if (com->iptr - com->ibuf == 8)
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))