xref: /csrg-svn/sys/i386/isa/com.c (revision 52660)
147752Swilliam /*-
249570Swilliam  * Copyright (c) 1991 The Regents of the University of California.
349570Swilliam  * All rights reserved.
447752Swilliam  *
547752Swilliam  * %sccs.include.redist.c%
647752Swilliam  *
7*52660Storek  *	@(#)com.c	7.6 (Berkeley) 02/25/92
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 {
8849697Swilliam 	/* force access to id reg */
8949697Swilliam 	outb(dev->id_iobase+com_cfcr, 0);
9049697Swilliam 	outb(dev->id_iobase+com_iir, 0);
9149697Swilliam 	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
12249697Swilliam 	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*/
20349751Smarc comclose(dev, flag, mode, p)
20447752Swilliam 	dev_t dev;
20549751Smarc 	int flag, mode;
20649751Smarc 	struct proc *p;
20747752Swilliam {
20847752Swilliam 	register struct tty *tp;
20947752Swilliam 	register com;
21047752Swilliam 	register int unit;
21147752Swilliam 
21247752Swilliam 	unit = UNIT(dev);
21347752Swilliam 	com = com_addr[unit];
21447752Swilliam 	tp = &com_tty[unit];
21549751Smarc 	(*linesw[tp->t_line].l_close)(tp, flag);
21647752Swilliam 	outb(com+com_cfcr, inb(com+com_cfcr) & ~CFCR_SBREAK);
21747752Swilliam #ifdef KGDB
21847752Swilliam 	/* do not disable interrupts if debugging */
21949570Swilliam 	if (kgdb_dev != makedev(commajor, unit))
22047752Swilliam #endif
22147752Swilliam 	outb(com+com_ier, 0);
22247752Swilliam 	if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN ||
22347752Swilliam 	    (tp->t_state&TS_ISOPEN) == 0)
22447752Swilliam 		(void) commctl(dev, 0, DMSET);
22547752Swilliam 	ttyclose(tp);
22647752Swilliam 	return(0);
22747752Swilliam }
22847752Swilliam 
22947752Swilliam comread(dev, uio, flag)
23047752Swilliam 	dev_t dev;
23147752Swilliam 	struct uio *uio;
23247752Swilliam {
23347752Swilliam 	register struct tty *tp = &com_tty[UNIT(dev)];
23447752Swilliam 
23547752Swilliam 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
23647752Swilliam }
23747752Swilliam 
23847752Swilliam comwrite(dev, uio, flag)
23947752Swilliam 	dev_t dev;
24047752Swilliam 	struct uio *uio;
24147752Swilliam {
24247752Swilliam 	int unit = UNIT(dev);
24347752Swilliam 	register struct tty *tp = &com_tty[unit];
24447752Swilliam 
24547752Swilliam 	/*
24647752Swilliam 	 * (XXX) We disallow virtual consoles if the physical console is
24747752Swilliam 	 * a serial port.  This is in case there is a display attached that
24847752Swilliam 	 * is not the console.  In that situation we don't need/want the X
24947752Swilliam 	 * server taking over the console.
25047752Swilliam 	 */
25147752Swilliam 	if (constty && unit == comconsole)
25247752Swilliam 		constty = NULL;
25347752Swilliam 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
25447752Swilliam }
25547752Swilliam 
25647752Swilliam comintr(unit)
25747752Swilliam 	register int unit;
25847752Swilliam {
25947752Swilliam 	register com;
26047752Swilliam 	register u_char code;
26147752Swilliam 	register struct tty *tp;
26247752Swilliam 
26347752Swilliam 	com = com_addr[unit];
26447752Swilliam 	while (1) {
26547752Swilliam 		code = inb(com+com_iir);
26649570Swilliam 		switch (code & IIR_IMASK) {
26747752Swilliam 		case IIR_NOPEND:
26847752Swilliam 			return (1);
26949570Swilliam 		case IIR_RXTOUT:
27047752Swilliam 		case IIR_RXRDY:
27147752Swilliam 			tp = &com_tty[unit];
27249570Swilliam /*
27349570Swilliam  * Process received bytes.  Inline for speed...
27449570Swilliam  */
27547752Swilliam #ifdef KGDB
27649570Swilliam #define	RCVBYTE() \
27749570Swilliam 			code = inb(com+com_data); \
27849570Swilliam 			if ((tp->t_state & TS_ISOPEN) == 0) { \
27949570Swilliam 				if (kgdb_dev == makedev(commajor, unit) && \
28049570Swilliam 				    code == FRAME_END) \
28149570Swilliam 					kgdb_connect(0); /* trap into kgdb */ \
28249570Swilliam 			} else \
28349570Swilliam 				(*linesw[tp->t_line].l_rint)(code, tp)
28449570Swilliam #else
28549570Swilliam #define	RCVBYTE() \
28649570Swilliam 			code = inb(com+com_data); \
28749570Swilliam 			if (tp->t_state & TS_ISOPEN) \
28849570Swilliam 				(*linesw[tp->t_line].l_rint)(code, tp)
28949570Swilliam #endif
29049570Swilliam 
29149570Swilliam 			RCVBYTE();
29249570Swilliam 
29349570Swilliam 			if (com_hasfifo & (1 << unit))
29449570Swilliam 				while ((code = inb(com+com_lsr)) & LSR_RCV_MASK) {
29549570Swilliam 					if (code == LSR_RXRDY) {
29649570Swilliam 						RCVBYTE();
29749570Swilliam 					} else
29849570Swilliam 						comeint(unit, code, com);
29947752Swilliam 				}
30047752Swilliam 			break;
30147752Swilliam 		case IIR_TXRDY:
30247752Swilliam 			tp = &com_tty[unit];
30347752Swilliam 			tp->t_state &=~ (TS_BUSY|TS_FLUSH);
30447752Swilliam 			if (tp->t_line)
30547752Swilliam 				(*linesw[tp->t_line].l_start)(tp);
30647752Swilliam 			else
30747752Swilliam 				comstart(tp);
30847752Swilliam 			break;
30947752Swilliam 		case IIR_RLS:
31049570Swilliam 			comeint(unit, inb(com+com_lsr), com);
31147752Swilliam 			break;
31247752Swilliam 		default:
31347752Swilliam 			if (code & IIR_NOPEND)
31447752Swilliam 				return (1);
31547752Swilliam 			log(LOG_WARNING, "com%d: weird interrupt: 0x%x\n",
31647752Swilliam 			    unit, code);
31747752Swilliam 			/* fall through */
31847752Swilliam 		case IIR_MLSC:
31947752Swilliam 			commint(unit, com);
32047752Swilliam 			break;
32147752Swilliam 		}
32247752Swilliam 	}
32347752Swilliam }
32447752Swilliam 
32549570Swilliam comeint(unit, stat, com)
32649570Swilliam 	register int unit, stat;
32747752Swilliam 	register com;
32847752Swilliam {
32947752Swilliam 	register struct tty *tp;
33049570Swilliam 	register int c;
33147752Swilliam 
33247752Swilliam 	tp = &com_tty[unit];
33347752Swilliam 	c = inb(com+com_data);
33447752Swilliam 	if ((tp->t_state & TS_ISOPEN) == 0) {
33547752Swilliam #ifdef KGDB
33647752Swilliam 		/* we don't care about parity errors */
33747752Swilliam 		if (((stat & (LSR_BI|LSR_FE|LSR_PE)) == LSR_PE) &&
33849570Swilliam 		    kgdb_dev == makedev(commajor, unit) && c == FRAME_END)
33949570Swilliam 			kgdb_connect(0); /* trap into kgdb */
34047752Swilliam #endif
34147752Swilliam 		return;
34247752Swilliam 	}
34347752Swilliam 	if (stat & (LSR_BI | LSR_FE))
34447752Swilliam 		c |= TTY_FE;
34547752Swilliam 	else if (stat & LSR_PE)
34647752Swilliam 		c |= TTY_PE;
34747752Swilliam 	else if (stat & LSR_OE)
34847752Swilliam 		log(LOG_WARNING, "com%d: silo overflow\n", unit);
34947752Swilliam 	(*linesw[tp->t_line].l_rint)(c, tp);
35047752Swilliam }
35147752Swilliam 
35247752Swilliam commint(unit, com)
35347752Swilliam 	register int unit;
35447752Swilliam 	register com;
35547752Swilliam {
35647752Swilliam 	register struct tty *tp;
35747752Swilliam 	register int stat;
35847752Swilliam 
35947752Swilliam 	tp = &com_tty[unit];
36047752Swilliam 	stat = inb(com+com_msr);
36147752Swilliam 	if ((stat & MSR_DDCD) && (comsoftCAR & (1 << unit)) == 0) {
36247752Swilliam 		if (stat & MSR_DCD)
36347752Swilliam 			(void)(*linesw[tp->t_line].l_modem)(tp, 1);
36447752Swilliam 		else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0)
36547752Swilliam 			outb(com+com_mcr,
36647752Swilliam 				inb(com+com_mcr) & ~(MCR_DTR | MCR_RTS) | MCR_IENABLE);
36747752Swilliam 	} else if ((stat & MSR_DCTS) && (tp->t_state & TS_ISOPEN) &&
36847752Swilliam 		   (tp->t_flags & CRTSCTS)) {
36947752Swilliam 		/* the line is up and we want to do rts/cts flow control */
37047752Swilliam 		if (stat & MSR_CTS) {
37147752Swilliam 			tp->t_state &=~ TS_TTSTOP;
37247752Swilliam 			ttstart(tp);
37347752Swilliam 		} else
37447752Swilliam 			tp->t_state |= TS_TTSTOP;
37547752Swilliam 	}
37647752Swilliam }
37747752Swilliam 
37847752Swilliam comioctl(dev, cmd, data, flag)
37947752Swilliam 	dev_t dev;
38047752Swilliam 	caddr_t data;
38147752Swilliam {
38247752Swilliam 	register struct tty *tp;
38347752Swilliam 	register int unit = UNIT(dev);
38447752Swilliam 	register com;
38547752Swilliam 	register int error;
38647752Swilliam 
38747752Swilliam 	tp = &com_tty[unit];
38847752Swilliam 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
38947752Swilliam 	if (error >= 0)
39047752Swilliam 		return (error);
39147752Swilliam 	error = ttioctl(tp, cmd, data, flag);
39247752Swilliam 	if (error >= 0)
39347752Swilliam 		return (error);
39447752Swilliam 
39547752Swilliam 	com = com_addr[unit];
39647752Swilliam 	switch (cmd) {
39747752Swilliam 
39847752Swilliam 	case TIOCSBRK:
39947752Swilliam 		outb(com+com_cfcr, inb(com+com_cfcr) | CFCR_SBREAK);
40047752Swilliam 		break;
40147752Swilliam 
40247752Swilliam 	case TIOCCBRK:
40347752Swilliam 		outb(com+com_cfcr, inb(com+com_cfcr) & ~CFCR_SBREAK);
40447752Swilliam 		break;
40547752Swilliam 
40647752Swilliam 	case TIOCSDTR:
40747752Swilliam 		(void) commctl(dev, MCR_DTR | MCR_RTS, DMBIS);
40847752Swilliam 		break;
40947752Swilliam 
41047752Swilliam 	case TIOCCDTR:
41147752Swilliam 		(void) commctl(dev, MCR_DTR | MCR_RTS, DMBIC);
41247752Swilliam 		break;
41347752Swilliam 
41447752Swilliam 	case TIOCMSET:
41547752Swilliam 		(void) commctl(dev, *(int *)data, DMSET);
41647752Swilliam 		break;
41747752Swilliam 
41847752Swilliam 	case TIOCMBIS:
41947752Swilliam 		(void) commctl(dev, *(int *)data, DMBIS);
42047752Swilliam 		break;
42147752Swilliam 
42247752Swilliam 	case TIOCMBIC:
42347752Swilliam 		(void) commctl(dev, *(int *)data, DMBIC);
42447752Swilliam 		break;
42547752Swilliam 
42647752Swilliam 	case TIOCMGET:
42747752Swilliam 		*(int *)data = commctl(dev, 0, DMGET);
42847752Swilliam 		break;
42947752Swilliam 
43047752Swilliam 	default:
43147752Swilliam 		return (ENOTTY);
43247752Swilliam 	}
43347752Swilliam 	return (0);
43447752Swilliam }
43547752Swilliam 
43647752Swilliam comparam(tp, t)
43747752Swilliam 	register struct tty *tp;
43847752Swilliam 	register struct termios *t;
43947752Swilliam {
44047752Swilliam 	register com;
44147752Swilliam 	register int cfcr, cflag = t->c_cflag;
44247752Swilliam 	int unit = UNIT(tp->t_dev);
44347752Swilliam 	int ospeed = ttspeedtab(t->c_ospeed, comspeedtab);
44447752Swilliam 
44547752Swilliam 	/* check requested parameters */
44647752Swilliam         if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
44747752Swilliam                 return(EINVAL);
44847752Swilliam         /* and copy to tty */
44947752Swilliam         tp->t_ispeed = t->c_ispeed;
45047752Swilliam         tp->t_ospeed = t->c_ospeed;
45147752Swilliam         tp->t_cflag = cflag;
45247752Swilliam 
45347752Swilliam 	com = com_addr[unit];
45447752Swilliam 	outb(com+com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS /*| IER_EMSC*/);
45547752Swilliam 	if (ospeed == 0) {
45647752Swilliam 		(void) commctl(unit, 0, DMSET);	/* hang up line */
45747752Swilliam 		return(0);
45847752Swilliam 	}
45947752Swilliam 	outb(com+com_cfcr, inb(com+com_cfcr) | CFCR_DLAB);
46047752Swilliam 	outb(com+com_data, ospeed & 0xFF);
46147752Swilliam 	outb(com+com_ier, ospeed >> 8);
46247752Swilliam 	switch (cflag&CSIZE) {
46347752Swilliam 	case CS5:
46447752Swilliam 		cfcr = CFCR_5BITS; break;
46547752Swilliam 	case CS6:
46647752Swilliam 		cfcr = CFCR_6BITS; break;
46747752Swilliam 	case CS7:
46847752Swilliam 		cfcr = CFCR_7BITS; break;
46947752Swilliam 	case CS8:
47047752Swilliam 		cfcr = CFCR_8BITS; break;
47147752Swilliam 	}
47247752Swilliam 	if (cflag&PARENB) {
47347752Swilliam 		cfcr |= CFCR_PENAB;
47447752Swilliam 		if ((cflag&PARODD) == 0)
47547752Swilliam 			cfcr |= CFCR_PEVEN;
47647752Swilliam 	}
47747752Swilliam 	if (cflag&CSTOPB)
47847752Swilliam 		cfcr |= CFCR_STOPB;
47947752Swilliam 	outb(com+com_cfcr, cfcr);
48049570Swilliam 
48149570Swilliam 	if (com_hasfifo & (1 << unit))
48249570Swilliam 		outb(com+com_fifo, FIFO_ENABLE | FIFO_TRIGGER_14);
48349570Swilliam 
48447752Swilliam 	return(0);
48547752Swilliam }
48647752Swilliam 
48747752Swilliam comstart(tp)
48847752Swilliam 	register struct tty *tp;
48947752Swilliam {
49047752Swilliam 	register com;
49147752Swilliam 	int s, unit, c;
49247752Swilliam 
49347752Swilliam 	unit = UNIT(tp->t_dev);
49447752Swilliam 	com = com_addr[unit];
49547752Swilliam 	s = spltty();
49647752Swilliam 	if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
49747752Swilliam 		goto out;
49847752Swilliam 	if (tp->t_outq.c_cc <= tp->t_lowat) {
49947752Swilliam 		if (tp->t_state&TS_ASLEEP) {
50047752Swilliam 			tp->t_state &= ~TS_ASLEEP;
50147752Swilliam 			wakeup((caddr_t)&tp->t_outq);
50247752Swilliam 		}
503*52660Storek 		selwakeup(&tp->t_wsel);
50447752Swilliam 	}
50547752Swilliam 	if (tp->t_outq.c_cc == 0)
50647752Swilliam 		goto out;
50747752Swilliam 	if (inb(com+com_lsr) & LSR_TXRDY) {
50847752Swilliam 		c = getc(&tp->t_outq);
50947752Swilliam 		tp->t_state |= TS_BUSY;
51047752Swilliam 		outb(com+com_data, c);
51149570Swilliam 		if (com_hasfifo & (1 << unit))
51249570Swilliam 			for (c = 1; c < 16 && tp->t_outq.c_cc; ++c)
51349570Swilliam 				outb(com+com_data, getc(&tp->t_outq));
51447752Swilliam 	}
51547752Swilliam out:
51647752Swilliam 	splx(s);
51747752Swilliam }
51847752Swilliam 
51947752Swilliam /*
52047752Swilliam  * Stop output on a line.
52147752Swilliam  */
52247752Swilliam /*ARGSUSED*/
52347752Swilliam comstop(tp, flag)
52447752Swilliam 	register struct tty *tp;
52547752Swilliam {
52647752Swilliam 	register int s;
52747752Swilliam 
52847752Swilliam 	s = spltty();
52947752Swilliam 	if (tp->t_state & TS_BUSY) {
53047752Swilliam 		if ((tp->t_state&TS_TTSTOP)==0)
53147752Swilliam 			tp->t_state |= TS_FLUSH;
53247752Swilliam 	}
53347752Swilliam 	splx(s);
53447752Swilliam }
53547752Swilliam 
53647752Swilliam commctl(dev, bits, how)
53747752Swilliam 	dev_t dev;
53847752Swilliam 	int bits, how;
53947752Swilliam {
54047752Swilliam 	register com;
54147752Swilliam 	register int unit;
54247752Swilliam 	int s;
54347752Swilliam 
54447752Swilliam 	unit = UNIT(dev);
54547752Swilliam 	com = com_addr[unit];
54647752Swilliam 	s = spltty();
54747752Swilliam 	switch (how) {
54847752Swilliam 
54947752Swilliam 	case DMSET:
55047752Swilliam 		outb(com+com_mcr, bits | MCR_IENABLE);
55147752Swilliam 		break;
55247752Swilliam 
55347752Swilliam 	case DMBIS:
55447752Swilliam 		outb(com+com_mcr, inb(com+com_mcr) | bits | MCR_IENABLE);
55547752Swilliam 		break;
55647752Swilliam 
55747752Swilliam 	case DMBIC:
55847752Swilliam 		outb(com+com_mcr, inb(com+com_mcr) & ~bits | MCR_IENABLE);
55947752Swilliam 		break;
56047752Swilliam 
56147752Swilliam 	case DMGET:
56247752Swilliam 		bits = inb(com+com_msr);
56347752Swilliam 		break;
56447752Swilliam 	}
56547752Swilliam 	(void) splx(s);
56647752Swilliam 	return(bits);
56747752Swilliam }
56849570Swilliam 
56949570Swilliam /*
57049570Swilliam  * Following are all routines needed for COM to act as console
57149570Swilliam  */
57249570Swilliam #include "i386/i386/cons.h"
57349570Swilliam 
57449570Swilliam comcnprobe(cp)
57549570Swilliam 	struct consdev *cp;
57649570Swilliam {
57749570Swilliam 	int unit;
57849570Swilliam 
57949570Swilliam 	/* locate the major number */
58049570Swilliam 	for (commajor = 0; commajor < nchrdev; commajor++)
58149570Swilliam 		if (cdevsw[commajor].d_open == comopen)
58249570Swilliam 			break;
58349570Swilliam 
58449570Swilliam 	/* XXX: ick */
58549570Swilliam 	unit = CONUNIT;
58649570Swilliam 	com_addr[CONUNIT] = CONADDR;
58749570Swilliam 
58849570Swilliam 	/* make sure hardware exists?  XXX */
58949570Swilliam 
59049570Swilliam 	/* initialize required fields */
59149570Swilliam 	cp->cn_dev = makedev(commajor, unit);
59249570Swilliam 	cp->cn_tp = &com_tty[unit];
59349570Swilliam #ifdef	COMCONSOLE
59449570Swilliam 	cp->cn_pri = CN_REMOTE;		/* Force a serial port console */
59549570Swilliam #else
59649570Swilliam 	cp->cn_pri = CN_NORMAL;
59747752Swilliam #endif
59849570Swilliam }
59949570Swilliam 
60049570Swilliam comcninit(cp)
60149570Swilliam 	struct consdev *cp;
60249570Swilliam {
60349570Swilliam 	int unit = UNIT(cp->cn_dev);
60449570Swilliam 
60549570Swilliam 	cominit(unit, comdefaultrate);
60649570Swilliam 	comconsole = unit;
60749570Swilliam 	comconsinit = 1;
60849570Swilliam }
60949570Swilliam 
61049570Swilliam cominit(unit, rate)
61149570Swilliam 	int unit, rate;
61249570Swilliam {
61349570Swilliam 	register int com;
61449570Swilliam 	int s;
61549570Swilliam 	short stat;
61649570Swilliam 
61749570Swilliam #ifdef lint
61849570Swilliam 	stat = unit; if (stat) return;
61949570Swilliam #endif
62049570Swilliam 	com = com_addr[unit];
62149570Swilliam 	s = splhigh();
62249570Swilliam 	outb(com+com_cfcr, CFCR_DLAB);
62349570Swilliam 	rate = ttspeedtab(comdefaultrate, comspeedtab);
62449570Swilliam 	outb(com+com_data, rate & 0xFF);
62549570Swilliam 	outb(com+com_ier, rate >> 8);
62649570Swilliam 	outb(com+com_cfcr, CFCR_8BITS);
62749570Swilliam 	outb(com+com_ier, IER_ERXRDY | IER_ETXRDY);
62849570Swilliam 	outb(com+com_fifo, FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14);
62949570Swilliam 	stat = inb(com+com_iir);
63049570Swilliam 	splx(s);
63149570Swilliam }
63249570Swilliam 
63349570Swilliam comcngetc(dev)
63449570Swilliam {
63549570Swilliam 	register com = com_addr[UNIT(dev)];
63649570Swilliam 	short stat;
63749570Swilliam 	int c, s;
63849570Swilliam 
63949570Swilliam #ifdef lint
64049570Swilliam 	stat = dev; if (stat) return(0);
64149570Swilliam #endif
64249570Swilliam 	s = splhigh();
64349570Swilliam 	while (((stat = inb(com+com_lsr)) & LSR_RXRDY) == 0)
64449570Swilliam 		;
64549570Swilliam 	c = inb(com+com_data);
64649570Swilliam 	stat = inb(com+com_iir);
64749570Swilliam 	splx(s);
64849570Swilliam 	return(c);
64949570Swilliam }
65049570Swilliam 
65149570Swilliam /*
65249570Swilliam  * Console kernel output character routine.
65349570Swilliam  */
65449570Swilliam comcnputc(dev, c)
65549570Swilliam 	dev_t dev;
65649570Swilliam 	register int c;
65749570Swilliam {
65849570Swilliam 	register com = com_addr[UNIT(dev)];
65949570Swilliam 	register int timo;
66049570Swilliam 	short stat;
66149570Swilliam 	int s = splhigh();
66249570Swilliam 
66349570Swilliam #ifdef lint
66449570Swilliam 	stat = dev; if (stat) return;
66549570Swilliam #endif
66649570Swilliam #ifdef KGDB
66749570Swilliam 	if (dev != kgdb_dev)
66849570Swilliam #endif
66949570Swilliam 	if (comconsinit == 0) {
67049570Swilliam 		(void) cominit(UNIT(dev), comdefaultrate);
67149570Swilliam 		comconsinit = 1;
67249570Swilliam 	}
67349570Swilliam 	/* wait for any pending transmission to finish */
67449570Swilliam 	timo = 50000;
67549570Swilliam 	while (((stat = inb(com+com_lsr)) & LSR_TXRDY) == 0 && --timo)
67649570Swilliam 		;
67749570Swilliam 	outb(com+com_data, c);
67849570Swilliam 	/* wait for this transmission to complete */
67949570Swilliam 	timo = 1500000;
68049570Swilliam 	while (((stat = inb(com+com_lsr)) & LSR_TXRDY) == 0 && --timo)
68149570Swilliam 		;
68249570Swilliam 	/* clear any interrupts generated by this transmission */
68349570Swilliam 	stat = inb(com+com_iir);
68449570Swilliam 	splx(s);
68549570Swilliam }
68649570Swilliam #endif
687