mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-15 10:17:20 +00:00
CHANGES from Bruce:
--- This list of changes is in approximately chronological order (oldest first). o Many cosmetic changes - renamed comintr1 -> siointr1, moved things around and fixed whitespace. o Reduced SLIP latency (FRAME_END hack) from 20-30 ms to 16 ms at 115200 bps (you won't notice the average 10 ms improvement on slow lines). ppp seems to use only counted transfers so there's no similar hack available. It's too hard for the driver to know the count. o Temporary #ifdefs for new and old interrupt handling (OLD_INTERRUPT_HANDLING decided by setsofttty() not being externally defined. o Don't test for the IIR_NOPEND bit being set - test for the non-fifo part of the iir equalling it like the docs say to. States with other IIR_NOPEND set in combination with the other iir bits are undefined. The docs may be stupid - the old test would not have broken when the fifo bits were introduced. o Noted more problems with DTR wait. o Rewrote console stuff. Still some initialization and state preservation problems. Same for kgdb stuff. The driver doesn't do anything about the console close bug. It needs to be fixed entirely in i386/cons.c. I like chmr's version where the the console driver revectors the device open and close routines. o Temporary (?) #ifdefs for references to tty buffers. o Noted further things to do in (2 comments about 3 places) for phk's change to not touch RTS unless it is being used for flow control. o Temporary #ifdefs for timestamp handling. It needs fixing. The microtime() call breaks the first rule of writing fast interrupt handlers: NO calls to functions that might do slow and bad things. microtime() enables interrupts. This turns out to be only moderately harmful. Also, I want the timestamp copy outside of the normal interrupt handler. o Don't init com->tp early for the !DONT_MALLOC_TTYS case - both sides are NULL. o Worry about com->tp == NULL in siopoll. I don't see how you survived the (incc <= 0 || !(tp->state & TS_ISOPEN)) test. Perhaps early sttys or comcontrols set up the tp's for _all_ the ports before this code is reached.
This commit is contained in:
parent
207a3900f0
commit
fd59ff8180
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=1325
@ -31,7 +31,7 @@
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* from: @(#)com.c 7.5 (Berkeley) 5/16/91
|
||||
* $Id: sio.c,v 1.41 1994/04/01 16:47:01 ache Exp $
|
||||
* $Id: sio.c,v 1.40 1994/03/26 13:40:18 ache Exp $
|
||||
*/
|
||||
|
||||
#include "sio.h"
|
||||
@ -59,7 +59,7 @@
|
||||
#include "i386/isa/comreg.h"
|
||||
#include "i386/isa/ic/ns16550.h"
|
||||
|
||||
#define FAKE_DCD(unit) ((unit) == comconsole)
|
||||
#define FAKE_DCD(unit) ((unit) == comconsole)
|
||||
#define LOTS_OF_EVENTS 64 /* helps separate urgent events from input */
|
||||
#define RB_I_HIGH_WATER (RBSZ - 2 * RS_IBUFSIZE)
|
||||
#define RB_I_LOW_WATER ((RBSZ - 2 * RS_IBUFSIZE) * 7 / 8)
|
||||
@ -67,23 +67,25 @@
|
||||
#define TTY_BI TTY_FE /* XXX */
|
||||
#define TTY_OE TTY_PE /* XXX */
|
||||
|
||||
#ifndef COM_BIDIR
|
||||
#define UNIT(x) (minor(x)) /* XXX */
|
||||
#ifdef COM_BIDIR
|
||||
#define CALLOUT(x) (minor(x) & COM_CALLOUT_MASK)
|
||||
#define COM_CALLOUT_MASK 0x80
|
||||
#define COM_MINOR_MAGIC_MASK 0x80
|
||||
#else /* COM_BIDIR */
|
||||
#define COM_UNITMASK 0x7f
|
||||
#define COM_CALLOUTMASK 0x80 /* for both minor and dev */
|
||||
#define UNIT(x) (minor(x) & COM_UNITMASK)
|
||||
#define CALLOUT(x) (minor(x) & COM_CALLOUTMASK)
|
||||
#define COM_MINOR_MAGIC_MASK 0
|
||||
#endif /* COM_BIDIR */
|
||||
|
||||
#define UNIT(x) (minor(x) & ~COM_MINOR_MAGIC_MASK)
|
||||
|
||||
#ifdef COM_MULTIPORT
|
||||
/* checks in flags for multiport and which is multiport "master chip"
|
||||
* for a given card
|
||||
*/
|
||||
#define COM_ISMULTIPORT(dev) ((dev)->id_flags & 0x01)
|
||||
#define COM_MPMASTER(dev) (((dev)->id_flags >> 8) & 0x0ff)
|
||||
#define COM_ISMULTIPORT(dev) ((dev)->id_flags & 0x01)
|
||||
#define COM_MPMASTER(dev) (((dev)->id_flags >> 8) & 0x0ff)
|
||||
#endif /* COM_MULTIPORT */
|
||||
#define COM_NOFIFO(dev) ((dev)->id_flags & 0x02)
|
||||
|
||||
#define COM_NOFIFO(dev) ((dev)->id_flags & 0x02)
|
||||
|
||||
#ifndef FIFO_TRIGGER
|
||||
/*
|
||||
@ -94,11 +96,18 @@
|
||||
* if more than one packet arrives at once. The low speeds used for
|
||||
* serial mice help avoid this, but not if (large) fifos are enabled.
|
||||
*/
|
||||
#define FIFO_TRIGGER FIFO_TRIGGER_14
|
||||
#define FIFO_TRIGGER FIFO_TRIGGER_14
|
||||
#endif
|
||||
|
||||
#define com_scr 7 /* scratch register for 16450-16550 (R/W) */
|
||||
|
||||
#ifndef setsofttty
|
||||
#define OLD_INTERRUPT_HANDLING /* XXX FreeBSD-1.1 and earlier */
|
||||
#define setsofttty() (ipending |= 1 << 4) /* XXX requires owning IRQ4 */
|
||||
extern u_int ipending; /* XXX */
|
||||
void softsio1 __P((void));
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Input buffer watermarks.
|
||||
* The external device is asked to stop sending when the buffer exactly reaches
|
||||
@ -194,6 +203,11 @@ struct com_s {
|
||||
|
||||
struct tty *tp; /* cross reference */
|
||||
|
||||
#ifdef TIOCTIMESTAMP
|
||||
bool_t do_timestamp;
|
||||
struct timeval timestamp;
|
||||
#endif
|
||||
|
||||
u_long bytes_in; /* statistics */
|
||||
u_long bytes_out;
|
||||
u_int delta_error_counts[CE_NTYPES];
|
||||
@ -206,46 +220,49 @@ struct com_s {
|
||||
#define CE_INPUT_OFFSET RS_IBUFSIZE
|
||||
u_char ibuf1[2 * RS_IBUFSIZE];
|
||||
u_char ibuf2[2 * RS_IBUFSIZE];
|
||||
int do_timestamp;
|
||||
struct timeval timestamp;
|
||||
};
|
||||
|
||||
/*
|
||||
* These functions in the com module ought to be declared (with a prototype)
|
||||
* in a com-driver system header. The void ones may need to be int to match
|
||||
* ancient devswitch declarations, but they don't actually return anything.
|
||||
* The public functions in the com module ought to be declared in a com-driver
|
||||
* system header.
|
||||
*/
|
||||
#define Dev_t int /* promoted dev_t */
|
||||
struct consdev;
|
||||
|
||||
/* Interrupt handling entry points. */
|
||||
void siointr __P((int unit));
|
||||
void siopoll __P((void));
|
||||
|
||||
/* Device switch entry points. */
|
||||
int sioopen __P((Dev_t dev, int oflags, int devtype,
|
||||
struct proc *p));
|
||||
int sioclose __P((Dev_t dev, int fflag, int devtype,
|
||||
struct proc *p));
|
||||
void siointr __P((int unit));
|
||||
int sioread __P((Dev_t dev, struct uio *uio, int ioflag));
|
||||
int siowrite __P((Dev_t dev, struct uio *uio, int ioflag));
|
||||
int sioioctl __P((Dev_t dev, int cmd, caddr_t data,
|
||||
int fflag, struct proc *p));
|
||||
void siostop __P((struct tty *tp, int rw));
|
||||
#define sioreset noreset
|
||||
int sioselect __P((Dev_t dev, int rw, struct proc *p));
|
||||
#define siommap nommap
|
||||
#define siostrategy nostrategy
|
||||
|
||||
/* Console device entry points. */
|
||||
int siocngetc __P((Dev_t dev));
|
||||
struct consdev;
|
||||
void siocninit __P((struct consdev *cp));
|
||||
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));
|
||||
int siowrite __P((Dev_t dev, struct uio *uio, int ioflag));
|
||||
void softsio1 __P((void));
|
||||
|
||||
static int sioattach __P((struct isa_device *dev));
|
||||
static void comflush __P((struct com_s *com));
|
||||
static void comhardclose __P((struct com_s *com));
|
||||
static void cominit __P((int unit, int rate));
|
||||
static void comintr1 __P((struct com_s *com));
|
||||
static void siointr1 __P((struct com_s *com));
|
||||
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 comstart __P((struct tty *tp));
|
||||
static void comwakeup __P((caddr_t chan, int ticks));
|
||||
static void comstart __P((struct tty *tp));
|
||||
static void comwakeup __P((caddr_t chan, int ticks));
|
||||
static int tiocm_xxx2mcr __P((int tiocm_xxx));
|
||||
|
||||
/* table and macro for fast conversion from a unit number to its com struct */
|
||||
@ -254,7 +271,9 @@ static struct com_s *p_com_addr[NSIO];
|
||||
|
||||
static struct com_s com_structs[NSIO];
|
||||
|
||||
static struct timeval intr_timestamp;
|
||||
#ifdef TIOCTIMESTAMP
|
||||
static struct timeval intr_timestamp;
|
||||
#endif
|
||||
|
||||
struct isa_driver siodriver = {
|
||||
sioprobe, sioattach, "sio"
|
||||
@ -265,13 +284,19 @@ static int comconsole = COMCONSOLE;
|
||||
#else
|
||||
static int comconsole = -1;
|
||||
#endif
|
||||
static bool_t comconsinit;
|
||||
static speed_t comdefaultrate = TTYDEF_SPEED;
|
||||
static u_int com_events; /* input chars + weighted output completions */
|
||||
static int commajor;
|
||||
#ifdef DONT_MALLOC_TTYS
|
||||
#define TB_OUT(tp) (&(tp)->t_out)
|
||||
#define TB_RAW(tp) (&(tp)->t_raw)
|
||||
struct tty sio_tty[NSIO];
|
||||
#else
|
||||
#define TB_OUT(tp) ((tp)->t_out)
|
||||
#define TB_RAW(tp) ((tp)->t_raw)
|
||||
struct tty *sio_tty[NSIO];
|
||||
#endif
|
||||
extern struct tty *constty;
|
||||
extern u_int ipending; /* XXX */
|
||||
extern int tk_nin; /* XXX */
|
||||
extern int tk_rawcc; /* XXX */
|
||||
|
||||
@ -370,7 +395,7 @@ sioprobe(dev)
|
||||
#endif
|
||||
|| (inb(iobase + com_iir) & IIR_IMASK) != IIR_TXRDY
|
||||
|| isa_irq_pending(dev)
|
||||
|| !(inb(iobase + com_iir) & IIR_NOPEND))
|
||||
|| (inb(iobase + com_iir) & IIR_IMASK) != IIR_NOPEND)
|
||||
result = 0;
|
||||
|
||||
/*
|
||||
@ -385,7 +410,7 @@ sioprobe(dev)
|
||||
outb(iobase + com_mcr, MCR_IENABLE); /* dummy to avoid bus echo */
|
||||
if ( inb(iobase + com_ier) != 0
|
||||
|| isa_irq_pending(dev)
|
||||
|| !(inb(iobase + com_iir) & IIR_NOPEND))
|
||||
|| (inb(iobase + com_iir) & IIR_IMASK) != IIR_NOPEND)
|
||||
result = 0;
|
||||
if (result == 0)
|
||||
outb(iobase + com_mcr, 0);
|
||||
@ -406,8 +431,6 @@ sioattach(isdp)
|
||||
|
||||
iobase = isdp->id_iobase;
|
||||
unit = isdp->id_unit;
|
||||
if (unit == comconsole)
|
||||
DELAY(1000); /* XXX */
|
||||
s = spltty();
|
||||
|
||||
/*
|
||||
@ -422,7 +445,7 @@ sioattach(isdp)
|
||||
* device from sending before we are ready.
|
||||
*/
|
||||
|
||||
com = &com_structs[unit];
|
||||
com = &com_structs[unit]; /* XXX malloc it */
|
||||
com->cfcr_image = CFCR_8BITS;
|
||||
com->mcr_image = MCR_IENABLE;
|
||||
com->dtr_wait = 3 * hz;
|
||||
@ -436,7 +459,9 @@ sioattach(isdp)
|
||||
com->modem_ctl_port = iobase + com_mcr;
|
||||
com->line_status_port = iobase + com_lsr;
|
||||
com->modem_status_port = iobase + com_msr;
|
||||
com->tp = sio_tty[unit];
|
||||
#ifdef DONT_MALLOC_TTYS
|
||||
com->tp = &sio_tty[unit];
|
||||
#endif
|
||||
|
||||
/* attempt to determine UART type */
|
||||
printf("sio%d: type", unit);
|
||||
@ -473,9 +498,9 @@ sioattach(isdp)
|
||||
break;
|
||||
case FIFO_TRIGGER_14:
|
||||
printf(" 16550A");
|
||||
if (COM_NOFIFO(isdp)) {
|
||||
printf(" fifo software disabled");
|
||||
} else {
|
||||
if (COM_NOFIFO(isdp))
|
||||
printf(" fifo disabled");
|
||||
else {
|
||||
com->hasfifo = TRUE;
|
||||
com->tx_fifo_size = 16;
|
||||
}
|
||||
@ -510,7 +535,22 @@ determined_type: ;
|
||||
if (comconsole == unit)
|
||||
kgdb_dev = -1; /* can't debug over console port */
|
||||
else {
|
||||
cominit(unit, kgdb_rate);
|
||||
int divisor;
|
||||
|
||||
/*
|
||||
* XXX now unfinished and broken. Need to do
|
||||
* something more like a full open(). There's no
|
||||
* suitable interrupt handler so don't enable device
|
||||
* interrupts. Watch out for null tp's.
|
||||
*/
|
||||
outb(iobase + com_cfcr, CFCR_DLAB);
|
||||
divisor = ttspeedtab(kgdb_rate, comspeedtab);
|
||||
outb(iobase + com_dlbl, divisor & 0xFF);
|
||||
outb(iobase + com_dlbh, (u_int) divisor >> 8);
|
||||
outb(iobase + com_cfcr, CFCR_8BITS);
|
||||
outb(com->modem_status_port,
|
||||
com->mcr_image |= MCR_DTR | MCR_RTS);
|
||||
|
||||
if (kgdb_debug_init) {
|
||||
/*
|
||||
* Print prefix of device name,
|
||||
@ -524,12 +564,6 @@ determined_type: ;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Need to reset baud rate, etc. of next print so reset comconsinit.
|
||||
*/
|
||||
if (unit == comconsole)
|
||||
comconsinit = FALSE;
|
||||
|
||||
com_addr(unit) = com;
|
||||
splx(s);
|
||||
if (!comwakeup_started) {
|
||||
@ -550,9 +584,9 @@ sioopen(dev, flag, mode, p)
|
||||
#ifdef COM_BIDIR
|
||||
bool_t callout;
|
||||
#endif /* COM_BIDIR */
|
||||
bool_t got_status = FALSE;
|
||||
struct com_s *com;
|
||||
int error = 0;
|
||||
bool_t got_status = FALSE;
|
||||
Port_t iobase;
|
||||
int s;
|
||||
struct tty *tp;
|
||||
@ -568,9 +602,12 @@ sioopen(dev, flag, mode, p)
|
||||
return (ENXIO);
|
||||
#endif /* COM_BIDIR */
|
||||
|
||||
|
||||
#ifdef DONT_MALLOC_TTYS
|
||||
tp = com->tp;
|
||||
#else
|
||||
sio_tty[unit] = ttymalloc(sio_tty[unit]);
|
||||
tp = com->tp = sio_tty[unit];
|
||||
#endif
|
||||
s = spltty();
|
||||
|
||||
#ifdef COM_BIDIR
|
||||
@ -611,12 +648,12 @@ sioopen(dev, flag, mode, p)
|
||||
}
|
||||
}
|
||||
disable_intr();
|
||||
com->last_modem_status =
|
||||
com->prev_modem_status = inb(com->modem_status_port);
|
||||
com->prev_modem_status =
|
||||
com->last_modem_status = inb(com->modem_status_port);
|
||||
enable_intr();
|
||||
got_status = TRUE;
|
||||
if (com->prev_modem_status & MSR_DCD
|
||||
|| FAKE_DCD(unit)) {
|
||||
|| FAKE_DCD(unit)) {
|
||||
/* there's a carrier on the line; we win */
|
||||
com->active_in = TRUE;
|
||||
} else {
|
||||
@ -665,7 +702,7 @@ sioopen(dev, flag, mode, p)
|
||||
ttychars(tp);
|
||||
if (tp->t_ispeed == 0) {
|
||||
/*
|
||||
* We no longer use the flags from <sys/ttydefaults.h>
|
||||
* We don't use all the flags from <sys/ttydefaults.h>
|
||||
* since those are only relevant for logins. It's
|
||||
* important to have echo off initially so that the
|
||||
* line doesn't start blathering before the echo flag
|
||||
@ -673,17 +710,19 @@ sioopen(dev, flag, mode, p)
|
||||
*/
|
||||
tp->t_iflag = 0;
|
||||
tp->t_oflag = 0;
|
||||
#ifdef COMCONSOLE
|
||||
if (unit == comconsole)
|
||||
tp->t_oflag = TTYDEF_OFLAG;
|
||||
#endif
|
||||
tp->t_cflag = CREAD | CS8;
|
||||
#ifdef COM_BIDIR
|
||||
if (com->bidir && !callout)
|
||||
tp->t_cflag |= HUPCL;
|
||||
tp->t_cflag |= HUPCL;
|
||||
#endif
|
||||
tp->t_lflag = 0;
|
||||
tp->t_ispeed = tp->t_ospeed = comdefaultrate;
|
||||
if (unit == comconsole) {
|
||||
tp->t_iflag = TTYDEF_IFLAG;
|
||||
tp->t_oflag = TTYDEF_OFLAG;
|
||||
tp->t_cflag = TTYDEF_CFLAG;
|
||||
tp->t_lflag = TTYDEF_LFLAG;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -715,8 +754,8 @@ sioopen(dev, flag, mode, p)
|
||||
(void) inb(com->line_status_port);
|
||||
(void) inb(com->data_port);
|
||||
if (!got_status)
|
||||
com->last_modem_status =
|
||||
com->prev_modem_status = inb(com->modem_status_port);
|
||||
com->prev_modem_status =
|
||||
com->last_modem_status = inb(com->modem_status_port);
|
||||
outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS
|
||||
| IER_EMSC);
|
||||
enable_intr();
|
||||
@ -736,7 +775,7 @@ sioopen(dev, flag, mode, p)
|
||||
#endif /* COM_BIDIR */
|
||||
&& !(tp->t_state & TS_CARR_ON)) {
|
||||
tp->t_state |= TS_WOPEN;
|
||||
error = ttysleep(tp, (caddr_t)tp->t_raw, TTIPRI | PCATCH,
|
||||
error = ttysleep(tp, (caddr_t)TB_RAW(tp), TTIPRI | PCATCH,
|
||||
ttopen, 0);
|
||||
if (error != 0)
|
||||
break;
|
||||
@ -775,14 +814,14 @@ sioclose(dev, flag, mode, p)
|
||||
struct proc *p;
|
||||
{
|
||||
struct com_s *com;
|
||||
int s;
|
||||
struct tty *tp;
|
||||
int s;
|
||||
|
||||
com = com_addr(UNIT(dev));
|
||||
tp = com->tp;
|
||||
s = spltty();
|
||||
(*linesw[tp->t_line].l_close)(tp, flag);
|
||||
siostop(tp, FREAD|FWRITE);
|
||||
siostop(tp, FREAD | FWRITE);
|
||||
comhardclose(com);
|
||||
ttyclose(tp);
|
||||
splx(s);
|
||||
@ -798,11 +837,13 @@ comhardclose(com)
|
||||
struct tty *tp;
|
||||
int unit;
|
||||
|
||||
s = spltty();
|
||||
iobase = com->iobase;
|
||||
com->do_timestamp = 0;
|
||||
outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
|
||||
unit = com - &com_structs[0];
|
||||
iobase = com->iobase;
|
||||
s = spltty();
|
||||
#ifdef TIOCTIMESTAMP
|
||||
com->do_timestamp = 0;
|
||||
#endif
|
||||
outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
|
||||
#ifdef KGDB
|
||||
/* do not disable interrupts or hang up if debugging */
|
||||
if (kgdb_dev != makedev(commajor, unit))
|
||||
@ -812,8 +853,19 @@ comhardclose(com)
|
||||
tp = com->tp;
|
||||
if (tp->t_cflag & HUPCL || tp->t_state & TS_WOPEN
|
||||
#ifdef COM_BIDIR
|
||||
/*
|
||||
* XXX we will miss any carrier drop between here and the
|
||||
* next open. Perhaps we should watch DCD even when the
|
||||
* port is closed; it is not sufficient to check it at
|
||||
* the next open because it might go up and down while
|
||||
* we're not watching. And we shouldn't look at DCD if
|
||||
* CLOCAL is set (here or for the dialin device ...).
|
||||
* When the termios state is reinitialized for initial
|
||||
* opens, the correct CLOCAL bit will be
|
||||
* ((the bit now) & (the initial bit)).
|
||||
*/
|
||||
|| com->active_in
|
||||
&& !(com->prev_modem_status & MSR_DCD) && !FAKE_DCD(unit)
|
||||
&& !(com->prev_modem_status & MSR_DCD) && !FAKE_DCD(unit)
|
||||
#endif
|
||||
|| !(tp->t_state & TS_ISOPEN)) {
|
||||
commctl(com, MCR_RTS, DMSET);
|
||||
@ -870,24 +922,23 @@ siowrite(dev, uio, flag)
|
||||
return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
|
||||
}
|
||||
|
||||
#ifdef TIOCTIMESTAMP
|
||||
/* Interrupt routine for timekeeping purposes */
|
||||
void
|
||||
siointrts(int unit)
|
||||
siointrts(unit)
|
||||
int unit;
|
||||
{
|
||||
microtime(&intr_timestamp);
|
||||
siointr(unit);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
siointr(unit)
|
||||
int unit;
|
||||
{
|
||||
struct com_s *com;
|
||||
|
||||
#ifndef COM_MULTIPORT
|
||||
com = com_addr(unit);
|
||||
if (com != NULL)
|
||||
comintr1(com);
|
||||
siointr1(com_addr(unit));
|
||||
#else /* COM_MULTIPORT */
|
||||
bool_t possibly_more_intrs;
|
||||
|
||||
@ -903,31 +954,30 @@ siointr(unit)
|
||||
for (unit = 0; unit < NSIO; ++unit) {
|
||||
com = com_addr(unit);
|
||||
if (com != NULL
|
||||
&& !(inb(com->int_id_port) & IIR_NOPEND)) {
|
||||
/*
|
||||
* XXX call comintr1() instead of here from
|
||||
* comwakeup(). The interrupt edge problem
|
||||
* only exists for real interrupts.
|
||||
*/
|
||||
comintr1(com);
|
||||
&& (inb(com->int_id_port) & IIR_IMASK)
|
||||
!= IIR_NOPEND) {
|
||||
siointr1(com);
|
||||
possibly_more_intrs = TRUE;
|
||||
}
|
||||
}
|
||||
} while (possibly_more_intrs);
|
||||
#endif /* COM_MULTIPORT */
|
||||
#endif /* COM_MULTIPORT */
|
||||
}
|
||||
|
||||
static void
|
||||
comintr1(com)
|
||||
siointr1(com)
|
||||
struct com_s *com;
|
||||
{
|
||||
u_char line_status;
|
||||
u_char modem_status;
|
||||
u_char *ioptr;
|
||||
u_char recv_data;
|
||||
u_char line_status;
|
||||
u_char modem_status;
|
||||
u_char *ioptr;
|
||||
u_char recv_data;
|
||||
|
||||
if(com->do_timestamp)
|
||||
#ifdef TIOCTIMESTAMP
|
||||
if (com->do_timestamp)
|
||||
/* XXX a little bloat here... */
|
||||
com->timestamp = intr_timestamp;
|
||||
#endif
|
||||
while (TRUE) {
|
||||
line_status = inb(com->line_status_port);
|
||||
|
||||
@ -939,6 +989,10 @@ comintr1(com)
|
||||
else
|
||||
recv_data = inb(com->data_port);
|
||||
++com->bytes_in;
|
||||
/* XXX reduce SLIP input latency */
|
||||
#define FRAME_END 0xc0
|
||||
if (recv_data == FRAME_END)
|
||||
setsofttty();
|
||||
#ifdef KGDB
|
||||
/* trap into kgdb? (XXX - needs testing and optim) */
|
||||
if (recv_data == FRAME_END
|
||||
@ -1017,7 +1071,7 @@ if (com->iptr - com->ibuf == 8)
|
||||
while (--ocount != 0);
|
||||
} else {
|
||||
outb(com->data_port, *ioptr++);
|
||||
++com->bytes_out;
|
||||
++com->bytes_out;
|
||||
}
|
||||
com->optr = ioptr;
|
||||
if (ioptr >= com->obufend) {
|
||||
@ -1030,7 +1084,7 @@ if (com->iptr - com->ibuf == 8)
|
||||
|
||||
/* finished? */
|
||||
#ifndef COM_MULTIPORT
|
||||
if (inb(com->int_id_port) & IIR_NOPEND)
|
||||
if ((inb(com->int_id_port) & IIR_IMASK) == IIR_NOPEND)
|
||||
#endif /* COM_MULTIPORT */
|
||||
return;
|
||||
}
|
||||
@ -1038,9 +1092,9 @@ if (com->iptr - com->ibuf == 8)
|
||||
|
||||
static int
|
||||
tiocm_xxx2mcr(tiocm_xxx)
|
||||
int tiocm_xxx;
|
||||
int tiocm_xxx;
|
||||
{
|
||||
int mcr;
|
||||
int mcr;
|
||||
|
||||
mcr = 0;
|
||||
if (tiocm_xxx & TIOCM_DTR)
|
||||
@ -1175,16 +1229,17 @@ sioioctl(dev, cmd, data, flag, p)
|
||||
splx(s);
|
||||
return(ENOTTY);
|
||||
}
|
||||
|
||||
com->dtr_wait = *(int *)data;
|
||||
break;
|
||||
case TIOCMGDTRWAIT:
|
||||
*(int *)data = com->dtr_wait;
|
||||
break;
|
||||
#ifdef TIOCTIMESTAMP
|
||||
case TIOCTIMESTAMP:
|
||||
com->do_timestamp = 1;
|
||||
com->do_timestamp = TRUE;
|
||||
*(struct timeval *)data = com->timestamp;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
splx(s);
|
||||
return (ENOTTY);
|
||||
@ -1205,7 +1260,7 @@ comflush(com)
|
||||
com_events -= LOTS_OF_EVENTS;
|
||||
com->state &= ~(CS_ODONE | CS_BUSY);
|
||||
enable_intr();
|
||||
rbp = com->tp->t_out;
|
||||
rbp = TB_OUT(com->tp);
|
||||
rbp->rb_hd += com->ocount;
|
||||
rbp->rb_hd = RB_ROLLOVER(rbp, rbp->rb_hd);
|
||||
com->ocount = 0;
|
||||
@ -1215,12 +1270,16 @@ comflush(com)
|
||||
void
|
||||
siopoll()
|
||||
{
|
||||
#ifdef OLD_INTERRUPT_HANDLING
|
||||
static bool_t awake = FALSE;
|
||||
int s;
|
||||
#endif
|
||||
int unit;
|
||||
|
||||
if (com_events == 0)
|
||||
return;
|
||||
|
||||
#ifdef OLD_INTERRUPT_HANDLING
|
||||
disable_intr();
|
||||
if (awake) {
|
||||
enable_intr();
|
||||
@ -1229,10 +1288,12 @@ siopoll()
|
||||
awake = TRUE;
|
||||
enable_intr();
|
||||
s = spltty();
|
||||
#endif
|
||||
|
||||
repeat:
|
||||
for (unit = 0; unit < NSIO; ++unit) {
|
||||
u_char *buf;
|
||||
struct com_s *com;
|
||||
u_char *buf;
|
||||
struct com_s *com;
|
||||
u_char *ibuf;
|
||||
int incc;
|
||||
struct tty *tp;
|
||||
@ -1241,6 +1302,10 @@ siopoll()
|
||||
if (com == NULL)
|
||||
continue;
|
||||
tp = com->tp;
|
||||
#ifdef DONT_MALLOC_TTYS
|
||||
if (tp == NULL)
|
||||
continue;
|
||||
#endif
|
||||
|
||||
/* switch the role of the low-level input buffers */
|
||||
if (com->iptr == (ibuf = com->ibuf)) {
|
||||
@ -1264,6 +1329,13 @@ siopoll()
|
||||
* of input, so enable RTS if it is now disabled and
|
||||
* there is room in the high-level buffer.
|
||||
*/
|
||||
/*
|
||||
* XXX this used not to look at CS_RTS_IFLOW. The
|
||||
* change is to allow full control of MCR_RTS via
|
||||
* ioctls after turning CS_RTS_IFLOW off. Check
|
||||
* for races. We shouldn't allow the ioctls while
|
||||
* CS_RTS_IFLOW is on.
|
||||
*/
|
||||
if ((com->state & CS_RTS_IFLOW)
|
||||
&& !(com->mcr_image & MCR_RTS)
|
||||
&& !(tp->t_state & TS_RTS_IFLOW))
|
||||
@ -1296,15 +1368,15 @@ siopoll()
|
||||
|
||||
/* XXX */
|
||||
if (TRUE) {
|
||||
u_int delta;
|
||||
int errnum;
|
||||
u_long total;
|
||||
u_int delta;
|
||||
int errnum;
|
||||
u_long total;
|
||||
|
||||
for (errnum = 0; errnum < CE_NTYPES; ++errnum) {
|
||||
disable_intr();
|
||||
disable_intr();
|
||||
delta = com->delta_error_counts[errnum];
|
||||
com->delta_error_counts[errnum] = 0;
|
||||
enable_intr();
|
||||
enable_intr();
|
||||
if (delta != 0) {
|
||||
total =
|
||||
com->error_counts[errnum] += delta;
|
||||
@ -1326,7 +1398,7 @@ siopoll()
|
||||
if (incc <= 0 || !(tp->t_state & TS_ISOPEN))
|
||||
continue;
|
||||
if (com->state & CS_RTS_IFLOW
|
||||
&& RB_LEN(tp->t_raw) + incc >= RB_I_HIGH_WATER
|
||||
&& RB_LEN(TB_RAW(tp)) + incc >= RB_I_HIGH_WATER
|
||||
&& !(tp->t_state & TS_RTS_IFLOW)
|
||||
/*
|
||||
* XXX - need RTS flow control for all line disciplines.
|
||||
@ -1353,7 +1425,7 @@ siopoll()
|
||||
tk_rawcc += incc;
|
||||
tp->t_rawcc += incc;
|
||||
com->delta_error_counts[CE_TTY_BUF_OVERFLOW]
|
||||
+= incc - rb_write(tp->t_raw, (char *) buf,
|
||||
+= incc - rb_write(TB_RAW(tp), (char *) buf,
|
||||
incc);
|
||||
ttwakeup(tp);
|
||||
if (tp->t_state & TS_TTSTOP
|
||||
@ -1389,8 +1461,11 @@ siopoll()
|
||||
}
|
||||
if (com_events >= LOTS_OF_EVENTS)
|
||||
goto repeat;
|
||||
|
||||
#ifdef OLD_INTERRUPT_HANDLING
|
||||
splx(s);
|
||||
awake = FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
@ -1451,7 +1526,7 @@ comparam(tp, t)
|
||||
* while the UART is doing output (they refuse to transmit anything
|
||||
* more until given a hard reset). Fix this by stopping filling
|
||||
* the device buffers and waiting for them to drain. Reading the
|
||||
* line status port outside of siointr() might lose some receiver
|
||||
* line status port outside of siointr1() might lose some receiver
|
||||
* error bits, but that is acceptable here.
|
||||
*/
|
||||
disable_intr();
|
||||
@ -1460,7 +1535,7 @@ comparam(tp, t)
|
||||
enable_intr();
|
||||
while ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
|
||||
!= (LSR_TSRE | LSR_TXRDY)) {
|
||||
error = ttysleep(tp, (caddr_t)tp->t_raw, TTIPRI | PCATCH,
|
||||
error = ttysleep(tp, (caddr_t)TB_RAW(tp), TTIPRI | PCATCH,
|
||||
"sioparam", 1);
|
||||
if (error != 0 && error != EAGAIN) {
|
||||
if (!(tp->t_state & TS_TTSTOP)) {
|
||||
@ -1482,7 +1557,7 @@ comparam(tp, t)
|
||||
* sufficient, for similar reasons.
|
||||
*/
|
||||
if ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
|
||||
!= (LSR_TSRE | LSR_TXRDY))
|
||||
!= (LSR_TSRE | LSR_TXRDY))
|
||||
goto retry;
|
||||
|
||||
if (divisor != 0) {
|
||||
@ -1512,7 +1587,7 @@ comparam(tp, t)
|
||||
}
|
||||
|
||||
/*
|
||||
* Recover from fiddling with CS_TTGO. We used to call siointr()
|
||||
* Recover from fiddling with CS_TTGO. We used to call siointr1()
|
||||
* unconditionally, but that defeated the careful discarding of
|
||||
* stale input in sioopen().
|
||||
*
|
||||
@ -1520,7 +1595,7 @@ comparam(tp, t)
|
||||
* case.
|
||||
*/
|
||||
if (com->state >= (CS_BUSY | CS_TTGO))
|
||||
comintr1(com);
|
||||
siointr1(com);
|
||||
|
||||
enable_intr();
|
||||
splx(s);
|
||||
@ -1547,16 +1622,21 @@ comstart(tp)
|
||||
if (com->mcr_image & MCR_RTS && com->state & CS_RTS_IFLOW)
|
||||
outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS);
|
||||
} else {
|
||||
/*
|
||||
* XXX don't raise MCR_RTS if CTS_RTS_IFLOW is off. Set it
|
||||
* appropriately in comparam() if RTS-flow is being changed.
|
||||
* Check for races.
|
||||
*/
|
||||
if (!(com->mcr_image & MCR_RTS) && com->iptr < com->ihighwater)
|
||||
outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
|
||||
}
|
||||
enable_intr();
|
||||
if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))
|
||||
goto out;
|
||||
if (RB_LEN(tp->t_out) <= tp->t_lowat) {
|
||||
if (RB_LEN(TB_OUT(tp)) <= tp->t_lowat) {
|
||||
if (tp->t_state & TS_ASLEEP) {
|
||||
tp->t_state &= ~TS_ASLEEP;
|
||||
wakeup((caddr_t)tp->t_out);
|
||||
wakeup((caddr_t)TB_OUT(tp));
|
||||
}
|
||||
if (tp->t_wsel) {
|
||||
selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
|
||||
@ -1566,16 +1646,16 @@ comstart(tp)
|
||||
}
|
||||
if (com->ocount != 0) {
|
||||
disable_intr();
|
||||
comintr1(com);
|
||||
siointr1(com);
|
||||
enable_intr();
|
||||
} else if (RB_LEN(tp->t_out) != 0) {
|
||||
} else if (RB_LEN(TB_OUT(tp)) != 0) {
|
||||
tp->t_state |= TS_BUSY;
|
||||
com->ocount = RB_CONTIGGET(tp->t_out);
|
||||
com->ocount = RB_CONTIGGET(TB_OUT(tp));
|
||||
disable_intr();
|
||||
com->obufend = (com->optr = (u_char *) tp->t_out->rb_hd)
|
||||
com->obufend = (com->optr = (u_char *)TB_OUT(tp)->rb_hd)
|
||||
+ com->ocount;
|
||||
com->state |= CS_BUSY;
|
||||
comintr1(com); /* fake interrupt to start output */
|
||||
siointr1(com); /* fake interrupt to start output */
|
||||
enable_intr();
|
||||
}
|
||||
out:
|
||||
@ -1610,11 +1690,7 @@ sioselect(dev, rw, p)
|
||||
int rw;
|
||||
struct proc *p;
|
||||
{
|
||||
#ifdef COM_BIDIR
|
||||
return ttselect(dev & ~COM_CALLOUTMASK, rw, p);
|
||||
#else
|
||||
return ttselect(dev, rw, p);
|
||||
#endif
|
||||
return (ttselect(dev & ~COM_MINOR_MAGIC_MASK, rw, p));
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1641,15 +1717,22 @@ commctl(com, bits, how)
|
||||
|
||||
static void
|
||||
comwakeup(chan, ticks)
|
||||
caddr_t chan;
|
||||
int ticks;
|
||||
caddr_t chan;
|
||||
int ticks;
|
||||
{
|
||||
int unit;
|
||||
int unit;
|
||||
|
||||
timeout(comwakeup, (caddr_t) NULL, hz / 100);
|
||||
if (com_events != 0)
|
||||
/* schedule siopoll() to run when the cpl allows */
|
||||
setsofttty();
|
||||
|
||||
if (com_events != 0) {
|
||||
#ifndef OLD_INTERRUPT_HANDLING
|
||||
int s = splsofttty();
|
||||
#endif
|
||||
siopoll();
|
||||
#ifndef OLD_INTERRUPT_HANDLING
|
||||
splx(s);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* recover from lost output interrupts */
|
||||
for (unit = 0; unit < NSIO; ++unit) {
|
||||
@ -1658,27 +1741,101 @@ comwakeup(chan, ticks)
|
||||
com = com_addr(unit);
|
||||
if (com != NULL && com->state >= (CS_BUSY | CS_TTGO)) {
|
||||
disable_intr();
|
||||
comintr1(com);
|
||||
siointr1(com);
|
||||
enable_intr();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef OLD_INTERRUPT_HANDLING
|
||||
void
|
||||
softsio1()
|
||||
{
|
||||
siopoll();
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Following are all routines needed for SIO to act as console
|
||||
* XXX - not tested in this version
|
||||
* XXX - i386/cons.c only knows about the com driver (NCOM and not NSIO)
|
||||
* XXX - check that the corresponding serial interrupts are never enabled
|
||||
*/
|
||||
#include "i386/i386/cons.h"
|
||||
|
||||
struct siocnstate {
|
||||
u_char dlbl;
|
||||
u_char dlbh;
|
||||
u_char ier;
|
||||
u_char cfcr;
|
||||
u_char mcr;
|
||||
};
|
||||
|
||||
static Port_t siocniobase;
|
||||
|
||||
static void
|
||||
siocntxwait()
|
||||
{
|
||||
int timo;
|
||||
|
||||
/*
|
||||
* Wait for any pending transmission to finish. Required to avoid
|
||||
* the UART lockup bug when the speed is changed, and for normal
|
||||
* transmits.
|
||||
*/
|
||||
timo = 100000;
|
||||
while ((inb(siocniobase + com_lsr) & (LSR_TSRE | LSR_TXRDY))
|
||||
!= (LSR_TSRE | LSR_TXRDY) && --timo != 0)
|
||||
;
|
||||
}
|
||||
|
||||
static void
|
||||
siocnopen(sp)
|
||||
struct siocnstate *sp;
|
||||
{
|
||||
int divisor;
|
||||
Port_t iobase;
|
||||
|
||||
/*
|
||||
* Save all the device control registers except the fifo register
|
||||
* and set our default ones (cs8 -parenb speed=comdefaultrate).
|
||||
* We can't save the fifo register since it is read-only.
|
||||
*/
|
||||
iobase = siocniobase;
|
||||
sp->ier = inb(iobase + com_ier);
|
||||
outb(iobase + com_ier, 0); /* spltty() doesn't stop siointr() */
|
||||
siocntxwait();
|
||||
sp->cfcr = inb(iobase + com_cfcr);
|
||||
outb(iobase + com_cfcr, CFCR_DLAB);
|
||||
sp->dlbl = inb(iobase + com_dlbl);
|
||||
sp->dlbh = inb(iobase + com_dlbh);
|
||||
divisor = ttspeedtab(comdefaultrate, comspeedtab);
|
||||
outb(iobase + com_dlbl, divisor & 0xFF);
|
||||
outb(iobase + com_dlbh, (u_int) divisor >> 8);
|
||||
outb(iobase + com_cfcr, CFCR_8BITS);
|
||||
sp->mcr = inb(iobase + com_mcr);
|
||||
outb(iobase + com_mcr, MCR_DTR | MCR_RTS);
|
||||
}
|
||||
|
||||
static void
|
||||
siocnclose(sp)
|
||||
struct siocnstate *sp;
|
||||
{
|
||||
Port_t iobase;
|
||||
|
||||
/*
|
||||
* Restore the device control registers.
|
||||
*/
|
||||
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, sp->cfcr);
|
||||
/*
|
||||
* XXX damp osicllations of MCR_DTR or MCR_RTS by not restoring them.
|
||||
*/
|
||||
outb(iobase + com_mcr, sp->mcr | MCR_DTR | MCR_RTS);
|
||||
outb(iobase + com_ier, sp->ier);
|
||||
}
|
||||
|
||||
void
|
||||
siocnprobe(cp)
|
||||
struct consdev *cp;
|
||||
@ -1686,14 +1843,14 @@ siocnprobe(cp)
|
||||
int unit;
|
||||
|
||||
/* locate the major number */
|
||||
/* XXX - should be elsewhere since KGDB uses it */
|
||||
for (commajor = 0; commajor < nchrdev; commajor++)
|
||||
if (cdevsw[commajor].d_open == sioopen)
|
||||
break;
|
||||
|
||||
/* XXX: ick */
|
||||
unit = UNIT(CONUNIT);
|
||||
com_addr(unit) = &com_structs[unit];
|
||||
com_addr(unit)->iobase = CONADDR;
|
||||
siocniobase = CONADDR;
|
||||
|
||||
/* make sure hardware exists? XXX */
|
||||
|
||||
@ -1710,43 +1867,11 @@ void
|
||||
siocninit(cp)
|
||||
struct consdev *cp;
|
||||
{
|
||||
int unit;
|
||||
|
||||
unit = UNIT(cp->cn_dev);
|
||||
cominit(unit, comdefaultrate);
|
||||
comconsole = unit;
|
||||
comconsinit = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
cominit(unit, rate)
|
||||
int unit;
|
||||
int rate;
|
||||
{
|
||||
Port_t iobase;
|
||||
int s;
|
||||
|
||||
iobase = com_addr(unit)->iobase;
|
||||
s = splhigh();
|
||||
outb(iobase + com_cfcr, CFCR_DLAB);
|
||||
rate = ttspeedtab(comdefaultrate, comspeedtab);
|
||||
outb(iobase + com_dlbl, rate & 0xFF);
|
||||
outb(iobase + com_dlbh, rate >> 8);
|
||||
outb(iobase + com_cfcr, CFCR_8BITS);
|
||||
outb(iobase + com_fifo,
|
||||
FIFO_ENABLE | FIFO_TRIGGER | FIFO_RCV_RST | FIFO_XMT_RST);
|
||||
DELAY(100);
|
||||
(void) inb(iobase + com_lsr);
|
||||
(void) inb(iobase + com_data);
|
||||
(void) inb(iobase + com_msr);
|
||||
|
||||
/*
|
||||
* XXX - fishy to enable interrupts and then poll.
|
||||
* It shouldn't be necessary to ready the iir.
|
||||
* XXX can delete more comconsole stuff now that i/o routines are
|
||||
* fairly reentrant.
|
||||
*/
|
||||
outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC);
|
||||
(void) inb(iobase + com_iir);
|
||||
splx(s);
|
||||
comconsole = UNIT(cp->cn_dev);
|
||||
}
|
||||
|
||||
int
|
||||
@ -1756,13 +1881,15 @@ siocngetc(dev)
|
||||
int c;
|
||||
Port_t iobase;
|
||||
int s;
|
||||
struct siocnstate sp;
|
||||
|
||||
iobase = com_addr(UNIT(dev))->iobase;
|
||||
s = splhigh();
|
||||
iobase = siocniobase;
|
||||
s = spltty();
|
||||
siocnopen(&sp);
|
||||
while (!(inb(iobase + com_lsr) & LSR_RXRDY))
|
||||
;
|
||||
c = inb(iobase + com_data);
|
||||
(void) inb(iobase + com_iir);
|
||||
siocnclose(&sp);
|
||||
splx(s);
|
||||
return (c);
|
||||
}
|
||||
@ -1772,30 +1899,14 @@ siocnputc(dev, c)
|
||||
dev_t dev;
|
||||
int c;
|
||||
{
|
||||
Port_t iobase;
|
||||
int s;
|
||||
int timo;
|
||||
struct siocnstate sp;
|
||||
|
||||
iobase = com_addr(UNIT(dev))->iobase;
|
||||
s = splhigh();
|
||||
#ifdef KGDB
|
||||
if (dev != kgdb_dev)
|
||||
#endif
|
||||
if (!comconsinit) {
|
||||
cominit(UNIT(dev), comdefaultrate);
|
||||
comconsinit = TRUE;
|
||||
}
|
||||
/* wait for any pending transmission to finish */
|
||||
timo = 50000;
|
||||
while (!(inb(iobase + com_lsr) & LSR_TXRDY) && --timo)
|
||||
;
|
||||
outb(iobase + com_data, c);
|
||||
/* wait for this transmission to complete */
|
||||
timo = 1500000;
|
||||
while (!(inb(iobase + com_lsr) & LSR_TXRDY) && --timo)
|
||||
;
|
||||
/* clear any interrupts generated by this transmission */
|
||||
(void) inb(iobase + com_iir);
|
||||
s = spltty();
|
||||
siocnopen(&sp);
|
||||
siocntxwait();
|
||||
outb(siocniobase + com_data, c);
|
||||
siocnclose(&sp);
|
||||
splx(s);
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* from: @(#)com.c 7.5 (Berkeley) 5/16/91
|
||||
* $Id: sio.c,v 1.41 1994/04/01 16:47:01 ache Exp $
|
||||
* $Id: sio.c,v 1.40 1994/03/26 13:40:18 ache Exp $
|
||||
*/
|
||||
|
||||
#include "sio.h"
|
||||
@ -59,7 +59,7 @@
|
||||
#include "i386/isa/comreg.h"
|
||||
#include "i386/isa/ic/ns16550.h"
|
||||
|
||||
#define FAKE_DCD(unit) ((unit) == comconsole)
|
||||
#define FAKE_DCD(unit) ((unit) == comconsole)
|
||||
#define LOTS_OF_EVENTS 64 /* helps separate urgent events from input */
|
||||
#define RB_I_HIGH_WATER (RBSZ - 2 * RS_IBUFSIZE)
|
||||
#define RB_I_LOW_WATER ((RBSZ - 2 * RS_IBUFSIZE) * 7 / 8)
|
||||
@ -67,23 +67,25 @@
|
||||
#define TTY_BI TTY_FE /* XXX */
|
||||
#define TTY_OE TTY_PE /* XXX */
|
||||
|
||||
#ifndef COM_BIDIR
|
||||
#define UNIT(x) (minor(x)) /* XXX */
|
||||
#ifdef COM_BIDIR
|
||||
#define CALLOUT(x) (minor(x) & COM_CALLOUT_MASK)
|
||||
#define COM_CALLOUT_MASK 0x80
|
||||
#define COM_MINOR_MAGIC_MASK 0x80
|
||||
#else /* COM_BIDIR */
|
||||
#define COM_UNITMASK 0x7f
|
||||
#define COM_CALLOUTMASK 0x80 /* for both minor and dev */
|
||||
#define UNIT(x) (minor(x) & COM_UNITMASK)
|
||||
#define CALLOUT(x) (minor(x) & COM_CALLOUTMASK)
|
||||
#define COM_MINOR_MAGIC_MASK 0
|
||||
#endif /* COM_BIDIR */
|
||||
|
||||
#define UNIT(x) (minor(x) & ~COM_MINOR_MAGIC_MASK)
|
||||
|
||||
#ifdef COM_MULTIPORT
|
||||
/* checks in flags for multiport and which is multiport "master chip"
|
||||
* for a given card
|
||||
*/
|
||||
#define COM_ISMULTIPORT(dev) ((dev)->id_flags & 0x01)
|
||||
#define COM_MPMASTER(dev) (((dev)->id_flags >> 8) & 0x0ff)
|
||||
#define COM_ISMULTIPORT(dev) ((dev)->id_flags & 0x01)
|
||||
#define COM_MPMASTER(dev) (((dev)->id_flags >> 8) & 0x0ff)
|
||||
#endif /* COM_MULTIPORT */
|
||||
#define COM_NOFIFO(dev) ((dev)->id_flags & 0x02)
|
||||
|
||||
#define COM_NOFIFO(dev) ((dev)->id_flags & 0x02)
|
||||
|
||||
#ifndef FIFO_TRIGGER
|
||||
/*
|
||||
@ -94,11 +96,18 @@
|
||||
* if more than one packet arrives at once. The low speeds used for
|
||||
* serial mice help avoid this, but not if (large) fifos are enabled.
|
||||
*/
|
||||
#define FIFO_TRIGGER FIFO_TRIGGER_14
|
||||
#define FIFO_TRIGGER FIFO_TRIGGER_14
|
||||
#endif
|
||||
|
||||
#define com_scr 7 /* scratch register for 16450-16550 (R/W) */
|
||||
|
||||
#ifndef setsofttty
|
||||
#define OLD_INTERRUPT_HANDLING /* XXX FreeBSD-1.1 and earlier */
|
||||
#define setsofttty() (ipending |= 1 << 4) /* XXX requires owning IRQ4 */
|
||||
extern u_int ipending; /* XXX */
|
||||
void softsio1 __P((void));
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Input buffer watermarks.
|
||||
* The external device is asked to stop sending when the buffer exactly reaches
|
||||
@ -194,6 +203,11 @@ struct com_s {
|
||||
|
||||
struct tty *tp; /* cross reference */
|
||||
|
||||
#ifdef TIOCTIMESTAMP
|
||||
bool_t do_timestamp;
|
||||
struct timeval timestamp;
|
||||
#endif
|
||||
|
||||
u_long bytes_in; /* statistics */
|
||||
u_long bytes_out;
|
||||
u_int delta_error_counts[CE_NTYPES];
|
||||
@ -206,46 +220,49 @@ struct com_s {
|
||||
#define CE_INPUT_OFFSET RS_IBUFSIZE
|
||||
u_char ibuf1[2 * RS_IBUFSIZE];
|
||||
u_char ibuf2[2 * RS_IBUFSIZE];
|
||||
int do_timestamp;
|
||||
struct timeval timestamp;
|
||||
};
|
||||
|
||||
/*
|
||||
* These functions in the com module ought to be declared (with a prototype)
|
||||
* in a com-driver system header. The void ones may need to be int to match
|
||||
* ancient devswitch declarations, but they don't actually return anything.
|
||||
* The public functions in the com module ought to be declared in a com-driver
|
||||
* system header.
|
||||
*/
|
||||
#define Dev_t int /* promoted dev_t */
|
||||
struct consdev;
|
||||
|
||||
/* Interrupt handling entry points. */
|
||||
void siointr __P((int unit));
|
||||
void siopoll __P((void));
|
||||
|
||||
/* Device switch entry points. */
|
||||
int sioopen __P((Dev_t dev, int oflags, int devtype,
|
||||
struct proc *p));
|
||||
int sioclose __P((Dev_t dev, int fflag, int devtype,
|
||||
struct proc *p));
|
||||
void siointr __P((int unit));
|
||||
int sioread __P((Dev_t dev, struct uio *uio, int ioflag));
|
||||
int siowrite __P((Dev_t dev, struct uio *uio, int ioflag));
|
||||
int sioioctl __P((Dev_t dev, int cmd, caddr_t data,
|
||||
int fflag, struct proc *p));
|
||||
void siostop __P((struct tty *tp, int rw));
|
||||
#define sioreset noreset
|
||||
int sioselect __P((Dev_t dev, int rw, struct proc *p));
|
||||
#define siommap nommap
|
||||
#define siostrategy nostrategy
|
||||
|
||||
/* Console device entry points. */
|
||||
int siocngetc __P((Dev_t dev));
|
||||
struct consdev;
|
||||
void siocninit __P((struct consdev *cp));
|
||||
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));
|
||||
int siowrite __P((Dev_t dev, struct uio *uio, int ioflag));
|
||||
void softsio1 __P((void));
|
||||
|
||||
static int sioattach __P((struct isa_device *dev));
|
||||
static void comflush __P((struct com_s *com));
|
||||
static void comhardclose __P((struct com_s *com));
|
||||
static void cominit __P((int unit, int rate));
|
||||
static void comintr1 __P((struct com_s *com));
|
||||
static void siointr1 __P((struct com_s *com));
|
||||
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 comstart __P((struct tty *tp));
|
||||
static void comwakeup __P((caddr_t chan, int ticks));
|
||||
static void comstart __P((struct tty *tp));
|
||||
static void comwakeup __P((caddr_t chan, int ticks));
|
||||
static int tiocm_xxx2mcr __P((int tiocm_xxx));
|
||||
|
||||
/* table and macro for fast conversion from a unit number to its com struct */
|
||||
@ -254,7 +271,9 @@ static struct com_s *p_com_addr[NSIO];
|
||||
|
||||
static struct com_s com_structs[NSIO];
|
||||
|
||||
static struct timeval intr_timestamp;
|
||||
#ifdef TIOCTIMESTAMP
|
||||
static struct timeval intr_timestamp;
|
||||
#endif
|
||||
|
||||
struct isa_driver siodriver = {
|
||||
sioprobe, sioattach, "sio"
|
||||
@ -265,13 +284,19 @@ static int comconsole = COMCONSOLE;
|
||||
#else
|
||||
static int comconsole = -1;
|
||||
#endif
|
||||
static bool_t comconsinit;
|
||||
static speed_t comdefaultrate = TTYDEF_SPEED;
|
||||
static u_int com_events; /* input chars + weighted output completions */
|
||||
static int commajor;
|
||||
#ifdef DONT_MALLOC_TTYS
|
||||
#define TB_OUT(tp) (&(tp)->t_out)
|
||||
#define TB_RAW(tp) (&(tp)->t_raw)
|
||||
struct tty sio_tty[NSIO];
|
||||
#else
|
||||
#define TB_OUT(tp) ((tp)->t_out)
|
||||
#define TB_RAW(tp) ((tp)->t_raw)
|
||||
struct tty *sio_tty[NSIO];
|
||||
#endif
|
||||
extern struct tty *constty;
|
||||
extern u_int ipending; /* XXX */
|
||||
extern int tk_nin; /* XXX */
|
||||
extern int tk_rawcc; /* XXX */
|
||||
|
||||
@ -370,7 +395,7 @@ sioprobe(dev)
|
||||
#endif
|
||||
|| (inb(iobase + com_iir) & IIR_IMASK) != IIR_TXRDY
|
||||
|| isa_irq_pending(dev)
|
||||
|| !(inb(iobase + com_iir) & IIR_NOPEND))
|
||||
|| (inb(iobase + com_iir) & IIR_IMASK) != IIR_NOPEND)
|
||||
result = 0;
|
||||
|
||||
/*
|
||||
@ -385,7 +410,7 @@ sioprobe(dev)
|
||||
outb(iobase + com_mcr, MCR_IENABLE); /* dummy to avoid bus echo */
|
||||
if ( inb(iobase + com_ier) != 0
|
||||
|| isa_irq_pending(dev)
|
||||
|| !(inb(iobase + com_iir) & IIR_NOPEND))
|
||||
|| (inb(iobase + com_iir) & IIR_IMASK) != IIR_NOPEND)
|
||||
result = 0;
|
||||
if (result == 0)
|
||||
outb(iobase + com_mcr, 0);
|
||||
@ -406,8 +431,6 @@ sioattach(isdp)
|
||||
|
||||
iobase = isdp->id_iobase;
|
||||
unit = isdp->id_unit;
|
||||
if (unit == comconsole)
|
||||
DELAY(1000); /* XXX */
|
||||
s = spltty();
|
||||
|
||||
/*
|
||||
@ -422,7 +445,7 @@ sioattach(isdp)
|
||||
* device from sending before we are ready.
|
||||
*/
|
||||
|
||||
com = &com_structs[unit];
|
||||
com = &com_structs[unit]; /* XXX malloc it */
|
||||
com->cfcr_image = CFCR_8BITS;
|
||||
com->mcr_image = MCR_IENABLE;
|
||||
com->dtr_wait = 3 * hz;
|
||||
@ -436,7 +459,9 @@ sioattach(isdp)
|
||||
com->modem_ctl_port = iobase + com_mcr;
|
||||
com->line_status_port = iobase + com_lsr;
|
||||
com->modem_status_port = iobase + com_msr;
|
||||
com->tp = sio_tty[unit];
|
||||
#ifdef DONT_MALLOC_TTYS
|
||||
com->tp = &sio_tty[unit];
|
||||
#endif
|
||||
|
||||
/* attempt to determine UART type */
|
||||
printf("sio%d: type", unit);
|
||||
@ -473,9 +498,9 @@ sioattach(isdp)
|
||||
break;
|
||||
case FIFO_TRIGGER_14:
|
||||
printf(" 16550A");
|
||||
if (COM_NOFIFO(isdp)) {
|
||||
printf(" fifo software disabled");
|
||||
} else {
|
||||
if (COM_NOFIFO(isdp))
|
||||
printf(" fifo disabled");
|
||||
else {
|
||||
com->hasfifo = TRUE;
|
||||
com->tx_fifo_size = 16;
|
||||
}
|
||||
@ -510,7 +535,22 @@ determined_type: ;
|
||||
if (comconsole == unit)
|
||||
kgdb_dev = -1; /* can't debug over console port */
|
||||
else {
|
||||
cominit(unit, kgdb_rate);
|
||||
int divisor;
|
||||
|
||||
/*
|
||||
* XXX now unfinished and broken. Need to do
|
||||
* something more like a full open(). There's no
|
||||
* suitable interrupt handler so don't enable device
|
||||
* interrupts. Watch out for null tp's.
|
||||
*/
|
||||
outb(iobase + com_cfcr, CFCR_DLAB);
|
||||
divisor = ttspeedtab(kgdb_rate, comspeedtab);
|
||||
outb(iobase + com_dlbl, divisor & 0xFF);
|
||||
outb(iobase + com_dlbh, (u_int) divisor >> 8);
|
||||
outb(iobase + com_cfcr, CFCR_8BITS);
|
||||
outb(com->modem_status_port,
|
||||
com->mcr_image |= MCR_DTR | MCR_RTS);
|
||||
|
||||
if (kgdb_debug_init) {
|
||||
/*
|
||||
* Print prefix of device name,
|
||||
@ -524,12 +564,6 @@ determined_type: ;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Need to reset baud rate, etc. of next print so reset comconsinit.
|
||||
*/
|
||||
if (unit == comconsole)
|
||||
comconsinit = FALSE;
|
||||
|
||||
com_addr(unit) = com;
|
||||
splx(s);
|
||||
if (!comwakeup_started) {
|
||||
@ -550,9 +584,9 @@ sioopen(dev, flag, mode, p)
|
||||
#ifdef COM_BIDIR
|
||||
bool_t callout;
|
||||
#endif /* COM_BIDIR */
|
||||
bool_t got_status = FALSE;
|
||||
struct com_s *com;
|
||||
int error = 0;
|
||||
bool_t got_status = FALSE;
|
||||
Port_t iobase;
|
||||
int s;
|
||||
struct tty *tp;
|
||||
@ -568,9 +602,12 @@ sioopen(dev, flag, mode, p)
|
||||
return (ENXIO);
|
||||
#endif /* COM_BIDIR */
|
||||
|
||||
|
||||
#ifdef DONT_MALLOC_TTYS
|
||||
tp = com->tp;
|
||||
#else
|
||||
sio_tty[unit] = ttymalloc(sio_tty[unit]);
|
||||
tp = com->tp = sio_tty[unit];
|
||||
#endif
|
||||
s = spltty();
|
||||
|
||||
#ifdef COM_BIDIR
|
||||
@ -611,12 +648,12 @@ sioopen(dev, flag, mode, p)
|
||||
}
|
||||
}
|
||||
disable_intr();
|
||||
com->last_modem_status =
|
||||
com->prev_modem_status = inb(com->modem_status_port);
|
||||
com->prev_modem_status =
|
||||
com->last_modem_status = inb(com->modem_status_port);
|
||||
enable_intr();
|
||||
got_status = TRUE;
|
||||
if (com->prev_modem_status & MSR_DCD
|
||||
|| FAKE_DCD(unit)) {
|
||||
|| FAKE_DCD(unit)) {
|
||||
/* there's a carrier on the line; we win */
|
||||
com->active_in = TRUE;
|
||||
} else {
|
||||
@ -665,7 +702,7 @@ sioopen(dev, flag, mode, p)
|
||||
ttychars(tp);
|
||||
if (tp->t_ispeed == 0) {
|
||||
/*
|
||||
* We no longer use the flags from <sys/ttydefaults.h>
|
||||
* We don't use all the flags from <sys/ttydefaults.h>
|
||||
* since those are only relevant for logins. It's
|
||||
* important to have echo off initially so that the
|
||||
* line doesn't start blathering before the echo flag
|
||||
@ -673,17 +710,19 @@ sioopen(dev, flag, mode, p)
|
||||
*/
|
||||
tp->t_iflag = 0;
|
||||
tp->t_oflag = 0;
|
||||
#ifdef COMCONSOLE
|
||||
if (unit == comconsole)
|
||||
tp->t_oflag = TTYDEF_OFLAG;
|
||||
#endif
|
||||
tp->t_cflag = CREAD | CS8;
|
||||
#ifdef COM_BIDIR
|
||||
if (com->bidir && !callout)
|
||||
tp->t_cflag |= HUPCL;
|
||||
tp->t_cflag |= HUPCL;
|
||||
#endif
|
||||
tp->t_lflag = 0;
|
||||
tp->t_ispeed = tp->t_ospeed = comdefaultrate;
|
||||
if (unit == comconsole) {
|
||||
tp->t_iflag = TTYDEF_IFLAG;
|
||||
tp->t_oflag = TTYDEF_OFLAG;
|
||||
tp->t_cflag = TTYDEF_CFLAG;
|
||||
tp->t_lflag = TTYDEF_LFLAG;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -715,8 +754,8 @@ sioopen(dev, flag, mode, p)
|
||||
(void) inb(com->line_status_port);
|
||||
(void) inb(com->data_port);
|
||||
if (!got_status)
|
||||
com->last_modem_status =
|
||||
com->prev_modem_status = inb(com->modem_status_port);
|
||||
com->prev_modem_status =
|
||||
com->last_modem_status = inb(com->modem_status_port);
|
||||
outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS
|
||||
| IER_EMSC);
|
||||
enable_intr();
|
||||
@ -736,7 +775,7 @@ sioopen(dev, flag, mode, p)
|
||||
#endif /* COM_BIDIR */
|
||||
&& !(tp->t_state & TS_CARR_ON)) {
|
||||
tp->t_state |= TS_WOPEN;
|
||||
error = ttysleep(tp, (caddr_t)tp->t_raw, TTIPRI | PCATCH,
|
||||
error = ttysleep(tp, (caddr_t)TB_RAW(tp), TTIPRI | PCATCH,
|
||||
ttopen, 0);
|
||||
if (error != 0)
|
||||
break;
|
||||
@ -775,14 +814,14 @@ sioclose(dev, flag, mode, p)
|
||||
struct proc *p;
|
||||
{
|
||||
struct com_s *com;
|
||||
int s;
|
||||
struct tty *tp;
|
||||
int s;
|
||||
|
||||
com = com_addr(UNIT(dev));
|
||||
tp = com->tp;
|
||||
s = spltty();
|
||||
(*linesw[tp->t_line].l_close)(tp, flag);
|
||||
siostop(tp, FREAD|FWRITE);
|
||||
siostop(tp, FREAD | FWRITE);
|
||||
comhardclose(com);
|
||||
ttyclose(tp);
|
||||
splx(s);
|
||||
@ -798,11 +837,13 @@ comhardclose(com)
|
||||
struct tty *tp;
|
||||
int unit;
|
||||
|
||||
s = spltty();
|
||||
iobase = com->iobase;
|
||||
com->do_timestamp = 0;
|
||||
outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
|
||||
unit = com - &com_structs[0];
|
||||
iobase = com->iobase;
|
||||
s = spltty();
|
||||
#ifdef TIOCTIMESTAMP
|
||||
com->do_timestamp = 0;
|
||||
#endif
|
||||
outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
|
||||
#ifdef KGDB
|
||||
/* do not disable interrupts or hang up if debugging */
|
||||
if (kgdb_dev != makedev(commajor, unit))
|
||||
@ -812,8 +853,19 @@ comhardclose(com)
|
||||
tp = com->tp;
|
||||
if (tp->t_cflag & HUPCL || tp->t_state & TS_WOPEN
|
||||
#ifdef COM_BIDIR
|
||||
/*
|
||||
* XXX we will miss any carrier drop between here and the
|
||||
* next open. Perhaps we should watch DCD even when the
|
||||
* port is closed; it is not sufficient to check it at
|
||||
* the next open because it might go up and down while
|
||||
* we're not watching. And we shouldn't look at DCD if
|
||||
* CLOCAL is set (here or for the dialin device ...).
|
||||
* When the termios state is reinitialized for initial
|
||||
* opens, the correct CLOCAL bit will be
|
||||
* ((the bit now) & (the initial bit)).
|
||||
*/
|
||||
|| com->active_in
|
||||
&& !(com->prev_modem_status & MSR_DCD) && !FAKE_DCD(unit)
|
||||
&& !(com->prev_modem_status & MSR_DCD) && !FAKE_DCD(unit)
|
||||
#endif
|
||||
|| !(tp->t_state & TS_ISOPEN)) {
|
||||
commctl(com, MCR_RTS, DMSET);
|
||||
@ -870,24 +922,23 @@ siowrite(dev, uio, flag)
|
||||
return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
|
||||
}
|
||||
|
||||
#ifdef TIOCTIMESTAMP
|
||||
/* Interrupt routine for timekeeping purposes */
|
||||
void
|
||||
siointrts(int unit)
|
||||
siointrts(unit)
|
||||
int unit;
|
||||
{
|
||||
microtime(&intr_timestamp);
|
||||
siointr(unit);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
siointr(unit)
|
||||
int unit;
|
||||
{
|
||||
struct com_s *com;
|
||||
|
||||
#ifndef COM_MULTIPORT
|
||||
com = com_addr(unit);
|
||||
if (com != NULL)
|
||||
comintr1(com);
|
||||
siointr1(com_addr(unit));
|
||||
#else /* COM_MULTIPORT */
|
||||
bool_t possibly_more_intrs;
|
||||
|
||||
@ -903,31 +954,30 @@ siointr(unit)
|
||||
for (unit = 0; unit < NSIO; ++unit) {
|
||||
com = com_addr(unit);
|
||||
if (com != NULL
|
||||
&& !(inb(com->int_id_port) & IIR_NOPEND)) {
|
||||
/*
|
||||
* XXX call comintr1() instead of here from
|
||||
* comwakeup(). The interrupt edge problem
|
||||
* only exists for real interrupts.
|
||||
*/
|
||||
comintr1(com);
|
||||
&& (inb(com->int_id_port) & IIR_IMASK)
|
||||
!= IIR_NOPEND) {
|
||||
siointr1(com);
|
||||
possibly_more_intrs = TRUE;
|
||||
}
|
||||
}
|
||||
} while (possibly_more_intrs);
|
||||
#endif /* COM_MULTIPORT */
|
||||
#endif /* COM_MULTIPORT */
|
||||
}
|
||||
|
||||
static void
|
||||
comintr1(com)
|
||||
siointr1(com)
|
||||
struct com_s *com;
|
||||
{
|
||||
u_char line_status;
|
||||
u_char modem_status;
|
||||
u_char *ioptr;
|
||||
u_char recv_data;
|
||||
u_char line_status;
|
||||
u_char modem_status;
|
||||
u_char *ioptr;
|
||||
u_char recv_data;
|
||||
|
||||
if(com->do_timestamp)
|
||||
#ifdef TIOCTIMESTAMP
|
||||
if (com->do_timestamp)
|
||||
/* XXX a little bloat here... */
|
||||
com->timestamp = intr_timestamp;
|
||||
#endif
|
||||
while (TRUE) {
|
||||
line_status = inb(com->line_status_port);
|
||||
|
||||
@ -939,6 +989,10 @@ comintr1(com)
|
||||
else
|
||||
recv_data = inb(com->data_port);
|
||||
++com->bytes_in;
|
||||
/* XXX reduce SLIP input latency */
|
||||
#define FRAME_END 0xc0
|
||||
if (recv_data == FRAME_END)
|
||||
setsofttty();
|
||||
#ifdef KGDB
|
||||
/* trap into kgdb? (XXX - needs testing and optim) */
|
||||
if (recv_data == FRAME_END
|
||||
@ -1017,7 +1071,7 @@ if (com->iptr - com->ibuf == 8)
|
||||
while (--ocount != 0);
|
||||
} else {
|
||||
outb(com->data_port, *ioptr++);
|
||||
++com->bytes_out;
|
||||
++com->bytes_out;
|
||||
}
|
||||
com->optr = ioptr;
|
||||
if (ioptr >= com->obufend) {
|
||||
@ -1030,7 +1084,7 @@ if (com->iptr - com->ibuf == 8)
|
||||
|
||||
/* finished? */
|
||||
#ifndef COM_MULTIPORT
|
||||
if (inb(com->int_id_port) & IIR_NOPEND)
|
||||
if ((inb(com->int_id_port) & IIR_IMASK) == IIR_NOPEND)
|
||||
#endif /* COM_MULTIPORT */
|
||||
return;
|
||||
}
|
||||
@ -1038,9 +1092,9 @@ if (com->iptr - com->ibuf == 8)
|
||||
|
||||
static int
|
||||
tiocm_xxx2mcr(tiocm_xxx)
|
||||
int tiocm_xxx;
|
||||
int tiocm_xxx;
|
||||
{
|
||||
int mcr;
|
||||
int mcr;
|
||||
|
||||
mcr = 0;
|
||||
if (tiocm_xxx & TIOCM_DTR)
|
||||
@ -1175,16 +1229,17 @@ sioioctl(dev, cmd, data, flag, p)
|
||||
splx(s);
|
||||
return(ENOTTY);
|
||||
}
|
||||
|
||||
com->dtr_wait = *(int *)data;
|
||||
break;
|
||||
case TIOCMGDTRWAIT:
|
||||
*(int *)data = com->dtr_wait;
|
||||
break;
|
||||
#ifdef TIOCTIMESTAMP
|
||||
case TIOCTIMESTAMP:
|
||||
com->do_timestamp = 1;
|
||||
com->do_timestamp = TRUE;
|
||||
*(struct timeval *)data = com->timestamp;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
splx(s);
|
||||
return (ENOTTY);
|
||||
@ -1205,7 +1260,7 @@ comflush(com)
|
||||
com_events -= LOTS_OF_EVENTS;
|
||||
com->state &= ~(CS_ODONE | CS_BUSY);
|
||||
enable_intr();
|
||||
rbp = com->tp->t_out;
|
||||
rbp = TB_OUT(com->tp);
|
||||
rbp->rb_hd += com->ocount;
|
||||
rbp->rb_hd = RB_ROLLOVER(rbp, rbp->rb_hd);
|
||||
com->ocount = 0;
|
||||
@ -1215,12 +1270,16 @@ comflush(com)
|
||||
void
|
||||
siopoll()
|
||||
{
|
||||
#ifdef OLD_INTERRUPT_HANDLING
|
||||
static bool_t awake = FALSE;
|
||||
int s;
|
||||
#endif
|
||||
int unit;
|
||||
|
||||
if (com_events == 0)
|
||||
return;
|
||||
|
||||
#ifdef OLD_INTERRUPT_HANDLING
|
||||
disable_intr();
|
||||
if (awake) {
|
||||
enable_intr();
|
||||
@ -1229,10 +1288,12 @@ siopoll()
|
||||
awake = TRUE;
|
||||
enable_intr();
|
||||
s = spltty();
|
||||
#endif
|
||||
|
||||
repeat:
|
||||
for (unit = 0; unit < NSIO; ++unit) {
|
||||
u_char *buf;
|
||||
struct com_s *com;
|
||||
u_char *buf;
|
||||
struct com_s *com;
|
||||
u_char *ibuf;
|
||||
int incc;
|
||||
struct tty *tp;
|
||||
@ -1241,6 +1302,10 @@ siopoll()
|
||||
if (com == NULL)
|
||||
continue;
|
||||
tp = com->tp;
|
||||
#ifdef DONT_MALLOC_TTYS
|
||||
if (tp == NULL)
|
||||
continue;
|
||||
#endif
|
||||
|
||||
/* switch the role of the low-level input buffers */
|
||||
if (com->iptr == (ibuf = com->ibuf)) {
|
||||
@ -1264,6 +1329,13 @@ siopoll()
|
||||
* of input, so enable RTS if it is now disabled and
|
||||
* there is room in the high-level buffer.
|
||||
*/
|
||||
/*
|
||||
* XXX this used not to look at CS_RTS_IFLOW. The
|
||||
* change is to allow full control of MCR_RTS via
|
||||
* ioctls after turning CS_RTS_IFLOW off. Check
|
||||
* for races. We shouldn't allow the ioctls while
|
||||
* CS_RTS_IFLOW is on.
|
||||
*/
|
||||
if ((com->state & CS_RTS_IFLOW)
|
||||
&& !(com->mcr_image & MCR_RTS)
|
||||
&& !(tp->t_state & TS_RTS_IFLOW))
|
||||
@ -1296,15 +1368,15 @@ siopoll()
|
||||
|
||||
/* XXX */
|
||||
if (TRUE) {
|
||||
u_int delta;
|
||||
int errnum;
|
||||
u_long total;
|
||||
u_int delta;
|
||||
int errnum;
|
||||
u_long total;
|
||||
|
||||
for (errnum = 0; errnum < CE_NTYPES; ++errnum) {
|
||||
disable_intr();
|
||||
disable_intr();
|
||||
delta = com->delta_error_counts[errnum];
|
||||
com->delta_error_counts[errnum] = 0;
|
||||
enable_intr();
|
||||
enable_intr();
|
||||
if (delta != 0) {
|
||||
total =
|
||||
com->error_counts[errnum] += delta;
|
||||
@ -1326,7 +1398,7 @@ siopoll()
|
||||
if (incc <= 0 || !(tp->t_state & TS_ISOPEN))
|
||||
continue;
|
||||
if (com->state & CS_RTS_IFLOW
|
||||
&& RB_LEN(tp->t_raw) + incc >= RB_I_HIGH_WATER
|
||||
&& RB_LEN(TB_RAW(tp)) + incc >= RB_I_HIGH_WATER
|
||||
&& !(tp->t_state & TS_RTS_IFLOW)
|
||||
/*
|
||||
* XXX - need RTS flow control for all line disciplines.
|
||||
@ -1353,7 +1425,7 @@ siopoll()
|
||||
tk_rawcc += incc;
|
||||
tp->t_rawcc += incc;
|
||||
com->delta_error_counts[CE_TTY_BUF_OVERFLOW]
|
||||
+= incc - rb_write(tp->t_raw, (char *) buf,
|
||||
+= incc - rb_write(TB_RAW(tp), (char *) buf,
|
||||
incc);
|
||||
ttwakeup(tp);
|
||||
if (tp->t_state & TS_TTSTOP
|
||||
@ -1389,8 +1461,11 @@ siopoll()
|
||||
}
|
||||
if (com_events >= LOTS_OF_EVENTS)
|
||||
goto repeat;
|
||||
|
||||
#ifdef OLD_INTERRUPT_HANDLING
|
||||
splx(s);
|
||||
awake = FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
@ -1451,7 +1526,7 @@ comparam(tp, t)
|
||||
* while the UART is doing output (they refuse to transmit anything
|
||||
* more until given a hard reset). Fix this by stopping filling
|
||||
* the device buffers and waiting for them to drain. Reading the
|
||||
* line status port outside of siointr() might lose some receiver
|
||||
* line status port outside of siointr1() might lose some receiver
|
||||
* error bits, but that is acceptable here.
|
||||
*/
|
||||
disable_intr();
|
||||
@ -1460,7 +1535,7 @@ comparam(tp, t)
|
||||
enable_intr();
|
||||
while ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
|
||||
!= (LSR_TSRE | LSR_TXRDY)) {
|
||||
error = ttysleep(tp, (caddr_t)tp->t_raw, TTIPRI | PCATCH,
|
||||
error = ttysleep(tp, (caddr_t)TB_RAW(tp), TTIPRI | PCATCH,
|
||||
"sioparam", 1);
|
||||
if (error != 0 && error != EAGAIN) {
|
||||
if (!(tp->t_state & TS_TTSTOP)) {
|
||||
@ -1482,7 +1557,7 @@ comparam(tp, t)
|
||||
* sufficient, for similar reasons.
|
||||
*/
|
||||
if ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
|
||||
!= (LSR_TSRE | LSR_TXRDY))
|
||||
!= (LSR_TSRE | LSR_TXRDY))
|
||||
goto retry;
|
||||
|
||||
if (divisor != 0) {
|
||||
@ -1512,7 +1587,7 @@ comparam(tp, t)
|
||||
}
|
||||
|
||||
/*
|
||||
* Recover from fiddling with CS_TTGO. We used to call siointr()
|
||||
* Recover from fiddling with CS_TTGO. We used to call siointr1()
|
||||
* unconditionally, but that defeated the careful discarding of
|
||||
* stale input in sioopen().
|
||||
*
|
||||
@ -1520,7 +1595,7 @@ comparam(tp, t)
|
||||
* case.
|
||||
*/
|
||||
if (com->state >= (CS_BUSY | CS_TTGO))
|
||||
comintr1(com);
|
||||
siointr1(com);
|
||||
|
||||
enable_intr();
|
||||
splx(s);
|
||||
@ -1547,16 +1622,21 @@ comstart(tp)
|
||||
if (com->mcr_image & MCR_RTS && com->state & CS_RTS_IFLOW)
|
||||
outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS);
|
||||
} else {
|
||||
/*
|
||||
* XXX don't raise MCR_RTS if CTS_RTS_IFLOW is off. Set it
|
||||
* appropriately in comparam() if RTS-flow is being changed.
|
||||
* Check for races.
|
||||
*/
|
||||
if (!(com->mcr_image & MCR_RTS) && com->iptr < com->ihighwater)
|
||||
outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
|
||||
}
|
||||
enable_intr();
|
||||
if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))
|
||||
goto out;
|
||||
if (RB_LEN(tp->t_out) <= tp->t_lowat) {
|
||||
if (RB_LEN(TB_OUT(tp)) <= tp->t_lowat) {
|
||||
if (tp->t_state & TS_ASLEEP) {
|
||||
tp->t_state &= ~TS_ASLEEP;
|
||||
wakeup((caddr_t)tp->t_out);
|
||||
wakeup((caddr_t)TB_OUT(tp));
|
||||
}
|
||||
if (tp->t_wsel) {
|
||||
selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
|
||||
@ -1566,16 +1646,16 @@ comstart(tp)
|
||||
}
|
||||
if (com->ocount != 0) {
|
||||
disable_intr();
|
||||
comintr1(com);
|
||||
siointr1(com);
|
||||
enable_intr();
|
||||
} else if (RB_LEN(tp->t_out) != 0) {
|
||||
} else if (RB_LEN(TB_OUT(tp)) != 0) {
|
||||
tp->t_state |= TS_BUSY;
|
||||
com->ocount = RB_CONTIGGET(tp->t_out);
|
||||
com->ocount = RB_CONTIGGET(TB_OUT(tp));
|
||||
disable_intr();
|
||||
com->obufend = (com->optr = (u_char *) tp->t_out->rb_hd)
|
||||
com->obufend = (com->optr = (u_char *)TB_OUT(tp)->rb_hd)
|
||||
+ com->ocount;
|
||||
com->state |= CS_BUSY;
|
||||
comintr1(com); /* fake interrupt to start output */
|
||||
siointr1(com); /* fake interrupt to start output */
|
||||
enable_intr();
|
||||
}
|
||||
out:
|
||||
@ -1610,11 +1690,7 @@ sioselect(dev, rw, p)
|
||||
int rw;
|
||||
struct proc *p;
|
||||
{
|
||||
#ifdef COM_BIDIR
|
||||
return ttselect(dev & ~COM_CALLOUTMASK, rw, p);
|
||||
#else
|
||||
return ttselect(dev, rw, p);
|
||||
#endif
|
||||
return (ttselect(dev & ~COM_MINOR_MAGIC_MASK, rw, p));
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1641,15 +1717,22 @@ commctl(com, bits, how)
|
||||
|
||||
static void
|
||||
comwakeup(chan, ticks)
|
||||
caddr_t chan;
|
||||
int ticks;
|
||||
caddr_t chan;
|
||||
int ticks;
|
||||
{
|
||||
int unit;
|
||||
int unit;
|
||||
|
||||
timeout(comwakeup, (caddr_t) NULL, hz / 100);
|
||||
if (com_events != 0)
|
||||
/* schedule siopoll() to run when the cpl allows */
|
||||
setsofttty();
|
||||
|
||||
if (com_events != 0) {
|
||||
#ifndef OLD_INTERRUPT_HANDLING
|
||||
int s = splsofttty();
|
||||
#endif
|
||||
siopoll();
|
||||
#ifndef OLD_INTERRUPT_HANDLING
|
||||
splx(s);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* recover from lost output interrupts */
|
||||
for (unit = 0; unit < NSIO; ++unit) {
|
||||
@ -1658,27 +1741,101 @@ comwakeup(chan, ticks)
|
||||
com = com_addr(unit);
|
||||
if (com != NULL && com->state >= (CS_BUSY | CS_TTGO)) {
|
||||
disable_intr();
|
||||
comintr1(com);
|
||||
siointr1(com);
|
||||
enable_intr();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef OLD_INTERRUPT_HANDLING
|
||||
void
|
||||
softsio1()
|
||||
{
|
||||
siopoll();
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Following are all routines needed for SIO to act as console
|
||||
* XXX - not tested in this version
|
||||
* XXX - i386/cons.c only knows about the com driver (NCOM and not NSIO)
|
||||
* XXX - check that the corresponding serial interrupts are never enabled
|
||||
*/
|
||||
#include "i386/i386/cons.h"
|
||||
|
||||
struct siocnstate {
|
||||
u_char dlbl;
|
||||
u_char dlbh;
|
||||
u_char ier;
|
||||
u_char cfcr;
|
||||
u_char mcr;
|
||||
};
|
||||
|
||||
static Port_t siocniobase;
|
||||
|
||||
static void
|
||||
siocntxwait()
|
||||
{
|
||||
int timo;
|
||||
|
||||
/*
|
||||
* Wait for any pending transmission to finish. Required to avoid
|
||||
* the UART lockup bug when the speed is changed, and for normal
|
||||
* transmits.
|
||||
*/
|
||||
timo = 100000;
|
||||
while ((inb(siocniobase + com_lsr) & (LSR_TSRE | LSR_TXRDY))
|
||||
!= (LSR_TSRE | LSR_TXRDY) && --timo != 0)
|
||||
;
|
||||
}
|
||||
|
||||
static void
|
||||
siocnopen(sp)
|
||||
struct siocnstate *sp;
|
||||
{
|
||||
int divisor;
|
||||
Port_t iobase;
|
||||
|
||||
/*
|
||||
* Save all the device control registers except the fifo register
|
||||
* and set our default ones (cs8 -parenb speed=comdefaultrate).
|
||||
* We can't save the fifo register since it is read-only.
|
||||
*/
|
||||
iobase = siocniobase;
|
||||
sp->ier = inb(iobase + com_ier);
|
||||
outb(iobase + com_ier, 0); /* spltty() doesn't stop siointr() */
|
||||
siocntxwait();
|
||||
sp->cfcr = inb(iobase + com_cfcr);
|
||||
outb(iobase + com_cfcr, CFCR_DLAB);
|
||||
sp->dlbl = inb(iobase + com_dlbl);
|
||||
sp->dlbh = inb(iobase + com_dlbh);
|
||||
divisor = ttspeedtab(comdefaultrate, comspeedtab);
|
||||
outb(iobase + com_dlbl, divisor & 0xFF);
|
||||
outb(iobase + com_dlbh, (u_int) divisor >> 8);
|
||||
outb(iobase + com_cfcr, CFCR_8BITS);
|
||||
sp->mcr = inb(iobase + com_mcr);
|
||||
outb(iobase + com_mcr, MCR_DTR | MCR_RTS);
|
||||
}
|
||||
|
||||
static void
|
||||
siocnclose(sp)
|
||||
struct siocnstate *sp;
|
||||
{
|
||||
Port_t iobase;
|
||||
|
||||
/*
|
||||
* Restore the device control registers.
|
||||
*/
|
||||
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, sp->cfcr);
|
||||
/*
|
||||
* XXX damp osicllations of MCR_DTR or MCR_RTS by not restoring them.
|
||||
*/
|
||||
outb(iobase + com_mcr, sp->mcr | MCR_DTR | MCR_RTS);
|
||||
outb(iobase + com_ier, sp->ier);
|
||||
}
|
||||
|
||||
void
|
||||
siocnprobe(cp)
|
||||
struct consdev *cp;
|
||||
@ -1686,14 +1843,14 @@ siocnprobe(cp)
|
||||
int unit;
|
||||
|
||||
/* locate the major number */
|
||||
/* XXX - should be elsewhere since KGDB uses it */
|
||||
for (commajor = 0; commajor < nchrdev; commajor++)
|
||||
if (cdevsw[commajor].d_open == sioopen)
|
||||
break;
|
||||
|
||||
/* XXX: ick */
|
||||
unit = UNIT(CONUNIT);
|
||||
com_addr(unit) = &com_structs[unit];
|
||||
com_addr(unit)->iobase = CONADDR;
|
||||
siocniobase = CONADDR;
|
||||
|
||||
/* make sure hardware exists? XXX */
|
||||
|
||||
@ -1710,43 +1867,11 @@ void
|
||||
siocninit(cp)
|
||||
struct consdev *cp;
|
||||
{
|
||||
int unit;
|
||||
|
||||
unit = UNIT(cp->cn_dev);
|
||||
cominit(unit, comdefaultrate);
|
||||
comconsole = unit;
|
||||
comconsinit = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
cominit(unit, rate)
|
||||
int unit;
|
||||
int rate;
|
||||
{
|
||||
Port_t iobase;
|
||||
int s;
|
||||
|
||||
iobase = com_addr(unit)->iobase;
|
||||
s = splhigh();
|
||||
outb(iobase + com_cfcr, CFCR_DLAB);
|
||||
rate = ttspeedtab(comdefaultrate, comspeedtab);
|
||||
outb(iobase + com_dlbl, rate & 0xFF);
|
||||
outb(iobase + com_dlbh, rate >> 8);
|
||||
outb(iobase + com_cfcr, CFCR_8BITS);
|
||||
outb(iobase + com_fifo,
|
||||
FIFO_ENABLE | FIFO_TRIGGER | FIFO_RCV_RST | FIFO_XMT_RST);
|
||||
DELAY(100);
|
||||
(void) inb(iobase + com_lsr);
|
||||
(void) inb(iobase + com_data);
|
||||
(void) inb(iobase + com_msr);
|
||||
|
||||
/*
|
||||
* XXX - fishy to enable interrupts and then poll.
|
||||
* It shouldn't be necessary to ready the iir.
|
||||
* XXX can delete more comconsole stuff now that i/o routines are
|
||||
* fairly reentrant.
|
||||
*/
|
||||
outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC);
|
||||
(void) inb(iobase + com_iir);
|
||||
splx(s);
|
||||
comconsole = UNIT(cp->cn_dev);
|
||||
}
|
||||
|
||||
int
|
||||
@ -1756,13 +1881,15 @@ siocngetc(dev)
|
||||
int c;
|
||||
Port_t iobase;
|
||||
int s;
|
||||
struct siocnstate sp;
|
||||
|
||||
iobase = com_addr(UNIT(dev))->iobase;
|
||||
s = splhigh();
|
||||
iobase = siocniobase;
|
||||
s = spltty();
|
||||
siocnopen(&sp);
|
||||
while (!(inb(iobase + com_lsr) & LSR_RXRDY))
|
||||
;
|
||||
c = inb(iobase + com_data);
|
||||
(void) inb(iobase + com_iir);
|
||||
siocnclose(&sp);
|
||||
splx(s);
|
||||
return (c);
|
||||
}
|
||||
@ -1772,30 +1899,14 @@ siocnputc(dev, c)
|
||||
dev_t dev;
|
||||
int c;
|
||||
{
|
||||
Port_t iobase;
|
||||
int s;
|
||||
int timo;
|
||||
struct siocnstate sp;
|
||||
|
||||
iobase = com_addr(UNIT(dev))->iobase;
|
||||
s = splhigh();
|
||||
#ifdef KGDB
|
||||
if (dev != kgdb_dev)
|
||||
#endif
|
||||
if (!comconsinit) {
|
||||
cominit(UNIT(dev), comdefaultrate);
|
||||
comconsinit = TRUE;
|
||||
}
|
||||
/* wait for any pending transmission to finish */
|
||||
timo = 50000;
|
||||
while (!(inb(iobase + com_lsr) & LSR_TXRDY) && --timo)
|
||||
;
|
||||
outb(iobase + com_data, c);
|
||||
/* wait for this transmission to complete */
|
||||
timo = 1500000;
|
||||
while (!(inb(iobase + com_lsr) & LSR_TXRDY) && --timo)
|
||||
;
|
||||
/* clear any interrupts generated by this transmission */
|
||||
(void) inb(iobase + com_iir);
|
||||
s = spltty();
|
||||
siocnopen(&sp);
|
||||
siocntxwait();
|
||||
outb(siocniobase + com_data, c);
|
||||
siocnclose(&sp);
|
||||
splx(s);
|
||||
}
|
||||
|
||||
|
505
sys/isa/sio.c
505
sys/isa/sio.c
@ -31,7 +31,7 @@
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* from: @(#)com.c 7.5 (Berkeley) 5/16/91
|
||||
* $Id: sio.c,v 1.41 1994/04/01 16:47:01 ache Exp $
|
||||
* $Id: sio.c,v 1.40 1994/03/26 13:40:18 ache Exp $
|
||||
*/
|
||||
|
||||
#include "sio.h"
|
||||
@ -59,7 +59,7 @@
|
||||
#include "i386/isa/comreg.h"
|
||||
#include "i386/isa/ic/ns16550.h"
|
||||
|
||||
#define FAKE_DCD(unit) ((unit) == comconsole)
|
||||
#define FAKE_DCD(unit) ((unit) == comconsole)
|
||||
#define LOTS_OF_EVENTS 64 /* helps separate urgent events from input */
|
||||
#define RB_I_HIGH_WATER (RBSZ - 2 * RS_IBUFSIZE)
|
||||
#define RB_I_LOW_WATER ((RBSZ - 2 * RS_IBUFSIZE) * 7 / 8)
|
||||
@ -67,23 +67,25 @@
|
||||
#define TTY_BI TTY_FE /* XXX */
|
||||
#define TTY_OE TTY_PE /* XXX */
|
||||
|
||||
#ifndef COM_BIDIR
|
||||
#define UNIT(x) (minor(x)) /* XXX */
|
||||
#ifdef COM_BIDIR
|
||||
#define CALLOUT(x) (minor(x) & COM_CALLOUT_MASK)
|
||||
#define COM_CALLOUT_MASK 0x80
|
||||
#define COM_MINOR_MAGIC_MASK 0x80
|
||||
#else /* COM_BIDIR */
|
||||
#define COM_UNITMASK 0x7f
|
||||
#define COM_CALLOUTMASK 0x80 /* for both minor and dev */
|
||||
#define UNIT(x) (minor(x) & COM_UNITMASK)
|
||||
#define CALLOUT(x) (minor(x) & COM_CALLOUTMASK)
|
||||
#define COM_MINOR_MAGIC_MASK 0
|
||||
#endif /* COM_BIDIR */
|
||||
|
||||
#define UNIT(x) (minor(x) & ~COM_MINOR_MAGIC_MASK)
|
||||
|
||||
#ifdef COM_MULTIPORT
|
||||
/* checks in flags for multiport and which is multiport "master chip"
|
||||
* for a given card
|
||||
*/
|
||||
#define COM_ISMULTIPORT(dev) ((dev)->id_flags & 0x01)
|
||||
#define COM_MPMASTER(dev) (((dev)->id_flags >> 8) & 0x0ff)
|
||||
#define COM_ISMULTIPORT(dev) ((dev)->id_flags & 0x01)
|
||||
#define COM_MPMASTER(dev) (((dev)->id_flags >> 8) & 0x0ff)
|
||||
#endif /* COM_MULTIPORT */
|
||||
#define COM_NOFIFO(dev) ((dev)->id_flags & 0x02)
|
||||
|
||||
#define COM_NOFIFO(dev) ((dev)->id_flags & 0x02)
|
||||
|
||||
#ifndef FIFO_TRIGGER
|
||||
/*
|
||||
@ -94,11 +96,18 @@
|
||||
* if more than one packet arrives at once. The low speeds used for
|
||||
* serial mice help avoid this, but not if (large) fifos are enabled.
|
||||
*/
|
||||
#define FIFO_TRIGGER FIFO_TRIGGER_14
|
||||
#define FIFO_TRIGGER FIFO_TRIGGER_14
|
||||
#endif
|
||||
|
||||
#define com_scr 7 /* scratch register for 16450-16550 (R/W) */
|
||||
|
||||
#ifndef setsofttty
|
||||
#define OLD_INTERRUPT_HANDLING /* XXX FreeBSD-1.1 and earlier */
|
||||
#define setsofttty() (ipending |= 1 << 4) /* XXX requires owning IRQ4 */
|
||||
extern u_int ipending; /* XXX */
|
||||
void softsio1 __P((void));
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Input buffer watermarks.
|
||||
* The external device is asked to stop sending when the buffer exactly reaches
|
||||
@ -194,6 +203,11 @@ struct com_s {
|
||||
|
||||
struct tty *tp; /* cross reference */
|
||||
|
||||
#ifdef TIOCTIMESTAMP
|
||||
bool_t do_timestamp;
|
||||
struct timeval timestamp;
|
||||
#endif
|
||||
|
||||
u_long bytes_in; /* statistics */
|
||||
u_long bytes_out;
|
||||
u_int delta_error_counts[CE_NTYPES];
|
||||
@ -206,46 +220,49 @@ struct com_s {
|
||||
#define CE_INPUT_OFFSET RS_IBUFSIZE
|
||||
u_char ibuf1[2 * RS_IBUFSIZE];
|
||||
u_char ibuf2[2 * RS_IBUFSIZE];
|
||||
int do_timestamp;
|
||||
struct timeval timestamp;
|
||||
};
|
||||
|
||||
/*
|
||||
* These functions in the com module ought to be declared (with a prototype)
|
||||
* in a com-driver system header. The void ones may need to be int to match
|
||||
* ancient devswitch declarations, but they don't actually return anything.
|
||||
* The public functions in the com module ought to be declared in a com-driver
|
||||
* system header.
|
||||
*/
|
||||
#define Dev_t int /* promoted dev_t */
|
||||
struct consdev;
|
||||
|
||||
/* Interrupt handling entry points. */
|
||||
void siointr __P((int unit));
|
||||
void siopoll __P((void));
|
||||
|
||||
/* Device switch entry points. */
|
||||
int sioopen __P((Dev_t dev, int oflags, int devtype,
|
||||
struct proc *p));
|
||||
int sioclose __P((Dev_t dev, int fflag, int devtype,
|
||||
struct proc *p));
|
||||
void siointr __P((int unit));
|
||||
int sioread __P((Dev_t dev, struct uio *uio, int ioflag));
|
||||
int siowrite __P((Dev_t dev, struct uio *uio, int ioflag));
|
||||
int sioioctl __P((Dev_t dev, int cmd, caddr_t data,
|
||||
int fflag, struct proc *p));
|
||||
void siostop __P((struct tty *tp, int rw));
|
||||
#define sioreset noreset
|
||||
int sioselect __P((Dev_t dev, int rw, struct proc *p));
|
||||
#define siommap nommap
|
||||
#define siostrategy nostrategy
|
||||
|
||||
/* Console device entry points. */
|
||||
int siocngetc __P((Dev_t dev));
|
||||
struct consdev;
|
||||
void siocninit __P((struct consdev *cp));
|
||||
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));
|
||||
int siowrite __P((Dev_t dev, struct uio *uio, int ioflag));
|
||||
void softsio1 __P((void));
|
||||
|
||||
static int sioattach __P((struct isa_device *dev));
|
||||
static void comflush __P((struct com_s *com));
|
||||
static void comhardclose __P((struct com_s *com));
|
||||
static void cominit __P((int unit, int rate));
|
||||
static void comintr1 __P((struct com_s *com));
|
||||
static void siointr1 __P((struct com_s *com));
|
||||
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 comstart __P((struct tty *tp));
|
||||
static void comwakeup __P((caddr_t chan, int ticks));
|
||||
static void comstart __P((struct tty *tp));
|
||||
static void comwakeup __P((caddr_t chan, int ticks));
|
||||
static int tiocm_xxx2mcr __P((int tiocm_xxx));
|
||||
|
||||
/* table and macro for fast conversion from a unit number to its com struct */
|
||||
@ -254,7 +271,9 @@ static struct com_s *p_com_addr[NSIO];
|
||||
|
||||
static struct com_s com_structs[NSIO];
|
||||
|
||||
static struct timeval intr_timestamp;
|
||||
#ifdef TIOCTIMESTAMP
|
||||
static struct timeval intr_timestamp;
|
||||
#endif
|
||||
|
||||
struct isa_driver siodriver = {
|
||||
sioprobe, sioattach, "sio"
|
||||
@ -265,13 +284,19 @@ static int comconsole = COMCONSOLE;
|
||||
#else
|
||||
static int comconsole = -1;
|
||||
#endif
|
||||
static bool_t comconsinit;
|
||||
static speed_t comdefaultrate = TTYDEF_SPEED;
|
||||
static u_int com_events; /* input chars + weighted output completions */
|
||||
static int commajor;
|
||||
#ifdef DONT_MALLOC_TTYS
|
||||
#define TB_OUT(tp) (&(tp)->t_out)
|
||||
#define TB_RAW(tp) (&(tp)->t_raw)
|
||||
struct tty sio_tty[NSIO];
|
||||
#else
|
||||
#define TB_OUT(tp) ((tp)->t_out)
|
||||
#define TB_RAW(tp) ((tp)->t_raw)
|
||||
struct tty *sio_tty[NSIO];
|
||||
#endif
|
||||
extern struct tty *constty;
|
||||
extern u_int ipending; /* XXX */
|
||||
extern int tk_nin; /* XXX */
|
||||
extern int tk_rawcc; /* XXX */
|
||||
|
||||
@ -370,7 +395,7 @@ sioprobe(dev)
|
||||
#endif
|
||||
|| (inb(iobase + com_iir) & IIR_IMASK) != IIR_TXRDY
|
||||
|| isa_irq_pending(dev)
|
||||
|| !(inb(iobase + com_iir) & IIR_NOPEND))
|
||||
|| (inb(iobase + com_iir) & IIR_IMASK) != IIR_NOPEND)
|
||||
result = 0;
|
||||
|
||||
/*
|
||||
@ -385,7 +410,7 @@ sioprobe(dev)
|
||||
outb(iobase + com_mcr, MCR_IENABLE); /* dummy to avoid bus echo */
|
||||
if ( inb(iobase + com_ier) != 0
|
||||
|| isa_irq_pending(dev)
|
||||
|| !(inb(iobase + com_iir) & IIR_NOPEND))
|
||||
|| (inb(iobase + com_iir) & IIR_IMASK) != IIR_NOPEND)
|
||||
result = 0;
|
||||
if (result == 0)
|
||||
outb(iobase + com_mcr, 0);
|
||||
@ -406,8 +431,6 @@ sioattach(isdp)
|
||||
|
||||
iobase = isdp->id_iobase;
|
||||
unit = isdp->id_unit;
|
||||
if (unit == comconsole)
|
||||
DELAY(1000); /* XXX */
|
||||
s = spltty();
|
||||
|
||||
/*
|
||||
@ -422,7 +445,7 @@ sioattach(isdp)
|
||||
* device from sending before we are ready.
|
||||
*/
|
||||
|
||||
com = &com_structs[unit];
|
||||
com = &com_structs[unit]; /* XXX malloc it */
|
||||
com->cfcr_image = CFCR_8BITS;
|
||||
com->mcr_image = MCR_IENABLE;
|
||||
com->dtr_wait = 3 * hz;
|
||||
@ -436,7 +459,9 @@ sioattach(isdp)
|
||||
com->modem_ctl_port = iobase + com_mcr;
|
||||
com->line_status_port = iobase + com_lsr;
|
||||
com->modem_status_port = iobase + com_msr;
|
||||
com->tp = sio_tty[unit];
|
||||
#ifdef DONT_MALLOC_TTYS
|
||||
com->tp = &sio_tty[unit];
|
||||
#endif
|
||||
|
||||
/* attempt to determine UART type */
|
||||
printf("sio%d: type", unit);
|
||||
@ -473,9 +498,9 @@ sioattach(isdp)
|
||||
break;
|
||||
case FIFO_TRIGGER_14:
|
||||
printf(" 16550A");
|
||||
if (COM_NOFIFO(isdp)) {
|
||||
printf(" fifo software disabled");
|
||||
} else {
|
||||
if (COM_NOFIFO(isdp))
|
||||
printf(" fifo disabled");
|
||||
else {
|
||||
com->hasfifo = TRUE;
|
||||
com->tx_fifo_size = 16;
|
||||
}
|
||||
@ -510,7 +535,22 @@ determined_type: ;
|
||||
if (comconsole == unit)
|
||||
kgdb_dev = -1; /* can't debug over console port */
|
||||
else {
|
||||
cominit(unit, kgdb_rate);
|
||||
int divisor;
|
||||
|
||||
/*
|
||||
* XXX now unfinished and broken. Need to do
|
||||
* something more like a full open(). There's no
|
||||
* suitable interrupt handler so don't enable device
|
||||
* interrupts. Watch out for null tp's.
|
||||
*/
|
||||
outb(iobase + com_cfcr, CFCR_DLAB);
|
||||
divisor = ttspeedtab(kgdb_rate, comspeedtab);
|
||||
outb(iobase + com_dlbl, divisor & 0xFF);
|
||||
outb(iobase + com_dlbh, (u_int) divisor >> 8);
|
||||
outb(iobase + com_cfcr, CFCR_8BITS);
|
||||
outb(com->modem_status_port,
|
||||
com->mcr_image |= MCR_DTR | MCR_RTS);
|
||||
|
||||
if (kgdb_debug_init) {
|
||||
/*
|
||||
* Print prefix of device name,
|
||||
@ -524,12 +564,6 @@ determined_type: ;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Need to reset baud rate, etc. of next print so reset comconsinit.
|
||||
*/
|
||||
if (unit == comconsole)
|
||||
comconsinit = FALSE;
|
||||
|
||||
com_addr(unit) = com;
|
||||
splx(s);
|
||||
if (!comwakeup_started) {
|
||||
@ -550,9 +584,9 @@ sioopen(dev, flag, mode, p)
|
||||
#ifdef COM_BIDIR
|
||||
bool_t callout;
|
||||
#endif /* COM_BIDIR */
|
||||
bool_t got_status = FALSE;
|
||||
struct com_s *com;
|
||||
int error = 0;
|
||||
bool_t got_status = FALSE;
|
||||
Port_t iobase;
|
||||
int s;
|
||||
struct tty *tp;
|
||||
@ -568,9 +602,12 @@ sioopen(dev, flag, mode, p)
|
||||
return (ENXIO);
|
||||
#endif /* COM_BIDIR */
|
||||
|
||||
|
||||
#ifdef DONT_MALLOC_TTYS
|
||||
tp = com->tp;
|
||||
#else
|
||||
sio_tty[unit] = ttymalloc(sio_tty[unit]);
|
||||
tp = com->tp = sio_tty[unit];
|
||||
#endif
|
||||
s = spltty();
|
||||
|
||||
#ifdef COM_BIDIR
|
||||
@ -611,12 +648,12 @@ sioopen(dev, flag, mode, p)
|
||||
}
|
||||
}
|
||||
disable_intr();
|
||||
com->last_modem_status =
|
||||
com->prev_modem_status = inb(com->modem_status_port);
|
||||
com->prev_modem_status =
|
||||
com->last_modem_status = inb(com->modem_status_port);
|
||||
enable_intr();
|
||||
got_status = TRUE;
|
||||
if (com->prev_modem_status & MSR_DCD
|
||||
|| FAKE_DCD(unit)) {
|
||||
|| FAKE_DCD(unit)) {
|
||||
/* there's a carrier on the line; we win */
|
||||
com->active_in = TRUE;
|
||||
} else {
|
||||
@ -665,7 +702,7 @@ sioopen(dev, flag, mode, p)
|
||||
ttychars(tp);
|
||||
if (tp->t_ispeed == 0) {
|
||||
/*
|
||||
* We no longer use the flags from <sys/ttydefaults.h>
|
||||
* We don't use all the flags from <sys/ttydefaults.h>
|
||||
* since those are only relevant for logins. It's
|
||||
* important to have echo off initially so that the
|
||||
* line doesn't start blathering before the echo flag
|
||||
@ -673,17 +710,19 @@ sioopen(dev, flag, mode, p)
|
||||
*/
|
||||
tp->t_iflag = 0;
|
||||
tp->t_oflag = 0;
|
||||
#ifdef COMCONSOLE
|
||||
if (unit == comconsole)
|
||||
tp->t_oflag = TTYDEF_OFLAG;
|
||||
#endif
|
||||
tp->t_cflag = CREAD | CS8;
|
||||
#ifdef COM_BIDIR
|
||||
if (com->bidir && !callout)
|
||||
tp->t_cflag |= HUPCL;
|
||||
tp->t_cflag |= HUPCL;
|
||||
#endif
|
||||
tp->t_lflag = 0;
|
||||
tp->t_ispeed = tp->t_ospeed = comdefaultrate;
|
||||
if (unit == comconsole) {
|
||||
tp->t_iflag = TTYDEF_IFLAG;
|
||||
tp->t_oflag = TTYDEF_OFLAG;
|
||||
tp->t_cflag = TTYDEF_CFLAG;
|
||||
tp->t_lflag = TTYDEF_LFLAG;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -715,8 +754,8 @@ sioopen(dev, flag, mode, p)
|
||||
(void) inb(com->line_status_port);
|
||||
(void) inb(com->data_port);
|
||||
if (!got_status)
|
||||
com->last_modem_status =
|
||||
com->prev_modem_status = inb(com->modem_status_port);
|
||||
com->prev_modem_status =
|
||||
com->last_modem_status = inb(com->modem_status_port);
|
||||
outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS
|
||||
| IER_EMSC);
|
||||
enable_intr();
|
||||
@ -736,7 +775,7 @@ sioopen(dev, flag, mode, p)
|
||||
#endif /* COM_BIDIR */
|
||||
&& !(tp->t_state & TS_CARR_ON)) {
|
||||
tp->t_state |= TS_WOPEN;
|
||||
error = ttysleep(tp, (caddr_t)tp->t_raw, TTIPRI | PCATCH,
|
||||
error = ttysleep(tp, (caddr_t)TB_RAW(tp), TTIPRI | PCATCH,
|
||||
ttopen, 0);
|
||||
if (error != 0)
|
||||
break;
|
||||
@ -775,14 +814,14 @@ sioclose(dev, flag, mode, p)
|
||||
struct proc *p;
|
||||
{
|
||||
struct com_s *com;
|
||||
int s;
|
||||
struct tty *tp;
|
||||
int s;
|
||||
|
||||
com = com_addr(UNIT(dev));
|
||||
tp = com->tp;
|
||||
s = spltty();
|
||||
(*linesw[tp->t_line].l_close)(tp, flag);
|
||||
siostop(tp, FREAD|FWRITE);
|
||||
siostop(tp, FREAD | FWRITE);
|
||||
comhardclose(com);
|
||||
ttyclose(tp);
|
||||
splx(s);
|
||||
@ -798,11 +837,13 @@ comhardclose(com)
|
||||
struct tty *tp;
|
||||
int unit;
|
||||
|
||||
s = spltty();
|
||||
iobase = com->iobase;
|
||||
com->do_timestamp = 0;
|
||||
outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
|
||||
unit = com - &com_structs[0];
|
||||
iobase = com->iobase;
|
||||
s = spltty();
|
||||
#ifdef TIOCTIMESTAMP
|
||||
com->do_timestamp = 0;
|
||||
#endif
|
||||
outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
|
||||
#ifdef KGDB
|
||||
/* do not disable interrupts or hang up if debugging */
|
||||
if (kgdb_dev != makedev(commajor, unit))
|
||||
@ -812,8 +853,19 @@ comhardclose(com)
|
||||
tp = com->tp;
|
||||
if (tp->t_cflag & HUPCL || tp->t_state & TS_WOPEN
|
||||
#ifdef COM_BIDIR
|
||||
/*
|
||||
* XXX we will miss any carrier drop between here and the
|
||||
* next open. Perhaps we should watch DCD even when the
|
||||
* port is closed; it is not sufficient to check it at
|
||||
* the next open because it might go up and down while
|
||||
* we're not watching. And we shouldn't look at DCD if
|
||||
* CLOCAL is set (here or for the dialin device ...).
|
||||
* When the termios state is reinitialized for initial
|
||||
* opens, the correct CLOCAL bit will be
|
||||
* ((the bit now) & (the initial bit)).
|
||||
*/
|
||||
|| com->active_in
|
||||
&& !(com->prev_modem_status & MSR_DCD) && !FAKE_DCD(unit)
|
||||
&& !(com->prev_modem_status & MSR_DCD) && !FAKE_DCD(unit)
|
||||
#endif
|
||||
|| !(tp->t_state & TS_ISOPEN)) {
|
||||
commctl(com, MCR_RTS, DMSET);
|
||||
@ -870,24 +922,23 @@ siowrite(dev, uio, flag)
|
||||
return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
|
||||
}
|
||||
|
||||
#ifdef TIOCTIMESTAMP
|
||||
/* Interrupt routine for timekeeping purposes */
|
||||
void
|
||||
siointrts(int unit)
|
||||
siointrts(unit)
|
||||
int unit;
|
||||
{
|
||||
microtime(&intr_timestamp);
|
||||
siointr(unit);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
siointr(unit)
|
||||
int unit;
|
||||
{
|
||||
struct com_s *com;
|
||||
|
||||
#ifndef COM_MULTIPORT
|
||||
com = com_addr(unit);
|
||||
if (com != NULL)
|
||||
comintr1(com);
|
||||
siointr1(com_addr(unit));
|
||||
#else /* COM_MULTIPORT */
|
||||
bool_t possibly_more_intrs;
|
||||
|
||||
@ -903,31 +954,30 @@ siointr(unit)
|
||||
for (unit = 0; unit < NSIO; ++unit) {
|
||||
com = com_addr(unit);
|
||||
if (com != NULL
|
||||
&& !(inb(com->int_id_port) & IIR_NOPEND)) {
|
||||
/*
|
||||
* XXX call comintr1() instead of here from
|
||||
* comwakeup(). The interrupt edge problem
|
||||
* only exists for real interrupts.
|
||||
*/
|
||||
comintr1(com);
|
||||
&& (inb(com->int_id_port) & IIR_IMASK)
|
||||
!= IIR_NOPEND) {
|
||||
siointr1(com);
|
||||
possibly_more_intrs = TRUE;
|
||||
}
|
||||
}
|
||||
} while (possibly_more_intrs);
|
||||
#endif /* COM_MULTIPORT */
|
||||
#endif /* COM_MULTIPORT */
|
||||
}
|
||||
|
||||
static void
|
||||
comintr1(com)
|
||||
siointr1(com)
|
||||
struct com_s *com;
|
||||
{
|
||||
u_char line_status;
|
||||
u_char modem_status;
|
||||
u_char *ioptr;
|
||||
u_char recv_data;
|
||||
u_char line_status;
|
||||
u_char modem_status;
|
||||
u_char *ioptr;
|
||||
u_char recv_data;
|
||||
|
||||
if(com->do_timestamp)
|
||||
#ifdef TIOCTIMESTAMP
|
||||
if (com->do_timestamp)
|
||||
/* XXX a little bloat here... */
|
||||
com->timestamp = intr_timestamp;
|
||||
#endif
|
||||
while (TRUE) {
|
||||
line_status = inb(com->line_status_port);
|
||||
|
||||
@ -939,6 +989,10 @@ comintr1(com)
|
||||
else
|
||||
recv_data = inb(com->data_port);
|
||||
++com->bytes_in;
|
||||
/* XXX reduce SLIP input latency */
|
||||
#define FRAME_END 0xc0
|
||||
if (recv_data == FRAME_END)
|
||||
setsofttty();
|
||||
#ifdef KGDB
|
||||
/* trap into kgdb? (XXX - needs testing and optim) */
|
||||
if (recv_data == FRAME_END
|
||||
@ -1017,7 +1071,7 @@ if (com->iptr - com->ibuf == 8)
|
||||
while (--ocount != 0);
|
||||
} else {
|
||||
outb(com->data_port, *ioptr++);
|
||||
++com->bytes_out;
|
||||
++com->bytes_out;
|
||||
}
|
||||
com->optr = ioptr;
|
||||
if (ioptr >= com->obufend) {
|
||||
@ -1030,7 +1084,7 @@ if (com->iptr - com->ibuf == 8)
|
||||
|
||||
/* finished? */
|
||||
#ifndef COM_MULTIPORT
|
||||
if (inb(com->int_id_port) & IIR_NOPEND)
|
||||
if ((inb(com->int_id_port) & IIR_IMASK) == IIR_NOPEND)
|
||||
#endif /* COM_MULTIPORT */
|
||||
return;
|
||||
}
|
||||
@ -1038,9 +1092,9 @@ if (com->iptr - com->ibuf == 8)
|
||||
|
||||
static int
|
||||
tiocm_xxx2mcr(tiocm_xxx)
|
||||
int tiocm_xxx;
|
||||
int tiocm_xxx;
|
||||
{
|
||||
int mcr;
|
||||
int mcr;
|
||||
|
||||
mcr = 0;
|
||||
if (tiocm_xxx & TIOCM_DTR)
|
||||
@ -1175,16 +1229,17 @@ sioioctl(dev, cmd, data, flag, p)
|
||||
splx(s);
|
||||
return(ENOTTY);
|
||||
}
|
||||
|
||||
com->dtr_wait = *(int *)data;
|
||||
break;
|
||||
case TIOCMGDTRWAIT:
|
||||
*(int *)data = com->dtr_wait;
|
||||
break;
|
||||
#ifdef TIOCTIMESTAMP
|
||||
case TIOCTIMESTAMP:
|
||||
com->do_timestamp = 1;
|
||||
com->do_timestamp = TRUE;
|
||||
*(struct timeval *)data = com->timestamp;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
splx(s);
|
||||
return (ENOTTY);
|
||||
@ -1205,7 +1260,7 @@ comflush(com)
|
||||
com_events -= LOTS_OF_EVENTS;
|
||||
com->state &= ~(CS_ODONE | CS_BUSY);
|
||||
enable_intr();
|
||||
rbp = com->tp->t_out;
|
||||
rbp = TB_OUT(com->tp);
|
||||
rbp->rb_hd += com->ocount;
|
||||
rbp->rb_hd = RB_ROLLOVER(rbp, rbp->rb_hd);
|
||||
com->ocount = 0;
|
||||
@ -1215,12 +1270,16 @@ comflush(com)
|
||||
void
|
||||
siopoll()
|
||||
{
|
||||
#ifdef OLD_INTERRUPT_HANDLING
|
||||
static bool_t awake = FALSE;
|
||||
int s;
|
||||
#endif
|
||||
int unit;
|
||||
|
||||
if (com_events == 0)
|
||||
return;
|
||||
|
||||
#ifdef OLD_INTERRUPT_HANDLING
|
||||
disable_intr();
|
||||
if (awake) {
|
||||
enable_intr();
|
||||
@ -1229,10 +1288,12 @@ siopoll()
|
||||
awake = TRUE;
|
||||
enable_intr();
|
||||
s = spltty();
|
||||
#endif
|
||||
|
||||
repeat:
|
||||
for (unit = 0; unit < NSIO; ++unit) {
|
||||
u_char *buf;
|
||||
struct com_s *com;
|
||||
u_char *buf;
|
||||
struct com_s *com;
|
||||
u_char *ibuf;
|
||||
int incc;
|
||||
struct tty *tp;
|
||||
@ -1241,6 +1302,10 @@ siopoll()
|
||||
if (com == NULL)
|
||||
continue;
|
||||
tp = com->tp;
|
||||
#ifdef DONT_MALLOC_TTYS
|
||||
if (tp == NULL)
|
||||
continue;
|
||||
#endif
|
||||
|
||||
/* switch the role of the low-level input buffers */
|
||||
if (com->iptr == (ibuf = com->ibuf)) {
|
||||
@ -1264,6 +1329,13 @@ siopoll()
|
||||
* of input, so enable RTS if it is now disabled and
|
||||
* there is room in the high-level buffer.
|
||||
*/
|
||||
/*
|
||||
* XXX this used not to look at CS_RTS_IFLOW. The
|
||||
* change is to allow full control of MCR_RTS via
|
||||
* ioctls after turning CS_RTS_IFLOW off. Check
|
||||
* for races. We shouldn't allow the ioctls while
|
||||
* CS_RTS_IFLOW is on.
|
||||
*/
|
||||
if ((com->state & CS_RTS_IFLOW)
|
||||
&& !(com->mcr_image & MCR_RTS)
|
||||
&& !(tp->t_state & TS_RTS_IFLOW))
|
||||
@ -1296,15 +1368,15 @@ siopoll()
|
||||
|
||||
/* XXX */
|
||||
if (TRUE) {
|
||||
u_int delta;
|
||||
int errnum;
|
||||
u_long total;
|
||||
u_int delta;
|
||||
int errnum;
|
||||
u_long total;
|
||||
|
||||
for (errnum = 0; errnum < CE_NTYPES; ++errnum) {
|
||||
disable_intr();
|
||||
disable_intr();
|
||||
delta = com->delta_error_counts[errnum];
|
||||
com->delta_error_counts[errnum] = 0;
|
||||
enable_intr();
|
||||
enable_intr();
|
||||
if (delta != 0) {
|
||||
total =
|
||||
com->error_counts[errnum] += delta;
|
||||
@ -1326,7 +1398,7 @@ siopoll()
|
||||
if (incc <= 0 || !(tp->t_state & TS_ISOPEN))
|
||||
continue;
|
||||
if (com->state & CS_RTS_IFLOW
|
||||
&& RB_LEN(tp->t_raw) + incc >= RB_I_HIGH_WATER
|
||||
&& RB_LEN(TB_RAW(tp)) + incc >= RB_I_HIGH_WATER
|
||||
&& !(tp->t_state & TS_RTS_IFLOW)
|
||||
/*
|
||||
* XXX - need RTS flow control for all line disciplines.
|
||||
@ -1353,7 +1425,7 @@ siopoll()
|
||||
tk_rawcc += incc;
|
||||
tp->t_rawcc += incc;
|
||||
com->delta_error_counts[CE_TTY_BUF_OVERFLOW]
|
||||
+= incc - rb_write(tp->t_raw, (char *) buf,
|
||||
+= incc - rb_write(TB_RAW(tp), (char *) buf,
|
||||
incc);
|
||||
ttwakeup(tp);
|
||||
if (tp->t_state & TS_TTSTOP
|
||||
@ -1389,8 +1461,11 @@ siopoll()
|
||||
}
|
||||
if (com_events >= LOTS_OF_EVENTS)
|
||||
goto repeat;
|
||||
|
||||
#ifdef OLD_INTERRUPT_HANDLING
|
||||
splx(s);
|
||||
awake = FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
@ -1451,7 +1526,7 @@ comparam(tp, t)
|
||||
* while the UART is doing output (they refuse to transmit anything
|
||||
* more until given a hard reset). Fix this by stopping filling
|
||||
* the device buffers and waiting for them to drain. Reading the
|
||||
* line status port outside of siointr() might lose some receiver
|
||||
* line status port outside of siointr1() might lose some receiver
|
||||
* error bits, but that is acceptable here.
|
||||
*/
|
||||
disable_intr();
|
||||
@ -1460,7 +1535,7 @@ comparam(tp, t)
|
||||
enable_intr();
|
||||
while ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
|
||||
!= (LSR_TSRE | LSR_TXRDY)) {
|
||||
error = ttysleep(tp, (caddr_t)tp->t_raw, TTIPRI | PCATCH,
|
||||
error = ttysleep(tp, (caddr_t)TB_RAW(tp), TTIPRI | PCATCH,
|
||||
"sioparam", 1);
|
||||
if (error != 0 && error != EAGAIN) {
|
||||
if (!(tp->t_state & TS_TTSTOP)) {
|
||||
@ -1482,7 +1557,7 @@ comparam(tp, t)
|
||||
* sufficient, for similar reasons.
|
||||
*/
|
||||
if ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
|
||||
!= (LSR_TSRE | LSR_TXRDY))
|
||||
!= (LSR_TSRE | LSR_TXRDY))
|
||||
goto retry;
|
||||
|
||||
if (divisor != 0) {
|
||||
@ -1512,7 +1587,7 @@ comparam(tp, t)
|
||||
}
|
||||
|
||||
/*
|
||||
* Recover from fiddling with CS_TTGO. We used to call siointr()
|
||||
* Recover from fiddling with CS_TTGO. We used to call siointr1()
|
||||
* unconditionally, but that defeated the careful discarding of
|
||||
* stale input in sioopen().
|
||||
*
|
||||
@ -1520,7 +1595,7 @@ comparam(tp, t)
|
||||
* case.
|
||||
*/
|
||||
if (com->state >= (CS_BUSY | CS_TTGO))
|
||||
comintr1(com);
|
||||
siointr1(com);
|
||||
|
||||
enable_intr();
|
||||
splx(s);
|
||||
@ -1547,16 +1622,21 @@ comstart(tp)
|
||||
if (com->mcr_image & MCR_RTS && com->state & CS_RTS_IFLOW)
|
||||
outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS);
|
||||
} else {
|
||||
/*
|
||||
* XXX don't raise MCR_RTS if CTS_RTS_IFLOW is off. Set it
|
||||
* appropriately in comparam() if RTS-flow is being changed.
|
||||
* Check for races.
|
||||
*/
|
||||
if (!(com->mcr_image & MCR_RTS) && com->iptr < com->ihighwater)
|
||||
outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
|
||||
}
|
||||
enable_intr();
|
||||
if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))
|
||||
goto out;
|
||||
if (RB_LEN(tp->t_out) <= tp->t_lowat) {
|
||||
if (RB_LEN(TB_OUT(tp)) <= tp->t_lowat) {
|
||||
if (tp->t_state & TS_ASLEEP) {
|
||||
tp->t_state &= ~TS_ASLEEP;
|
||||
wakeup((caddr_t)tp->t_out);
|
||||
wakeup((caddr_t)TB_OUT(tp));
|
||||
}
|
||||
if (tp->t_wsel) {
|
||||
selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
|
||||
@ -1566,16 +1646,16 @@ comstart(tp)
|
||||
}
|
||||
if (com->ocount != 0) {
|
||||
disable_intr();
|
||||
comintr1(com);
|
||||
siointr1(com);
|
||||
enable_intr();
|
||||
} else if (RB_LEN(tp->t_out) != 0) {
|
||||
} else if (RB_LEN(TB_OUT(tp)) != 0) {
|
||||
tp->t_state |= TS_BUSY;
|
||||
com->ocount = RB_CONTIGGET(tp->t_out);
|
||||
com->ocount = RB_CONTIGGET(TB_OUT(tp));
|
||||
disable_intr();
|
||||
com->obufend = (com->optr = (u_char *) tp->t_out->rb_hd)
|
||||
com->obufend = (com->optr = (u_char *)TB_OUT(tp)->rb_hd)
|
||||
+ com->ocount;
|
||||
com->state |= CS_BUSY;
|
||||
comintr1(com); /* fake interrupt to start output */
|
||||
siointr1(com); /* fake interrupt to start output */
|
||||
enable_intr();
|
||||
}
|
||||
out:
|
||||
@ -1610,11 +1690,7 @@ sioselect(dev, rw, p)
|
||||
int rw;
|
||||
struct proc *p;
|
||||
{
|
||||
#ifdef COM_BIDIR
|
||||
return ttselect(dev & ~COM_CALLOUTMASK, rw, p);
|
||||
#else
|
||||
return ttselect(dev, rw, p);
|
||||
#endif
|
||||
return (ttselect(dev & ~COM_MINOR_MAGIC_MASK, rw, p));
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1641,15 +1717,22 @@ commctl(com, bits, how)
|
||||
|
||||
static void
|
||||
comwakeup(chan, ticks)
|
||||
caddr_t chan;
|
||||
int ticks;
|
||||
caddr_t chan;
|
||||
int ticks;
|
||||
{
|
||||
int unit;
|
||||
int unit;
|
||||
|
||||
timeout(comwakeup, (caddr_t) NULL, hz / 100);
|
||||
if (com_events != 0)
|
||||
/* schedule siopoll() to run when the cpl allows */
|
||||
setsofttty();
|
||||
|
||||
if (com_events != 0) {
|
||||
#ifndef OLD_INTERRUPT_HANDLING
|
||||
int s = splsofttty();
|
||||
#endif
|
||||
siopoll();
|
||||
#ifndef OLD_INTERRUPT_HANDLING
|
||||
splx(s);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* recover from lost output interrupts */
|
||||
for (unit = 0; unit < NSIO; ++unit) {
|
||||
@ -1658,27 +1741,101 @@ comwakeup(chan, ticks)
|
||||
com = com_addr(unit);
|
||||
if (com != NULL && com->state >= (CS_BUSY | CS_TTGO)) {
|
||||
disable_intr();
|
||||
comintr1(com);
|
||||
siointr1(com);
|
||||
enable_intr();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef OLD_INTERRUPT_HANDLING
|
||||
void
|
||||
softsio1()
|
||||
{
|
||||
siopoll();
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Following are all routines needed for SIO to act as console
|
||||
* XXX - not tested in this version
|
||||
* XXX - i386/cons.c only knows about the com driver (NCOM and not NSIO)
|
||||
* XXX - check that the corresponding serial interrupts are never enabled
|
||||
*/
|
||||
#include "i386/i386/cons.h"
|
||||
|
||||
struct siocnstate {
|
||||
u_char dlbl;
|
||||
u_char dlbh;
|
||||
u_char ier;
|
||||
u_char cfcr;
|
||||
u_char mcr;
|
||||
};
|
||||
|
||||
static Port_t siocniobase;
|
||||
|
||||
static void
|
||||
siocntxwait()
|
||||
{
|
||||
int timo;
|
||||
|
||||
/*
|
||||
* Wait for any pending transmission to finish. Required to avoid
|
||||
* the UART lockup bug when the speed is changed, and for normal
|
||||
* transmits.
|
||||
*/
|
||||
timo = 100000;
|
||||
while ((inb(siocniobase + com_lsr) & (LSR_TSRE | LSR_TXRDY))
|
||||
!= (LSR_TSRE | LSR_TXRDY) && --timo != 0)
|
||||
;
|
||||
}
|
||||
|
||||
static void
|
||||
siocnopen(sp)
|
||||
struct siocnstate *sp;
|
||||
{
|
||||
int divisor;
|
||||
Port_t iobase;
|
||||
|
||||
/*
|
||||
* Save all the device control registers except the fifo register
|
||||
* and set our default ones (cs8 -parenb speed=comdefaultrate).
|
||||
* We can't save the fifo register since it is read-only.
|
||||
*/
|
||||
iobase = siocniobase;
|
||||
sp->ier = inb(iobase + com_ier);
|
||||
outb(iobase + com_ier, 0); /* spltty() doesn't stop siointr() */
|
||||
siocntxwait();
|
||||
sp->cfcr = inb(iobase + com_cfcr);
|
||||
outb(iobase + com_cfcr, CFCR_DLAB);
|
||||
sp->dlbl = inb(iobase + com_dlbl);
|
||||
sp->dlbh = inb(iobase + com_dlbh);
|
||||
divisor = ttspeedtab(comdefaultrate, comspeedtab);
|
||||
outb(iobase + com_dlbl, divisor & 0xFF);
|
||||
outb(iobase + com_dlbh, (u_int) divisor >> 8);
|
||||
outb(iobase + com_cfcr, CFCR_8BITS);
|
||||
sp->mcr = inb(iobase + com_mcr);
|
||||
outb(iobase + com_mcr, MCR_DTR | MCR_RTS);
|
||||
}
|
||||
|
||||
static void
|
||||
siocnclose(sp)
|
||||
struct siocnstate *sp;
|
||||
{
|
||||
Port_t iobase;
|
||||
|
||||
/*
|
||||
* Restore the device control registers.
|
||||
*/
|
||||
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, sp->cfcr);
|
||||
/*
|
||||
* XXX damp osicllations of MCR_DTR or MCR_RTS by not restoring them.
|
||||
*/
|
||||
outb(iobase + com_mcr, sp->mcr | MCR_DTR | MCR_RTS);
|
||||
outb(iobase + com_ier, sp->ier);
|
||||
}
|
||||
|
||||
void
|
||||
siocnprobe(cp)
|
||||
struct consdev *cp;
|
||||
@ -1686,14 +1843,14 @@ siocnprobe(cp)
|
||||
int unit;
|
||||
|
||||
/* locate the major number */
|
||||
/* XXX - should be elsewhere since KGDB uses it */
|
||||
for (commajor = 0; commajor < nchrdev; commajor++)
|
||||
if (cdevsw[commajor].d_open == sioopen)
|
||||
break;
|
||||
|
||||
/* XXX: ick */
|
||||
unit = UNIT(CONUNIT);
|
||||
com_addr(unit) = &com_structs[unit];
|
||||
com_addr(unit)->iobase = CONADDR;
|
||||
siocniobase = CONADDR;
|
||||
|
||||
/* make sure hardware exists? XXX */
|
||||
|
||||
@ -1710,43 +1867,11 @@ void
|
||||
siocninit(cp)
|
||||
struct consdev *cp;
|
||||
{
|
||||
int unit;
|
||||
|
||||
unit = UNIT(cp->cn_dev);
|
||||
cominit(unit, comdefaultrate);
|
||||
comconsole = unit;
|
||||
comconsinit = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
cominit(unit, rate)
|
||||
int unit;
|
||||
int rate;
|
||||
{
|
||||
Port_t iobase;
|
||||
int s;
|
||||
|
||||
iobase = com_addr(unit)->iobase;
|
||||
s = splhigh();
|
||||
outb(iobase + com_cfcr, CFCR_DLAB);
|
||||
rate = ttspeedtab(comdefaultrate, comspeedtab);
|
||||
outb(iobase + com_dlbl, rate & 0xFF);
|
||||
outb(iobase + com_dlbh, rate >> 8);
|
||||
outb(iobase + com_cfcr, CFCR_8BITS);
|
||||
outb(iobase + com_fifo,
|
||||
FIFO_ENABLE | FIFO_TRIGGER | FIFO_RCV_RST | FIFO_XMT_RST);
|
||||
DELAY(100);
|
||||
(void) inb(iobase + com_lsr);
|
||||
(void) inb(iobase + com_data);
|
||||
(void) inb(iobase + com_msr);
|
||||
|
||||
/*
|
||||
* XXX - fishy to enable interrupts and then poll.
|
||||
* It shouldn't be necessary to ready the iir.
|
||||
* XXX can delete more comconsole stuff now that i/o routines are
|
||||
* fairly reentrant.
|
||||
*/
|
||||
outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC);
|
||||
(void) inb(iobase + com_iir);
|
||||
splx(s);
|
||||
comconsole = UNIT(cp->cn_dev);
|
||||
}
|
||||
|
||||
int
|
||||
@ -1756,13 +1881,15 @@ siocngetc(dev)
|
||||
int c;
|
||||
Port_t iobase;
|
||||
int s;
|
||||
struct siocnstate sp;
|
||||
|
||||
iobase = com_addr(UNIT(dev))->iobase;
|
||||
s = splhigh();
|
||||
iobase = siocniobase;
|
||||
s = spltty();
|
||||
siocnopen(&sp);
|
||||
while (!(inb(iobase + com_lsr) & LSR_RXRDY))
|
||||
;
|
||||
c = inb(iobase + com_data);
|
||||
(void) inb(iobase + com_iir);
|
||||
siocnclose(&sp);
|
||||
splx(s);
|
||||
return (c);
|
||||
}
|
||||
@ -1772,30 +1899,14 @@ siocnputc(dev, c)
|
||||
dev_t dev;
|
||||
int c;
|
||||
{
|
||||
Port_t iobase;
|
||||
int s;
|
||||
int timo;
|
||||
struct siocnstate sp;
|
||||
|
||||
iobase = com_addr(UNIT(dev))->iobase;
|
||||
s = splhigh();
|
||||
#ifdef KGDB
|
||||
if (dev != kgdb_dev)
|
||||
#endif
|
||||
if (!comconsinit) {
|
||||
cominit(UNIT(dev), comdefaultrate);
|
||||
comconsinit = TRUE;
|
||||
}
|
||||
/* wait for any pending transmission to finish */
|
||||
timo = 50000;
|
||||
while (!(inb(iobase + com_lsr) & LSR_TXRDY) && --timo)
|
||||
;
|
||||
outb(iobase + com_data, c);
|
||||
/* wait for this transmission to complete */
|
||||
timo = 1500000;
|
||||
while (!(inb(iobase + com_lsr) & LSR_TXRDY) && --timo)
|
||||
;
|
||||
/* clear any interrupts generated by this transmission */
|
||||
(void) inb(iobase + com_iir);
|
||||
s = spltty();
|
||||
siocnopen(&sp);
|
||||
siocntxwait();
|
||||
outb(siocniobase + com_data, c);
|
||||
siocnclose(&sp);
|
||||
splx(s);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user