xref: /csrg-svn/sys/i386/isa/com.c (revision 49570)
147752Swilliam /*-
2*49570Swilliam  * Copyright (c) 1991 The Regents of the University of California.
3*49570Swilliam  * All rights reserved.
447752Swilliam  *
547752Swilliam  * %sccs.include.redist.c%
647752Swilliam  *
7*49570Swilliam  *	@(#)com.c	7.3 (Berkeley) 05/09/91
847752Swilliam  */
947752Swilliam 
1049569Swilliam #include "com.h"
1149569Swilliam #if NCOM > 0
1247752Swilliam /*
13*49570Swilliam  * COM driver, based on HP dca driver
14*49570Swilliam  * uses National Semiconductor NS16450/NS16550AF UART
1547752Swilliam  */
16*49570Swilliam #include "param.h"
17*49570Swilliam #include "systm.h"
18*49570Swilliam #include "ioctl.h"
19*49570Swilliam #include "tty.h"
20*49570Swilliam #include "proc.h"
21*49570Swilliam #include "user.h"
22*49570Swilliam #include "conf.h"
23*49570Swilliam #include "file.h"
24*49570Swilliam #include "uio.h"
25*49570Swilliam #include "kernel.h"
26*49570Swilliam #include "syslog.h"
2747752Swilliam 
2847752Swilliam #include "i386/isa/isa_device.h"
2947752Swilliam #include "i386/isa/comreg.h"
30*49570Swilliam #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;
40*49570Swilliam int	com_hasfifo;
4149569Swilliam int	ncom = NCOM;
42*49570Swilliam #ifdef COMCONSOLE
43*49570Swilliam int	comconsole = COMCONSOLE;
44*49570Swilliam #else
4547752Swilliam int	comconsole = -1;
46*49570Swilliam #endif
47*49570Swilliam int	comconsinit;
4847752Swilliam int	comdefaultrate = TTYDEF_SPEED;
49*49570Swilliam 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
76*49570Swilliam #include "machine/remote-sl.h"
77*49570Swilliam 
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*49570Swilliam 	/*if ((inb(dev->id_iobase+com_iir) & 0x38) == 0)
8947752Swilliam 		return(1);
90*49570Swilliam printf("base %x val %x ", dev->id_iobase,
91*49570Swilliam 	inb(dev->id_iobase+com_iir));*/
92*49570Swilliam 	return(1);
9347752Swilliam 
9447752Swilliam }
9547752Swilliam 
9647752Swilliam 
9747752Swilliam int
9847752Swilliam comattach(isdp)
9947752Swilliam struct isa_device *isdp;
10047752Swilliam {
10147752Swilliam 	struct	tty	*tp;
10247752Swilliam 	u_char		unit;
10347752Swilliam 	int		port = isdp->id_iobase;
10447752Swilliam 
105*49570Swilliam 	unit = isdp->id_unit;
10647752Swilliam 	if (unit == comconsole)
10747752Swilliam 		DELAY(100000);
10847752Swilliam 	com_addr[unit] = port;
10947752Swilliam 	com_active |= 1 << unit;
110*49570Swilliam 	comsoftCAR |= 1 << unit;	/* XXX */
111*49570Swilliam 
112*49570Swilliam 	/* look for a NS 16550AF UART with FIFOs */
113*49570Swilliam 	outb(port+com_fifo, FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14);
114*49570Swilliam 	DELAY(100);
115*49570Swilliam 	if ((inb(port+com_iir) & IIR_FIFO_MASK) == IIR_FIFO_MASK)
116*49570Swilliam 		com_hasfifo |= 1 << unit;
117*49570Swilliam 
11847752Swilliam 	outb(port+com_ier, 0);
11947752Swilliam 	outb(port+com_mcr, 0 | MCR_IENABLE);
12047752Swilliam #ifdef KGDB
121*49570Swilliam 	if (1/*kgdb_dev == makedev(commajor, unit)*/) {
12247752Swilliam 		if (comconsole == unit)
12347752Swilliam 			kgdb_dev = -1;	/* can't debug over console port */
12447752Swilliam 		else {
125*49570Swilliam 			(void) cominit(unit, kgdb_rate);
12647752Swilliam 			if (kgdb_debug_init) {
127*49570Swilliam 				/*
128*49570Swilliam 				 * Print prefix of device name,
129*49570Swilliam 				 * let kgdb_connect print the rest.
130*49570Swilliam 				 */
131*49570Swilliam 				printf("com%d: ", unit);
132*49570Swilliam 				kgdb_connect(1);
13347752Swilliam 			} else
13447752Swilliam 				printf("com%d: kgdb enabled\n", unit);
13547752Swilliam 		}
13647752Swilliam 	}
13747752Swilliam #endif
13847752Swilliam 	/*
139*49570Swilliam 	 * Need to reset baud rate, etc. of next print so reset comconsinit.
14047752Swilliam 	 * Also make sure console is always "hardwired"
14147752Swilliam 	 */
14247752Swilliam 	if (unit == comconsole) {
143*49570Swilliam 		comconsinit = 0;
14447752Swilliam 		comsoftCAR |= (1 << unit);
14547752Swilliam 	}
14647752Swilliam 	return (1);
14747752Swilliam }
14847752Swilliam 
14949569Swilliam /* ARGSUSED */
15049569Swilliam #ifdef __STDC__
15149569Swilliam comopen(dev_t dev, int flag, int mode, struct proc *p)
15249569Swilliam #else
15349569Swilliam comopen(dev, flag, mode, p)
15447752Swilliam 	dev_t dev;
15549569Swilliam 	int flag, mode;
15649569Swilliam 	struct proc *p;
15749569Swilliam #endif
15847752Swilliam {
15947752Swilliam 	register struct tty *tp;
16047752Swilliam 	register int unit;
16147752Swilliam 	int error = 0;
16247752Swilliam 
16347752Swilliam 	unit = UNIT(dev);
16449569Swilliam 	if (unit >= NCOM || (com_active & (1 << unit)) == 0)
16547752Swilliam 		return (ENXIO);
16647752Swilliam 	tp = &com_tty[unit];
16747752Swilliam 	tp->t_oproc = comstart;
16847752Swilliam 	tp->t_param = comparam;
16947752Swilliam 	tp->t_dev = dev;
17047752Swilliam 	if ((tp->t_state & TS_ISOPEN) == 0) {
17147752Swilliam 		tp->t_state |= TS_WOPEN;
17247752Swilliam 		ttychars(tp);
173*49570Swilliam 		if (tp->t_ispeed == 0) {
174*49570Swilliam 			tp->t_iflag = TTYDEF_IFLAG;
175*49570Swilliam 			tp->t_oflag = TTYDEF_OFLAG;
176*49570Swilliam 			tp->t_cflag = TTYDEF_CFLAG;
177*49570Swilliam 			tp->t_lflag = TTYDEF_LFLAG;
178*49570Swilliam 			tp->t_ispeed = tp->t_ospeed = comdefaultrate;
179*49570Swilliam 		}
18047752Swilliam 		comparam(tp, &tp->t_termios);
18147752Swilliam 		ttsetwater(tp);
18249569Swilliam 	} else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
18347752Swilliam 		return (EBUSY);
18447752Swilliam 	(void) spltty();
18547752Swilliam 	(void) commctl(dev, MCR_DTR | MCR_RTS, DMSET);
18647752Swilliam 	if ((comsoftCAR & (1 << unit)) || (commctl(dev, 0, DMGET) & MSR_DCD))
18747752Swilliam 		tp->t_state |= TS_CARR_ON;
18847752Swilliam 	while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 &&
18947752Swilliam 	       (tp->t_state & TS_CARR_ON) == 0) {
19047752Swilliam 		tp->t_state |= TS_WOPEN;
19147752Swilliam 		if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
19247752Swilliam 		    ttopen, 0))
19347752Swilliam 			break;
19447752Swilliam 	}
19547752Swilliam 	(void) spl0();
19647752Swilliam 	if (error == 0)
19747752Swilliam 		error = (*linesw[tp->t_line].l_open)(dev, tp);
19847752Swilliam 	return (error);
19947752Swilliam }
20047752Swilliam 
20147752Swilliam /*ARGSUSED*/
20247752Swilliam comclose(dev, flag)
20347752Swilliam 	dev_t dev;
20447752Swilliam {
20547752Swilliam 	register struct tty *tp;
20647752Swilliam 	register com;
20747752Swilliam 	register int unit;
20847752Swilliam 
20947752Swilliam 	unit = UNIT(dev);
21047752Swilliam 	com = com_addr[unit];
21147752Swilliam 	tp = &com_tty[unit];
21247752Swilliam 	(*linesw[tp->t_line].l_close)(tp);
21347752Swilliam 	outb(com+com_cfcr, inb(com+com_cfcr) & ~CFCR_SBREAK);
21447752Swilliam #ifdef KGDB
21547752Swilliam 	/* do not disable interrupts if debugging */
216*49570Swilliam 	if (kgdb_dev != makedev(commajor, unit))
21747752Swilliam #endif
21847752Swilliam 	outb(com+com_ier, 0);
21947752Swilliam 	if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN ||
22047752Swilliam 	    (tp->t_state&TS_ISOPEN) == 0)
22147752Swilliam 		(void) commctl(dev, 0, DMSET);
22247752Swilliam 	ttyclose(tp);
22347752Swilliam 	return(0);
22447752Swilliam }
22547752Swilliam 
22647752Swilliam comread(dev, uio, flag)
22747752Swilliam 	dev_t dev;
22847752Swilliam 	struct uio *uio;
22947752Swilliam {
23047752Swilliam 	register struct tty *tp = &com_tty[UNIT(dev)];
23147752Swilliam 
23247752Swilliam 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
23347752Swilliam }
23447752Swilliam 
23547752Swilliam comwrite(dev, uio, flag)
23647752Swilliam 	dev_t dev;
23747752Swilliam 	struct uio *uio;
23847752Swilliam {
23947752Swilliam 	int unit = UNIT(dev);
24047752Swilliam 	register struct tty *tp = &com_tty[unit];
24147752Swilliam 
24247752Swilliam 	/*
24347752Swilliam 	 * (XXX) We disallow virtual consoles if the physical console is
24447752Swilliam 	 * a serial port.  This is in case there is a display attached that
24547752Swilliam 	 * is not the console.  In that situation we don't need/want the X
24647752Swilliam 	 * server taking over the console.
24747752Swilliam 	 */
24847752Swilliam 	if (constty && unit == comconsole)
24947752Swilliam 		constty = NULL;
25047752Swilliam 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
25147752Swilliam }
25247752Swilliam 
25347752Swilliam comintr(unit)
25447752Swilliam 	register int unit;
25547752Swilliam {
25647752Swilliam 	register com;
25747752Swilliam 	register u_char code;
25847752Swilliam 	register struct tty *tp;
25947752Swilliam 
26047752Swilliam 	com = com_addr[unit];
26147752Swilliam 	while (1) {
26247752Swilliam 		code = inb(com+com_iir);
263*49570Swilliam 		switch (code & IIR_IMASK) {
26447752Swilliam 		case IIR_NOPEND:
26547752Swilliam 			return (1);
266*49570Swilliam 		case IIR_RXTOUT:
26747752Swilliam 		case IIR_RXRDY:
26847752Swilliam 			tp = &com_tty[unit];
269*49570Swilliam /*
270*49570Swilliam  * Process received bytes.  Inline for speed...
271*49570Swilliam  */
27247752Swilliam #ifdef KGDB
273*49570Swilliam #define	RCVBYTE() \
274*49570Swilliam 			code = inb(com+com_data); \
275*49570Swilliam 			if ((tp->t_state & TS_ISOPEN) == 0) { \
276*49570Swilliam 				if (kgdb_dev == makedev(commajor, unit) && \
277*49570Swilliam 				    code == FRAME_END) \
278*49570Swilliam 					kgdb_connect(0); /* trap into kgdb */ \
279*49570Swilliam 			} else \
280*49570Swilliam 				(*linesw[tp->t_line].l_rint)(code, tp)
281*49570Swilliam #else
282*49570Swilliam #define	RCVBYTE() \
283*49570Swilliam 			code = inb(com+com_data); \
284*49570Swilliam 			if (tp->t_state & TS_ISOPEN) \
285*49570Swilliam 				(*linesw[tp->t_line].l_rint)(code, tp)
286*49570Swilliam #endif
287*49570Swilliam 
288*49570Swilliam 			RCVBYTE();
289*49570Swilliam 
290*49570Swilliam 			if (com_hasfifo & (1 << unit))
291*49570Swilliam 				while ((code = inb(com+com_lsr)) & LSR_RCV_MASK) {
292*49570Swilliam 					if (code == LSR_RXRDY) {
293*49570Swilliam 						RCVBYTE();
294*49570Swilliam 					} else
295*49570Swilliam 						comeint(unit, code, com);
29647752Swilliam 				}
29747752Swilliam 			break;
29847752Swilliam 		case IIR_TXRDY:
29947752Swilliam 			tp = &com_tty[unit];
30047752Swilliam 			tp->t_state &=~ (TS_BUSY|TS_FLUSH);
30147752Swilliam 			if (tp->t_line)
30247752Swilliam 				(*linesw[tp->t_line].l_start)(tp);
30347752Swilliam 			else
30447752Swilliam 				comstart(tp);
30547752Swilliam 			break;
30647752Swilliam 		case IIR_RLS:
307*49570Swilliam 			comeint(unit, inb(com+com_lsr), com);
30847752Swilliam 			break;
30947752Swilliam 		default:
31047752Swilliam 			if (code & IIR_NOPEND)
31147752Swilliam 				return (1);
31247752Swilliam 			log(LOG_WARNING, "com%d: weird interrupt: 0x%x\n",
31347752Swilliam 			    unit, code);
31447752Swilliam 			/* fall through */
31547752Swilliam 		case IIR_MLSC:
31647752Swilliam 			commint(unit, com);
31747752Swilliam 			break;
31847752Swilliam 		}
31947752Swilliam 	}
32047752Swilliam }
32147752Swilliam 
322*49570Swilliam comeint(unit, stat, com)
323*49570Swilliam 	register int unit, stat;
32447752Swilliam 	register com;
32547752Swilliam {
32647752Swilliam 	register struct tty *tp;
327*49570Swilliam 	register int c;
32847752Swilliam 
32947752Swilliam 	tp = &com_tty[unit];
33047752Swilliam 	c = inb(com+com_data);
33147752Swilliam 	if ((tp->t_state & TS_ISOPEN) == 0) {
33247752Swilliam #ifdef KGDB
33347752Swilliam 		/* we don't care about parity errors */
33447752Swilliam 		if (((stat & (LSR_BI|LSR_FE|LSR_PE)) == LSR_PE) &&
335*49570Swilliam 		    kgdb_dev == makedev(commajor, unit) && c == FRAME_END)
336*49570Swilliam 			kgdb_connect(0); /* trap into kgdb */
33747752Swilliam #endif
33847752Swilliam 		return;
33947752Swilliam 	}
34047752Swilliam 	if (stat & (LSR_BI | LSR_FE))
34147752Swilliam 		c |= TTY_FE;
34247752Swilliam 	else if (stat & LSR_PE)
34347752Swilliam 		c |= TTY_PE;
34447752Swilliam 	else if (stat & LSR_OE)
34547752Swilliam 		log(LOG_WARNING, "com%d: silo overflow\n", unit);
34647752Swilliam 	(*linesw[tp->t_line].l_rint)(c, tp);
34747752Swilliam }
34847752Swilliam 
34947752Swilliam commint(unit, com)
35047752Swilliam 	register int unit;
35147752Swilliam 	register com;
35247752Swilliam {
35347752Swilliam 	register struct tty *tp;
35447752Swilliam 	register int stat;
35547752Swilliam 
35647752Swilliam 	tp = &com_tty[unit];
35747752Swilliam 	stat = inb(com+com_msr);
35847752Swilliam 	if ((stat & MSR_DDCD) && (comsoftCAR & (1 << unit)) == 0) {
35947752Swilliam 		if (stat & MSR_DCD)
36047752Swilliam 			(void)(*linesw[tp->t_line].l_modem)(tp, 1);
36147752Swilliam 		else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0)
36247752Swilliam 			outb(com+com_mcr,
36347752Swilliam 				inb(com+com_mcr) & ~(MCR_DTR | MCR_RTS) | MCR_IENABLE);
36447752Swilliam 	} else if ((stat & MSR_DCTS) && (tp->t_state & TS_ISOPEN) &&
36547752Swilliam 		   (tp->t_flags & CRTSCTS)) {
36647752Swilliam 		/* the line is up and we want to do rts/cts flow control */
36747752Swilliam 		if (stat & MSR_CTS) {
36847752Swilliam 			tp->t_state &=~ TS_TTSTOP;
36947752Swilliam 			ttstart(tp);
37047752Swilliam 		} else
37147752Swilliam 			tp->t_state |= TS_TTSTOP;
37247752Swilliam 	}
37347752Swilliam }
37447752Swilliam 
37547752Swilliam comioctl(dev, cmd, data, flag)
37647752Swilliam 	dev_t dev;
37747752Swilliam 	caddr_t data;
37847752Swilliam {
37947752Swilliam 	register struct tty *tp;
38047752Swilliam 	register int unit = UNIT(dev);
38147752Swilliam 	register com;
38247752Swilliam 	register int error;
38347752Swilliam 
38447752Swilliam 	tp = &com_tty[unit];
38547752Swilliam 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
38647752Swilliam 	if (error >= 0)
38747752Swilliam 		return (error);
38847752Swilliam 	error = ttioctl(tp, cmd, data, flag);
38947752Swilliam 	if (error >= 0)
39047752Swilliam 		return (error);
39147752Swilliam 
39247752Swilliam 	com = com_addr[unit];
39347752Swilliam 	switch (cmd) {
39447752Swilliam 
39547752Swilliam 	case TIOCSBRK:
39647752Swilliam 		outb(com+com_cfcr, inb(com+com_cfcr) | CFCR_SBREAK);
39747752Swilliam 		break;
39847752Swilliam 
39947752Swilliam 	case TIOCCBRK:
40047752Swilliam 		outb(com+com_cfcr, inb(com+com_cfcr) & ~CFCR_SBREAK);
40147752Swilliam 		break;
40247752Swilliam 
40347752Swilliam 	case TIOCSDTR:
40447752Swilliam 		(void) commctl(dev, MCR_DTR | MCR_RTS, DMBIS);
40547752Swilliam 		break;
40647752Swilliam 
40747752Swilliam 	case TIOCCDTR:
40847752Swilliam 		(void) commctl(dev, MCR_DTR | MCR_RTS, DMBIC);
40947752Swilliam 		break;
41047752Swilliam 
41147752Swilliam 	case TIOCMSET:
41247752Swilliam 		(void) commctl(dev, *(int *)data, DMSET);
41347752Swilliam 		break;
41447752Swilliam 
41547752Swilliam 	case TIOCMBIS:
41647752Swilliam 		(void) commctl(dev, *(int *)data, DMBIS);
41747752Swilliam 		break;
41847752Swilliam 
41947752Swilliam 	case TIOCMBIC:
42047752Swilliam 		(void) commctl(dev, *(int *)data, DMBIC);
42147752Swilliam 		break;
42247752Swilliam 
42347752Swilliam 	case TIOCMGET:
42447752Swilliam 		*(int *)data = commctl(dev, 0, DMGET);
42547752Swilliam 		break;
42647752Swilliam 
42747752Swilliam 	default:
42847752Swilliam 		return (ENOTTY);
42947752Swilliam 	}
43047752Swilliam 	return (0);
43147752Swilliam }
43247752Swilliam 
43347752Swilliam comparam(tp, t)
43447752Swilliam 	register struct tty *tp;
43547752Swilliam 	register struct termios *t;
43647752Swilliam {
43747752Swilliam 	register com;
43847752Swilliam 	register int cfcr, cflag = t->c_cflag;
43947752Swilliam 	int unit = UNIT(tp->t_dev);
44047752Swilliam 	int ospeed = ttspeedtab(t->c_ospeed, comspeedtab);
44147752Swilliam 
44247752Swilliam 	/* check requested parameters */
44347752Swilliam         if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
44447752Swilliam                 return(EINVAL);
44547752Swilliam         /* and copy to tty */
44647752Swilliam         tp->t_ispeed = t->c_ispeed;
44747752Swilliam         tp->t_ospeed = t->c_ospeed;
44847752Swilliam         tp->t_cflag = cflag;
44947752Swilliam 
45047752Swilliam 	com = com_addr[unit];
45147752Swilliam 	outb(com+com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS /*| IER_EMSC*/);
45247752Swilliam 	if (ospeed == 0) {
45347752Swilliam 		(void) commctl(unit, 0, DMSET);	/* hang up line */
45447752Swilliam 		return(0);
45547752Swilliam 	}
45647752Swilliam 	outb(com+com_cfcr, inb(com+com_cfcr) | CFCR_DLAB);
45747752Swilliam 	outb(com+com_data, ospeed & 0xFF);
45847752Swilliam 	outb(com+com_ier, ospeed >> 8);
45947752Swilliam 	switch (cflag&CSIZE) {
46047752Swilliam 	case CS5:
46147752Swilliam 		cfcr = CFCR_5BITS; break;
46247752Swilliam 	case CS6:
46347752Swilliam 		cfcr = CFCR_6BITS; break;
46447752Swilliam 	case CS7:
46547752Swilliam 		cfcr = CFCR_7BITS; break;
46647752Swilliam 	case CS8:
46747752Swilliam 		cfcr = CFCR_8BITS; break;
46847752Swilliam 	}
46947752Swilliam 	if (cflag&PARENB) {
47047752Swilliam 		cfcr |= CFCR_PENAB;
47147752Swilliam 		if ((cflag&PARODD) == 0)
47247752Swilliam 			cfcr |= CFCR_PEVEN;
47347752Swilliam 	}
47447752Swilliam 	if (cflag&CSTOPB)
47547752Swilliam 		cfcr |= CFCR_STOPB;
47647752Swilliam 	outb(com+com_cfcr, cfcr);
477*49570Swilliam 
478*49570Swilliam 	if (com_hasfifo & (1 << unit))
479*49570Swilliam 		outb(com+com_fifo, FIFO_ENABLE | FIFO_TRIGGER_14);
480*49570Swilliam 
48147752Swilliam 	return(0);
48247752Swilliam }
48347752Swilliam 
48447752Swilliam comstart(tp)
48547752Swilliam 	register struct tty *tp;
48647752Swilliam {
48747752Swilliam 	register com;
48847752Swilliam 	int s, unit, c;
48947752Swilliam 
49047752Swilliam 	unit = UNIT(tp->t_dev);
49147752Swilliam 	com = com_addr[unit];
49247752Swilliam 	s = spltty();
49347752Swilliam 	if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
49447752Swilliam 		goto out;
49547752Swilliam 	if (tp->t_outq.c_cc <= tp->t_lowat) {
49647752Swilliam 		if (tp->t_state&TS_ASLEEP) {
49747752Swilliam 			tp->t_state &= ~TS_ASLEEP;
49847752Swilliam 			wakeup((caddr_t)&tp->t_outq);
49947752Swilliam 		}
50047752Swilliam 		if (tp->t_wsel) {
50147752Swilliam 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
50247752Swilliam 			tp->t_wsel = 0;
50347752Swilliam 			tp->t_state &= ~TS_WCOLL;
50447752Swilliam 		}
50547752Swilliam 	}
50647752Swilliam 	if (tp->t_outq.c_cc == 0)
50747752Swilliam 		goto out;
50847752Swilliam 	if (inb(com+com_lsr) & LSR_TXRDY) {
50947752Swilliam 		c = getc(&tp->t_outq);
51047752Swilliam 		tp->t_state |= TS_BUSY;
51147752Swilliam 		outb(com+com_data, c);
512*49570Swilliam 		if (com_hasfifo & (1 << unit))
513*49570Swilliam 			for (c = 1; c < 16 && tp->t_outq.c_cc; ++c)
514*49570Swilliam 				outb(com+com_data, getc(&tp->t_outq));
51547752Swilliam 	}
51647752Swilliam out:
51747752Swilliam 	splx(s);
51847752Swilliam }
51947752Swilliam 
52047752Swilliam /*
52147752Swilliam  * Stop output on a line.
52247752Swilliam  */
52347752Swilliam /*ARGSUSED*/
52447752Swilliam comstop(tp, flag)
52547752Swilliam 	register struct tty *tp;
52647752Swilliam {
52747752Swilliam 	register int s;
52847752Swilliam 
52947752Swilliam 	s = spltty();
53047752Swilliam 	if (tp->t_state & TS_BUSY) {
53147752Swilliam 		if ((tp->t_state&TS_TTSTOP)==0)
53247752Swilliam 			tp->t_state |= TS_FLUSH;
53347752Swilliam 	}
53447752Swilliam 	splx(s);
53547752Swilliam }
53647752Swilliam 
53747752Swilliam commctl(dev, bits, how)
53847752Swilliam 	dev_t dev;
53947752Swilliam 	int bits, how;
54047752Swilliam {
54147752Swilliam 	register com;
54247752Swilliam 	register int unit;
54347752Swilliam 	int s;
54447752Swilliam 
54547752Swilliam 	unit = UNIT(dev);
54647752Swilliam 	com = com_addr[unit];
54747752Swilliam 	s = spltty();
54847752Swilliam 	switch (how) {
54947752Swilliam 
55047752Swilliam 	case DMSET:
55147752Swilliam 		outb(com+com_mcr, bits | MCR_IENABLE);
55247752Swilliam 		break;
55347752Swilliam 
55447752Swilliam 	case DMBIS:
55547752Swilliam 		outb(com+com_mcr, inb(com+com_mcr) | bits | MCR_IENABLE);
55647752Swilliam 		break;
55747752Swilliam 
55847752Swilliam 	case DMBIC:
55947752Swilliam 		outb(com+com_mcr, inb(com+com_mcr) & ~bits | MCR_IENABLE);
56047752Swilliam 		break;
56147752Swilliam 
56247752Swilliam 	case DMGET:
56347752Swilliam 		bits = inb(com+com_msr);
56447752Swilliam 		break;
56547752Swilliam 	}
56647752Swilliam 	(void) splx(s);
56747752Swilliam 	return(bits);
56847752Swilliam }
569*49570Swilliam 
570*49570Swilliam /*
571*49570Swilliam  * Following are all routines needed for COM to act as console
572*49570Swilliam  */
573*49570Swilliam #include "i386/i386/cons.h"
574*49570Swilliam 
575*49570Swilliam comcnprobe(cp)
576*49570Swilliam 	struct consdev *cp;
577*49570Swilliam {
578*49570Swilliam 	int unit;
579*49570Swilliam 	extern int comopen();
580*49570Swilliam 
581*49570Swilliam 	/* locate the major number */
582*49570Swilliam 	for (commajor = 0; commajor < nchrdev; commajor++)
583*49570Swilliam 		if (cdevsw[commajor].d_open == comopen)
584*49570Swilliam 			break;
585*49570Swilliam 
586*49570Swilliam 	/* XXX: ick */
587*49570Swilliam 	unit = CONUNIT;
588*49570Swilliam 	com_addr[CONUNIT] = CONADDR;
589*49570Swilliam 
590*49570Swilliam 	/* make sure hardware exists?  XXX */
591*49570Swilliam 
592*49570Swilliam 	/* initialize required fields */
593*49570Swilliam 	cp->cn_dev = makedev(commajor, unit);
594*49570Swilliam 	cp->cn_tp = &com_tty[unit];
595*49570Swilliam #ifdef	COMCONSOLE
596*49570Swilliam 	cp->cn_pri = CN_REMOTE;		/* Force a serial port console */
597*49570Swilliam #else
598*49570Swilliam 	cp->cn_pri = CN_NORMAL;
59947752Swilliam #endif
600*49570Swilliam }
601*49570Swilliam 
602*49570Swilliam comcninit(cp)
603*49570Swilliam 	struct consdev *cp;
604*49570Swilliam {
605*49570Swilliam 	int unit = UNIT(cp->cn_dev);
606*49570Swilliam 
607*49570Swilliam 	cominit(unit, comdefaultrate);
608*49570Swilliam 	comconsole = unit;
609*49570Swilliam 	comconsinit = 1;
610*49570Swilliam }
611*49570Swilliam 
612*49570Swilliam cominit(unit, rate)
613*49570Swilliam 	int unit, rate;
614*49570Swilliam {
615*49570Swilliam 	register int com;
616*49570Swilliam 	int s;
617*49570Swilliam 	short stat;
618*49570Swilliam 
619*49570Swilliam #ifdef lint
620*49570Swilliam 	stat = unit; if (stat) return;
621*49570Swilliam #endif
622*49570Swilliam 	com = com_addr[unit];
623*49570Swilliam 	s = splhigh();
624*49570Swilliam 	outb(com+com_cfcr, CFCR_DLAB);
625*49570Swilliam 	rate = ttspeedtab(comdefaultrate, comspeedtab);
626*49570Swilliam 	outb(com+com_data, rate & 0xFF);
627*49570Swilliam 	outb(com+com_ier, rate >> 8);
628*49570Swilliam 	outb(com+com_cfcr, CFCR_8BITS);
629*49570Swilliam 	outb(com+com_ier, IER_ERXRDY | IER_ETXRDY);
630*49570Swilliam 	outb(com+com_fifo, FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14);
631*49570Swilliam 	stat = inb(com+com_iir);
632*49570Swilliam 	splx(s);
633*49570Swilliam }
634*49570Swilliam 
635*49570Swilliam comcngetc(dev)
636*49570Swilliam {
637*49570Swilliam 	register com = com_addr[UNIT(dev)];
638*49570Swilliam 	short stat;
639*49570Swilliam 	int c, s;
640*49570Swilliam 
641*49570Swilliam #ifdef lint
642*49570Swilliam 	stat = dev; if (stat) return(0);
643*49570Swilliam #endif
644*49570Swilliam 	s = splhigh();
645*49570Swilliam 	while (((stat = inb(com+com_lsr)) & LSR_RXRDY) == 0)
646*49570Swilliam 		;
647*49570Swilliam 	c = inb(com+com_data);
648*49570Swilliam 	stat = inb(com+com_iir);
649*49570Swilliam 	splx(s);
650*49570Swilliam 	return(c);
651*49570Swilliam }
652*49570Swilliam 
653*49570Swilliam /*
654*49570Swilliam  * Console kernel output character routine.
655*49570Swilliam  */
656*49570Swilliam comcnputc(dev, c)
657*49570Swilliam 	dev_t dev;
658*49570Swilliam 	register int c;
659*49570Swilliam {
660*49570Swilliam 	register com = com_addr[UNIT(dev)];
661*49570Swilliam 	register int timo;
662*49570Swilliam 	short stat;
663*49570Swilliam 	int s = splhigh();
664*49570Swilliam 
665*49570Swilliam #ifdef lint
666*49570Swilliam 	stat = dev; if (stat) return;
667*49570Swilliam #endif
668*49570Swilliam #ifdef KGDB
669*49570Swilliam 	if (dev != kgdb_dev)
670*49570Swilliam #endif
671*49570Swilliam 	if (comconsinit == 0) {
672*49570Swilliam 		(void) cominit(UNIT(dev), comdefaultrate);
673*49570Swilliam 		comconsinit = 1;
674*49570Swilliam 	}
675*49570Swilliam 	/* wait for any pending transmission to finish */
676*49570Swilliam 	timo = 50000;
677*49570Swilliam 	while (((stat = inb(com+com_lsr)) & LSR_TXRDY) == 0 && --timo)
678*49570Swilliam 		;
679*49570Swilliam 	outb(com+com_data, c);
680*49570Swilliam 	/* wait for this transmission to complete */
681*49570Swilliam 	timo = 1500000;
682*49570Swilliam 	while (((stat = inb(com+com_lsr)) & LSR_TXRDY) == 0 && --timo)
683*49570Swilliam 		;
684*49570Swilliam 	/* clear any interrupts generated by this transmission */
685*49570Swilliam 	stat = inb(com+com_iir);
686*49570Swilliam 	splx(s);
687*49570Swilliam }
688*49570Swilliam #endif
689