xref: /csrg-svn/sys/i386/isa/com.c (revision 49697)
147752Swilliam /*-
249570Swilliam  * Copyright (c) 1991 The Regents of the University of California.
349570Swilliam  * All rights reserved.
447752Swilliam  *
547752Swilliam  * %sccs.include.redist.c%
647752Swilliam  *
7*49697Swilliam  *	@(#)com.c	7.4 (Berkeley) 05/12/91
847752Swilliam  */
947752Swilliam 
1049569Swilliam #include "com.h"
1149569Swilliam #if NCOM > 0
1247752Swilliam /*
1349570Swilliam  * COM driver, based on HP dca driver
1449570Swilliam  * uses National Semiconductor NS16450/NS16550AF UART
1547752Swilliam  */
1649570Swilliam #include "param.h"
1749570Swilliam #include "systm.h"
1849570Swilliam #include "ioctl.h"
1949570Swilliam #include "tty.h"
2049570Swilliam #include "proc.h"
2149570Swilliam #include "user.h"
2249570Swilliam #include "conf.h"
2349570Swilliam #include "file.h"
2449570Swilliam #include "uio.h"
2549570Swilliam #include "kernel.h"
2649570Swilliam #include "syslog.h"
2747752Swilliam 
2847752Swilliam #include "i386/isa/isa_device.h"
2947752Swilliam #include "i386/isa/comreg.h"
3049570Swilliam #include "i386/isa/ic/ns16550.h"
3147752Swilliam 
3247752Swilliam int 	comprobe(), comattach(), comintr(), comstart(), comparam();
3347752Swilliam 
3447752Swilliam struct	isa_driver comdriver = {
3547752Swilliam 	comprobe, comattach, "com"
3647752Swilliam };
3747752Swilliam 
3847752Swilliam int	comsoftCAR;
3947752Swilliam int	com_active;
4049570Swilliam int	com_hasfifo;
4149569Swilliam int	ncom = NCOM;
4249570Swilliam #ifdef COMCONSOLE
4349570Swilliam int	comconsole = COMCONSOLE;
4449570Swilliam #else
4547752Swilliam int	comconsole = -1;
4649570Swilliam #endif
4749570Swilliam int	comconsinit;
4847752Swilliam int	comdefaultrate = TTYDEF_SPEED;
4949570Swilliam int	commajor;
5049569Swilliam short com_addr[NCOM];
5149569Swilliam struct	tty com_tty[NCOM];
5247752Swilliam 
5347752Swilliam struct speedtab comspeedtab[] = {
5447752Swilliam 	0,	0,
5547752Swilliam 	50,	COMBRD(50),
5647752Swilliam 	75,	COMBRD(75),
5747752Swilliam 	110,	COMBRD(110),
5847752Swilliam 	134,	COMBRD(134),
5947752Swilliam 	150,	COMBRD(150),
6047752Swilliam 	200,	COMBRD(200),
6147752Swilliam 	300,	COMBRD(300),
6247752Swilliam 	600,	COMBRD(600),
6347752Swilliam 	1200,	COMBRD(1200),
6447752Swilliam 	1800,	COMBRD(1800),
6547752Swilliam 	2400,	COMBRD(2400),
6647752Swilliam 	4800,	COMBRD(4800),
6747752Swilliam 	9600,	COMBRD(9600),
6847752Swilliam 	19200,	COMBRD(19200),
6947752Swilliam 	38400,	COMBRD(38400),
7047752Swilliam 	57600,	COMBRD(57600),
7147752Swilliam 	-1,	-1
7247752Swilliam };
7347752Swilliam 
7447752Swilliam extern	struct tty *constty;
7547752Swilliam #ifdef KGDB
7649570Swilliam #include "machine/remote-sl.h"
7749570Swilliam 
7847752Swilliam extern int kgdb_dev;
7947752Swilliam extern int kgdb_rate;
8047752Swilliam extern int kgdb_debug_init;
8147752Swilliam #endif
8247752Swilliam 
8347752Swilliam #define	UNIT(x)		minor(x)
8447752Swilliam 
8547752Swilliam comprobe(dev)
8647752Swilliam struct isa_device *dev;
8747752Swilliam {
88*49697Swilliam 	/* force access to id reg */
89*49697Swilliam 	outb(dev->id_iobase+com_cfcr, 0);
90*49697Swilliam 	outb(dev->id_iobase+com_iir, 0);
91*49697Swilliam 	if ((inb(dev->id_iobase+com_iir) & 0x38) == 0)
9247752Swilliam 		return(1);
9349570Swilliam 	return(1);
9447752Swilliam 
9547752Swilliam }
9647752Swilliam 
9747752Swilliam 
9847752Swilliam int
9947752Swilliam comattach(isdp)
10047752Swilliam struct isa_device *isdp;
10147752Swilliam {
10247752Swilliam 	struct	tty	*tp;
10347752Swilliam 	u_char		unit;
10447752Swilliam 	int		port = isdp->id_iobase;
10547752Swilliam 
10649570Swilliam 	unit = isdp->id_unit;
10747752Swilliam 	if (unit == comconsole)
10847752Swilliam 		DELAY(100000);
10947752Swilliam 	com_addr[unit] = port;
11047752Swilliam 	com_active |= 1 << unit;
11149570Swilliam 	comsoftCAR |= 1 << unit;	/* XXX */
11249570Swilliam 
11349570Swilliam 	/* look for a NS 16550AF UART with FIFOs */
11449570Swilliam 	outb(port+com_fifo, FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14);
11549570Swilliam 	DELAY(100);
11649570Swilliam 	if ((inb(port+com_iir) & IIR_FIFO_MASK) == IIR_FIFO_MASK)
11749570Swilliam 		com_hasfifo |= 1 << unit;
11849570Swilliam 
11947752Swilliam 	outb(port+com_ier, 0);
12047752Swilliam 	outb(port+com_mcr, 0 | MCR_IENABLE);
12147752Swilliam #ifdef KGDB
122*49697Swilliam 	if (kgdb_dev == makedev(commajor, unit)) {
12347752Swilliam 		if (comconsole == unit)
12447752Swilliam 			kgdb_dev = -1;	/* can't debug over console port */
12547752Swilliam 		else {
12649570Swilliam 			(void) cominit(unit, kgdb_rate);
12747752Swilliam 			if (kgdb_debug_init) {
12849570Swilliam 				/*
12949570Swilliam 				 * Print prefix of device name,
13049570Swilliam 				 * let kgdb_connect print the rest.
13149570Swilliam 				 */
13249570Swilliam 				printf("com%d: ", unit);
13349570Swilliam 				kgdb_connect(1);
13447752Swilliam 			} else
13547752Swilliam 				printf("com%d: kgdb enabled\n", unit);
13647752Swilliam 		}
13747752Swilliam 	}
13847752Swilliam #endif
13947752Swilliam 	/*
14049570Swilliam 	 * Need to reset baud rate, etc. of next print so reset comconsinit.
14147752Swilliam 	 * Also make sure console is always "hardwired"
14247752Swilliam 	 */
14347752Swilliam 	if (unit == comconsole) {
14449570Swilliam 		comconsinit = 0;
14547752Swilliam 		comsoftCAR |= (1 << unit);
14647752Swilliam 	}
14747752Swilliam 	return (1);
14847752Swilliam }
14947752Swilliam 
15049569Swilliam /* ARGSUSED */
15149569Swilliam #ifdef __STDC__
15249569Swilliam comopen(dev_t dev, int flag, int mode, struct proc *p)
15349569Swilliam #else
15449569Swilliam comopen(dev, flag, mode, p)
15547752Swilliam 	dev_t dev;
15649569Swilliam 	int flag, mode;
15749569Swilliam 	struct proc *p;
15849569Swilliam #endif
15947752Swilliam {
16047752Swilliam 	register struct tty *tp;
16147752Swilliam 	register int unit;
16247752Swilliam 	int error = 0;
16347752Swilliam 
16447752Swilliam 	unit = UNIT(dev);
16549569Swilliam 	if (unit >= NCOM || (com_active & (1 << unit)) == 0)
16647752Swilliam 		return (ENXIO);
16747752Swilliam 	tp = &com_tty[unit];
16847752Swilliam 	tp->t_oproc = comstart;
16947752Swilliam 	tp->t_param = comparam;
17047752Swilliam 	tp->t_dev = dev;
17147752Swilliam 	if ((tp->t_state & TS_ISOPEN) == 0) {
17247752Swilliam 		tp->t_state |= TS_WOPEN;
17347752Swilliam 		ttychars(tp);
17449570Swilliam 		if (tp->t_ispeed == 0) {
17549570Swilliam 			tp->t_iflag = TTYDEF_IFLAG;
17649570Swilliam 			tp->t_oflag = TTYDEF_OFLAG;
17749570Swilliam 			tp->t_cflag = TTYDEF_CFLAG;
17849570Swilliam 			tp->t_lflag = TTYDEF_LFLAG;
17949570Swilliam 			tp->t_ispeed = tp->t_ospeed = comdefaultrate;
18049570Swilliam 		}
18147752Swilliam 		comparam(tp, &tp->t_termios);
18247752Swilliam 		ttsetwater(tp);
18349569Swilliam 	} else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
18447752Swilliam 		return (EBUSY);
18547752Swilliam 	(void) spltty();
18647752Swilliam 	(void) commctl(dev, MCR_DTR | MCR_RTS, DMSET);
18747752Swilliam 	if ((comsoftCAR & (1 << unit)) || (commctl(dev, 0, DMGET) & MSR_DCD))
18847752Swilliam 		tp->t_state |= TS_CARR_ON;
18947752Swilliam 	while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 &&
19047752Swilliam 	       (tp->t_state & TS_CARR_ON) == 0) {
19147752Swilliam 		tp->t_state |= TS_WOPEN;
19247752Swilliam 		if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
19347752Swilliam 		    ttopen, 0))
19447752Swilliam 			break;
19547752Swilliam 	}
19647752Swilliam 	(void) spl0();
19747752Swilliam 	if (error == 0)
19847752Swilliam 		error = (*linesw[tp->t_line].l_open)(dev, tp);
19947752Swilliam 	return (error);
20047752Swilliam }
20147752Swilliam 
20247752Swilliam /*ARGSUSED*/
20347752Swilliam comclose(dev, flag)
20447752Swilliam 	dev_t dev;
20547752Swilliam {
20647752Swilliam 	register struct tty *tp;
20747752Swilliam 	register com;
20847752Swilliam 	register int unit;
20947752Swilliam 
21047752Swilliam 	unit = UNIT(dev);
21147752Swilliam 	com = com_addr[unit];
21247752Swilliam 	tp = &com_tty[unit];
21347752Swilliam 	(*linesw[tp->t_line].l_close)(tp);
21447752Swilliam 	outb(com+com_cfcr, inb(com+com_cfcr) & ~CFCR_SBREAK);
21547752Swilliam #ifdef KGDB
21647752Swilliam 	/* do not disable interrupts if debugging */
21749570Swilliam 	if (kgdb_dev != makedev(commajor, unit))
21847752Swilliam #endif
21947752Swilliam 	outb(com+com_ier, 0);
22047752Swilliam 	if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN ||
22147752Swilliam 	    (tp->t_state&TS_ISOPEN) == 0)
22247752Swilliam 		(void) commctl(dev, 0, DMSET);
22347752Swilliam 	ttyclose(tp);
22447752Swilliam 	return(0);
22547752Swilliam }
22647752Swilliam 
22747752Swilliam comread(dev, uio, flag)
22847752Swilliam 	dev_t dev;
22947752Swilliam 	struct uio *uio;
23047752Swilliam {
23147752Swilliam 	register struct tty *tp = &com_tty[UNIT(dev)];
23247752Swilliam 
23347752Swilliam 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
23447752Swilliam }
23547752Swilliam 
23647752Swilliam comwrite(dev, uio, flag)
23747752Swilliam 	dev_t dev;
23847752Swilliam 	struct uio *uio;
23947752Swilliam {
24047752Swilliam 	int unit = UNIT(dev);
24147752Swilliam 	register struct tty *tp = &com_tty[unit];
24247752Swilliam 
24347752Swilliam 	/*
24447752Swilliam 	 * (XXX) We disallow virtual consoles if the physical console is
24547752Swilliam 	 * a serial port.  This is in case there is a display attached that
24647752Swilliam 	 * is not the console.  In that situation we don't need/want the X
24747752Swilliam 	 * server taking over the console.
24847752Swilliam 	 */
24947752Swilliam 	if (constty && unit == comconsole)
25047752Swilliam 		constty = NULL;
25147752Swilliam 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
25247752Swilliam }
25347752Swilliam 
25447752Swilliam comintr(unit)
25547752Swilliam 	register int unit;
25647752Swilliam {
25747752Swilliam 	register com;
25847752Swilliam 	register u_char code;
25947752Swilliam 	register struct tty *tp;
26047752Swilliam 
26147752Swilliam 	com = com_addr[unit];
26247752Swilliam 	while (1) {
26347752Swilliam 		code = inb(com+com_iir);
26449570Swilliam 		switch (code & IIR_IMASK) {
26547752Swilliam 		case IIR_NOPEND:
26647752Swilliam 			return (1);
26749570Swilliam 		case IIR_RXTOUT:
26847752Swilliam 		case IIR_RXRDY:
26947752Swilliam 			tp = &com_tty[unit];
27049570Swilliam /*
27149570Swilliam  * Process received bytes.  Inline for speed...
27249570Swilliam  */
27347752Swilliam #ifdef KGDB
27449570Swilliam #define	RCVBYTE() \
27549570Swilliam 			code = inb(com+com_data); \
27649570Swilliam 			if ((tp->t_state & TS_ISOPEN) == 0) { \
27749570Swilliam 				if (kgdb_dev == makedev(commajor, unit) && \
27849570Swilliam 				    code == FRAME_END) \
27949570Swilliam 					kgdb_connect(0); /* trap into kgdb */ \
28049570Swilliam 			} else \
28149570Swilliam 				(*linesw[tp->t_line].l_rint)(code, tp)
28249570Swilliam #else
28349570Swilliam #define	RCVBYTE() \
28449570Swilliam 			code = inb(com+com_data); \
28549570Swilliam 			if (tp->t_state & TS_ISOPEN) \
28649570Swilliam 				(*linesw[tp->t_line].l_rint)(code, tp)
28749570Swilliam #endif
28849570Swilliam 
28949570Swilliam 			RCVBYTE();
29049570Swilliam 
29149570Swilliam 			if (com_hasfifo & (1 << unit))
29249570Swilliam 				while ((code = inb(com+com_lsr)) & LSR_RCV_MASK) {
29349570Swilliam 					if (code == LSR_RXRDY) {
29449570Swilliam 						RCVBYTE();
29549570Swilliam 					} else
29649570Swilliam 						comeint(unit, code, com);
29747752Swilliam 				}
29847752Swilliam 			break;
29947752Swilliam 		case IIR_TXRDY:
30047752Swilliam 			tp = &com_tty[unit];
30147752Swilliam 			tp->t_state &=~ (TS_BUSY|TS_FLUSH);
30247752Swilliam 			if (tp->t_line)
30347752Swilliam 				(*linesw[tp->t_line].l_start)(tp);
30447752Swilliam 			else
30547752Swilliam 				comstart(tp);
30647752Swilliam 			break;
30747752Swilliam 		case IIR_RLS:
30849570Swilliam 			comeint(unit, inb(com+com_lsr), com);
30947752Swilliam 			break;
31047752Swilliam 		default:
31147752Swilliam 			if (code & IIR_NOPEND)
31247752Swilliam 				return (1);
31347752Swilliam 			log(LOG_WARNING, "com%d: weird interrupt: 0x%x\n",
31447752Swilliam 			    unit, code);
31547752Swilliam 			/* fall through */
31647752Swilliam 		case IIR_MLSC:
31747752Swilliam 			commint(unit, com);
31847752Swilliam 			break;
31947752Swilliam 		}
32047752Swilliam 	}
32147752Swilliam }
32247752Swilliam 
32349570Swilliam comeint(unit, stat, com)
32449570Swilliam 	register int unit, stat;
32547752Swilliam 	register com;
32647752Swilliam {
32747752Swilliam 	register struct tty *tp;
32849570Swilliam 	register int c;
32947752Swilliam 
33047752Swilliam 	tp = &com_tty[unit];
33147752Swilliam 	c = inb(com+com_data);
33247752Swilliam 	if ((tp->t_state & TS_ISOPEN) == 0) {
33347752Swilliam #ifdef KGDB
33447752Swilliam 		/* we don't care about parity errors */
33547752Swilliam 		if (((stat & (LSR_BI|LSR_FE|LSR_PE)) == LSR_PE) &&
33649570Swilliam 		    kgdb_dev == makedev(commajor, unit) && c == FRAME_END)
33749570Swilliam 			kgdb_connect(0); /* trap into kgdb */
33847752Swilliam #endif
33947752Swilliam 		return;
34047752Swilliam 	}
34147752Swilliam 	if (stat & (LSR_BI | LSR_FE))
34247752Swilliam 		c |= TTY_FE;
34347752Swilliam 	else if (stat & LSR_PE)
34447752Swilliam 		c |= TTY_PE;
34547752Swilliam 	else if (stat & LSR_OE)
34647752Swilliam 		log(LOG_WARNING, "com%d: silo overflow\n", unit);
34747752Swilliam 	(*linesw[tp->t_line].l_rint)(c, tp);
34847752Swilliam }
34947752Swilliam 
35047752Swilliam commint(unit, com)
35147752Swilliam 	register int unit;
35247752Swilliam 	register com;
35347752Swilliam {
35447752Swilliam 	register struct tty *tp;
35547752Swilliam 	register int stat;
35647752Swilliam 
35747752Swilliam 	tp = &com_tty[unit];
35847752Swilliam 	stat = inb(com+com_msr);
35947752Swilliam 	if ((stat & MSR_DDCD) && (comsoftCAR & (1 << unit)) == 0) {
36047752Swilliam 		if (stat & MSR_DCD)
36147752Swilliam 			(void)(*linesw[tp->t_line].l_modem)(tp, 1);
36247752Swilliam 		else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0)
36347752Swilliam 			outb(com+com_mcr,
36447752Swilliam 				inb(com+com_mcr) & ~(MCR_DTR | MCR_RTS) | MCR_IENABLE);
36547752Swilliam 	} else if ((stat & MSR_DCTS) && (tp->t_state & TS_ISOPEN) &&
36647752Swilliam 		   (tp->t_flags & CRTSCTS)) {
36747752Swilliam 		/* the line is up and we want to do rts/cts flow control */
36847752Swilliam 		if (stat & MSR_CTS) {
36947752Swilliam 			tp->t_state &=~ TS_TTSTOP;
37047752Swilliam 			ttstart(tp);
37147752Swilliam 		} else
37247752Swilliam 			tp->t_state |= TS_TTSTOP;
37347752Swilliam 	}
37447752Swilliam }
37547752Swilliam 
37647752Swilliam comioctl(dev, cmd, data, flag)
37747752Swilliam 	dev_t dev;
37847752Swilliam 	caddr_t data;
37947752Swilliam {
38047752Swilliam 	register struct tty *tp;
38147752Swilliam 	register int unit = UNIT(dev);
38247752Swilliam 	register com;
38347752Swilliam 	register int error;
38447752Swilliam 
38547752Swilliam 	tp = &com_tty[unit];
38647752Swilliam 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
38747752Swilliam 	if (error >= 0)
38847752Swilliam 		return (error);
38947752Swilliam 	error = ttioctl(tp, cmd, data, flag);
39047752Swilliam 	if (error >= 0)
39147752Swilliam 		return (error);
39247752Swilliam 
39347752Swilliam 	com = com_addr[unit];
39447752Swilliam 	switch (cmd) {
39547752Swilliam 
39647752Swilliam 	case TIOCSBRK:
39747752Swilliam 		outb(com+com_cfcr, inb(com+com_cfcr) | CFCR_SBREAK);
39847752Swilliam 		break;
39947752Swilliam 
40047752Swilliam 	case TIOCCBRK:
40147752Swilliam 		outb(com+com_cfcr, inb(com+com_cfcr) & ~CFCR_SBREAK);
40247752Swilliam 		break;
40347752Swilliam 
40447752Swilliam 	case TIOCSDTR:
40547752Swilliam 		(void) commctl(dev, MCR_DTR | MCR_RTS, DMBIS);
40647752Swilliam 		break;
40747752Swilliam 
40847752Swilliam 	case TIOCCDTR:
40947752Swilliam 		(void) commctl(dev, MCR_DTR | MCR_RTS, DMBIC);
41047752Swilliam 		break;
41147752Swilliam 
41247752Swilliam 	case TIOCMSET:
41347752Swilliam 		(void) commctl(dev, *(int *)data, DMSET);
41447752Swilliam 		break;
41547752Swilliam 
41647752Swilliam 	case TIOCMBIS:
41747752Swilliam 		(void) commctl(dev, *(int *)data, DMBIS);
41847752Swilliam 		break;
41947752Swilliam 
42047752Swilliam 	case TIOCMBIC:
42147752Swilliam 		(void) commctl(dev, *(int *)data, DMBIC);
42247752Swilliam 		break;
42347752Swilliam 
42447752Swilliam 	case TIOCMGET:
42547752Swilliam 		*(int *)data = commctl(dev, 0, DMGET);
42647752Swilliam 		break;
42747752Swilliam 
42847752Swilliam 	default:
42947752Swilliam 		return (ENOTTY);
43047752Swilliam 	}
43147752Swilliam 	return (0);
43247752Swilliam }
43347752Swilliam 
43447752Swilliam comparam(tp, t)
43547752Swilliam 	register struct tty *tp;
43647752Swilliam 	register struct termios *t;
43747752Swilliam {
43847752Swilliam 	register com;
43947752Swilliam 	register int cfcr, cflag = t->c_cflag;
44047752Swilliam 	int unit = UNIT(tp->t_dev);
44147752Swilliam 	int ospeed = ttspeedtab(t->c_ospeed, comspeedtab);
44247752Swilliam 
44347752Swilliam 	/* check requested parameters */
44447752Swilliam         if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
44547752Swilliam                 return(EINVAL);
44647752Swilliam         /* and copy to tty */
44747752Swilliam         tp->t_ispeed = t->c_ispeed;
44847752Swilliam         tp->t_ospeed = t->c_ospeed;
44947752Swilliam         tp->t_cflag = cflag;
45047752Swilliam 
45147752Swilliam 	com = com_addr[unit];
45247752Swilliam 	outb(com+com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS /*| IER_EMSC*/);
45347752Swilliam 	if (ospeed == 0) {
45447752Swilliam 		(void) commctl(unit, 0, DMSET);	/* hang up line */
45547752Swilliam 		return(0);
45647752Swilliam 	}
45747752Swilliam 	outb(com+com_cfcr, inb(com+com_cfcr) | CFCR_DLAB);
45847752Swilliam 	outb(com+com_data, ospeed & 0xFF);
45947752Swilliam 	outb(com+com_ier, ospeed >> 8);
46047752Swilliam 	switch (cflag&CSIZE) {
46147752Swilliam 	case CS5:
46247752Swilliam 		cfcr = CFCR_5BITS; break;
46347752Swilliam 	case CS6:
46447752Swilliam 		cfcr = CFCR_6BITS; break;
46547752Swilliam 	case CS7:
46647752Swilliam 		cfcr = CFCR_7BITS; break;
46747752Swilliam 	case CS8:
46847752Swilliam 		cfcr = CFCR_8BITS; break;
46947752Swilliam 	}
47047752Swilliam 	if (cflag&PARENB) {
47147752Swilliam 		cfcr |= CFCR_PENAB;
47247752Swilliam 		if ((cflag&PARODD) == 0)
47347752Swilliam 			cfcr |= CFCR_PEVEN;
47447752Swilliam 	}
47547752Swilliam 	if (cflag&CSTOPB)
47647752Swilliam 		cfcr |= CFCR_STOPB;
47747752Swilliam 	outb(com+com_cfcr, cfcr);
47849570Swilliam 
47949570Swilliam 	if (com_hasfifo & (1 << unit))
48049570Swilliam 		outb(com+com_fifo, FIFO_ENABLE | FIFO_TRIGGER_14);
48149570Swilliam 
48247752Swilliam 	return(0);
48347752Swilliam }
48447752Swilliam 
48547752Swilliam comstart(tp)
48647752Swilliam 	register struct tty *tp;
48747752Swilliam {
48847752Swilliam 	register com;
48947752Swilliam 	int s, unit, c;
49047752Swilliam 
49147752Swilliam 	unit = UNIT(tp->t_dev);
49247752Swilliam 	com = com_addr[unit];
49347752Swilliam 	s = spltty();
49447752Swilliam 	if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
49547752Swilliam 		goto out;
49647752Swilliam 	if (tp->t_outq.c_cc <= tp->t_lowat) {
49747752Swilliam 		if (tp->t_state&TS_ASLEEP) {
49847752Swilliam 			tp->t_state &= ~TS_ASLEEP;
49947752Swilliam 			wakeup((caddr_t)&tp->t_outq);
50047752Swilliam 		}
50147752Swilliam 		if (tp->t_wsel) {
50247752Swilliam 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
50347752Swilliam 			tp->t_wsel = 0;
50447752Swilliam 			tp->t_state &= ~TS_WCOLL;
50547752Swilliam 		}
50647752Swilliam 	}
50747752Swilliam 	if (tp->t_outq.c_cc == 0)
50847752Swilliam 		goto out;
50947752Swilliam 	if (inb(com+com_lsr) & LSR_TXRDY) {
51047752Swilliam 		c = getc(&tp->t_outq);
51147752Swilliam 		tp->t_state |= TS_BUSY;
51247752Swilliam 		outb(com+com_data, c);
51349570Swilliam 		if (com_hasfifo & (1 << unit))
51449570Swilliam 			for (c = 1; c < 16 && tp->t_outq.c_cc; ++c)
51549570Swilliam 				outb(com+com_data, getc(&tp->t_outq));
51647752Swilliam 	}
51747752Swilliam out:
51847752Swilliam 	splx(s);
51947752Swilliam }
52047752Swilliam 
52147752Swilliam /*
52247752Swilliam  * Stop output on a line.
52347752Swilliam  */
52447752Swilliam /*ARGSUSED*/
52547752Swilliam comstop(tp, flag)
52647752Swilliam 	register struct tty *tp;
52747752Swilliam {
52847752Swilliam 	register int s;
52947752Swilliam 
53047752Swilliam 	s = spltty();
53147752Swilliam 	if (tp->t_state & TS_BUSY) {
53247752Swilliam 		if ((tp->t_state&TS_TTSTOP)==0)
53347752Swilliam 			tp->t_state |= TS_FLUSH;
53447752Swilliam 	}
53547752Swilliam 	splx(s);
53647752Swilliam }
53747752Swilliam 
53847752Swilliam commctl(dev, bits, how)
53947752Swilliam 	dev_t dev;
54047752Swilliam 	int bits, how;
54147752Swilliam {
54247752Swilliam 	register com;
54347752Swilliam 	register int unit;
54447752Swilliam 	int s;
54547752Swilliam 
54647752Swilliam 	unit = UNIT(dev);
54747752Swilliam 	com = com_addr[unit];
54847752Swilliam 	s = spltty();
54947752Swilliam 	switch (how) {
55047752Swilliam 
55147752Swilliam 	case DMSET:
55247752Swilliam 		outb(com+com_mcr, bits | MCR_IENABLE);
55347752Swilliam 		break;
55447752Swilliam 
55547752Swilliam 	case DMBIS:
55647752Swilliam 		outb(com+com_mcr, inb(com+com_mcr) | bits | MCR_IENABLE);
55747752Swilliam 		break;
55847752Swilliam 
55947752Swilliam 	case DMBIC:
56047752Swilliam 		outb(com+com_mcr, inb(com+com_mcr) & ~bits | MCR_IENABLE);
56147752Swilliam 		break;
56247752Swilliam 
56347752Swilliam 	case DMGET:
56447752Swilliam 		bits = inb(com+com_msr);
56547752Swilliam 		break;
56647752Swilliam 	}
56747752Swilliam 	(void) splx(s);
56847752Swilliam 	return(bits);
56947752Swilliam }
57049570Swilliam 
57149570Swilliam /*
57249570Swilliam  * Following are all routines needed for COM to act as console
57349570Swilliam  */
57449570Swilliam #include "i386/i386/cons.h"
57549570Swilliam 
57649570Swilliam comcnprobe(cp)
57749570Swilliam 	struct consdev *cp;
57849570Swilliam {
57949570Swilliam 	int unit;
58049570Swilliam 
58149570Swilliam 	/* locate the major number */
58249570Swilliam 	for (commajor = 0; commajor < nchrdev; commajor++)
58349570Swilliam 		if (cdevsw[commajor].d_open == comopen)
58449570Swilliam 			break;
58549570Swilliam 
58649570Swilliam 	/* XXX: ick */
58749570Swilliam 	unit = CONUNIT;
58849570Swilliam 	com_addr[CONUNIT] = CONADDR;
58949570Swilliam 
59049570Swilliam 	/* make sure hardware exists?  XXX */
59149570Swilliam 
59249570Swilliam 	/* initialize required fields */
59349570Swilliam 	cp->cn_dev = makedev(commajor, unit);
59449570Swilliam 	cp->cn_tp = &com_tty[unit];
59549570Swilliam #ifdef	COMCONSOLE
59649570Swilliam 	cp->cn_pri = CN_REMOTE;		/* Force a serial port console */
59749570Swilliam #else
59849570Swilliam 	cp->cn_pri = CN_NORMAL;
59947752Swilliam #endif
60049570Swilliam }
60149570Swilliam 
60249570Swilliam comcninit(cp)
60349570Swilliam 	struct consdev *cp;
60449570Swilliam {
60549570Swilliam 	int unit = UNIT(cp->cn_dev);
60649570Swilliam 
60749570Swilliam 	cominit(unit, comdefaultrate);
60849570Swilliam 	comconsole = unit;
60949570Swilliam 	comconsinit = 1;
61049570Swilliam }
61149570Swilliam 
61249570Swilliam cominit(unit, rate)
61349570Swilliam 	int unit, rate;
61449570Swilliam {
61549570Swilliam 	register int com;
61649570Swilliam 	int s;
61749570Swilliam 	short stat;
61849570Swilliam 
61949570Swilliam #ifdef lint
62049570Swilliam 	stat = unit; if (stat) return;
62149570Swilliam #endif
62249570Swilliam 	com = com_addr[unit];
62349570Swilliam 	s = splhigh();
62449570Swilliam 	outb(com+com_cfcr, CFCR_DLAB);
62549570Swilliam 	rate = ttspeedtab(comdefaultrate, comspeedtab);
62649570Swilliam 	outb(com+com_data, rate & 0xFF);
62749570Swilliam 	outb(com+com_ier, rate >> 8);
62849570Swilliam 	outb(com+com_cfcr, CFCR_8BITS);
62949570Swilliam 	outb(com+com_ier, IER_ERXRDY | IER_ETXRDY);
63049570Swilliam 	outb(com+com_fifo, FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14);
63149570Swilliam 	stat = inb(com+com_iir);
63249570Swilliam 	splx(s);
63349570Swilliam }
63449570Swilliam 
63549570Swilliam comcngetc(dev)
63649570Swilliam {
63749570Swilliam 	register com = com_addr[UNIT(dev)];
63849570Swilliam 	short stat;
63949570Swilliam 	int c, s;
64049570Swilliam 
64149570Swilliam #ifdef lint
64249570Swilliam 	stat = dev; if (stat) return(0);
64349570Swilliam #endif
64449570Swilliam 	s = splhigh();
64549570Swilliam 	while (((stat = inb(com+com_lsr)) & LSR_RXRDY) == 0)
64649570Swilliam 		;
64749570Swilliam 	c = inb(com+com_data);
64849570Swilliam 	stat = inb(com+com_iir);
64949570Swilliam 	splx(s);
65049570Swilliam 	return(c);
65149570Swilliam }
65249570Swilliam 
65349570Swilliam /*
65449570Swilliam  * Console kernel output character routine.
65549570Swilliam  */
65649570Swilliam comcnputc(dev, c)
65749570Swilliam 	dev_t dev;
65849570Swilliam 	register int c;
65949570Swilliam {
66049570Swilliam 	register com = com_addr[UNIT(dev)];
66149570Swilliam 	register int timo;
66249570Swilliam 	short stat;
66349570Swilliam 	int s = splhigh();
66449570Swilliam 
66549570Swilliam #ifdef lint
66649570Swilliam 	stat = dev; if (stat) return;
66749570Swilliam #endif
66849570Swilliam #ifdef KGDB
66949570Swilliam 	if (dev != kgdb_dev)
67049570Swilliam #endif
67149570Swilliam 	if (comconsinit == 0) {
67249570Swilliam 		(void) cominit(UNIT(dev), comdefaultrate);
67349570Swilliam 		comconsinit = 1;
67449570Swilliam 	}
67549570Swilliam 	/* wait for any pending transmission to finish */
67649570Swilliam 	timo = 50000;
67749570Swilliam 	while (((stat = inb(com+com_lsr)) & LSR_TXRDY) == 0 && --timo)
67849570Swilliam 		;
67949570Swilliam 	outb(com+com_data, c);
68049570Swilliam 	/* wait for this transmission to complete */
68149570Swilliam 	timo = 1500000;
68249570Swilliam 	while (((stat = inb(com+com_lsr)) & LSR_TXRDY) == 0 && --timo)
68349570Swilliam 		;
68449570Swilliam 	/* clear any interrupts generated by this transmission */
68549570Swilliam 	stat = inb(com+com_iir);
68649570Swilliam 	splx(s);
68749570Swilliam }
68849570Swilliam #endif
689