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